1 2/* /web/static/src/module_loader.js */ 3(function(odoo){"use strict";if(odoo.loader){return;} 4class ModuleLoader{bus=new EventTarget();checkErrorProm=null;factories=new Map();failed=new Set();jobs=new Set();modules=new Map();constructor(root){this.root=root;const strDebug=new URLSearchParams(location.search).get("debug");this.debug=Boolean(strDebug&&strDebug!=="0");} 5addJob(name){this.jobs.add(name);this.startModules();} 6define(name,deps,factory,lazy=false){if(typeof name!=="string"){throw new Error(`Module name should be a string, got: ${String(name)}`);} 7if(!Array.isArray(deps)){throw new Error(`Module dependencies should be a list of strings, got: ${String(deps)}`);} 8if(typeof factory!=="function"){throw new Error(`Module factory should be a function, got: ${String(factory)}`);} 9if(this.factories.has(name)){return;} 10this.factories.set(name,{deps,fn:factory,ignoreMissingDeps:globalThis.__odooIgnoreMissingDependencies,});if(!lazy){this.addJob(name);this.checkErrorProm||=Promise.resolve().then(()=>{this.checkErrorProm=null;this.reportErrors(this.findErrors());});}} 11findErrors(moduleNames){const findCycle=(currentModuleNames,visited)=>{for(const name of currentModuleNames||[]){if(visited.has(name)){const cycleModuleNames=[...visited,name];return cycleModuleNames.slice(cycleModuleNames.indexOf(name)).map((j)=>`"${j}"`).join(" => ");} 12const cycle=findCycle(dependencyGraph[name],new Set(visited).add(name));if(cycle){return cycle;}} 13return null;};moduleNames||=this.jobs;const dependencyGraph=Object.create(null);const missing=new Set();const unloaded=new Set();for(const moduleName of moduleNames){const{deps,ignoreMissingDeps}=this.factories.get(moduleName);dependencyGraph[moduleName]=deps;if(ignoreMissingDeps){continue;} 14unloaded.add(moduleName);for(const dep of deps){if(!this.factories.has(dep)){missing.add(dep);}}} 15const cycle=findCycle(moduleNames,new Set());const errors={};if(cycle){errors.cycle=cycle;} 16if(this.failed.size){errors.failed=this.failed;} 17if(missing.size){errors.missing=missing;} 18if(unloaded.size){errors.unloaded=unloaded;} 19return errors;} 20findJob(){for(const job of this.jobs){if(this.factories.get(job).deps.every((dep)=>this.modules.has(dep))){return job;}} 21return null;} 22async reportErrors(errors){if(!Object.keys(errors).length){return;} 23if(errors.failed){console.error("The following modules failed to load because of an error:",[...errors.failed,]);} 24if(errors.missing){console.error("The following modules are needed by other modules but have not been defined, they may not be present in the correct asset bundle:",[...errors.missing]);} 25if(errors.cycle){console.error("The following modules could not be loaded because they form a dependency cycle:",errors.cycle);} 26if(errors.unloaded){console.error("The following modules could not be loaded because they have unmet dependencies, this is a secondary error which is likely caused by one of the above problems:",[...errors.unloaded]);} 27const document=this.root?.ownerDocument||globalThis.document;if(document.readyState==="loading"){await new Promise((resolve)=>document.addEventListener("DOMContentLoaded",resolve));} 28if(this.debug){const style=document.createElement("style");style.className="o_module_error_banner";style.textContent=` 29 body::before { 30 font-weight: bold; 31 content: "An error occurred while loading javascript modules, you may find more information in the devtools console"; 32 position: fixed; 33 left: 0; 34 bottom: 0; 35 z-index: 100000000000; 36 background-color: #C00; 37 color: #DDD; 38 } 39 `;document.head.appendChild(style);}} 40startModules(){let job;while((job=this.findJob())){this.startModule(job);}} 41startModule(name){const require=(dependency)=>this.modules.get(dependency);this.jobs.delete(name);const factory=this.factories.get(name);let module=null;try{module=factory.fn(require);}catch(error){this.failed.add(name);throw new Error(`Error while loading "${name}":\n${error}`);} 42this.modules.set(name,module);this.bus.dispatchEvent(new CustomEvent("module-started",{detail:{moduleName:name,module},}));return module;}} 43const loader=new ModuleLoader();odoo.define=loader.define.bind(loader);odoo.loader=loader;if(odoo.debug&&!loader.debug){odoo.debug="";}})((globalThis.odoo||={}));; 44 45/* /web/static/lib/luxon/luxon.js */ 46var luxon=(function(exports){'use strict';function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,_toPropertyKey(descriptor.key),descriptor);}} 47function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);Object.defineProperty(Constructor,"prototype",{writable:false});return Constructor;} 48function _extends(){_extends=Object.assign?Object.assign.bind():function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}} 49return target;};return _extends.apply(this,arguments);} 50function _inheritsLoose(subClass,superClass){subClass.prototype=Object.create(superClass.prototype);subClass.prototype.constructor=subClass;_setPrototypeOf(subClass,superClass);}
vendor: 8,575 bytes, lines 51-80
51function _getPrototypeOf(o){_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf.bind():function _getPrototypeOf(o){return o.__proto__||Object.getPrototypeOf(o);};return _getPrototypeOf(o);} 52function _setPrototypeOf(o,p){_setPrototypeOf=Object.setPrototypeOf?Object.setPrototypeOf.bind():function _setPrototypeOf(o,p){o.__proto__=p;return o;};return _setPrototypeOf(o,p);} 53function _isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}));return true;}catch(e){return false;}} 54function _construct(Parent,args,Class){if(_isNativeReflectConstruct()){_construct=Reflect.construct.bind();}else{_construct=function _construct(Parent,args,Class){var a=[null];a.push.apply(a,args);var Constructor=Function.bind.apply(Parent,a);var instance=new Constructor();if(Class)_setPrototypeOf(instance,Class.prototype);return instance;};} 55return _construct.apply(null,arguments);} 56function _isNativeFunction(fn){return Function.toString.call(fn).indexOf("[native code]")!==-1;} 57function _wrapNativeSuper(Class){var _cache=typeof Map==="function"?new Map():undefined;_wrapNativeSuper=function _wrapNativeSuper(Class){if(Class===null||!_isNativeFunction(Class))return Class;if(typeof Class!=="function"){throw new TypeError("Super expression must either be null or a function");} 58if(typeof _cache!=="undefined"){if(_cache.has(Class))return _cache.get(Class);_cache.set(Class,Wrapper);} 59function Wrapper(){return _construct(Class,arguments,_getPrototypeOf(this).constructor);} 60Wrapper.prototype=Object.create(Class.prototype,{constructor:{value:Wrapper,enumerable:false,writable:true,configurable:true}});return _setPrototypeOf(Wrapper,Class);};return _wrapNativeSuper(Class);} 61function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];} 62return target;} 63function _unsupportedIterableToArray(o,minLen){if(!o)return;if(typeof o==="string")return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(o);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen);} 64function _arrayLikeToArray(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2;} 65function _createForOfIteratorHelperLoose(o,allowArrayLike){var it=typeof Symbol!=="undefined"&&o[Symbol.iterator]||o["@@iterator"];if(it)return(it=it.call(o)).next.bind(it);if(Array.isArray(o)||(it=_unsupportedIterableToArray(o))||allowArrayLike&&o&&typeof o.length==="number"){if(it)o=it;var i=0;return function(){if(i>=o.length)return{done:true};return{done:false,value:o[i++]};};} 66throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");} 67function _toPrimitive(input,hint){if(typeof input!=="object"||input===null)return input;var prim=input[Symbol.toPrimitive];if(prim!==undefined){var res=prim.call(input,hint||"default");if(typeof res!=="object")return res;throw new TypeError("@@toPrimitive must return a primitive value.");} 68return(hint==="string"?String:Number)(input);} 69function _toPropertyKey(arg){var key=_toPrimitive(arg,"string");return typeof key==="symbol"?key:String(key);} 70var LuxonError=function(_Error){_inheritsLoose(LuxonError,_Error);function LuxonError(){return _Error.apply(this,arguments)||this;} 71return LuxonError;}(_wrapNativeSuper(Error));var InvalidDateTimeError=function(_LuxonError){_inheritsLoose(InvalidDateTimeError,_LuxonError);function InvalidDateTimeError(reason){return _LuxonError.call(this,"Invalid DateTime: "+reason.toMessage())||this;} 72return InvalidDateTimeError;}(LuxonError);var InvalidIntervalError=function(_LuxonError2){_inheritsLoose(InvalidIntervalError,_LuxonError2);function InvalidIntervalError(reason){return _LuxonError2.call(this,"Invalid Interval: "+reason.toMessage())||this;} 73return InvalidIntervalError;}(LuxonError);var InvalidDurationError=function(_LuxonError3){_inheritsLoose(InvalidDurationError,_LuxonError3);function InvalidDurationError(reason){return _LuxonError3.call(this,"Invalid Duration: "+reason.toMessage())||this;} 74return InvalidDurationError;}(LuxonError);var ConflictingSpecificationError=function(_LuxonError4){_inheritsLoose(ConflictingSpecificationError,_LuxonError4);function ConflictingSpecificationError(){return _LuxonError4.apply(this,arguments)||this;} 75return ConflictingSpecificationError;}(LuxonError);var InvalidUnitError=function(_LuxonError5){_inheritsLoose(InvalidUnitError,_LuxonError5);function InvalidUnitError(unit){return _LuxonError5.call(this,"Invalid unit "+unit)||this;} 76return InvalidUnitError;}(LuxonError);var InvalidArgumentError=function(_LuxonError6){_inheritsLoose(InvalidArgumentError,_LuxonError6);function InvalidArgumentError(){return _LuxonError6.apply(this,arguments)||this;} 77return InvalidArgumentError;}(LuxonError);var ZoneIsAbstractError=function(_LuxonError7){_inheritsLoose(ZoneIsAbstractError,_LuxonError7);function ZoneIsAbstractError(){return _LuxonError7.call(this,"Zone is an abstract class")||this;} 78return ZoneIsAbstractError;}(LuxonError);var n="numeric",s="short",l="long";var DATE_SHORT={year:n,month:n,day:n};var DATE_MED={year:n,month:s,day:n};var DATE_MED_WITH_WEEKDAY={year:n,month:s,day:n,weekday:s};var DATE_FULL={year:n,month:l,day:n};var DATE_HUGE={year:n,month:l,day:n,weekday:l};var TIME_SIMPLE={hour:n,minute:n};var TIME_WITH_SECONDS={hour:n,minute:n,second:n};var TIME_WITH_SHORT_OFFSET={hour:n,minute:n,second:n,timeZoneName:s};var TIME_WITH_LONG_OFFSET={hour:n,minute:n,second:n,timeZoneName:l};var TIME_24_SIMPLE={hour:n,minute:n,hourCycle:"h23"};var TIME_24_WITH_SECONDS={hour:n,minute:n,second:n,hourCycle:"h23"};var TIME_24_WITH_SHORT_OFFSET={hour:n,minute:n,second:n,hourCycle:"h23",timeZoneName:s};var TIME_24_WITH_LONG_OFFSET={hour:n,minute:n,second:n,hourCycle:"h23",timeZoneName:l};var DATETIME_SHORT={year:n,month:n,day:n,hour:n,minute:n};var DATETIME_SHORT_WITH_SECONDS={year:n,month:n,day:n,hour:n,minute:n,second:n};var DATETIME_MED={year:n,month:s,day:n,hour:n,minute:n};var DATETIME_MED_WITH_SECONDS={year:n,month:s,day:n,hour:n,minute:n,second:n};var DATETIME_MED_WITH_WEEKDAY={year:n,month:s,day:n,weekday:s,hour:n,minute:n};var DATETIME_FULL={year:n,month:l,day:n,hour:n,minute:n,timeZoneName:s};var DATETIME_FULL_WITH_SECONDS={year:n,month:l,day:n,hour:n,minute:n,second:n,timeZoneName:s};var DATETIME_HUGE={year:n,month:l,day:n,weekday:l,hour:n,minute:n,timeZoneName:l};var DATETIME_HUGE_WITH_SECONDS={year:n,month:l,day:n,weekday:l,hour:n,minute:n,second:n,timeZoneName:l};var Zone=function(){function Zone(){} 79var _proto=Zone.prototype;_proto.offsetName=function offsetName(ts,opts){throw new ZoneIsAbstractError();};_proto.formatOffset=function formatOffset(ts,format){throw new ZoneIsAbstractError();};_proto.offset=function offset(ts){throw new ZoneIsAbstractError();};_proto.equals=function equals(otherZone){throw new ZoneIsAbstractError();};_createClass(Zone,[{key:"type",get:function get(){throw new ZoneIsAbstractError();}},{key:"name",get:function get(){throw new ZoneIsAbstractError();}},{key:"ianaName",get:function get(){return this.name;}},{key:"isUniversal",get:function get(){throw new ZoneIsAbstractError();}},{key:"isValid",get:function get(){throw new ZoneIsAbstractError();}}]);return Zone;}();var singleton$1=null;var SystemZone=function(_Zone){_inheritsLoose(SystemZone,_Zone);function SystemZone(){return _Zone.apply(this,arguments)||this;} 80var _proto=SystemZone.prototype;_proto.offsetName=function offsetName(ts,_ref){var format=_ref.format,locale=_ref.locale;return parseZoneInfo(ts,format,locale);};_proto.formatOffset=function formatOffset$1(ts,format){return formatOffset(this.offset(ts),format);};_proto.offset=function offset(ts){return-new Date(ts).getTimezoneOffset();};_proto.equals=function equals(otherZone){return otherZone.type==="system";};_createClass(SystemZone,[{key:"type",get:function get(){return"system";}},{key:"name",get:function get(){return new Intl.DateTimeFormat().resolvedOptions().timeZone;}},{key:"isUniversal",get:function get(){return false;}},{key:"isValid",get:function get(){return true;}}
vendor: 4,582 bytes, lines 80-104
80],[{key:"instance",get:function get(){if(singleton$1===null){singleton$1=new SystemZone();} 81return singleton$1;}}]);return SystemZone;}(Zone);var dtfCache={};function makeDTF(zone){if(!dtfCache[zone]){dtfCache[zone]=new Intl.DateTimeFormat("en-US",{hour12:false,timeZone:zone,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",era:"short"});} 82return dtfCache[zone];} 83var typeToPos={year:0,month:1,day:2,era:3,hour:4,minute:5,second:6};function hackyOffset(dtf,date){var formatted=dtf.format(date).replace(/\u200E/g,""),parsed=/(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),fMonth=parsed[1],fDay=parsed[2],fYear=parsed[3],fadOrBc=parsed[4],fHour=parsed[5],fMinute=parsed[6],fSecond=parsed[7];return[fYear,fMonth,fDay,fadOrBc,fHour,fMinute,fSecond];} 84function partsOffset(dtf,date){var formatted=dtf.formatToParts(date);var filled=[];for(var i=0;i<formatted.length;i++){var _formatted$i=formatted[i],type=_formatted$i.type,value=_formatted$i.value;var pos=typeToPos[type];if(type==="era"){filled[pos]=value;}else if(!isUndefined(pos)){filled[pos]=parseInt(value,10);}} 85return filled;} 86var ianaZoneCache={};var IANAZone=function(_Zone){_inheritsLoose(IANAZone,_Zone);IANAZone.create=function create(name){if(!ianaZoneCache[name]){ianaZoneCache[name]=new IANAZone(name);} 87return ianaZoneCache[name];};IANAZone.resetCache=function resetCache(){ianaZoneCache={};dtfCache={};};IANAZone.isValidSpecifier=function isValidSpecifier(s){return this.isValidZone(s);};IANAZone.isValidZone=function isValidZone(zone){if(!zone){return false;} 88try{new Intl.DateTimeFormat("en-US",{timeZone:zone}).format();return true;}catch(e){return false;}};function IANAZone(name){var _this;_this=_Zone.call(this)||this;_this.zoneName=name;_this.valid=IANAZone.isValidZone(name);return _this;} 89var _proto=IANAZone.prototype;_proto.offsetName=function offsetName(ts,_ref){var format=_ref.format,locale=_ref.locale;return parseZoneInfo(ts,format,locale,this.name);};_proto.formatOffset=function formatOffset$1(ts,format){return formatOffset(this.offset(ts),format);};_proto.offset=function offset(ts){var date=new Date(ts);if(isNaN(date))return NaN;var dtf=makeDTF(this.name);var _ref2=dtf.formatToParts?partsOffset(dtf,date):hackyOffset(dtf,date),year=_ref2[0],month=_ref2[1],day=_ref2[2],adOrBc=_ref2[3],hour=_ref2[4],minute=_ref2[5],second=_ref2[6];if(adOrBc==="BC"){year=-Math.abs(year)+1;} 90var adjustedHour=hour===24?0:hour;var asUTC=objToLocalTS({year:year,month:month,day:day,hour:adjustedHour,minute:minute,second:second,millisecond:0});var asTS=+date;var over=asTS%1000;asTS-=over>=0?over:1000+over;return(asUTC-asTS)/(60*1000);};_proto.equals=function equals(otherZone){return otherZone.type==="iana"&&otherZone.name===this.name;};_createClass(IANAZone,[{key:"type",get:function get(){return"iana";}},{key:"name",get:function get(){return this.zoneName;}},{key:"isUniversal",get:function get(){return false;}},{key:"isValid",get:function get(){return this.valid;}}]);return IANAZone;}(Zone);var _excluded=["base"],_excluded2=["padTo","floor"];var intlLFCache={};function getCachedLF(locString,opts){if(opts===void 0){opts={};} 91var key=JSON.stringify([locString,opts]);var dtf=intlLFCache[key];if(!dtf){dtf=new Intl.ListFormat(locString,opts);intlLFCache[key]=dtf;} 92return dtf;} 93var intlDTCache={};function getCachedDTF(locString,opts){if(opts===void 0){opts={};} 94var key=JSON.stringify([locString,opts]);var dtf=intlDTCache[key];if(!dtf){dtf=new Intl.DateTimeFormat(locString,opts);intlDTCache[key]=dtf;} 95return dtf;} 96var intlNumCache={};function getCachedINF(locString,opts){if(opts===void 0){opts={};} 97var key=JSON.stringify([locString,opts]);var inf=intlNumCache[key];if(!inf){inf=new Intl.NumberFormat(locString,opts);intlNumCache[key]=inf;} 98return inf;} 99var intlRelCache={};function getCachedRTF(locString,opts){if(opts===void 0){opts={};} 100var _opts=opts;_opts.base;var cacheKeyOpts=_objectWithoutPropertiesLoose(_opts,_excluded);var key=JSON.stringify([locString,cacheKeyOpts]);var inf=intlRelCache[key];if(!inf){inf=new Intl.RelativeTimeFormat(locString,opts);intlRelCache[key]=inf;} 101return inf;} 102var sysLocaleCache=null;function systemLocale(){if(sysLocaleCache){return sysLocaleCache;}else{sysLocaleCache=new Intl.DateTimeFormat().resolvedOptions().locale;return sysLocaleCache;}} 103var weekInfoCache={};function getCachedWeekInfo(locString){var data=weekInfoCache[locString];if(!data){var locale=new Intl.Locale(locString);data="getWeekInfo"in locale?locale.getWeekInfo():locale.weekInfo;weekInfoCache[locString]=data;} 104return data;}
vendor: 37,543 bytes, lines 105-246
105function parseLocaleString(localeStr){var xIndex=localeStr.indexOf("-x-");if(xIndex!==-1){localeStr=localeStr.substring(0,xIndex);} 106var uIndex=localeStr.indexOf("-u-");if(uIndex===-1){return[localeStr];}else{var options;var selectedStr;try{options=getCachedDTF(localeStr).resolvedOptions();selectedStr=localeStr;}catch(e){var smaller=localeStr.substring(0,uIndex);options=getCachedDTF(smaller).resolvedOptions();selectedStr=smaller;} 107var _options=options,numberingSystem=_options.numberingSystem,calendar=_options.calendar;return[selectedStr,numberingSystem,calendar];}} 108function intlConfigString(localeStr,numberingSystem,outputCalendar){if(outputCalendar||numberingSystem){if(!localeStr.includes("-u-")){localeStr+="-u";} 109if(outputCalendar){localeStr+="-ca-"+outputCalendar;} 110if(numberingSystem){localeStr+="-nu-"+numberingSystem;} 111return localeStr;}else{return localeStr;}} 112function mapMonths(f){var ms=[];for(var i=1;i<=12;i++){var dt=DateTime.utc(2009,i,1);ms.push(f(dt));} 113return ms;} 114function mapWeekdays(f){var ms=[];for(var i=1;i<=7;i++){var dt=DateTime.utc(2016,11,13+i);ms.push(f(dt));} 115return ms;} 116function listStuff(loc,length,englishFn,intlFn){var mode=loc.listingMode();if(mode==="error"){return null;}else if(mode==="en"){return englishFn(length);}else{return intlFn(length);}} 117function supportsFastNumbers(loc){if(loc.numberingSystem&&loc.numberingSystem!=="latn"){return false;}else{return loc.numberingSystem==="latn"||!loc.locale||loc.locale.startsWith("en")||new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem==="latn";}} 118var PolyNumberFormatter=function(){function PolyNumberFormatter(intl,forceSimple,opts){this.padTo=opts.padTo||0;this.floor=opts.floor||false;opts.padTo;opts.floor;var otherOpts=_objectWithoutPropertiesLoose(opts,_excluded2);if(!forceSimple||Object.keys(otherOpts).length>0){var intlOpts=_extends({useGrouping:false},opts);if(opts.padTo>0)intlOpts.minimumIntegerDigits=opts.padTo;this.inf=getCachedINF(intl,intlOpts);}} 119var _proto=PolyNumberFormatter.prototype;_proto.format=function format(i){if(this.inf){var fixed=this.floor?Math.floor(i):i;return this.inf.format(fixed);}else{var _fixed=this.floor?Math.floor(i):roundTo(i,3);return padStart(_fixed,this.padTo);}};return PolyNumberFormatter;}();var PolyDateFormatter=function(){function PolyDateFormatter(dt,intl,opts){this.opts=opts;this.originalZone=undefined;var z=undefined;if(this.opts.timeZone){this.dt=dt;}else if(dt.zone.type==="fixed"){var gmtOffset=-1*(dt.offset/60);var offsetZ=gmtOffset>=0?"Etc/GMT+"+gmtOffset:"Etc/GMT"+gmtOffset;if(dt.offset!==0&&IANAZone.create(offsetZ).valid){z=offsetZ;this.dt=dt;}else{z="UTC";this.dt=dt.offset===0?dt:dt.setZone("UTC").plus({minutes:dt.offset});this.originalZone=dt.zone;}}else if(dt.zone.type==="system"){this.dt=dt;}else if(dt.zone.type==="iana"){this.dt=dt;z=dt.zone.name;}else{z="UTC";this.dt=dt.setZone("UTC").plus({minutes:dt.offset});this.originalZone=dt.zone;} 120var intlOpts=_extends({},this.opts);intlOpts.timeZone=intlOpts.timeZone||z;this.dtf=getCachedDTF(intl,intlOpts);} 121var _proto2=PolyDateFormatter.prototype;_proto2.format=function format(){if(this.originalZone){return this.formatToParts().map(function(_ref){var value=_ref.value;return value;}).join("");} 122return this.dtf.format(this.dt.toJSDate());};_proto2.formatToParts=function formatToParts(){var _this=this;var parts=this.dtf.formatToParts(this.dt.toJSDate());if(this.originalZone){return parts.map(function(part){if(part.type==="timeZoneName"){var offsetName=_this.originalZone.offsetName(_this.dt.ts,{locale:_this.dt.locale,format:_this.opts.timeZoneName});return _extends({},part,{value:offsetName});}else{return part;}});} 123return parts;};_proto2.resolvedOptions=function resolvedOptions(){return this.dtf.resolvedOptions();};return PolyDateFormatter;}();var PolyRelFormatter=function(){function PolyRelFormatter(intl,isEnglish,opts){this.opts=_extends({style:"long"},opts);if(!isEnglish&&hasRelative()){this.rtf=getCachedRTF(intl,opts);}} 124var _proto3=PolyRelFormatter.prototype;_proto3.format=function format(count,unit){if(this.rtf){return this.rtf.format(count,unit);}else{return formatRelativeTime(unit,count,this.opts.numeric,this.opts.style!=="long");}};_proto3.formatToParts=function formatToParts(count,unit){if(this.rtf){return this.rtf.formatToParts(count,unit);}else{return[];}};return PolyRelFormatter;}();var fallbackWeekSettings={firstDay:1,minimalDays:4,weekend:[6,7]};var Locale=function(){Locale.fromOpts=function fromOpts(opts){return Locale.create(opts.locale,opts.numberingSystem,opts.outputCalendar,opts.weekSettings,opts.defaultToEN);};Locale.create=function create(locale,numberingSystem,outputCalendar,weekSettings,defaultToEN){if(defaultToEN===void 0){defaultToEN=false;} 125var specifiedLocale=locale||Settings.defaultLocale;var localeR=specifiedLocale||(defaultToEN?"en-US":systemLocale());var numberingSystemR=numberingSystem||Settings.defaultNumberingSystem;var outputCalendarR=outputCalendar||Settings.defaultOutputCalendar;var weekSettingsR=validateWeekSettings(weekSettings)||Settings.defaultWeekSettings;return new Locale(localeR,numberingSystemR,outputCalendarR,weekSettingsR,specifiedLocale);};Locale.resetCache=function resetCache(){sysLocaleCache=null;intlDTCache={};intlNumCache={};intlRelCache={};};Locale.fromObject=function fromObject(_temp){var _ref2=_temp===void 0?{}:_temp,locale=_ref2.locale,numberingSystem=_ref2.numberingSystem,outputCalendar=_ref2.outputCalendar,weekSettings=_ref2.weekSettings;return Locale.create(locale,numberingSystem,outputCalendar,weekSettings);};function Locale(locale,numbering,outputCalendar,weekSettings,specifiedLocale){var _parseLocaleString=parseLocaleString(locale),parsedLocale=_parseLocaleString[0],parsedNumberingSystem=_parseLocaleString[1],parsedOutputCalendar=_parseLocaleString[2];this.locale=parsedLocale;this.numberingSystem=numbering||parsedNumberingSystem||null;this.outputCalendar=outputCalendar||parsedOutputCalendar||null;this.weekSettings=weekSettings;this.intl=intlConfigString(this.locale,this.numberingSystem,this.outputCalendar);this.weekdaysCache={format:{},standalone:{}};this.monthsCache={format:{},standalone:{}};this.meridiemCache=null;this.eraCache={};this.specifiedLocale=specifiedLocale;this.fastNumbersCached=null;} 126var _proto4=Locale.prototype;_proto4.listingMode=function listingMode(){var isActuallyEn=this.isEnglish();var hasNoWeirdness=(this.numberingSystem===null||this.numberingSystem==="latn")&&(this.outputCalendar===null||this.outputCalendar==="gregory");return isActuallyEn&&hasNoWeirdness?"en":"intl";};_proto4.clone=function clone(alts){if(!alts||Object.getOwnPropertyNames(alts).length===0){return this;}else{return Locale.create(alts.locale||this.specifiedLocale,alts.numberingSystem||this.numberingSystem,alts.outputCalendar||this.outputCalendar,validateWeekSettings(alts.weekSettings)||this.weekSettings,alts.defaultToEN||false);}};_proto4.redefaultToEN=function redefaultToEN(alts){if(alts===void 0){alts={};} 127return this.clone(_extends({},alts,{defaultToEN:true}));};_proto4.redefaultToSystem=function redefaultToSystem(alts){if(alts===void 0){alts={};} 128return this.clone(_extends({},alts,{defaultToEN:false}));};_proto4.months=function months$1(length,format){var _this2=this;if(format===void 0){format=false;} 129return listStuff(this,length,months,function(){var intl=format?{month:length,day:"numeric"}:{month:length},formatStr=format?"format":"standalone";if(!_this2.monthsCache[formatStr][length]){_this2.monthsCache[formatStr][length]=mapMonths(function(dt){return _this2.extract(dt,intl,"month");});} 130return _this2.monthsCache[formatStr][length];});};_proto4.weekdays=function weekdays$1(length,format){var _this3=this;if(format===void 0){format=false;} 131return listStuff(this,length,weekdays,function(){var intl=format?{weekday:length,year:"numeric",month:"long",day:"numeric"}:{weekday:length},formatStr=format?"format":"standalone";if(!_this3.weekdaysCache[formatStr][length]){_this3.weekdaysCache[formatStr][length]=mapWeekdays(function(dt){return _this3.extract(dt,intl,"weekday");});} 132return _this3.weekdaysCache[formatStr][length];});};_proto4.meridiems=function meridiems$1(){var _this4=this;return listStuff(this,undefined,function(){return meridiems;},function(){if(!_this4.meridiemCache){var intl={hour:"numeric",hourCycle:"h12"};_this4.meridiemCache=[DateTime.utc(2016,11,13,9),DateTime.utc(2016,11,13,19)].map(function(dt){return _this4.extract(dt,intl,"dayperiod");});} 133return _this4.meridiemCache;});};_proto4.eras=function eras$1(length){var _this5=this;return listStuff(this,length,eras,function(){var intl={era:length};if(!_this5.eraCache[length]){_this5.eraCache[length]=[DateTime.utc(-40,1,1),DateTime.utc(2017,1,1)].map(function(dt){return _this5.extract(dt,intl,"era");});} 134return _this5.eraCache[length];});};_proto4.extract=function extract(dt,intlOpts,field){var df=this.dtFormatter(dt,intlOpts),results=df.formatToParts(),matching=results.find(function(m){return m.type.toLowerCase()===field;});return matching?matching.value:null;};_proto4.numberFormatter=function numberFormatter(opts){if(opts===void 0){opts={};} 135return new PolyNumberFormatter(this.intl,opts.forceSimple||this.fastNumbers,opts);};_proto4.dtFormatter=function dtFormatter(dt,intlOpts){if(intlOpts===void 0){intlOpts={};} 136return new PolyDateFormatter(dt,this.intl,intlOpts);};_proto4.relFormatter=function relFormatter(opts){if(opts===void 0){opts={};} 137return new PolyRelFormatter(this.intl,this.isEnglish(),opts);};_proto4.listFormatter=function listFormatter(opts){if(opts===void 0){opts={};} 138return getCachedLF(this.intl,opts);};_proto4.isEnglish=function isEnglish(){return this.locale==="en"||this.locale.toLowerCase()==="en-us"||new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us");};_proto4.getWeekSettings=function getWeekSettings(){if(this.weekSettings){return this.weekSettings;}else if(!hasLocaleWeekInfo()){return fallbackWeekSettings;}else{return getCachedWeekInfo(this.locale);}};_proto4.getStartOfWeek=function getStartOfWeek(){return this.getWeekSettings().firstDay;};_proto4.getMinDaysInFirstWeek=function getMinDaysInFirstWeek(){return this.getWeekSettings().minimalDays;};_proto4.getWeekendDays=function getWeekendDays(){return this.getWeekSettings().weekend;};_proto4.equals=function equals(other){return this.locale===other.locale&&this.numberingSystem===other.numberingSystem&&this.outputCalendar===other.outputCalendar;};_proto4.toString=function toString(){return"Locale("+this.locale+", "+this.numberingSystem+", "+this.outputCalendar+")";};_createClass(Locale,[{key:"fastNumbers",get:function get(){if(this.fastNumbersCached==null){this.fastNumbersCached=supportsFastNumbers(this);} 139return this.fastNumbersCached;}}]);return Locale;}();var singleton=null;var FixedOffsetZone=function(_Zone){_inheritsLoose(FixedOffsetZone,_Zone);FixedOffsetZone.instance=function instance(offset){return offset===0?FixedOffsetZone.utcInstance:new FixedOffsetZone(offset);};FixedOffsetZone.parseSpecifier=function parseSpecifier(s){if(s){var r=s.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);if(r){return new FixedOffsetZone(signedOffset(r[1],r[2]));}} 140return null;};function FixedOffsetZone(offset){var _this;_this=_Zone.call(this)||this;_this.fixed=offset;return _this;} 141var _proto=FixedOffsetZone.prototype;_proto.offsetName=function offsetName(){return this.name;};_proto.formatOffset=function formatOffset$1(ts,format){return formatOffset(this.fixed,format);};_proto.offset=function offset(){return this.fixed;};_proto.equals=function equals(otherZone){return otherZone.type==="fixed"&&otherZone.fixed===this.fixed;};_createClass(FixedOffsetZone,[{key:"type",get:function get(){return"fixed";}},{key:"name",get:function get(){return this.fixed===0?"UTC":"UTC"+formatOffset(this.fixed,"narrow");}},{key:"ianaName",get:function get(){if(this.fixed===0){return"Etc/UTC";}else{return"Etc/GMT"+formatOffset(-this.fixed,"narrow");}}},{key:"isUniversal",get:function get(){return true;}},{key:"isValid",get:function get(){return true;}}],[{key:"utcInstance",get:function get(){if(singleton===null){singleton=new FixedOffsetZone(0);} 142return singleton;}}]);return FixedOffsetZone;}(Zone);var InvalidZone=function(_Zone){_inheritsLoose(InvalidZone,_Zone);function InvalidZone(zoneName){var _this;_this=_Zone.call(this)||this;_this.zoneName=zoneName;return _this;} 143var _proto=InvalidZone.prototype;_proto.offsetName=function offsetName(){return null;};_proto.formatOffset=function formatOffset(){return"";};_proto.offset=function offset(){return NaN;};_proto.equals=function equals(){return false;};_createClass(InvalidZone,[{key:"type",get:function get(){return"invalid";}},{key:"name",get:function get(){return this.zoneName;}},{key:"isUniversal",get:function get(){return false;}},{key:"isValid",get:function get(){return false;}}]);return InvalidZone;}(Zone);function normalizeZone(input,defaultZone){if(isUndefined(input)||input===null){return defaultZone;}else if(input instanceof Zone){return input;}else if(isString(input)){var lowered=input.toLowerCase();if(lowered==="default")return defaultZone;else if(lowered==="local"||lowered==="system")return SystemZone.instance;else if(lowered==="utc"||lowered==="gmt")return FixedOffsetZone.utcInstance;else return FixedOffsetZone.parseSpecifier(lowered)||IANAZone.create(input);}else if(isNumber(input)){return FixedOffsetZone.instance(input);}else if(typeof input==="object"&&"offset"in input&&typeof input.offset==="function"){return input;}else{return new InvalidZone(input);}} 144var numberingSystems={arab:"[\u0660-\u0669]",arabext:"[\u06F0-\u06F9]",bali:"[\u1B50-\u1B59]",beng:"[\u09E6-\u09EF]",deva:"[\u0966-\u096F]",fullwide:"[\uFF10-\uFF19]",gujr:"[\u0AE6-\u0AEF]",hanidec:"[ã|ä¸|äº|ä¸|å|äº|å |ä¸|å «|ä¹]",khmr:"[\u17E0-\u17E9]",knda:"[\u0CE6-\u0CEF]",laoo:"[\u0ED0-\u0ED9]",limb:"[\u1946-\u194F]",mlym:"[\u0D66-\u0D6F]",mong:"[\u1810-\u1819]",mymr:"[\u1040-\u1049]",orya:"[\u0B66-\u0B6F]",tamldec:"[\u0BE6-\u0BEF]",telu:"[\u0C66-\u0C6F]",thai:"[\u0E50-\u0E59]",tibt:"[\u0F20-\u0F29]",latn:"\\d"};var numberingSystemsUTF16={arab:[1632,1641],arabext:[1776,1785],bali:[6992,7001],beng:[2534,2543],deva:[2406,2415],fullwide:[65296,65303],gujr:[2790,2799],khmr:[6112,6121],knda:[3302,3311],laoo:[3792,3801],limb:[6470,6479],mlym:[3430,3439],mong:[6160,6169],mymr:[4160,4169],orya:[2918,2927],tamldec:[3046,3055],telu:[3174,3183],thai:[3664,3673],tibt:[3872,3881]};var hanidecChars=numberingSystems.hanidec.replace(/[\[|\]]/g,"").split("");function parseDigits(str){var value=parseInt(str,10);if(isNaN(value)){value="";for(var i=0;i<str.length;i++){var code=str.charCodeAt(i);if(str[i].search(numberingSystems.hanidec)!==-1){value+=hanidecChars.indexOf(str[i]);}else{for(var key in numberingSystemsUTF16){var _numberingSystemsUTF=numberingSystemsUTF16[key],min=_numberingSystemsUTF[0],max=_numberingSystemsUTF[1];if(code>=min&&code<=max){value+=code-min;}}}} 145return parseInt(value,10);}else{return value;}} 146var digitRegexCache={};function resetDigitRegexCache(){digitRegexCache={};} 147function digitRegex(_ref,append){var numberingSystem=_ref.numberingSystem;if(append===void 0){append="";} 148var ns=numberingSystem||"latn";if(!digitRegexCache[ns]){digitRegexCache[ns]={};} 149if(!digitRegexCache[ns][append]){digitRegexCache[ns][append]=new RegExp(""+numberingSystems[ns]+append);} 150return digitRegexCache[ns][append];} 151var now=function now(){return Date.now();},defaultZone="system",defaultLocale=null,defaultNumberingSystem=null,defaultOutputCalendar=null,twoDigitCutoffYear=60,throwOnInvalid,defaultWeekSettings=null;var Settings=function(){function Settings(){} 152Settings.resetCaches=function resetCaches(){Locale.resetCache();IANAZone.resetCache();DateTime.resetCache();resetDigitRegexCache();};_createClass(Settings,null,[{key:"now",get:function get(){return now;},set:function set(n){now=n;}},{key:"defaultZone",get:function get(){return normalizeZone(defaultZone,SystemZone.instance);},set:function set(zone){defaultZone=zone;}},{key:"defaultLocale",get:function get(){return defaultLocale;},set:function set(locale){defaultLocale=locale;}},{key:"defaultNumberingSystem",get:function get(){return defaultNumberingSystem;},set:function set(numberingSystem){defaultNumberingSystem=numberingSystem;}},{key:"defaultOutputCalendar",get:function get(){return defaultOutputCalendar;},set:function set(outputCalendar){defaultOutputCalendar=outputCalendar;}},{key:"defaultWeekSettings",get:function get(){return defaultWeekSettings;},set:function set(weekSettings){defaultWeekSettings=validateWeekSettings(weekSettings);}},{key:"twoDigitCutoffYear",get:function get(){return twoDigitCutoffYear;},set:function set(cutoffYear){twoDigitCutoffYear=cutoffYear%100;}},{key:"throwOnInvalid",get:function get(){return throwOnInvalid;},set:function set(t){throwOnInvalid=t;}}]);return Settings;}();var Invalid=function(){function Invalid(reason,explanation){this.reason=reason;this.explanation=explanation;} 153var _proto=Invalid.prototype;_proto.toMessage=function toMessage(){if(this.explanation){return this.reason+": "+this.explanation;}else{return this.reason;}};return Invalid;}();var nonLeapLadder=[0,31,59,90,120,151,181,212,243,273,304,334],leapLadder=[0,31,60,91,121,152,182,213,244,274,305,335];function unitOutOfRange(unit,value){return new Invalid("unit out of range","you specified "+value+" (of type "+typeof value+") as a "+unit+", which is invalid");} 154function dayOfWeek(year,month,day){var d=new Date(Date.UTC(year,month-1,day));if(year<100&&year>=0){d.setUTCFullYear(d.getUTCFullYear()-1900);} 155var js=d.getUTCDay();return js===0?7:js;} 156function computeOrdinal(year,month,day){return day+(isLeapYear(year)?leapLadder:nonLeapLadder)[month-1];} 157function uncomputeOrdinal(year,ordinal){var table=isLeapYear(year)?leapLadder:nonLeapLadder,month0=table.findIndex(function(i){return i<ordinal;}),day=ordinal-table[month0];return{month:month0+1,day:day};} 158function isoWeekdayToLocal(isoWeekday,startOfWeek){return(isoWeekday-startOfWeek+7)%7+1;} 159function gregorianToWeek(gregObj,minDaysInFirstWeek,startOfWeek){if(minDaysInFirstWeek===void 0){minDaysInFirstWeek=4;} 160if(startOfWeek===void 0){startOfWeek=1;} 161var year=gregObj.year,month=gregObj.month,day=gregObj.day,ordinal=computeOrdinal(year,month,day),weekday=isoWeekdayToLocal(dayOfWeek(year,month,day),startOfWeek);var weekNumber=Math.floor((ordinal-weekday+14-minDaysInFirstWeek)/7),weekYear;if(weekNumber<1){weekYear=year-1;weekNumber=weeksInWeekYear(weekYear,minDaysInFirstWeek,startOfWeek);}else if(weekNumber>weeksInWeekYear(year,minDaysInFirstWeek,startOfWeek)){weekYear=year+1;weekNumber=1;}else{weekYear=year;} 162return _extends({weekYear:weekYear,weekNumber:weekNumber,weekday:weekday},timeObject(gregObj));} 163function weekToGregorian(weekData,minDaysInFirstWeek,startOfWeek){if(minDaysInFirstWeek===void 0){minDaysInFirstWeek=4;} 164if(startOfWeek===void 0){startOfWeek=1;} 165var weekYear=weekData.weekYear,weekNumber=weekData.weekNumber,weekday=weekData.weekday,weekdayOfJan4=isoWeekdayToLocal(dayOfWeek(weekYear,1,minDaysInFirstWeek),startOfWeek),yearInDays=daysInYear(weekYear);var ordinal=weekNumber*7+weekday-weekdayOfJan4-7+minDaysInFirstWeek,year;if(ordinal<1){year=weekYear-1;ordinal+=daysInYear(year);}else if(ordinal>yearInDays){year=weekYear+1;ordinal-=daysInYear(weekYear);}else{year=weekYear;} 166var _uncomputeOrdinal=uncomputeOrdinal(year,ordinal),month=_uncomputeOrdinal.month,day=_uncomputeOrdinal.day;return _extends({year:year,month:month,day:day},timeObject(weekData));} 167function gregorianToOrdinal(gregData){var year=gregData.year,month=gregData.month,day=gregData.day;var ordinal=computeOrdinal(year,month,day);return _extends({year:year,ordinal:ordinal},timeObject(gregData));} 168function ordinalToGregorian(ordinalData){var year=ordinalData.year,ordinal=ordinalData.ordinal;var _uncomputeOrdinal2=uncomputeOrdinal(year,ordinal),month=_uncomputeOrdinal2.month,day=_uncomputeOrdinal2.day;return _extends({year:year,month:month,day:day},timeObject(ordinalData));} 169function usesLocalWeekValues(obj,loc){var hasLocaleWeekData=!isUndefined(obj.localWeekday)||!isUndefined(obj.localWeekNumber)||!isUndefined(obj.localWeekYear);if(hasLocaleWeekData){var hasIsoWeekData=!isUndefined(obj.weekday)||!isUndefined(obj.weekNumber)||!isUndefined(obj.weekYear);if(hasIsoWeekData){throw new ConflictingSpecificationError("Cannot mix locale-based week fields with ISO-based week fields");} 170if(!isUndefined(obj.localWeekday))obj.weekday=obj.localWeekday;if(!isUndefined(obj.localWeekNumber))obj.weekNumber=obj.localWeekNumber;if(!isUndefined(obj.localWeekYear))obj.weekYear=obj.localWeekYear;delete obj.localWeekday;delete obj.localWeekNumber;delete obj.localWeekYear;return{minDaysInFirstWeek:loc.getMinDaysInFirstWeek(),startOfWeek:loc.getStartOfWeek()};}else{return{minDaysInFirstWeek:4,startOfWeek:1};}} 171function hasInvalidWeekData(obj,minDaysInFirstWeek,startOfWeek){if(minDaysInFirstWeek===void 0){minDaysInFirstWeek=4;} 172if(startOfWeek===void 0){startOfWeek=1;} 173var validYear=isInteger(obj.weekYear),validWeek=integerBetween(obj.weekNumber,1,weeksInWeekYear(obj.weekYear,minDaysInFirstWeek,startOfWeek)),validWeekday=integerBetween(obj.weekday,1,7);if(!validYear){return unitOutOfRange("weekYear",obj.weekYear);}else if(!validWeek){return unitOutOfRange("week",obj.weekNumber);}else if(!validWeekday){return unitOutOfRange("weekday",obj.weekday);}else return false;} 174function hasInvalidOrdinalData(obj){var validYear=isInteger(obj.year),validOrdinal=integerBetween(obj.ordinal,1,daysInYear(obj.year));if(!validYear){return unitOutOfRange("year",obj.year);}else if(!validOrdinal){return unitOutOfRange("ordinal",obj.ordinal);}else return false;} 175function hasInvalidGregorianData(obj){var validYear=isInteger(obj.year),validMonth=integerBetween(obj.month,1,12),validDay=integerBetween(obj.day,1,daysInMonth(obj.year,obj.month));if(!validYear){return unitOutOfRange("year",obj.year);}else if(!validMonth){return unitOutOfRange("month",obj.month);}else if(!validDay){return unitOutOfRange("day",obj.day);}else return false;} 176function hasInvalidTimeData(obj){var hour=obj.hour,minute=obj.minute,second=obj.second,millisecond=obj.millisecond;var validHour=integerBetween(hour,0,23)||hour===24&&minute===0&&second===0&&millisecond===0,validMinute=integerBetween(minute,0,59),validSecond=integerBetween(second,0,59),validMillisecond=integerBetween(millisecond,0,999);if(!validHour){return unitOutOfRange("hour",hour);}else if(!validMinute){return unitOutOfRange("minute",minute);}else if(!validSecond){return unitOutOfRange("second",second);}else if(!validMillisecond){return unitOutOfRange("millisecond",millisecond);}else return false;} 177function isUndefined(o){return typeof o==="undefined";} 178function isNumber(o){return typeof o==="number";} 179function isInteger(o){return typeof o==="number"&&o%1===0;} 180function isString(o){return typeof o==="string";} 181function isDate(o){return Object.prototype.toString.call(o)==="[object Date]";} 182function hasRelative(){try{return typeof Intl!=="undefined"&&!!Intl.RelativeTimeFormat;}catch(e){return false;}} 183function hasLocaleWeekInfo(){try{return typeof Intl!=="undefined"&&!!Intl.Locale&&("weekInfo"in Intl.Locale.prototype||"getWeekInfo"in Intl.Locale.prototype);}catch(e){return false;}} 184function maybeArray(thing){return Array.isArray(thing)?thing:[thing];} 185function bestBy(arr,by,compare){if(arr.length===0){return undefined;} 186return arr.reduce(function(best,next){var pair=[by(next),next];if(!best){return pair;}else if(compare(best[0],pair[0])===best[0]){return best;}else{return pair;}},null)[1];} 187function pick(obj,keys){return keys.reduce(function(a,k){a[k]=obj[k];return a;},{});} 188function hasOwnProperty(obj,prop){return Object.prototype.hasOwnProperty.call(obj,prop);} 189function validateWeekSettings(settings){if(settings==null){return null;}else if(typeof settings!=="object"){throw new InvalidArgumentError("Week settings must be an object");}else{if(!integerBetween(settings.firstDay,1,7)||!integerBetween(settings.minimalDays,1,7)||!Array.isArray(settings.weekend)||settings.weekend.some(function(v){return!integerBetween(v,1,7);})){throw new InvalidArgumentError("Invalid week settings");} 190return{firstDay:settings.firstDay,minimalDays:settings.minimalDays,weekend:Array.from(settings.weekend)};}} 191function integerBetween(thing,bottom,top){return isInteger(thing)&&thing>=bottom&&thing<=top;} 192function floorMod(x,n){return x-n*Math.floor(x/n);} 193function padStart(input,n){if(n===void 0){n=2;} 194var isNeg=input<0;var padded;if(isNeg){padded="-"+(""+-input).padStart(n,"0");}else{padded=(""+input).padStart(n,"0");} 195return padded;} 196function parseInteger(string){if(isUndefined(string)||string===null||string===""){return undefined;}else{return parseInt(string,10);}} 197function parseFloating(string){if(isUndefined(string)||string===null||string===""){return undefined;}else{return parseFloat(string);}} 198function parseMillis(fraction){if(isUndefined(fraction)||fraction===null||fraction===""){return undefined;}else{var f=parseFloat("0."+fraction)*1000;return Math.floor(f);}} 199function roundTo(number,digits,towardZero){if(towardZero===void 0){towardZero=false;} 200var factor=Math.pow(10,digits),rounder=towardZero?Math.trunc:Math.round;return rounder(number*factor)/factor;} 201function isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0);} 202function daysInYear(year){return isLeapYear(year)?366:365;} 203function daysInMonth(year,month){var modMonth=floorMod(month-1,12)+1,modYear=year+(month-modMonth)/12;if(modMonth===2){return isLeapYear(modYear)?29:28;}else{return[31,null,31,30,31,30,31,31,30,31,30,31][modMonth-1];}} 204function objToLocalTS(obj){var d=Date.UTC(obj.year,obj.month-1,obj.day,obj.hour,obj.minute,obj.second,obj.millisecond);if(obj.year<100&&obj.year>=0){d=new Date(d);d.setUTCFullYear(obj.year,obj.month-1,obj.day);} 205return+d;} 206function firstWeekOffset(year,minDaysInFirstWeek,startOfWeek){var fwdlw=isoWeekdayToLocal(dayOfWeek(year,1,minDaysInFirstWeek),startOfWeek);return-fwdlw+minDaysInFirstWeek-1;} 207function weeksInWeekYear(weekYear,minDaysInFirstWeek,startOfWeek){if(minDaysInFirstWeek===void 0){minDaysInFirstWeek=4;} 208if(startOfWeek===void 0){startOfWeek=1;} 209var weekOffset=firstWeekOffset(weekYear,minDaysInFirstWeek,startOfWeek);var weekOffsetNext=firstWeekOffset(weekYear+1,minDaysInFirstWeek,startOfWeek);return(daysInYear(weekYear)-weekOffset+weekOffsetNext)/7;} 210function untruncateYear(year){if(year>99){return year;}else return year>Settings.twoDigitCutoffYear?1900+year:2000+year;} 211function parseZoneInfo(ts,offsetFormat,locale,timeZone){if(timeZone===void 0){timeZone=null;} 212var date=new Date(ts),intlOpts={hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"};if(timeZone){intlOpts.timeZone=timeZone;} 213var modified=_extends({timeZoneName:offsetFormat},intlOpts);var parsed=new Intl.DateTimeFormat(locale,modified).formatToParts(date).find(function(m){return m.type.toLowerCase()==="timezonename";});return parsed?parsed.value:null;} 214function signedOffset(offHourStr,offMinuteStr){var offHour=parseInt(offHourStr,10);if(Number.isNaN(offHour)){offHour=0;} 215var offMin=parseInt(offMinuteStr,10)||0,offMinSigned=offHour<0||Object.is(offHour,-0)?-offMin:offMin;return offHour*60+offMinSigned;} 216function asNumber(value){var numericValue=Number(value);if(typeof value==="boolean"||value===""||Number.isNaN(numericValue))throw new InvalidArgumentError("Invalid unit value "+value);return numericValue;} 217function normalizeObject(obj,normalizer){var normalized={};for(var u in obj){if(hasOwnProperty(obj,u)){var v=obj[u];if(v===undefined||v===null)continue;normalized[normalizer(u)]=asNumber(v);}} 218return normalized;} 219function formatOffset(offset,format){var hours=Math.trunc(Math.abs(offset/60)),minutes=Math.trunc(Math.abs(offset%60)),sign=offset>=0?"+":"-";switch(format){case"short":return""+sign+padStart(hours,2)+":"+padStart(minutes,2);case"narrow":return""+sign+hours+(minutes>0?":"+minutes:"");case"techie":return""+sign+padStart(hours,2)+padStart(minutes,2);default:throw new RangeError("Value format "+format+" is out of range for property format");}} 220function timeObject(obj){return pick(obj,["hour","minute","second","millisecond"]);} 221var monthsLong=["January","February","March","April","May","June","July","August","September","October","November","December"];var monthsShort=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var monthsNarrow=["J","F","M","A","M","J","J","A","S","O","N","D"];function months(length){switch(length){case"narrow":return[].concat(monthsNarrow);case"short":return[].concat(monthsShort);case"long":return[].concat(monthsLong);case"numeric":return["1","2","3","4","5","6","7","8","9","10","11","12"];case"2-digit":return["01","02","03","04","05","06","07","08","09","10","11","12"];default:return null;}} 222var weekdaysLong=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"];var weekdaysShort=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];var weekdaysNarrow=["M","T","W","T","F","S","S"];function weekdays(length){switch(length){case"narrow":return[].concat(weekdaysNarrow);case"short":return[].concat(weekdaysShort);case"long":return[].concat(weekdaysLong);case"numeric":return["1","2","3","4","5","6","7"];default:return null;}} 223var meridiems=["AM","PM"];var erasLong=["Before Christ","Anno Domini"];var erasShort=["BC","AD"];var erasNarrow=["B","A"];function eras(length){switch(length){case"narrow":return[].concat(erasNarrow);case"short":return[].concat(erasShort);case"long":return[].concat(erasLong);default:return null;}} 224function meridiemForDateTime(dt){return meridiems[dt.hour<12?0:1];} 225function weekdayForDateTime(dt,length){return weekdays(length)[dt.weekday-1];} 226function monthForDateTime(dt,length){return months(length)[dt.month-1];} 227function eraForDateTime(dt,length){return eras(length)[dt.year<0?0:1];} 228function formatRelativeTime(unit,count,numeric,narrow){if(numeric===void 0){numeric="always";} 229if(narrow===void 0){narrow=false;} 230var units={years:["year","yr."],quarters:["quarter","qtr."],months:["month","mo."],weeks:["week","wk."],days:["day","day","days"],hours:["hour","hr."],minutes:["minute","min."],seconds:["second","sec."]};var lastable=["hours","minutes","seconds"].indexOf(unit)===-1;if(numeric==="auto"&&lastable){var isDay=unit==="days";switch(count){case 1:return isDay?"tomorrow":"next "+units[unit][0];case-1:return isDay?"yesterday":"last "+units[unit][0];case 0:return isDay?"today":"this "+units[unit][0];}} 231var isInPast=Object.is(count,-0)||count<0,fmtValue=Math.abs(count),singular=fmtValue===1,lilUnits=units[unit],fmtUnit=narrow?singular?lilUnits[1]:lilUnits[2]||lilUnits[1]:singular?units[unit][0]:unit;return isInPast?fmtValue+" "+fmtUnit+" ago":"in "+fmtValue+" "+fmtUnit;} 232function stringifyTokens(splits,tokenToString){var s="";for(var _iterator=_createForOfIteratorHelperLoose(splits),_step;!(_step=_iterator()).done;){var token=_step.value;if(token.literal){s+=token.val;}else{s+=tokenToString(token.val);}} 233return s;} 234var _macroTokenToFormatOpts={D:DATE_SHORT,DD:DATE_MED,DDD:DATE_FULL,DDDD:DATE_HUGE,t:TIME_SIMPLE,tt:TIME_WITH_SECONDS,ttt:TIME_WITH_SHORT_OFFSET,tttt:TIME_WITH_LONG_OFFSET,T:TIME_24_SIMPLE,TT:TIME_24_WITH_SECONDS,TTT:TIME_24_WITH_SHORT_OFFSET,TTTT:TIME_24_WITH_LONG_OFFSET,f:DATETIME_SHORT,ff:DATETIME_MED,fff:DATETIME_FULL,ffff:DATETIME_HUGE,F:DATETIME_SHORT_WITH_SECONDS,FF:DATETIME_MED_WITH_SECONDS,FFF:DATETIME_FULL_WITH_SECONDS,FFFF:DATETIME_HUGE_WITH_SECONDS};var Formatter=function(){Formatter.create=function create(locale,opts){if(opts===void 0){opts={};} 235return new Formatter(locale,opts);};Formatter.parseFormat=function parseFormat(fmt){var current=null,currentFull="",bracketed=false;var splits=[];for(var i=0;i<fmt.length;i++){var c=fmt.charAt(i);if(c==="'"){if(currentFull.length>0){splits.push({literal:bracketed||/^\s+$/.test(currentFull),val:currentFull});} 236current=null;currentFull="";bracketed=!bracketed;}else if(bracketed){currentFull+=c;}else if(c===current){currentFull+=c;}else{if(currentFull.length>0){splits.push({literal:/^\s+$/.test(currentFull),val:currentFull});} 237currentFull=c;current=c;}} 238if(currentFull.length>0){splits.push({literal:bracketed||/^\s+$/.test(currentFull),val:currentFull});} 239return splits;};Formatter.macroTokenToFormatOpts=function macroTokenToFormatOpts(token){return _macroTokenToFormatOpts[token];};function Formatter(locale,formatOpts){this.opts=formatOpts;this.loc=locale;this.systemLoc=null;} 240var _proto=Formatter.prototype;_proto.formatWithSystemDefault=function formatWithSystemDefault(dt,opts){if(this.systemLoc===null){this.systemLoc=this.loc.redefaultToSystem();} 241var df=this.systemLoc.dtFormatter(dt,_extends({},this.opts,opts));return df.format();};_proto.dtFormatter=function dtFormatter(dt,opts){if(opts===void 0){opts={};} 242return this.loc.dtFormatter(dt,_extends({},this.opts,opts));};_proto.formatDateTime=function formatDateTime(dt,opts){return this.dtFormatter(dt,opts).format();};_proto.formatDateTimeParts=function formatDateTimeParts(dt,opts){return this.dtFormatter(dt,opts).formatToParts();};_proto.formatInterval=function formatInterval(interval,opts){var df=this.dtFormatter(interval.start,opts);return df.dtf.formatRange(interval.start.toJSDate(),interval.end.toJSDate());};_proto.resolvedOptions=function resolvedOptions(dt,opts){return this.dtFormatter(dt,opts).resolvedOptions();};_proto.num=function num(n,p){if(p===void 0){p=0;} 243if(this.opts.forceSimple){return padStart(n,p);} 244var opts=_extends({},this.opts);if(p>0){opts.padTo=p;} 245return this.loc.numberFormatter(opts).format(n);};_proto.formatDateTimeFromString=function formatDateTimeFromString(dt,fmt){var _this=this;var knownEnglish=this.loc.listingMode()==="en",useDateTimeFormatter=this.loc.outputCalendar&&this.loc.outputCalendar!=="gregory",string=function string(opts,extract){return _this.loc.extract(dt,opts,extract);},formatOffset=function formatOffset(opts){if(dt.isOffsetFixed&&dt.offset===0&&opts.allowZ){return"Z";} 246return dt.isValid?dt.zone.formatOffset(dt.ts,opts.format):"";},meridiem=function meridiem(){return knownEnglish?meridiemForDateTime(dt):string({hour:"numeric",hourCycle:"h12"},"dayperiod");},month=function month(length,standalone){return knownEnglish?monthForDateTime(dt,length):string(standalone?{month:length}:{month:length,day:"numeric"},"month");},weekday=function weekday(length,standalone){return knownEnglish?weekdayForDateTime(dt,length):string(standalone?{weekday:length}:{weekday:length,month:"long",day:"numeric"},"weekday");},maybeMacro=function maybeMacro(token){var formatOpts=Formatter.macroTokenToFormatOpts(token);if(formatOpts){return _this.formatWithSystemDefault(dt,formatOpts);}else{return token;}},era=function era(length){return knownEnglish?eraForDateTime(dt,length):string({era:length},"era");},tokenToString=function tokenToString(token){switch(token){case"S":return _this.num(dt.millisecond);case"u":case"SSS":return _this.num(dt.millisecond,3);case"s":return _this.num(dt.second);case"ss":return _this.num(dt.second,2);case"uu":return _this.num(Math.floor(dt.millisecond/10),2);case"uuu":return _this.num(Math.floor(dt.millisecond/100));case"m":return _this.num(dt.minute);case"mm":return _this.num(dt.minute,2);case"h":return _this.num(dt.hour%12===0?12:dt.hour%12);case"hh":return _this.num(dt.hour%12===0?12:dt.hour%12,2);case"H":return _this.num(dt.hour);case"HH":return _this.num(dt.hour,2);case"Z":return formatOffset({format:"narrow",allowZ:_this.opts.allowZ});case"ZZ":return formatOffset({format:"short",allowZ:_this.opts.allowZ});case"ZZZ":return formatOffset({format:"techie",allowZ:_this.opts.allowZ});case"ZZZZ":return dt.zone.offsetName(dt.ts,{format:"short",locale:_this.loc.locale});case"ZZZZZ":return dt.zone.offsetName(dt.ts,{format:"long",locale:_this.loc.locale});case"z":return dt.zoneName;case"a":return meridiem();case"d":return useDateTimeFormatter?string({day:"numeric"},"day"):_this.num(dt.day);case"dd":return useDateTimeFormatter?string({day:"2-digit"},"day"):_this.num(dt.day,2);case"c":return _this.num(dt.weekday);case"ccc":return weekday("short",true);case"cccc":return weekday("long",true);case"ccccc":return weekday("narrow",true);case"E":return _this.num(dt.weekday);case"EEE":return weekday("short",false);case"EEEE":return weekday("long",false);case"EEEEE":return weekday("narrow",false);case"L":return useDateTimeFormatter?string({month:"numeric",day:"numeric"},"month"):_this.num(dt.month);case"LL":return useDateTimeFormatter?string({month:"2-digit",day:"numeric"},"month"):_this.num(dt.month,2);case"LLL":return month("short",true);case"LLLL":return month("long",true);case"LLLLL":return month("narrow",true);case"M":return useDateTimeFormatter?string({month:"numeric"},"month"):_this.num(dt.month);case"MM":return useDateTimeFormatter?string({month:"2-digit"},"month"):_this.num(dt.month,2);case"MMM":return month("short",false);case"MMMM":return month("long",false);case"MMMMM":return month("narrow",false);case"y":return useDateTimeFormatter?string({year:"numeric"},"year"):_this.num(dt.year);case"yy":return useDateTimeFormatter?string({year:"2-digit"},"year"):_this.num(dt.year.toString().slice(-2),2);case"yyyy":return useDateTimeFormatter?string({year:"numeric"},"year"):_this.num(dt.year,4);case"yyyyyy":return useDateTimeFormatter?string({year:"numeric"},"year"):_this.num(dt.year,6);case"G":return era("short");case"GG":return era("long");case"GGGGG":return era("narrow");case"kk":return _this.num(dt.weekYear.toString().slice(-2),2);case"kkkk":return _this.num(dt.weekYear,4);case"W":return _this.num(dt.weekNumber);
vendor: 7,272 bytes, lines 246-269
246case"WW":return _this.num(dt.weekNumber,2);case"n":return _this.num(dt.localWeekNumber);case"nn":return _this.num(dt.localWeekNumber,2);case"ii":return _this.num(dt.localWeekYear.toString().slice(-2),2);case"iiii":return _this.num(dt.localWeekYear,4);case"o":return _this.num(dt.ordinal);case"ooo":return _this.num(dt.ordinal,3);case"q":return _this.num(dt.quarter);case"qq":return _this.num(dt.quarter,2);case"X":return _this.num(Math.floor(dt.ts/1000));case"x":return _this.num(dt.ts);default:return maybeMacro(token);}};return stringifyTokens(Formatter.parseFormat(fmt),tokenToString);};_proto.formatDurationFromString=function formatDurationFromString(dur,fmt){var _this2=this;var tokenToField=function tokenToField(token){switch(token[0]){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":return"hour";case"d":return"day";case"w":return"week";case"M":return"month";case"y":return"year";default:return null;}},tokenToString=function tokenToString(lildur){return function(token){var mapped=tokenToField(token);if(mapped){return _this2.num(lildur.get(mapped),token.length);}else{return token;}};},tokens=Formatter.parseFormat(fmt),realTokens=tokens.reduce(function(found,_ref){var literal=_ref.literal,val=_ref.val;return literal?found:found.concat(val);},[]),collapsed=dur.shiftTo.apply(dur,realTokens.map(tokenToField).filter(function(t){return t;}));return stringifyTokens(tokens,tokenToString(collapsed));};return Formatter;}();var ianaRegex=/[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;function combineRegexes(){for(var _len=arguments.length,regexes=new Array(_len),_key=0;_key<_len;_key++){regexes[_key]=arguments[_key];} 247var full=regexes.reduce(function(f,r){return f+r.source;},"");return RegExp("^"+full+"$");} 248function combineExtractors(){for(var _len2=arguments.length,extractors=new Array(_len2),_key2=0;_key2<_len2;_key2++){extractors[_key2]=arguments[_key2];} 249return function(m){return extractors.reduce(function(_ref,ex){var mergedVals=_ref[0],mergedZone=_ref[1],cursor=_ref[2];var _ex=ex(m,cursor),val=_ex[0],zone=_ex[1],next=_ex[2];return[_extends({},mergedVals,val),zone||mergedZone,next];},[{},null,1]).slice(0,2);};} 250function parse(s){if(s==null){return[null,null];} 251for(var _len3=arguments.length,patterns=new Array(_len3>1?_len3-1:0),_key3=1;_key3<_len3;_key3++){patterns[_key3-1]=arguments[_key3];} 252for(var _i=0,_patterns=patterns;_i<_patterns.length;_i++){var _patterns$_i=_patterns[_i],regex=_patterns$_i[0],extractor=_patterns$_i[1];var m=regex.exec(s);if(m){return extractor(m);}} 253return[null,null];} 254function simpleParse(){for(var _len4=arguments.length,keys=new Array(_len4),_key4=0;_key4<_len4;_key4++){keys[_key4]=arguments[_key4];} 255return function(match,cursor){var ret={};var i;for(i=0;i<keys.length;i++){ret[keys[i]]=parseInteger(match[cursor+i]);} 256return[ret,null,cursor+i];};} 257var offsetRegex=/(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/;var isoExtendedZone="(?:"+offsetRegex.source+"?(?:\\[("+ianaRegex.source+")\\])?)?";var isoTimeBaseRegex=/(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;var isoTimeRegex=RegExp(""+isoTimeBaseRegex.source+isoExtendedZone);var isoTimeExtensionRegex=RegExp("(?:T"+isoTimeRegex.source+")?");var isoYmdRegex=/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;var isoWeekRegex=/(\d{4})-?W(\d\d)(?:-?(\d))?/;var isoOrdinalRegex=/(\d{4})-?(\d{3})/;var extractISOWeekData=simpleParse("weekYear","weekNumber","weekDay");var extractISOOrdinalData=simpleParse("year","ordinal");var sqlYmdRegex=/(\d{4})-(\d\d)-(\d\d)/;var sqlTimeRegex=RegExp(isoTimeBaseRegex.source+" ?(?:"+offsetRegex.source+"|("+ianaRegex.source+"))?");var sqlTimeExtensionRegex=RegExp("(?: "+sqlTimeRegex.source+")?");function int(match,pos,fallback){var m=match[pos];return isUndefined(m)?fallback:parseInteger(m);} 258function extractISOYmd(match,cursor){var item={year:int(match,cursor),month:int(match,cursor+1,1),day:int(match,cursor+2,1)};return[item,null,cursor+3];} 259function extractISOTime(match,cursor){var item={hours:int(match,cursor,0),minutes:int(match,cursor+1,0),seconds:int(match,cursor+2,0),milliseconds:parseMillis(match[cursor+3])};return[item,null,cursor+4];} 260function extractISOOffset(match,cursor){var local=!match[cursor]&&!match[cursor+1],fullOffset=signedOffset(match[cursor+1],match[cursor+2]),zone=local?null:FixedOffsetZone.instance(fullOffset);return[{},zone,cursor+3];} 261function extractIANAZone(match,cursor){var zone=match[cursor]?IANAZone.create(match[cursor]):null;return[{},zone,cursor+1];} 262var isoTimeOnly=RegExp("^T?"+isoTimeBaseRegex.source+"$");var isoDuration=/^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;function extractISODuration(match){var s=match[0],yearStr=match[1],monthStr=match[2],weekStr=match[3],dayStr=match[4],hourStr=match[5],minuteStr=match[6],secondStr=match[7],millisecondsStr=match[8];var hasNegativePrefix=s[0]==="-";var negativeSeconds=secondStr&&secondStr[0]==="-";var maybeNegate=function maybeNegate(num,force){if(force===void 0){force=false;} 263return num!==undefined&&(force||num&&hasNegativePrefix)?-num:num;};return[{years:maybeNegate(parseFloating(yearStr)),months:maybeNegate(parseFloating(monthStr)),weeks:maybeNegate(parseFloating(weekStr)),days:maybeNegate(parseFloating(dayStr)),hours:maybeNegate(parseFloating(hourStr)),minutes:maybeNegate(parseFloating(minuteStr)),seconds:maybeNegate(parseFloating(secondStr),secondStr==="-0"),milliseconds:maybeNegate(parseMillis(millisecondsStr),negativeSeconds)}];} 264var obsOffsets={GMT:0,EDT:-4*60,EST:-5*60,CDT:-5*60,CST:-6*60,MDT:-6*60,MST:-7*60,PDT:-7*60,PST:-8*60};function fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr){var result={year:yearStr.length===2?untruncateYear(parseInteger(yearStr)):parseInteger(yearStr),month:monthsShort.indexOf(monthStr)+1,day:parseInteger(dayStr),hour:parseInteger(hourStr),minute:parseInteger(minuteStr)};if(secondStr)result.second=parseInteger(secondStr);if(weekdayStr){result.weekday=weekdayStr.length>3?weekdaysLong.indexOf(weekdayStr)+1:weekdaysShort.indexOf(weekdayStr)+1;} 265return result;} 266var rfc2822=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;function extractRFC2822(match){var weekdayStr=match[1],dayStr=match[2],monthStr=match[3],yearStr=match[4],hourStr=match[5],minuteStr=match[6],secondStr=match[7],obsOffset=match[8],milOffset=match[9],offHourStr=match[10],offMinuteStr=match[11],result=fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr);var offset;if(obsOffset){offset=obsOffsets[obsOffset];}else if(milOffset){offset=0;}else{offset=signedOffset(offHourStr,offMinuteStr);} 267return[result,new FixedOffsetZone(offset)];} 268function preprocessRFC2822(s){return s.replace(/\([^()]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim();} 269var rfc1123=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,rfc850=/^(Monday|Tuesday|Wednesday|Thursday|Frid
vendor: 39,278 bytes, lines 269-382
269ay|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,ascii=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;function extractRFC1123Or850(match){var weekdayStr=match[1],dayStr=match[2],monthStr=match[3],yearStr=match[4],hourStr=match[5],minuteStr=match[6],secondStr=match[7],result=fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr);return[result,FixedOffsetZone.utcInstance];} 270function extractASCII(match){var weekdayStr=match[1],monthStr=match[2],dayStr=match[3],hourStr=match[4],minuteStr=match[5],secondStr=match[6],yearStr=match[7],result=fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr);return[result,FixedOffsetZone.utcInstance];} 271var isoYmdWithTimeExtensionRegex=combineRegexes(isoYmdRegex,isoTimeExtensionRegex);var isoWeekWithTimeExtensionRegex=combineRegexes(isoWeekRegex,isoTimeExtensionRegex);var isoOrdinalWithTimeExtensionRegex=combineRegexes(isoOrdinalRegex,isoTimeExtensionRegex);var isoTimeCombinedRegex=combineRegexes(isoTimeRegex);var extractISOYmdTimeAndOffset=combineExtractors(extractISOYmd,extractISOTime,extractISOOffset,extractIANAZone);var extractISOWeekTimeAndOffset=combineExtractors(extractISOWeekData,extractISOTime,extractISOOffset,extractIANAZone);var extractISOOrdinalDateAndTime=combineExtractors(extractISOOrdinalData,extractISOTime,extractISOOffset,extractIANAZone);var extractISOTimeAndOffset=combineExtractors(extractISOTime,extractISOOffset,extractIANAZone);function parseISODate(s){return parse(s,[isoYmdWithTimeExtensionRegex,extractISOYmdTimeAndOffset],[isoWeekWithTimeExtensionRegex,extractISOWeekTimeAndOffset],[isoOrdinalWithTimeExtensionRegex,extractISOOrdinalDateAndTime],[isoTimeCombinedRegex,extractISOTimeAndOffset]);} 272function parseRFC2822Date(s){return parse(preprocessRFC2822(s),[rfc2822,extractRFC2822]);} 273function parseHTTPDate(s){return parse(s,[rfc1123,extractRFC1123Or850],[rfc850,extractRFC1123Or850],[ascii,extractASCII]);} 274function parseISODuration(s){return parse(s,[isoDuration,extractISODuration]);} 275var extractISOTimeOnly=combineExtractors(extractISOTime);function parseISOTimeOnly(s){return parse(s,[isoTimeOnly,extractISOTimeOnly]);} 276var sqlYmdWithTimeExtensionRegex=combineRegexes(sqlYmdRegex,sqlTimeExtensionRegex);var sqlTimeCombinedRegex=combineRegexes(sqlTimeRegex);var extractISOTimeOffsetAndIANAZone=combineExtractors(extractISOTime,extractISOOffset,extractIANAZone);function parseSQL(s){return parse(s,[sqlYmdWithTimeExtensionRegex,extractISOYmdTimeAndOffset],[sqlTimeCombinedRegex,extractISOTimeOffsetAndIANAZone]);} 277var INVALID$2="Invalid Duration";var lowOrderMatrix={weeks:{days:7,hours:7*24,minutes:7*24*60,seconds:7*24*60*60,milliseconds:7*24*60*60*1000},days:{hours:24,minutes:24*60,seconds:24*60*60,milliseconds:24*60*60*1000},hours:{minutes:60,seconds:60*60,milliseconds:60*60*1000},minutes:{seconds:60,milliseconds:60*1000},seconds:{milliseconds:1000}},casualMatrix=_extends({years:{quarters:4,months:12,weeks:52,days:365,hours:365*24,minutes:365*24*60,seconds:365*24*60*60,milliseconds:365*24*60*60*1000},quarters:{months:3,weeks:13,days:91,hours:91*24,minutes:91*24*60,seconds:91*24*60*60,milliseconds:91*24*60*60*1000},months:{weeks:4,days:30,hours:30*24,minutes:30*24*60,seconds:30*24*60*60,milliseconds:30*24*60*60*1000}},lowOrderMatrix),daysInYearAccurate=146097.0/400,daysInMonthAccurate=146097.0/4800,accurateMatrix=_extends({years:{quarters:4,months:12,weeks:daysInYearAccurate/7,days:daysInYearAccurate,hours:daysInYearAccurate*24,minutes:daysInYearAccurate*24*60,seconds:daysInYearAccurate*24*60*60,milliseconds:daysInYearAccurate*24*60*60*1000},quarters:{months:3,weeks:daysInYearAccurate/28,days:daysInYearAccurate/4,hours:daysInYearAccurate*24/4,minutes:daysInYearAccurate*24*60/4,seconds:daysInYearAccurate*24*60*60/4,milliseconds:daysInYearAccurate*24*60*60*1000/4},months:{weeks:daysInMonthAccurate/7,days:daysInMonthAccurate,hours:daysInMonthAccurate*24,minutes:daysInMonthAccurate*24*60,seconds:daysInMonthAccurate*24*60*60,milliseconds:daysInMonthAccurate*24*60*60*1000}},lowOrderMatrix);var orderedUnits$1=["years","quarters","months","weeks","days","hours","minutes","seconds","milliseconds"];var reverseUnits=orderedUnits$1.slice(0).reverse();function clone$1(dur,alts,clear){if(clear===void 0){clear=false;} 278var conf={values:clear?alts.values:_extends({},dur.values,alts.values||{}),loc:dur.loc.clone(alts.loc),conversionAccuracy:alts.conversionAccuracy||dur.conversionAccuracy,matrix:alts.matrix||dur.matrix};return new Duration(conf);} 279function durationToMillis(matrix,vals){var _vals$milliseconds;var sum=(_vals$milliseconds=vals.milliseconds)!=null?_vals$milliseconds:0;for(var _iterator=_createForOfIteratorHelperLoose(reverseUnits.slice(1)),_step;!(_step=_iterator()).done;){var unit=_step.value;if(vals[unit]){sum+=vals[unit]*matrix[unit]["milliseconds"];}} 280return sum;} 281function normalizeValues(matrix,vals){var factor=durationToMillis(matrix,vals)<0?-1:1;orderedUnits$1.reduceRight(function(previous,current){if(!isUndefined(vals[current])){if(previous){var previousVal=vals[previous]*factor;var conv=matrix[current][previous];var rollUp=Math.floor(previousVal/conv);vals[current]+=rollUp*factor;vals[previous]-=rollUp*conv*factor;} 282return current;}else{return previous;}},null);orderedUnits$1.reduce(function(previous,current){if(!isUndefined(vals[current])){if(previous){var fraction=vals[previous]%1;vals[previous]-=fraction;vals[current]+=fraction*matrix[previous][current];} 283return current;}else{return previous;}},null);} 284function removeZeroes(vals){var newVals={};for(var _i=0,_Object$entries=Object.entries(vals);_i<_Object$entries.length;_i++){var _Object$entries$_i=_Object$entries[_i],key=_Object$entries$_i[0],value=_Object$entries$_i[1];if(value!==0){newVals[key]=value;}} 285return newVals;} 286var Duration=function(_Symbol$for){function Duration(config){var accurate=config.conversionAccuracy==="longterm"||false;var matrix=accurate?accurateMatrix:casualMatrix;if(config.matrix){matrix=config.matrix;} 287this.values=config.values;this.loc=config.loc||Locale.create();this.conversionAccuracy=accurate?"longterm":"casual";this.invalid=config.invalid||null;this.matrix=matrix;this.isLuxonDuration=true;} 288Duration.fromMillis=function fromMillis(count,opts){return Duration.fromObject({milliseconds:count},opts);};Duration.fromObject=function fromObject(obj,opts){if(opts===void 0){opts={};} 289if(obj==null||typeof obj!=="object"){throw new InvalidArgumentError("Duration.fromObject: argument expected to be an object, got "+(obj===null?"null":typeof obj));} 290return new Duration({values:normalizeObject(obj,Duration.normalizeUnit),loc:Locale.fromObject(opts),conversionAccuracy:opts.conversionAccuracy,matrix:opts.matrix});};Duration.fromDurationLike=function fromDurationLike(durationLike){if(isNumber(durationLike)){return Duration.fromMillis(durationLike);}else if(Duration.isDuration(durationLike)){return durationLike;}else if(typeof durationLike==="object"){return Duration.fromObject(durationLike);}else{throw new InvalidArgumentError("Unknown duration argument "+durationLike+" of type "+typeof durationLike);}};Duration.fromISO=function fromISO(text,opts){var _parseISODuration=parseISODuration(text),parsed=_parseISODuration[0];if(parsed){return Duration.fromObject(parsed,opts);}else{return Duration.invalid("unparsable","the input \""+text+"\" can't be parsed as ISO 8601");}};Duration.fromISOTime=function fromISOTime(text,opts){var _parseISOTimeOnly=parseISOTimeOnly(text),parsed=_parseISOTimeOnly[0];if(parsed){return Duration.fromObject(parsed,opts);}else{return Duration.invalid("unparsable","the input \""+text+"\" can't be parsed as ISO 8601");}};Duration.invalid=function invalid(reason,explanation){if(explanation===void 0){explanation=null;} 291if(!reason){throw new InvalidArgumentError("need to specify a reason the Duration is invalid");} 292var invalid=reason instanceof Invalid?reason:new Invalid(reason,explanation);if(Settings.throwOnInvalid){throw new InvalidDurationError(invalid);}else{return new Duration({invalid:invalid});}};Duration.normalizeUnit=function normalizeUnit(unit){var normalized={year:"years",years:"years",quarter:"quarters",quarters:"quarters",month:"months",months:"months",week:"weeks",weeks:"weeks",day:"days",days:"days",hour:"hours",hours:"hours",minute:"minutes",minutes:"minutes",second:"seconds",seconds:"seconds",millisecond:"milliseconds",milliseconds:"milliseconds"}[unit?unit.toLowerCase():unit];if(!normalized)throw new InvalidUnitError(unit);return normalized;};Duration.isDuration=function isDuration(o){return o&&o.isLuxonDuration||false;};var _proto=Duration.prototype;_proto.toFormat=function toFormat(fmt,opts){if(opts===void 0){opts={};} 293var fmtOpts=_extends({},opts,{floor:opts.round!==false&&opts.floor!==false});return this.isValid?Formatter.create(this.loc,fmtOpts).formatDurationFromString(this,fmt):INVALID$2;};_proto.toHuman=function toHuman(opts){var _this=this;if(opts===void 0){opts={};} 294if(!this.isValid)return INVALID$2;var l=orderedUnits$1.map(function(unit){var val=_this.values[unit];if(isUndefined(val)){return null;} 295return _this.loc.numberFormatter(_extends({style:"unit",unitDisplay:"long"},opts,{unit:unit.slice(0,-1)})).format(val);}).filter(function(n){return n;});return this.loc.listFormatter(_extends({type:"conjunction",style:opts.listStyle||"narrow"},opts)).format(l);};_proto.toObject=function toObject(){if(!this.isValid)return{};return _extends({},this.values);};_proto.toISO=function toISO(){if(!this.isValid)return null;var s="P";if(this.years!==0)s+=this.years+"Y";if(this.months!==0||this.quarters!==0)s+=this.months+this.quarters*3+"M";if(this.weeks!==0)s+=this.weeks+"W";if(this.days!==0)s+=this.days+"D";if(this.hours!==0||this.minutes!==0||this.seconds!==0||this.milliseconds!==0)s+="T";if(this.hours!==0)s+=this.hours+"H";if(this.minutes!==0)s+=this.minutes+"M";if(this.seconds!==0||this.milliseconds!==0) 296s+=roundTo(this.seconds+this.milliseconds/1000,3)+"S";if(s==="P")s+="T0S";return s;};_proto.toISOTime=function toISOTime(opts){if(opts===void 0){opts={};} 297if(!this.isValid)return null;var millis=this.toMillis();if(millis<0||millis>=86400000)return null;opts=_extends({suppressMilliseconds:false,suppressSeconds:false,includePrefix:false,format:"extended"},opts,{includeOffset:false});var dateTime=DateTime.fromMillis(millis,{zone:"UTC"});return dateTime.toISOTime(opts);};_proto.toJSON=function toJSON(){return this.toISO();};_proto.toString=function toString(){return this.toISO();};_proto[_Symbol$for]=function(){if(this.isValid){return"Duration { values: "+JSON.stringify(this.values)+" }";}else{return"Duration { Invalid, reason: "+this.invalidReason+" }";}};_proto.toMillis=function toMillis(){if(!this.isValid)return NaN;return durationToMillis(this.matrix,this.values);};_proto.valueOf=function valueOf(){return this.toMillis();};_proto.plus=function plus(duration){if(!this.isValid)return this;var dur=Duration.fromDurationLike(duration),result={};for(var _i2=0,_orderedUnits=orderedUnits$1;_i2<_orderedUnits.length;_i2++){var k=_orderedUnits[_i2];if(hasOwnProperty(dur.values,k)||hasOwnProperty(this.values,k)){result[k]=dur.get(k)+this.get(k);}} 298return clone$1(this,{values:result},true);};_proto.minus=function minus(duration){if(!this.isValid)return this;var dur=Duration.fromDurationLike(duration);return this.plus(dur.negate());};_proto.mapUnits=function mapUnits(fn){if(!this.isValid)return this;var result={};for(var _i3=0,_Object$keys=Object.keys(this.values);_i3<_Object$keys.length;_i3++){var k=_Object$keys[_i3];result[k]=asNumber(fn(this.values[k],k));} 299return clone$1(this,{values:result},true);};_proto.get=function get(unit){return this[Duration.normalizeUnit(unit)];};_proto.set=function set(values){if(!this.isValid)return this;var mixed=_extends({},this.values,normalizeObject(values,Duration.normalizeUnit));return clone$1(this,{values:mixed});};_proto.reconfigure=function reconfigure(_temp){var _ref=_temp===void 0?{}:_temp,locale=_ref.locale,numberingSystem=_ref.numberingSystem,conversionAccuracy=_ref.conversionAccuracy,matrix=_ref.matrix;var loc=this.loc.clone({locale:locale,numberingSystem:numberingSystem});var opts={loc:loc,matrix:matrix,conversionAccuracy:conversionAccuracy};return clone$1(this,opts);};_proto.as=function as(unit){return this.isValid?this.shiftTo(unit).get(unit):NaN;};_proto.normalize=function normalize(){if(!this.isValid)return this;var vals=this.toObject();normalizeValues(this.matrix,vals);return clone$1(this,{values:vals},true);};_proto.rescale=function rescale(){if(!this.isValid)return this;var vals=removeZeroes(this.normalize().shiftToAll().toObject());return clone$1(this,{values:vals},true);};_proto.shiftTo=function shiftTo(){for(var _len=arguments.length,units=new Array(_len),_key=0;_key<_len;_key++){units[_key]=arguments[_key];} 300if(!this.isValid)return this;if(units.length===0){return this;} 301units=units.map(function(u){return Duration.normalizeUnit(u);});var built={},accumulated={},vals=this.toObject();var lastUnit;for(var _i4=0,_orderedUnits2=orderedUnits$1;_i4<_orderedUnits2.length;_i4++){var k=_orderedUnits2[_i4];if(units.indexOf(k)>=0){lastUnit=k;var own=0;for(var ak in accumulated){own+=this.matrix[ak][k]*accumulated[ak];accumulated[ak]=0;} 302if(isNumber(vals[k])){own+=vals[k];} 303var i=Math.trunc(own);built[k]=i;accumulated[k]=(own*1000-i*1000)/1000;}else if(isNumber(vals[k])){accumulated[k]=vals[k];}} 304for(var key in accumulated){if(accumulated[key]!==0){built[lastUnit]+=key===lastUnit?accumulated[key]:accumulated[key]/this.matrix[lastUnit][key];}} 305normalizeValues(this.matrix,built);return clone$1(this,{values:built},true);};_proto.shiftToAll=function shiftToAll(){if(!this.isValid)return this;return this.shiftTo("years","months","weeks","days","hours","minutes","seconds","milliseconds");};_proto.negate=function negate(){if(!this.isValid)return this;var negated={};for(var _i5=0,_Object$keys2=Object.keys(this.values);_i5<_Object$keys2.length;_i5++){var k=_Object$keys2[_i5];negated[k]=this.values[k]===0?0:-this.values[k];} 306return clone$1(this,{values:negated},true);};_proto.equals=function equals(other){if(!this.isValid||!other.isValid){return false;} 307if(!this.loc.equals(other.loc)){return false;} 308function eq(v1,v2){if(v1===undefined||v1===0)return v2===undefined||v2===0;return v1===v2;} 309for(var _i6=0,_orderedUnits3=orderedUnits$1;_i6<_orderedUnits3.length;_i6++){var u=_orderedUnits3[_i6];if(!eq(this.values[u],other.values[u])){return false;}} 310return true;};_createClass(Duration,[{key:"locale",get:function get(){return this.isValid?this.loc.locale:null;}},{key:"numberingSystem",get:function get(){return this.isValid?this.loc.numberingSystem:null;}},{key:"years",get:function get(){return this.isValid?this.values.years||0:NaN;}},{key:"quarters",get:function get(){return this.isValid?this.values.quarters||0:NaN;}},{key:"months",get:function get(){return this.isValid?this.values.months||0:NaN;}},{key:"weeks",get:function get(){return this.isValid?this.values.weeks||0:NaN;}},{key:"days",get:function get(){return this.isValid?this.values.days||0:NaN;}},{key:"hours",get:function get(){return this.isValid?this.values.hours||0:NaN;}},{key:"minutes",get:function get(){return this.isValid?this.values.minutes||0:NaN;}},{key:"seconds",get:function get(){return this.isValid?this.values.seconds||0:NaN;}},{key:"milliseconds",get:function get(){return this.isValid?this.values.milliseconds||0:NaN;}},{key:"isValid",get:function get(){return this.invalid===null;}},{key:"invalidReason",get:function get(){return this.invalid?this.invalid.reason:null;}},{key:"invalidExplanation",get:function get(){return this.invalid?this.invalid.explanation:null;}}]);return Duration;}(Symbol.for("nodejs.util.inspect.custom"));var INVALID$1="Invalid Interval";function validateStartEnd(start,end){if(!start||!start.isValid){return Interval.invalid("missing or invalid start");}else if(!end||!end.isValid){return Interval.invalid("missing or invalid end");}else if(end<start){return Interval.invalid("end before start","The end of an interval must be after its start, but you had start="+start.toISO()+" and end="+end.toISO());}else{return null;}} 311var Interval=function(_Symbol$for){function Interval(config){this.s=config.start;this.e=config.end;this.invalid=config.invalid||null;this.isLuxonInterval=true;} 312Interval.invalid=function invalid(reason,explanation){if(explanation===void 0){explanation=null;} 313if(!reason){throw new InvalidArgumentError("need to specify a reason the Interval is invalid");} 314var invalid=reason instanceof Invalid?reason:new Invalid(reason,explanation);if(Settings.throwOnInvalid){throw new InvalidIntervalError(invalid);}else{return new Interval({invalid:invalid});}};Interval.fromDateTimes=function fromDateTimes(start,end){var builtStart=friendlyDateTime(start),builtEnd=friendlyDateTime(end);var validateError=validateStartEnd(builtStart,builtEnd);if(validateError==null){return new Interval({start:builtStart,end:builtEnd});}else{return validateError;}};Interval.after=function after(start,duration){var dur=Duration.fromDurationLike(duration),dt=friendlyDateTime(start);return Interval.fromDateTimes(dt,dt.plus(dur));};Interval.before=function before(end,duration){var dur=Duration.fromDurationLike(duration),dt=friendlyDateTime(end);return Interval.fromDateTimes(dt.minus(dur),dt);};Interval.fromISO=function fromISO(text,opts){var _split=(text||"").split("/",2),s=_split[0],e=_split[1];if(s&&e){var start,startIsValid;try{start=DateTime.fromISO(s,opts);startIsValid=start.isValid;}catch(e){startIsValid=false;} 315var end,endIsValid;try{end=DateTime.fromISO(e,opts);endIsValid=end.isValid;}catch(e){endIsValid=false;} 316if(startIsValid&&endIsValid){return Interval.fromDateTimes(start,end);} 317if(startIsValid){var dur=Duration.fromISO(e,opts);if(dur.isValid){return Interval.after(start,dur);}}else if(endIsValid){var _dur=Duration.fromISO(s,opts);if(_dur.isValid){return Interval.before(end,_dur);}}} 318return Interval.invalid("unparsable","the input \""+text+"\" can't be parsed as ISO 8601");};Interval.isInterval=function isInterval(o){return o&&o.isLuxonInterval||false;};var _proto=Interval.prototype;_proto.length=function length(unit){if(unit===void 0){unit="milliseconds";} 319return this.isValid?this.toDuration.apply(this,[unit]).get(unit):NaN;};_proto.count=function count(unit,opts){if(unit===void 0){unit="milliseconds";} 320if(!this.isValid)return NaN;var start=this.start.startOf(unit,opts);var end;if(opts!=null&&opts.useLocaleWeeks){end=this.end.reconfigure({locale:start.locale});}else{end=this.end;} 321end=end.startOf(unit,opts);return Math.floor(end.diff(start,unit).get(unit))+(end.valueOf()!==this.end.valueOf());};_proto.hasSame=function hasSame(unit){return this.isValid?this.isEmpty()||this.e.minus(1).hasSame(this.s,unit):false;};_proto.isEmpty=function isEmpty(){return this.s.valueOf()===this.e.valueOf();};_proto.isAfter=function isAfter(dateTime){if(!this.isValid)return false;return this.s>dateTime;};_proto.isBefore=function isBefore(dateTime){if(!this.isValid)return false;return this.e<=dateTime;};_proto.contains=function contains(dateTime){if(!this.isValid)return false;return this.s<=dateTime&&this.e>dateTime;};_proto.set=function set(_temp){var _ref=_temp===void 0?{}:_temp,start=_ref.start,end=_ref.end;if(!this.isValid)return this;return Interval.fromDateTimes(start||this.s,end||this.e);};_proto.splitAt=function splitAt(){var _this=this;if(!this.isValid)return[];for(var _len=arguments.length,dateTimes=new Array(_len),_key=0;_key<_len;_key++){dateTimes[_key]=arguments[_key];} 322var sorted=dateTimes.map(friendlyDateTime).filter(function(d){return _this.contains(d);}).sort(function(a,b){return a.toMillis()-b.toMillis();}),results=[];var s=this.s,i=0;while(s<this.e){var added=sorted[i]||this.e,next=+added>+this.e?this.e:added;results.push(Interval.fromDateTimes(s,next));s=next;i+=1;} 323return results;};_proto.splitBy=function splitBy(duration){var dur=Duration.fromDurationLike(duration);if(!this.isValid||!dur.isValid||dur.as("milliseconds")===0){return[];} 324var s=this.s,idx=1,next;var results=[];while(s<this.e){var added=this.start.plus(dur.mapUnits(function(x){return x*idx;}));next=+added>+this.e?this.e:added;results.push(Interval.fromDateTimes(s,next));s=next;idx+=1;} 325return results;};_proto.divideEqually=function divideEqually(numberOfParts){if(!this.isValid)return[];return this.splitBy(this.length()/numberOfParts).slice(0,numberOfParts);};_proto.overlaps=function overlaps(other){return this.e>other.s&&this.s<other.e;};_proto.abutsStart=function abutsStart(other){if(!this.isValid)return false;return+this.e===+other.s;};_proto.abutsEnd=function abutsEnd(other){if(!this.isValid)return false;return+other.e===+this.s;};_proto.engulfs=function engulfs(other){if(!this.isValid)return false;return this.s<=other.s&&this.e>=other.e;};_proto.equals=function equals(other){if(!this.isValid||!other.isValid){return false;} 326return this.s.equals(other.s)&&this.e.equals(other.e);};_proto.intersection=function intersection(other){if(!this.isValid)return this;var s=this.s>other.s?this.s:other.s,e=this.e<other.e?this.e:other.e;if(s>=e){return null;}else{return Interval.fromDateTimes(s,e);}};_proto.union=function union(other){if(!this.isValid)return this;var s=this.s<other.s?this.s:other.s,e=this.e>other.e?this.e:other.e;return Interval.fromDateTimes(s,e);};Interval.merge=function merge(intervals){var _intervals$sort$reduc=intervals.sort(function(a,b){return a.s-b.s;}).reduce(function(_ref2,item){var sofar=_ref2[0],current=_ref2[1];if(!current){return[sofar,item];}else if(current.overlaps(item)||current.abutsStart(item)){return[sofar,current.union(item)];}else{return[sofar.concat([current]),item];}},[[],null]),found=_intervals$sort$reduc[0],final=_intervals$sort$reduc[1];if(final){found.push(final);} 327return found;};Interval.xor=function xor(intervals){var _Array$prototype;var start=null,currentCount=0;var results=[],ends=intervals.map(function(i){return[{time:i.s,type:"s"},{time:i.e,type:"e"}];}),flattened=(_Array$prototype=Array.prototype).concat.apply(_Array$prototype,ends),arr=flattened.sort(function(a,b){return a.time-b.time;});for(var _iterator=_createForOfIteratorHelperLoose(arr),_step;!(_step=_iterator()).done;){var i=_step.value;currentCount+=i.type==="s"?1:-1;if(currentCount===1){start=i.time;}else{if(start&&+start!==+i.time){results.push(Interval.fromDateTimes(start,i.time));} 328start=null;}} 329return Interval.merge(results);};_proto.difference=function difference(){var _this2=this;for(var _len2=arguments.length,intervals=new Array(_len2),_key2=0;_key2<_len2;_key2++){intervals[_key2]=arguments[_key2];} 330return Interval.xor([this].concat(intervals)).map(function(i){return _this2.intersection(i);}).filter(function(i){return i&&!i.isEmpty();});};_proto.toString=function toString(){if(!this.isValid)return INVALID$1;return"["+this.s.toISO()+" \u2013 "+this.e.toISO()+")";};_proto[_Symbol$for]=function(){if(this.isValid){return"Interval { start: "+this.s.toISO()+", end: "+this.e.toISO()+" }";}else{return"Interval { Invalid, reason: "+this.invalidReason+" }";}};_proto.toLocaleString=function toLocaleString(formatOpts,opts){if(formatOpts===void 0){formatOpts=DATE_SHORT;} 331if(opts===void 0){opts={};} 332return this.isValid?Formatter.create(this.s.loc.clone(opts),formatOpts).formatInterval(this):INVALID$1;};_proto.toISO=function toISO(opts){if(!this.isValid)return INVALID$1;return this.s.toISO(opts)+"/"+this.e.toISO(opts);};_proto.toISODate=function toISODate(){if(!this.isValid)return INVALID$1;return this.s.toISODate()+"/"+this.e.toISODate();};_proto.toISOTime=function toISOTime(opts){if(!this.isValid)return INVALID$1;return this.s.toISOTime(opts)+"/"+this.e.toISOTime(opts);};_proto.toFormat=function toFormat(dateFormat,_temp2){var _ref3=_temp2===void 0?{}:_temp2,_ref3$separator=_ref3.separator,separator=_ref3$separator===void 0?" â ":_ref3$separator;if(!this.isValid)return INVALID$1;return""+this.s.toFormat(dateFormat)+separator+this.e.toFormat(dateFormat);};_proto.toDuration=function toDuration(unit,opts){if(!this.isValid){return Duration.invalid(this.invalidReason);} 333return this.e.diff(this.s,unit,opts);};_proto.mapEndpoints=function mapEndpoints(mapFn){return Interval.fromDateTimes(mapFn(this.s),mapFn(this.e));};_createClass(Interval,[{key:"start",get:function get(){return this.isValid?this.s:null;}},{key:"end",get:function get(){return this.isValid?this.e:null;}},{key:"isValid",get:function get(){return this.invalidReason===null;}},{key:"invalidReason",get:function get(){return this.invalid?this.invalid.reason:null;}},{key:"invalidExplanation",get:function get(){return this.invalid?this.invalid.explanation:null;}}]);return Interval;}(Symbol.for("nodejs.util.inspect.custom"));var Info=function(){function Info(){} 334Info.hasDST=function hasDST(zone){if(zone===void 0){zone=Settings.defaultZone;} 335var proto=DateTime.now().setZone(zone).set({month:12});return!zone.isUniversal&&proto.offset!==proto.set({month:6}).offset;};Info.isValidIANAZone=function isValidIANAZone(zone){return IANAZone.isValidZone(zone);};Info.normalizeZone=function normalizeZone$1(input){return normalizeZone(input,Settings.defaultZone);};Info.getStartOfWeek=function getStartOfWeek(_temp){var _ref=_temp===void 0?{}:_temp,_ref$locale=_ref.locale,locale=_ref$locale===void 0?null:_ref$locale,_ref$locObj=_ref.locObj,locObj=_ref$locObj===void 0?null:_ref$locObj;return(locObj||Locale.create(locale)).getStartOfWeek();};Info.getMinimumDaysInFirstWeek=function getMinimumDaysInFirstWeek(_temp2){var _ref2=_temp2===void 0?{}:_temp2,_ref2$locale=_ref2.locale,locale=_ref2$locale===void 0?null:_ref2$locale,_ref2$locObj=_ref2.locObj,locObj=_ref2$locObj===void 0?null:_ref2$locObj;return(locObj||Locale.create(locale)).getMinDaysInFirstWeek();};Info.getWeekendWeekdays=function getWeekendWeekdays(_temp3){var _ref3=_temp3===void 0?{}:_temp3,_ref3$locale=_ref3.locale,locale=_ref3$locale===void 0?null:_ref3$locale,_ref3$locObj=_ref3.locObj,locObj=_ref3$locObj===void 0?null:_ref3$locObj;return(locObj||Locale.create(locale)).getWeekendDays().slice();};Info.months=function months(length,_temp4){if(length===void 0){length="long";} 336var _ref4=_temp4===void 0?{}:_temp4,_ref4$locale=_ref4.locale,locale=_ref4$locale===void 0?null:_ref4$locale,_ref4$numberingSystem=_ref4.numberingSystem,numberingSystem=_ref4$numberingSystem===void 0?null:_ref4$numberingSystem,_ref4$locObj=_ref4.locObj,locObj=_ref4$locObj===void 0?null:_ref4$locObj,_ref4$outputCalendar=_ref4.outputCalendar,outputCalendar=_ref4$outputCalendar===void 0?"gregory":_ref4$outputCalendar;return(locObj||Locale.create(locale,numberingSystem,outputCalendar)).months(length);};Info.monthsFormat=function monthsFormat(length,_temp5){if(length===void 0){length="long";} 337var _ref5=_temp5===void 0?{}:_temp5,_ref5$locale=_ref5.locale,locale=_ref5$locale===void 0?null:_ref5$locale,_ref5$numberingSystem=_ref5.numberingSystem,numberingSystem=_ref5$numberingSystem===void 0?null:_ref5$numberingSystem,_ref5$locObj=_ref5.locObj,locObj=_ref5$locObj===void 0?null:_ref5$locObj,_ref5$outputCalendar=_ref5.outputCalendar,outputCalendar=_ref5$outputCalendar===void 0?"gregory":_ref5$outputCalendar;return(locObj||Locale.create(locale,numberingSystem,outputCalendar)).months(length,true);};Info.weekdays=function weekdays(length,_temp6){if(length===void 0){length="long";} 338var _ref6=_temp6===void 0?{}:_temp6,_ref6$locale=_ref6.locale,locale=_ref6$locale===void 0?null:_ref6$locale,_ref6$numberingSystem=_ref6.numberingSystem,numberingSystem=_ref6$numberingSystem===void 0?null:_ref6$numberingSystem,_ref6$locObj=_ref6.locObj,locObj=_ref6$locObj===void 0?null:_ref6$locObj;return(locObj||Locale.create(locale,numberingSystem,null)).weekdays(length);};Info.weekdaysFormat=function weekdaysFormat(length,_temp7){if(length===void 0){length="long";} 339var _ref7=_temp7===void 0?{}:_temp7,_ref7$locale=_ref7.locale,locale=_ref7$locale===void 0?null:_ref7$locale,_ref7$numberingSystem=_ref7.numberingSystem,numberingSystem=_ref7$numberingSystem===void 0?null:_ref7$numberingSystem,_ref7$locObj=_ref7.locObj,locObj=_ref7$locObj===void 0?null:_ref7$locObj;return(locObj||Locale.create(locale,numberingSystem,null)).weekdays(length,true);};Info.meridiems=function meridiems(_temp8){var _ref8=_temp8===void 0?{}:_temp8,_ref8$locale=_ref8.locale,locale=_ref8$locale===void 0?null:_ref8$locale;return Locale.create(locale).meridiems();};Info.eras=function eras(length,_temp9){if(length===void 0){length="short";} 340var _ref9=_temp9===void 0?{}:_temp9,_ref9$locale=_ref9.locale,locale=_ref9$locale===void 0?null:_ref9$locale;return Locale.create(locale,null,"gregory").eras(length);};Info.features=function features(){return{relative:hasRelative(),localeWeek:hasLocaleWeekInfo()};};return Info;}();function dayDiff(earlier,later){var utcDayStart=function utcDayStart(dt){return dt.toUTC(0,{keepLocalTime:true}).startOf("day").valueOf();},ms=utcDayStart(later)-utcDayStart(earlier);return Math.floor(Duration.fromMillis(ms).as("days"));} 341function highOrderDiffs(cursor,later,units){var differs=[["years",function(a,b){return b.year-a.year;}],["quarters",function(a,b){return b.quarter-a.quarter+(b.year-a.year)*4;}],["months",function(a,b){return b.month-a.month+(b.year-a.year)*12;}],["weeks",function(a,b){var days=dayDiff(a,b);return(days-days%7)/7;}],["days",dayDiff]];var results={};var earlier=cursor;var lowestOrder,highWater;for(var _i=0,_differs=differs;_i<_differs.length;_i++){var _differs$_i=_differs[_i],unit=_differs$_i[0],differ=_differs$_i[1];if(units.indexOf(unit)>=0){lowestOrder=unit;results[unit]=differ(cursor,later);highWater=earlier.plus(results);if(highWater>later){results[unit]--;cursor=earlier.plus(results);if(cursor>later){highWater=cursor;results[unit]--;cursor=earlier.plus(results);}}else{cursor=highWater;}}} 342return[cursor,results,highWater,lowestOrder];} 343function _diff(earlier,later,units,opts){var _highOrderDiffs=highOrderDiffs(earlier,later,units),cursor=_highOrderDiffs[0],results=_highOrderDiffs[1],highWater=_highOrderDiffs[2],lowestOrder=_highOrderDiffs[3];var remainingMillis=later-cursor;var lowerOrderUnits=units.filter(function(u){return["hours","minutes","seconds","milliseconds"].indexOf(u)>=0;});if(lowerOrderUnits.length===0){if(highWater<later){var _cursor$plus;highWater=cursor.plus((_cursor$plus={},_cursor$plus[lowestOrder]=1,_cursor$plus));} 344if(highWater!==cursor){results[lowestOrder]=(results[lowestOrder]||0)+remainingMillis/(highWater-cursor);}} 345var duration=Duration.fromObject(results,opts);if(lowerOrderUnits.length>0){var _Duration$fromMillis;return(_Duration$fromMillis=Duration.fromMillis(remainingMillis,opts)).shiftTo.apply(_Duration$fromMillis,lowerOrderUnits).plus(duration);}else{return duration;}} 346var MISSING_FTP="missing Intl.DateTimeFormat.formatToParts support";function intUnit(regex,post){if(post===void 0){post=function post(i){return i;};} 347return{regex:regex,deser:function deser(_ref){var s=_ref[0];return post(parseDigits(s));}};} 348var NBSP=String.fromCharCode(160);var spaceOrNBSP="[ "+NBSP+"]";var spaceOrNBSPRegExp=new RegExp(spaceOrNBSP,"g");function fixListRegex(s){return s.replace(/\./g,"\\.?").replace(spaceOrNBSPRegExp,spaceOrNBSP);} 349function stripInsensitivities(s){return s.replace(/\./g,"").replace(spaceOrNBSPRegExp," ").toLowerCase();} 350function oneOf(strings,startIndex){if(strings===null){return null;}else{return{regex:RegExp(strings.map(fixListRegex).join("|")),deser:function deser(_ref2){var s=_ref2[0];return strings.findIndex(function(i){return stripInsensitivities(s)===stripInsensitivities(i);})+startIndex;}};}} 351function offset(regex,groups){return{regex:regex,deser:function deser(_ref3){var h=_ref3[1],m=_ref3[2];return signedOffset(h,m);},groups:groups};} 352function simple(regex){return{regex:regex,deser:function deser(_ref4){var s=_ref4[0];return s;}};} 353function escapeToken(value){return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");} 354function unitForToken(token,loc){var one=digitRegex(loc),two=digitRegex(loc,"{2}"),three=digitRegex(loc,"{3}"),four=digitRegex(loc,"{4}"),six=digitRegex(loc,"{6}"),oneOrTwo=digitRegex(loc,"{1,2}"),oneToThree=digitRegex(loc,"{1,3}"),oneToSix=digitRegex(loc,"{1,6}"),oneToNine=digitRegex(loc,"{1,9}"),twoToFour=digitRegex(loc,"{2,4}"),fourToSix=digitRegex(loc,"{4,6}"),literal=function literal(t){return{regex:RegExp(escapeToken(t.val)),deser:function deser(_ref5){var s=_ref5[0];return s;},literal:true};},unitate=function unitate(t){if(token.literal){return literal(t);} 355switch(t.val){case"G":return oneOf(loc.eras("short"),0);case"GG":return oneOf(loc.eras("long"),0);case"y":return intUnit(oneToSix);case"yy":return intUnit(twoToFour,untruncateYear);case"yyyy":return intUnit(four);case"yyyyy":return intUnit(fourToSix);case"yyyyyy":return intUnit(six);case"M":return intUnit(oneOrTwo);case"MM":return intUnit(two);case"MMM":return oneOf(loc.months("short",true),1);case"MMMM":return oneOf(loc.months("long",true),1);case"L":return intUnit(oneOrTwo);case"LL":return intUnit(two);case"LLL":return oneOf(loc.months("short",false),1);case"LLLL":return oneOf(loc.months("long",false),1);case"d":return intUnit(oneOrTwo);case"dd":return intUnit(two);case"o":return intUnit(oneToThree);case"ooo":return intUnit(three);case"HH":return intUnit(two);case"H":return intUnit(oneOrTwo);case"hh":return intUnit(two);case"h":return intUnit(oneOrTwo);case"mm":return intUnit(two);case"m":return intUnit(oneOrTwo);case"q":return intUnit(oneOrTwo);case"qq":return intUnit(two);case"s":return intUnit(oneOrTwo);case"ss":return intUnit(two);case"S":return intUnit(oneToThree);case"SSS":return intUnit(three);case"u":return simple(oneToNine);case"uu":return simple(oneOrTwo);case"uuu":return intUnit(one);case"a":return oneOf(loc.meridiems(),0);case"kkkk":return intUnit(four);case"kk":return intUnit(twoToFour,untruncateYear);case"W":return intUnit(oneOrTwo);case"WW":return intUnit(two);case"E":case"c":return intUnit(one);case"EEE":return oneOf(loc.weekdays("short",false),1);case"EEEE":return oneOf(loc.weekdays("long",false),1);case"ccc":return oneOf(loc.weekdays("short",true),1);case"cccc":return oneOf(loc.weekdays("long",true),1);case"Z":case"ZZ":return offset(new RegExp("([+-]"+oneOrTwo.source+")(?::("+two.source+"))?"),2);case"ZZZ":return offset(new RegExp("([+-]"+oneOrTwo.source+")("+two.source+")?"),2);case"z":return simple(/[a-z_+-/]{1,256}?/i);case" ":return simple(/[^\S\n\r]/);default:return literal(t);}};var unit=unitate(token)||{invalidReason:MISSING_FTP};unit.token=token;return unit;} 356var partTypeStyleToTokenVal={year:{"2-digit":"yy",numeric:"yyyyy"},month:{numeric:"M","2-digit":"MM",short:"MMM",long:"MMMM"},day:{numeric:"d","2-digit":"dd"},weekday:{short:"EEE",long:"EEEE"},dayperiod:"a",dayPeriod:"a",hour12:{numeric:"h","2-digit":"hh"},hour24:{numeric:"H","2-digit":"HH"},minute:{numeric:"m","2-digit":"mm"},second:{numeric:"s","2-digit":"ss"},timeZoneName:{long:"ZZZZZ",short:"ZZZ"}};function tokenForPart(part,formatOpts,resolvedOpts){var type=part.type,value=part.value;if(type==="literal"){var isSpace=/^\s+$/.test(value);return{literal:!isSpace,val:isSpace?" ":value};} 357var style=formatOpts[type];var actualType=type;if(type==="hour"){if(formatOpts.hour12!=null){actualType=formatOpts.hour12?"hour12":"hour24";}else if(formatOpts.hourCycle!=null){if(formatOpts.hourCycle==="h11"||formatOpts.hourCycle==="h12"){actualType="hour12";}else{actualType="hour24";}}else{actualType=resolvedOpts.hour12?"hour12":"hour24";}} 358var val=partTypeStyleToTokenVal[actualType];if(typeof val==="object"){val=val[style];} 359if(val){return{literal:false,val:val};} 360return undefined;} 361function buildRegex(units){var re=units.map(function(u){return u.regex;}).reduce(function(f,r){return f+"("+r.source+")";},"");return["^"+re+"$",units];} 362function match(input,regex,handlers){var matches=input.match(regex);if(matches){var all={};var matchIndex=1;for(var i in handlers){if(hasOwnProperty(handlers,i)){var h=handlers[i],groups=h.groups?h.groups+1:1;if(!h.literal&&h.token){all[h.token.val[0]]=h.deser(matches.slice(matchIndex,matchIndex+groups));} 363matchIndex+=groups;}} 364return[matches,all];}else{return[matches,{}];}} 365function dateTimeFromMatches(matches){var toField=function toField(token){switch(token){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":case"H":return"hour";case"d":return"day";case"o":return"ordinal";case"L":case"M":return"month";case"y":return"year";case"E":case"c":return"weekday";case"W":return"weekNumber";case"k":return"weekYear";case"q":return"quarter";default:return null;}};var zone=null;var specificOffset;if(!isUndefined(matches.z)){zone=IANAZone.create(matches.z);} 366if(!isUndefined(matches.Z)){if(!zone){zone=new FixedOffsetZone(matches.Z);} 367specificOffset=matches.Z;} 368if(!isUndefined(matches.q)){matches.M=(matches.q-1)*3+1;} 369if(!isUndefined(matches.h)){if(matches.h<12&&matches.a===1){matches.h+=12;}else if(matches.h===12&&matches.a===0){matches.h=0;}} 370if(matches.G===0&&matches.y){matches.y=-matches.y;} 371if(!isUndefined(matches.u)){matches.S=parseMillis(matches.u);} 372var vals=Object.keys(matches).reduce(function(r,k){var f=toField(k);if(f){r[f]=matches[k];} 373return r;},{});return[vals,zone,specificOffset];} 374var dummyDateTimeCache=null;function getDummyDateTime(){if(!dummyDateTimeCache){dummyDateTimeCache=DateTime.fromMillis(1555555555555);} 375return dummyDateTimeCache;} 376function maybeExpandMacroToken(token,locale){if(token.literal){return token;} 377var formatOpts=Formatter.macroTokenToFormatOpts(token.val);var tokens=formatOptsToTokens(formatOpts,locale);if(tokens==null||tokens.includes(undefined)){return token;} 378return tokens;} 379function expandMacroTokens(tokens,locale){var _Array$prototype;return(_Array$prototype=Array.prototype).concat.apply(_Array$prototype,tokens.map(function(t){return maybeExpandMacroToken(t,locale);}));} 380var TokenParser=function(){function TokenParser(locale,format){this.locale=locale;this.format=format;this.tokens=expandMacroTokens(Formatter.parseFormat(format),locale);this.units=this.tokens.map(function(t){return unitForToken(t,locale);});this.disqualifyingUnit=this.units.find(function(t){return t.invalidReason;});if(!this.disqualifyingUnit){var _buildRegex=buildRegex(this.units),regexString=_buildRegex[0],handlers=_buildRegex[1];this.regex=RegExp(regexString,"i");this.handlers=handlers;}} 381var _proto=TokenParser.prototype;_proto.explainFromTokens=function explainFromTokens(input){if(!this.isValid){return{input:input,tokens:this.tokens,invalidReason:this.invalidReason};}else{var _match=match(input,this.regex,this.handlers),rawMatches=_match[0],matches=_match[1],_ref6=matches?dateTimeFromMatches(matches):[null,null,undefined],result=_ref6[0],zone=_ref6[1],specificOffset=_ref6[2];if(hasOwnProperty(matches,"a")&&hasOwnProperty(matches,"H")){throw new ConflictingSpecificationError("Can't include meridiem when specifying 24-hour format");} 382return{input:input,tokens:this.tokens,regex:this.regex,rawMatches:rawMatches,matches:matches,result:result,zone:zone,specificOffset:specificOffset};}};_createClass(TokenParser,[{key:"isValid",get:function get(){return!this.disqualifyingUnit;}},{key:"invalidReason",get:function get(){return this.disqualifyingUnit?this.disqualifyingUnit.invali
vendor: 4,464 bytes, lines 382-406
382dReason:null;}}]);return TokenParser;}();function explainFromTokens(locale,input,format){var parser=new TokenParser(locale,format);return parser.explainFromTokens(input);} 383function parseFromTokens(locale,input,format){var _explainFromTokens=explainFromTokens(locale,input,format),result=_explainFromTokens.result,zone=_explainFromTokens.zone,specificOffset=_explainFromTokens.specificOffset,invalidReason=_explainFromTokens.invalidReason;return[result,zone,specificOffset,invalidReason];} 384function formatOptsToTokens(formatOpts,locale){if(!formatOpts){return null;} 385var formatter=Formatter.create(locale,formatOpts);var df=formatter.dtFormatter(getDummyDateTime());var parts=df.formatToParts();var resolvedOpts=df.resolvedOptions();return parts.map(function(p){return tokenForPart(p,formatOpts,resolvedOpts);});} 386var INVALID="Invalid DateTime";var MAX_DATE=8.64e15;function unsupportedZone(zone){return new Invalid("unsupported zone","the zone \""+zone.name+"\" is not supported");} 387function possiblyCachedWeekData(dt){if(dt.weekData===null){dt.weekData=gregorianToWeek(dt.c);} 388return dt.weekData;} 389function possiblyCachedLocalWeekData(dt){if(dt.localWeekData===null){dt.localWeekData=gregorianToWeek(dt.c,dt.loc.getMinDaysInFirstWeek(),dt.loc.getStartOfWeek());} 390return dt.localWeekData;} 391function clone(inst,alts){var current={ts:inst.ts,zone:inst.zone,c:inst.c,o:inst.o,loc:inst.loc,invalid:inst.invalid};return new DateTime(_extends({},current,alts,{old:current}));} 392function fixOffset(localTS,o,tz){var utcGuess=localTS-o*60*1000;var o2=tz.offset(utcGuess);if(o===o2){return[utcGuess,o];} 393utcGuess-=(o2-o)*60*1000;var o3=tz.offset(utcGuess);if(o2===o3){return[utcGuess,o2];} 394return[localTS-Math.min(o2,o3)*60*1000,Math.max(o2,o3)];} 395function tsToObj(ts,offset){ts+=offset*60*1000;var d=new Date(ts);return{year:d.getUTCFullYear(),month:d.getUTCMonth()+1,day:d.getUTCDate(),hour:d.getUTCHours(),minute:d.getUTCMinutes(),second:d.getUTCSeconds(),millisecond:d.getUTCMilliseconds()};} 396function objToTS(obj,offset,zone){return fixOffset(objToLocalTS(obj),offset,zone);} 397function adjustTime(inst,dur){var oPre=inst.o,year=inst.c.year+Math.trunc(dur.years),month=inst.c.month+Math.trunc(dur.months)+Math.trunc(dur.quarters)*3,c=_extends({},inst.c,{year:year,month:month,day:Math.min(inst.c.day,daysInMonth(year,month))+Math.trunc(dur.days)+Math.trunc(dur.weeks)*7}),millisToAdd=Duration.fromObject({years:dur.years-Math.trunc(dur.years),quarters:dur.quarters-Math.trunc(dur.quarters),months:dur.months-Math.trunc(dur.months),weeks:dur.weeks-Math.trunc(dur.weeks),days:dur.days-Math.trunc(dur.days),hours:dur.hours,minutes:dur.minutes,seconds:dur.seconds,milliseconds:dur.milliseconds}).as("milliseconds"),localTS=objToLocalTS(c);var _fixOffset=fixOffset(localTS,oPre,inst.zone),ts=_fixOffset[0],o=_fixOffset[1];if(millisToAdd!==0){ts+=millisToAdd;o=inst.zone.offset(ts);} 398return{ts:ts,o:o};} 399function parseDataToDateTime(parsed,parsedZone,opts,format,text,specificOffset){var setZone=opts.setZone,zone=opts.zone;if(parsed&&Object.keys(parsed).length!==0||parsedZone){var interpretationZone=parsedZone||zone,inst=DateTime.fromObject(parsed,_extends({},opts,{zone:interpretationZone,specificOffset:specificOffset}));return setZone?inst:inst.setZone(zone);}else{return DateTime.invalid(new Invalid("unparsable","the input \""+text+"\" can't be parsed as "+format));}} 400function toTechFormat(dt,format,allowZ){if(allowZ===void 0){allowZ=true;} 401return dt.isValid?Formatter.create(Locale.create("en-US"),{allowZ:allowZ,forceSimple:true}).formatDateTimeFromString(dt,format):null;} 402function _toISODate(o,extended){var longFormat=o.c.year>9999||o.c.year<0;var c="";if(longFormat&&o.c.year>=0)c+="+";c+=padStart(o.c.year,longFormat?6:4);if(extended){c+="-";c+=padStart(o.c.month);c+="-";c+=padStart(o.c.day);}else{c+=padStart(o.c.month);c+=padStart(o.c.day);} 403return c;} 404function _toISOTime(o,extended,suppressSeconds,suppressMilliseconds,includeOffset,extendedZone){var c=padStart(o.c.hour);if(extended){c+=":";c+=padStart(o.c.minute);if(o.c.millisecond!==0||o.c.second!==0||!suppressSeconds){c+=":";}}else{c+=padStart(o.c.minute);} 405if(o.c.millisecond!==0||o.c.second!==0||!suppressSeconds){c+=padStart(o.c.second);if(o.c.millisecond!==0||!suppressMilliseconds){c+=".";c+=padStart(o.c.millisecond,3);}} 406if(includeOffset){if(o.isOffsetFixed&&o.offset===0&&!extendedZone){c+="Z";}else if(o.o<0){c+="-";c+=padStart(Math.trunc(-o.o/60));c+=":";c+=padStart(Math.trunc(-o.o%60));}
vendor: 26,874 bytes, lines 406-497
406else{c+="+";c+=padStart(Math.trunc(o.o/60));c+=":";c+=padStart(Math.trunc(o.o%60));}} 407if(extendedZone){c+="["+o.zone.ianaName+"]";} 408return c;} 409var defaultUnitValues={month:1,day:1,hour:0,minute:0,second:0,millisecond:0},defaultWeekUnitValues={weekNumber:1,weekday:1,hour:0,minute:0,second:0,millisecond:0},defaultOrdinalUnitValues={ordinal:1,hour:0,minute:0,second:0,millisecond:0};var orderedUnits=["year","month","day","hour","minute","second","millisecond"],orderedWeekUnits=["weekYear","weekNumber","weekday","hour","minute","second","millisecond"],orderedOrdinalUnits=["year","ordinal","hour","minute","second","millisecond"];function normalizeUnit(unit){var normalized={year:"year",years:"year",month:"month",months:"month",day:"day",days:"day",hour:"hour",hours:"hour",minute:"minute",minutes:"minute",quarter:"quarter",quarters:"quarter",second:"second",seconds:"second",millisecond:"millisecond",milliseconds:"millisecond",weekday:"weekday",weekdays:"weekday",weeknumber:"weekNumber",weeksnumber:"weekNumber",weeknumbers:"weekNumber",weekyear:"weekYear",weekyears:"weekYear",ordinal:"ordinal"}[unit.toLowerCase()];if(!normalized)throw new InvalidUnitError(unit);return normalized;} 410function normalizeUnitWithLocalWeeks(unit){switch(unit.toLowerCase()){case"localweekday":case"localweekdays":return"localWeekday";case"localweeknumber":case"localweeknumbers":return"localWeekNumber";case"localweekyear":case"localweekyears":return"localWeekYear";default:return normalizeUnit(unit);}} 411function guessOffsetForZone(zone){if(!zoneOffsetGuessCache[zone]){if(zoneOffsetTs===undefined){zoneOffsetTs=Settings.now();} 412zoneOffsetGuessCache[zone]=zone.offset(zoneOffsetTs);} 413return zoneOffsetGuessCache[zone];} 414function quickDT(obj,opts){var zone=normalizeZone(opts.zone,Settings.defaultZone);if(!zone.isValid){return DateTime.invalid(unsupportedZone(zone));} 415var loc=Locale.fromObject(opts);var ts,o;if(!isUndefined(obj.year)){for(var _i=0,_orderedUnits=orderedUnits;_i<_orderedUnits.length;_i++){var u=_orderedUnits[_i];if(isUndefined(obj[u])){obj[u]=defaultUnitValues[u];}} 416var invalid=hasInvalidGregorianData(obj)||hasInvalidTimeData(obj);if(invalid){return DateTime.invalid(invalid);} 417var offsetProvis=guessOffsetForZone(zone);var _objToTS=objToTS(obj,offsetProvis,zone);ts=_objToTS[0];o=_objToTS[1];}else{ts=Settings.now();} 418return new DateTime({ts:ts,zone:zone,loc:loc,o:o});} 419function diffRelative(start,end,opts){var round=isUndefined(opts.round)?true:opts.round,format=function format(c,unit){c=roundTo(c,round||opts.calendary?0:2,true);var formatter=end.loc.clone(opts).relFormatter(opts);return formatter.format(c,unit);},differ=function differ(unit){if(opts.calendary){if(!end.hasSame(start,unit)){return end.startOf(unit).diff(start.startOf(unit),unit).get(unit);}else return 0;}else{return end.diff(start,unit).get(unit);}};if(opts.unit){return format(differ(opts.unit),opts.unit);} 420for(var _iterator=_createForOfIteratorHelperLoose(opts.units),_step;!(_step=_iterator()).done;){var unit=_step.value;var count=differ(unit);if(Math.abs(count)>=1){return format(count,unit);}} 421return format(start>end?-0:0,opts.units[opts.units.length-1]);} 422function lastOpts(argList){var opts={},args;if(argList.length>0&&typeof argList[argList.length-1]==="object"){opts=argList[argList.length-1];args=Array.from(argList).slice(0,argList.length-1);}else{args=Array.from(argList);} 423return[opts,args];} 424var zoneOffsetTs;var zoneOffsetGuessCache={};var DateTime=function(_Symbol$for){function DateTime(config){var zone=config.zone||Settings.defaultZone;var invalid=config.invalid||(Number.isNaN(config.ts)?new Invalid("invalid input"):null)||(!zone.isValid?unsupportedZone(zone):null);this.ts=isUndefined(config.ts)?Settings.now():config.ts;var c=null,o=null;if(!invalid){var unchanged=config.old&&config.old.ts===this.ts&&config.old.zone.equals(zone);if(unchanged){var _ref=[config.old.c,config.old.o];c=_ref[0];o=_ref[1];}else{var ot=isNumber(config.o)&&!config.old?config.o:zone.offset(this.ts);c=tsToObj(this.ts,ot);invalid=Number.isNaN(c.year)?new Invalid("invalid input"):null;c=invalid?null:c;o=invalid?null:ot;}} 425this._zone=zone;this.loc=config.loc||Locale.create();this.invalid=invalid;this.weekData=null;this.localWeekData=null;this.c=c;this.o=o;this.isLuxonDateTime=true;} 426DateTime.now=function now(){return new DateTime({});};DateTime.local=function local(){var _lastOpts=lastOpts(arguments),opts=_lastOpts[0],args=_lastOpts[1],year=args[0],month=args[1],day=args[2],hour=args[3],minute=args[4],second=args[5],millisecond=args[6];return quickDT({year:year,month:month,day:day,hour:hour,minute:minute,second:second,millisecond:millisecond},opts);};DateTime.utc=function utc(){var _lastOpts2=lastOpts(arguments),opts=_lastOpts2[0],args=_lastOpts2[1],year=args[0],month=args[1],day=args[2],hour=args[3],minute=args[4],second=args[5],millisecond=args[6];opts.zone=FixedOffsetZone.utcInstance;return quickDT({year:year,month:month,day:day,hour:hour,minute:minute,second:second,millisecond:millisecond},opts);};DateTime.fromJSDate=function fromJSDate(date,options){if(options===void 0){options={};} 427var ts=isDate(date)?date.valueOf():NaN;if(Number.isNaN(ts)){return DateTime.invalid("invalid input");} 428var zoneToUse=normalizeZone(options.zone,Settings.defaultZone);if(!zoneToUse.isValid){return DateTime.invalid(unsupportedZone(zoneToUse));} 429return new DateTime({ts:ts,zone:zoneToUse,loc:Locale.fromObject(options)});};DateTime.fromMillis=function fromMillis(milliseconds,options){if(options===void 0){options={};} 430if(!isNumber(milliseconds)){throw new InvalidArgumentError("fromMillis requires a numerical input, but received a "+typeof milliseconds+" with value "+milliseconds);}else if(milliseconds<-MAX_DATE||milliseconds>MAX_DATE){return DateTime.invalid("Timestamp out of range");}else{return new DateTime({ts:milliseconds,zone:normalizeZone(options.zone,Settings.defaultZone),loc:Locale.fromObject(options)});}};DateTime.fromSeconds=function fromSeconds(seconds,options){if(options===void 0){options={};} 431if(!isNumber(seconds)){throw new InvalidArgumentError("fromSeconds requires a numerical input");}else{return new DateTime({ts:seconds*1000,zone:normalizeZone(options.zone,Settings.defaultZone),loc:Locale.fromObject(options)});}};DateTime.fromObject=function fromObject(obj,opts){if(opts===void 0){opts={};} 432obj=obj||{};var zoneToUse=normalizeZone(opts.zone,Settings.defaultZone);if(!zoneToUse.isValid){return DateTime.invalid(unsupportedZone(zoneToUse));} 433var loc=Locale.fromObject(opts);var normalized=normalizeObject(obj,normalizeUnitWithLocalWeeks);var _usesLocalWeekValues=usesLocalWeekValues(normalized,loc),minDaysInFirstWeek=_usesLocalWeekValues.minDaysInFirstWeek,startOfWeek=_usesLocalWeekValues.startOfWeek;var tsNow=Settings.now(),offsetProvis=!isUndefined(opts.specificOffset)?opts.specificOffset:zoneToUse.offset(tsNow),containsOrdinal=!isUndefined(normalized.ordinal),containsGregorYear=!isUndefined(normalized.year),containsGregorMD=!isUndefined(normalized.month)||!isUndefined(normalized.day),containsGregor=containsGregorYear||containsGregorMD,definiteWeekDef=normalized.weekYear||normalized.weekNumber;if((containsGregor||containsOrdinal)&&definiteWeekDef){throw new ConflictingSpecificationError("Can't mix weekYear/weekNumber units with year/month/day or ordinals");} 434if(containsGregorMD&&containsOrdinal){throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");} 435var useWeekData=definiteWeekDef||normalized.weekday&&!containsGregor;var units,defaultValues,objNow=tsToObj(tsNow,offsetProvis);if(useWeekData){units=orderedWeekUnits;defaultValues=defaultWeekUnitValues;objNow=gregorianToWeek(objNow,minDaysInFirstWeek,startOfWeek);}else if(containsOrdinal){units=orderedOrdinalUnits;defaultValues=defaultOrdinalUnitValues;objNow=gregorianToOrdinal(objNow);}else{units=orderedUnits;defaultValues=defaultUnitValues;} 436var foundFirst=false;for(var _iterator2=_createForOfIteratorHelperLoose(units),_step2;!(_step2=_iterator2()).done;){var u=_step2.value;var v=normalized[u];if(!isUndefined(v)){foundFirst=true;}else if(foundFirst){normalized[u]=defaultValues[u];}else{normalized[u]=objNow[u];}} 437var higherOrderInvalid=useWeekData?hasInvalidWeekData(normalized,minDaysInFirstWeek,startOfWeek):containsOrdinal?hasInvalidOrdinalData(normalized):hasInvalidGregorianData(normalized),invalid=higherOrderInvalid||hasInvalidTimeData(normalized);if(invalid){return DateTime.invalid(invalid);} 438var gregorian=useWeekData?weekToGregorian(normalized,minDaysInFirstWeek,startOfWeek):containsOrdinal?ordinalToGregorian(normalized):normalized,_objToTS2=objToTS(gregorian,offsetProvis,zoneToUse),tsFinal=_objToTS2[0],offsetFinal=_objToTS2[1],inst=new DateTime({ts:tsFinal,zone:zoneToUse,o:offsetFinal,loc:loc});if(normalized.weekday&&containsGregor&&obj.weekday!==inst.weekday){return DateTime.invalid("mismatched weekday","you can't specify both a weekday of "+normalized.weekday+" and a date of "+inst.toISO());} 439if(!inst.isValid){return DateTime.invalid(inst.invalid);} 440return inst;};DateTime.fromISO=function fromISO(text,opts){if(opts===void 0){opts={};} 441var _parseISODate=parseISODate(text),vals=_parseISODate[0],parsedZone=_parseISODate[1];return parseDataToDateTime(vals,parsedZone,opts,"ISO 8601",text);};DateTime.fromRFC2822=function fromRFC2822(text,opts){if(opts===void 0){opts={};} 442var _parseRFC2822Date=parseRFC2822Date(text),vals=_parseRFC2822Date[0],parsedZone=_parseRFC2822Date[1];return parseDataToDateTime(vals,parsedZone,opts,"RFC 2822",text);};DateTime.fromHTTP=function fromHTTP(text,opts){if(opts===void 0){opts={};} 443var _parseHTTPDate=parseHTTPDate(text),vals=_parseHTTPDate[0],parsedZone=_parseHTTPDate[1];return parseDataToDateTime(vals,parsedZone,opts,"HTTP",opts);};DateTime.fromFormat=function fromFormat(text,fmt,opts){if(opts===void 0){opts={};} 444if(isUndefined(text)||isUndefined(fmt)){throw new InvalidArgumentError("fromFormat requires an input string and a format");} 445var _opts=opts,_opts$locale=_opts.locale,locale=_opts$locale===void 0?null:_opts$locale,_opts$numberingSystem=_opts.numberingSystem,numberingSystem=_opts$numberingSystem===void 0?null:_opts$numberingSystem,localeToUse=Locale.fromOpts({locale:locale,numberingSystem:numberingSystem,defaultToEN:true}),_parseFromTokens=parseFromTokens(localeToUse,text,fmt),vals=_parseFromTokens[0],parsedZone=_parseFromTokens[1],specificOffset=_parseFromTokens[2],invalid=_parseFromTokens[3];if(invalid){return DateTime.invalid(invalid);}else{return parseDataToDateTime(vals,parsedZone,opts,"format "+fmt,text,specificOffset);}};DateTime.fromString=function fromString(text,fmt,opts){if(opts===void 0){opts={};} 446return DateTime.fromFormat(text,fmt,opts);};DateTime.fromSQL=function fromSQL(text,opts){if(opts===void 0){opts={};} 447var _parseSQL=parseSQL(text),vals=_parseSQL[0],parsedZone=_parseSQL[1];return parseDataToDateTime(vals,parsedZone,opts,"SQL",text);};DateTime.invalid=function invalid(reason,explanation){if(explanation===void 0){explanation=null;} 448if(!reason){throw new InvalidArgumentError("need to specify a reason the DateTime is invalid");} 449var invalid=reason instanceof Invalid?reason:new Invalid(reason,explanation);if(Settings.throwOnInvalid){throw new InvalidDateTimeError(invalid);}else{return new DateTime({invalid:invalid});}};DateTime.isDateTime=function isDateTime(o){return o&&o.isLuxonDateTime||false;};DateTime.parseFormatForOpts=function parseFormatForOpts(formatOpts,localeOpts){if(localeOpts===void 0){localeOpts={};} 450var tokenList=formatOptsToTokens(formatOpts,Locale.fromObject(localeOpts));return!tokenList?null:tokenList.map(function(t){return t?t.val:null;}).join("");};DateTime.expandFormat=function expandFormat(fmt,localeOpts){if(localeOpts===void 0){localeOpts={};} 451var expanded=expandMacroTokens(Formatter.parseFormat(fmt),Locale.fromObject(localeOpts));return expanded.map(function(t){return t.val;}).join("");};DateTime.resetCache=function resetCache(){zoneOffsetTs=undefined;zoneOffsetGuessCache={};};var _proto=DateTime.prototype;_proto.get=function get(unit){return this[unit];};_proto.getPossibleOffsets=function getPossibleOffsets(){if(!this.isValid||this.isOffsetFixed){return[this];} 452var dayMs=86400000;var minuteMs=60000;var localTS=objToLocalTS(this.c);var oEarlier=this.zone.offset(localTS-dayMs);var oLater=this.zone.offset(localTS+dayMs);var o1=this.zone.offset(localTS-oEarlier*minuteMs);var o2=this.zone.offset(localTS-oLater*minuteMs);if(o1===o2){return[this];} 453var ts1=localTS-o1*minuteMs;var ts2=localTS-o2*minuteMs;var c1=tsToObj(ts1,o1);var c2=tsToObj(ts2,o2);if(c1.hour===c2.hour&&c1.minute===c2.minute&&c1.second===c2.second&&c1.millisecond===c2.millisecond){return[clone(this,{ts:ts1}),clone(this,{ts:ts2})];} 454return[this];};_proto.resolvedLocaleOptions=function resolvedLocaleOptions(opts){if(opts===void 0){opts={};} 455var _Formatter$create$res=Formatter.create(this.loc.clone(opts),opts).resolvedOptions(this),locale=_Formatter$create$res.locale,numberingSystem=_Formatter$create$res.numberingSystem,calendar=_Formatter$create$res.calendar;return{locale:locale,numberingSystem:numberingSystem,outputCalendar:calendar};};_proto.toUTC=function toUTC(offset,opts){if(offset===void 0){offset=0;} 456if(opts===void 0){opts={};} 457return this.setZone(FixedOffsetZone.instance(offset),opts);};_proto.toLocal=function toLocal(){return this.setZone(Settings.defaultZone);};_proto.setZone=function setZone(zone,_temp){var _ref2=_temp===void 0?{}:_temp,_ref2$keepLocalTime=_ref2.keepLocalTime,keepLocalTime=_ref2$keepLocalTime===void 0?false:_ref2$keepLocalTime,_ref2$keepCalendarTim=_ref2.keepCalendarTime,keepCalendarTime=_ref2$keepCalendarTim===void 0?false:_ref2$keepCalendarTim;zone=normalizeZone(zone,Settings.defaultZone);if(zone.equals(this.zone)){return this;}else if(!zone.isValid){return DateTime.invalid(unsupportedZone(zone));}else{var newTS=this.ts;if(keepLocalTime||keepCalendarTime){var offsetGuess=zone.offset(this.ts);var asObj=this.toObject();var _objToTS3=objToTS(asObj,offsetGuess,zone);newTS=_objToTS3[0];} 458return clone(this,{ts:newTS,zone:zone});}};_proto.reconfigure=function reconfigure(_temp2){var _ref3=_temp2===void 0?{}:_temp2,locale=_ref3.locale,numberingSystem=_ref3.numberingSystem,outputCalendar=_ref3.outputCalendar;var loc=this.loc.clone({locale:locale,numberingSystem:numberingSystem,outputCalendar:outputCalendar});return clone(this,{loc:loc});};_proto.setLocale=function setLocale(locale){return this.reconfigure({locale:locale});};_proto.set=function set(values){if(!this.isValid)return this;var normalized=normalizeObject(values,normalizeUnitWithLocalWeeks);var _usesLocalWeekValues2=usesLocalWeekValues(normalized,this.loc),minDaysInFirstWeek=_usesLocalWeekValues2.minDaysInFirstWeek,startOfWeek=_usesLocalWeekValues2.startOfWeek;var settingWeekStuff=!isUndefined(normalized.weekYear)||!isUndefined(normalized.weekNumber)||!isUndefined(normalized.weekday),containsOrdinal=!isUndefined(normalized.ordinal),containsGregorYear=!isUndefined(normalized.year),containsGregorMD=!isUndefined(normalized.month)||!isUndefined(normalized.day),containsGregor=containsGregorYear||containsGregorMD,definiteWeekDef=normalized.weekYear||normalized.weekNumber;if((containsGregor||containsOrdinal)&&definiteWeekDef){throw new ConflictingSpecificationError("Can't mix weekYear/weekNumber units with year/month/day or ordinals");} 459if(containsGregorMD&&containsOrdinal){throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");} 460var mixed;if(settingWeekStuff){mixed=weekToGregorian(_extends({},gregorianToWeek(this.c,minDaysInFirstWeek,startOfWeek),normalized),minDaysInFirstWeek,startOfWeek);}else if(!isUndefined(normalized.ordinal)){mixed=ordinalToGregorian(_extends({},gregorianToOrdinal(this.c),normalized));}else{mixed=_extends({},this.toObject(),normalized);if(isUndefined(normalized.day)){mixed.day=Math.min(daysInMonth(mixed.year,mixed.month),mixed.day);}} 461var _objToTS4=objToTS(mixed,this.o,this.zone),ts=_objToTS4[0],o=_objToTS4[1];return clone(this,{ts:ts,o:o});};_proto.plus=function plus(duration){if(!this.isValid)return this;var dur=Duration.fromDurationLike(duration);return clone(this,adjustTime(this,dur));};_proto.minus=function minus(duration){if(!this.isValid)return this;var dur=Duration.fromDurationLike(duration).negate();return clone(this,adjustTime(this,dur));};_proto.startOf=function startOf(unit,_temp3){var _ref4=_temp3===void 0?{}:_temp3,_ref4$useLocaleWeeks=_ref4.useLocaleWeeks,useLocaleWeeks=_ref4$useLocaleWeeks===void 0?false:_ref4$useLocaleWeeks;if(!this.isValid)return this;var o={},normalizedUnit=Duration.normalizeUnit(unit);switch(normalizedUnit){case"years":o.month=1;case"quarters":case"months":o.day=1;case"weeks":case"days":o.hour=0;case"hours":o.minute=0;case"minutes":o.second=0;case"seconds":o.millisecond=0;break;} 462if(normalizedUnit==="weeks"){if(useLocaleWeeks){var startOfWeek=this.loc.getStartOfWeek();var weekday=this.weekday;if(weekday<startOfWeek){o.weekNumber=this.weekNumber-1;} 463o.weekday=startOfWeek;}else{o.weekday=1;}} 464if(normalizedUnit==="quarters"){var q=Math.ceil(this.month/3);o.month=(q-1)*3+1;} 465return this.set(o);};_proto.endOf=function endOf(unit,opts){var _this$plus;return this.isValid?this.plus((_this$plus={},_this$plus[unit]=1,_this$plus)).startOf(unit,opts).minus(1):this;};_proto.toFormat=function toFormat(fmt,opts){if(opts===void 0){opts={};} 466return this.isValid?Formatter.create(this.loc.redefaultToEN(opts)).formatDateTimeFromString(this,fmt):INVALID;};_proto.toLocaleString=function toLocaleString(formatOpts,opts){if(formatOpts===void 0){formatOpts=DATE_SHORT;} 467if(opts===void 0){opts={};} 468return this.isValid?Formatter.create(this.loc.clone(opts),formatOpts).formatDateTime(this):INVALID;};_proto.toLocaleParts=function toLocaleParts(opts){if(opts===void 0){opts={};} 469return this.isValid?Formatter.create(this.loc.clone(opts),opts).formatDateTimeParts(this):[];};_proto.toISO=function toISO(_temp4){var _ref5=_temp4===void 0?{}:_temp4,_ref5$format=_ref5.format,format=_ref5$format===void 0?"extended":_ref5$format,_ref5$suppressSeconds=_ref5.suppressSeconds,suppressSeconds=_ref5$suppressSeconds===void 0?false:_ref5$suppressSeconds,_ref5$suppressMillise=_ref5.suppressMilliseconds,suppressMilliseconds=_ref5$suppressMillise===void 0?false:_ref5$suppressMillise,_ref5$includeOffset=_ref5.includeOffset,includeOffset=_ref5$includeOffset===void 0?true:_ref5$includeOffset,_ref5$extendedZone=_ref5.extendedZone,extendedZone=_ref5$extendedZone===void 0?false:_ref5$extendedZone;if(!this.isValid){return null;} 470var ext=format==="extended";var c=_toISODate(this,ext);c+="T";c+=_toISOTime(this,ext,suppressSeconds,suppressMilliseconds,includeOffset,extendedZone);return c;};_proto.toISODate=function toISODate(_temp5){var _ref6=_temp5===void 0?{}:_temp5,_ref6$format=_ref6.format,format=_ref6$format===void 0?"extended":_ref6$format;if(!this.isValid){return null;} 471return _toISODate(this,format==="extended");};_proto.toISOWeekDate=function toISOWeekDate(){return toTechFormat(this,"kkkk-'W'WW-c");};_proto.toISOTime=function toISOTime(_temp6){var _ref7=_temp6===void 0?{}:_temp6,_ref7$suppressMillise=_ref7.suppressMilliseconds,suppressMilliseconds=_ref7$suppressMillise===void 0?false:_ref7$suppressMillise,_ref7$suppressSeconds=_ref7.suppressSeconds,suppressSeconds=_ref7$suppressSeconds===void 0?false:_ref7$suppressSeconds,_ref7$includeOffset=_ref7.includeOffset,includeOffset=_ref7$includeOffset===void 0?true:_ref7$includeOffset,_ref7$includePrefix=_ref7.includePrefix,includePrefix=_ref7$includePrefix===void 0?false:_ref7$includePrefix,_ref7$extendedZone=_ref7.extendedZone,extendedZone=_ref7$extendedZone===void 0?false:_ref7$extendedZone,_ref7$format=_ref7.format,format=_ref7$format===void 0?"extended":_ref7$format;if(!this.isValid){return null;} 472var c=includePrefix?"T":"";return c+_toISOTime(this,format==="extended",suppressSeconds,suppressMilliseconds,includeOffset,extendedZone);};_proto.toRFC2822=function toRFC2822(){return toTechFormat(this,"EEE, dd LLL yyyy HH:mm:ss ZZZ",false);};_proto.toHTTP=function toHTTP(){return toTechFormat(this.toUTC(),"EEE, dd LLL yyyy HH:mm:ss 'GMT'");};_proto.toSQLDate=function toSQLDate(){if(!this.isValid){return null;} 473return _toISODate(this,true);};_proto.toSQLTime=function toSQLTime(_temp7){var _ref8=_temp7===void 0?{}:_temp7,_ref8$includeOffset=_ref8.includeOffset,includeOffset=_ref8$includeOffset===void 0?true:_ref8$includeOffset,_ref8$includeZone=_ref8.includeZone,includeZone=_ref8$includeZone===void 0?false:_ref8$includeZone,_ref8$includeOffsetSp=_ref8.includeOffsetSpace,includeOffsetSpace=_ref8$includeOffsetSp===void 0?true:_ref8$includeOffsetSp;var fmt="HH:mm:ss.SSS";if(includeZone||includeOffset){if(includeOffsetSpace){fmt+=" ";} 474if(includeZone){fmt+="z";}else if(includeOffset){fmt+="ZZ";}} 475return toTechFormat(this,fmt,true);};_proto.toSQL=function toSQL(opts){if(opts===void 0){opts={};} 476if(!this.isValid){return null;} 477return this.toSQLDate()+" "+this.toSQLTime(opts);};_proto.toString=function toString(){return this.isValid?this.toISO():INVALID;};_proto[_Symbol$for]=function(){if(this.isValid){return"DateTime { ts: "+this.toISO()+", zone: "+this.zone.name+", locale: "+this.locale+" }";}else{return"DateTime { Invalid, reason: "+this.invalidReason+" }";}};_proto.valueOf=function valueOf(){return this.toMillis();};_proto.toMillis=function toMillis(){return this.isValid?this.ts:NaN;};_proto.toSeconds=function toSeconds(){return this.isValid?this.ts/1000:NaN;};_proto.toUnixInteger=function toUnixInteger(){return this.isValid?Math.floor(this.ts/1000):NaN;};_proto.toJSON=function toJSON(){return this.toISO();};_proto.toBSON=function toBSON(){return this.toJSDate();};_proto.toObject=function toObject(opts){if(opts===void 0){opts={};} 478if(!this.isValid)return{};var base=_extends({},this.c);if(opts.includeConfig){base.outputCalendar=this.outputCalendar;base.numberingSystem=this.loc.numberingSystem;base.locale=this.loc.locale;} 479return base;};_proto.toJSDate=function toJSDate(){return new Date(this.isValid?this.ts:NaN);};_proto.diff=function diff(otherDateTime,unit,opts){if(unit===void 0){unit="milliseconds";} 480if(opts===void 0){opts={};} 481if(!this.isValid||!otherDateTime.isValid){return Duration.invalid("created by diffing an invalid DateTime");} 482var durOpts=_extends({locale:this.locale,numberingSystem:this.numberingSystem},opts);var units=maybeArray(unit).map(Duration.normalizeUnit),otherIsLater=otherDateTime.valueOf()>this.valueOf(),earlier=otherIsLater?this:otherDateTime,later=otherIsLater?otherDateTime:this,diffed=_diff(earlier,later,units,durOpts);return otherIsLater?diffed.negate():diffed;};_proto.diffNow=function diffNow(unit,opts){if(unit===void 0){unit="milliseconds";} 483if(opts===void 0){opts={};} 484return this.diff(DateTime.now(),unit,opts);};_proto.until=function until(otherDateTime){return this.isValid?Interval.fromDateTimes(this,otherDateTime):this;};_proto.hasSame=function hasSame(otherDateTime,unit,opts){if(!this.isValid)return false;var inputMs=otherDateTime.valueOf();var adjustedToZone=this.setZone(otherDateTime.zone,{keepLocalTime:true});return adjustedToZone.startOf(unit,opts)<=inputMs&&inputMs<=adjustedToZone.endOf(unit,opts);};_proto.equals=function equals(other){return this.isValid&&other.isValid&&this.valueOf()===other.valueOf()&&this.zone.equals(other.zone)&&this.loc.equals(other.loc);};_proto.toRelative=function toRelative(options){if(options===void 0){options={};} 485if(!this.isValid)return null;var base=options.base||DateTime.fromObject({},{zone:this.zone}),padding=options.padding?this<base?-options.padding:options.padding:0;var units=["years","months","days","hours","minutes","seconds"];var unit=options.unit;if(Array.isArray(options.unit)){units=options.unit;unit=undefined;} 486return diffRelative(base,this.plus(padding),_extends({},options,{numeric:"always",units:units,unit:unit}));};_proto.toRelativeCalendar=function toRelativeCalendar(options){if(options===void 0){options={};} 487if(!this.isValid)return null;return diffRelative(options.base||DateTime.fromObject({},{zone:this.zone}),this,_extends({},options,{numeric:"auto",units:["years","months","days"],calendary:true}));};DateTime.min=function min(){for(var _len=arguments.length,dateTimes=new Array(_len),_key=0;_key<_len;_key++){dateTimes[_key]=arguments[_key];} 488if(!dateTimes.every(DateTime.isDateTime)){throw new InvalidArgumentError("min requires all arguments be DateTimes");} 489return bestBy(dateTimes,function(i){return i.valueOf();},Math.min);};DateTime.max=function max(){for(var _len2=arguments.length,dateTimes=new Array(_len2),_key2=0;_key2<_len2;_key2++){dateTimes[_key2]=arguments[_key2];} 490if(!dateTimes.every(DateTime.isDateTime)){throw new InvalidArgumentError("max requires all arguments be DateTimes");} 491return bestBy(dateTimes,function(i){return i.valueOf();},Math.max);};DateTime.fromFormatExplain=function fromFormatExplain(text,fmt,options){if(options===void 0){options={};} 492var _options=options,_options$locale=_options.locale,locale=_options$locale===void 0?null:_options$locale,_options$numberingSys=_options.numberingSystem,numberingSystem=_options$numberingSys===void 0?null:_options$numberingSys,localeToUse=Locale.fromOpts({locale:locale,numberingSystem:numberingSystem,defaultToEN:true});return explainFromTokens(localeToUse,text,fmt);};DateTime.fromStringExplain=function fromStringExplain(text,fmt,options){if(options===void 0){options={};} 493return DateTime.fromFormatExplain(text,fmt,options);};DateTime.buildFormatParser=function buildFormatParser(fmt,options){if(options===void 0){options={};} 494var _options2=options,_options2$locale=_options2.locale,locale=_options2$locale===void 0?null:_options2$locale,_options2$numberingSy=_options2.numberingSystem,numberingSystem=_options2$numberingSy===void 0?null:_options2$numberingSy,localeToUse=Locale.fromOpts({locale:locale,numberingSystem:numberingSystem,defaultToEN:true});return new TokenParser(localeToUse,fmt);};DateTime.fromFormatParser=function fromFormatParser(text,formatParser,opts){if(opts===void 0){opts={};} 495if(isUndefined(text)||isUndefined(formatParser)){throw new InvalidArgumentError("fromFormatParser requires an input string and a format parser");} 496var _opts2=opts,_opts2$locale=_opts2.locale,locale=_opts2$locale===void 0?null:_opts2$locale,_opts2$numberingSyste=_opts2.numberingSystem,numberingSystem=_opts2$numberingSyste===void 0?null:_opts2$numberingSyste,localeToUse=Locale.fromOpts({locale:locale,numberingSystem:numberingSystem,defaultToEN:true});if(!localeToUse.equals(formatParser.locale)){throw new InvalidArgumentError("fromFormatParser called with a locale of "+localeToUse+", "+("but the format parser was created for "+formatParser.locale));} 497var _formatParser$explain=formatParser.explainFromTokens(text),result=_formatParser$explain.result,zone=_formatParser$explain.zone,specificOffset=_formatParser$explain.specificOffset,invalidReason=_formatParser$explain.invalidReason;
497if(invalidReason){return DateTime.invalid(invalidReason);}else{return parseDataToDateTime(result,zone,opts,"format "+formatParser.format,text,specificOffset);}};_createClass(DateTime,[{key:"isValid",get:function get(){return this.invalid===null;}},{key:"invalidReason",get:function get(){return this.invalid?this.invalid.reason:null;}},{key:"invalidExplanation",get:function get(){return this.invalid?this.invalid.explanation:null;}},{key:"locale",get:function get(){return this.isValid?this.loc.locale:null;}},{key:"numberingSystem",get:function get(){return this.isValid?this.loc.numberingSystem:null;}},{key:"outputCalendar",get:function get(){return this.isValid?this.loc.outputCalendar:null;}},{key:"zone",get:function get(){return this._zone;}},{key:"zoneName",get:function get(){return this.isValid?this.zone.name:null;}},{key:"year",get:function get(){return this.isValid?this.c.year:NaN;}},{key:"quarter",get:function get(){return this.isValid?Math.ceil(this.c.month/3):NaN;}},{key:"month",get:function get(){return this.isValid?this.c.month:NaN;}},{key:"day",get:function get(){return this.isValid?this.c.day:NaN;}},{key:"hour",get:function get(){return this.isValid?this.c.hour:NaN;}},{key:"minute",get:function get(){return this.isValid?this.c.minute:NaN;}},{key:"second",get:function get(){return this.isValid?this.c.second:NaN;}},{key:"millisecond",get:function get(){return this.isValid?this.c.millisecond:NaN;}},{key:"weekYear",get:function get(){return this.isValid?possiblyCachedWeekData(this).weekYear:NaN;}},{key:"weekNumber",get:function get(){return this.isValid?possiblyCachedWeekData(this).weekNumber:NaN;}},{key:"weekday",get:function get(){return this.isValid?possiblyCachedWeekData(this).weekday:NaN;}},{key:"isWeekend",get:function get(){return this.isValid&&this.loc.getWeekendDays().includes(this.weekday);}},{key:"localWeekday",get:function get(){return this.isValid?possiblyCachedLocalWeekData(this).weekday:NaN;}},{key:"localWeekNumber",get:function get(){return this.isValid?possiblyCachedLocalWeekData(this).weekNumber:NaN;}},{key:"localWeekYear",get:function get(){return this.isValid?possiblyCachedLocalWeekData(this).weekYear:NaN;}},{key:"ordinal",get:function get(){return this.isValid?gregorianToOrdinal(this.c).ordinal:NaN;}},{key:"monthShort",get:function get(){return this.isValid?Info.months("short",{locObj:this.loc})[this.month-1]:null;}},{key:"monthLong",get:function get(){return this.isValid?Info.months("long",{locObj:this.loc})[this.month-1]:null;}},{key:"weekdayShort",get:function get(){return this.isValid?Info.weekdays("short",{locObj:this.loc})[this.weekday-1]:null;}},{key:"weekdayLong",get:function get(){return this.isValid?Info.weekdays("long",{locObj:this.loc})[this.weekday-1]:null;}},{key:"offset",get:function get(){return this.isValid?+this.o:NaN;}},{key:"offsetNameShort",get:function get(){if(this.isValid){return this.zone.offsetName(this.ts,{format:"short",locale:this.locale});}else{return null;}}},{key:"offsetNameLong",get:function get(){if(this.isValid){return this.zone.offsetName(this.ts,{format:"long",locale:this.locale});}else{return null;}}},{key:"isOffsetFixed",get:function get(){return this.isValid?this.zone.isUniversal:null;}},{key:"isInDST",get:function get(){if(this.isOffsetFixed){return false;}else{return this.offset>this.set({month:1,day:1}).offset||this.offset>this.set({month:5}).offset;}}},{key:"isInLeapYear",get:function get(){return isLeapYear(this.year);}},{key:"daysInMonth",get:function get(){return daysInMonth(this.year,this.month);}},{key:"daysInYear",get:function get(){return this.isValid?daysInYear(this.year):NaN;}},{key:"weeksInWeekYear",get:function get(){return this.isValid?weeksInWeekYear(this.weekYear):NaN;}},{key:"weeksInLocalWeekYear",get:function get(){return this.isValid?weeksInWeekYear(this.localWeekYear,this.loc.getMinDaysInFirstWeek(),this.loc.getStartOfWeek()):NaN;}}],[{key:"DATE_SHORT",get:function get(){return DATE_SHORT;}},{key:"DATE_MED",get:function get(){return DATE_MED;}},{key:"DATE_MED_WITH_WEEKDAY",get:function get(){return DATE_MED_WITH_WEEKDAY;}},{key:"DATE_FULL",get:function get(){return DATE_FULL;}},{key:"DATE_HUGE",get:function get(){return DATE_HUGE;}},{key:"TIME_SIMPLE",get:function get(){return TIME_SIMPLE;}},{key:"TIME_WITH_SECONDS",get:function get(){return TIME_WITH_SECONDS;}},{key:"TIME_WITH_SHORT_OFFSET",get:function get(){return TIME_WITH_SHORT_OFFSET;}},{key:"TIME_WITH_LONG_OFFSET",get:function get(){return TIME_WITH_LONG_OFFSET;}},{key:"TIME_24_SIMPLE",get:function get(){return TIME_24_SIMPLE;}},{key:"TIME_24_WITH_SECONDS",get:function get(){return TIME_24_WITH_SECONDS;}},{key:"TIME_24_WITH_SHORT_OFFSET",get:function get(){return TIME_24_WITH_SHORT_OFFSET;}},{key:"TIME_24_WITH_LONG_OFFSET",get:function get(){return TIME_24_WITH_LONG_OFFSET;}},{key:"DATETIME_SHORT",get:function get(){return DATETIME_SHORT;}},{key:"DATETIME_SHORT_WITH_SECONDS",get:function get(){return DATETIME_SHORT_WITH_SECONDS;}},{key:"DATETIME_MED",get:function get(){return DATETIME_MED;}},{key:"DATETIME_MED_WITH_SECONDS",get:function get(){return DATETIME_MED_WITH_SECONDS;}},{key:"DATETIME_MED_WITH_WEEKDAY",get:function get(){return DATETIME_MED_WITH_WEEKDAY;}},{key:"DATETIME_FULL",get:function get(){return DATETIME_FULL;}},{key:"DATETIME_FULL_WITH_SECONDS",get:function get(){return DATETIME_FULL_WITH_SECONDS;}},{key:"DATETIME_HUGE",get:function get(){return DATETIME_HUGE;}},{key:"DATETIME_HUGE_WITH_SECONDS",get:function get(){return DATETIME_HUGE_WITH_SECONDS;}}]);return DateTime;}(Symbol.for("nodejs.util.inspect.custom"));function friendlyDateTime(dateTimeish){if(DateTime.isDateTime(dateTimeish)){return dateTimeish;}else if(dateTimeish&&dateTimeish.valueOf&&isNumber(dateTimeish.valueOf())){return DateTime.fromJSDate(dateTimeish);}else if(dateTimeish&&typeof dateTimeish==="object"){return DateTime.fromObject(dateTimeish);}else{throw new InvalidArgumentError("Unknown datetime argument: "+dateTimeish+", of type "+typeof dateTimeish);}} 498var VERSION="3.5.0";exports.DateTime=DateTime;exports.Duration=Duration;exports.FixedOffsetZone=FixedOffsetZone;exports.IANAZone=IANAZone;exports.Info=Info;exports.Interval=Interval;exports.InvalidZone=InvalidZone;exports.Settings=Settings;exports.SystemZone=SystemZone;exports.VERSION=VERSION;exports.Zone=Zone;Object.defineProperty(exports,'__esModule',{value:true});return exports;})({});luxon.DateTime.prototype[Symbol.toStringTag]="LuxonDateTime";luxon.Duration.prototype[Symbol.toStringTag]="LuxonDuration";luxon.Interval.prototype[Symbol.toStringTag]="LuxonInterval";luxon.Settings.prototype[Symbol.toStringTag]="LuxonSettings";luxon.Info.prototype[Symbol.toStringTag]="LuxonInfo";luxon.Zone.prototype[Symbol.toStringTag]="LuxonZone";; 499 500/* /web/static/lib/owl/owl.js */ 501(function(exports){'use strict';function filterOutModifiersFromData(dataList){dataList=dataList.slice();const modifiers=[];let elm;while((elm=dataList[0])&&typeof elm==="string"){modifiers.push(dataList.shift());} 502return{modifiers,data:dataList};} 503const config={shouldNormalizeDom:true,mainEventHandler:(data,ev,currentTarget)=>{if(typeof data==="function"){data(ev);} 504else if(Array.isArray(data)){data=filterOutModifiersFromData(data).data;data[0](data[1],ev);} 505return false;},};class VToggler{constructor(key,child){this.key=key;this.child=child;} 506mount(parent,afterNode){this.parentEl=parent;this.child.mount(parent,afterNode);} 507moveBeforeDOMNode(node,parent){this.child.moveBeforeDOMNode(node,parent);} 508moveBeforeVNode(other,afterNode){this.moveBeforeDOMNode((other&&other.firstNode())||afterNode);} 509patch(other,withBeforeRemove){if(this===other){return;} 510let child1=this.child;let child2=other.child;if(this.key===other.key){child1.patch(child2,withBeforeRemove);} 511else{child2.mount(this.parentEl,child1.firstNode());if(withBeforeRemove){child1.beforeRemove();} 512child1.remove();this.child=child2;this.key=other.key;}} 513beforeRemove(){this.child.beforeRemove();} 514remove(){this.child.remove();} 515firstNode(){return this.child.firstNode();} 516toString(){return this.child.toString();}} 517function toggler(key,child){return new VToggler(key,child);}
518class OwlError extends Error{} 519let elemSetAttribute;let removeAttribute;let tokenListAdd;let tokenListRemove;if(typeof Element!=="undefined"){({setAttribute:elemSetAttribute,removeAttribute}=Element.prototype);const tokenList=DOMTokenList.prototype;tokenListAdd=tokenList.add;tokenListRemove=tokenList.remove;} 520const isArray=Array.isArray;const{split,trim}=String.prototype;const wordRegexp=/\s+/;function setAttribute(key,value){switch(value){case false:case undefined:removeAttribute.call(this,key);break;case true:elemSetAttribute.call(this,key,"");break;default:elemSetAttribute.call(this,key,value);}} 521function createAttrUpdater(attr){return function(value){setAttribute.call(this,attr,value);};} 522function attrsSetter(attrs){if(isArray(attrs)){if(attrs[0]==="class"){setClass.call(this,attrs[1]);} 523else{setAttribute.call(this,attrs[0],attrs[1]);}} 524else{for(let k in attrs){if(k==="class"){setClass.call(this,attrs[k]);} 525else{setAttribute.call(this,k,attrs[k]);}}}} 526function attrsUpdater(attrs,oldAttrs){if(isArray(attrs)){const name=attrs[0];const val=attrs[1];if(name===oldAttrs[0]){if(val===oldAttrs[1]){return;} 527if(name==="class"){updateClass.call(this,val,oldAttrs[1]);} 528else{setAttribute.call(this,name,val);}} 529else{removeAttribute.call(this,oldAttrs[0]);setAttribute.call(this,name,val);}} 530else{for(let k in oldAttrs){if(!(k in attrs)){if(k==="class"){updateClass.call(this,"",oldAttrs[k]);} 531else{removeAttribute.call(this,k);}}} 532for(let k in attrs){const val=attrs[k];if(val!==oldAttrs[k]){if(k==="class"){updateClass.call(this,val,oldAttrs[k]);} 533else{setAttribute.call(this,k,val);}}}}} 534function toClassObj(expr){const result={};switch(typeof expr){case"string":const str=trim.call(expr);if(!str){return{};} 535let words=split.call(str,wordRegexp);for(let i=0,l=words.length;i<l;i++){result[words[i]]=true;} 536return result;case"object":for(let key in expr){const value=expr[key];if(value){key=trim.call(key);if(!key){continue;} 537const words=split.call(key,wordRegexp);for(let word of words){result[word]=value;}}} 538return result;case"undefined":return{};case"number":return{[expr]:true};default:return{[expr]:true};}} 539function setClass(val){val=val===""?{}:toClassObj(val);const cl=this.classList;for(let c in val){tokenListAdd.call(cl,c);}} 540function updateClass(val,oldVal){oldVal=oldVal===""?{}:toClassObj(oldVal);val=val===""?{}:toClassObj(val);const cl=this.classList;for(let c in oldVal){if(!(c in val)){tokenListRemove.call(cl,c);}} 541for(let c in val){if(!(c in oldVal)){tokenListAdd.call(cl,c);}}} 542function batched(callback){let scheduled=false;return async(...args)=>{if(!scheduled){scheduled=true;await Promise.resolve();scheduled=false;callback(...args);}};} 543function inOwnerDocument(el){if(!el){return false;} 544if(el.ownerDocument.contains(el)){return true;} 545const rootNode=el.getRootNode();return rootNode instanceof ShadowRoot&&el.ownerDocument.contains(rootNode.host);} 546function isAttachedToDocument(element,documentElement){let current=element;const shadowRoot=documentElement.defaultView.ShadowRoot;while(current){if(current===documentElement){return true;} 547if(current.parentNode){current=current.parentNode;} 548else if(current instanceof shadowRoot&¤t.host){current=current.host;} 549else{return false;}} 550return false;} 551function validateTarget(target){const document=target&&target.ownerDocument;if(document){if(!document.defaultView){throw new OwlError("Cannot mount a component: the target document is not attached to a window (defaultView is missing)");} 552const HTMLElement=document.defaultView.HTMLElement;if(target instanceof HTMLElement||target instanceof ShadowRoot){if(!isAttachedToDocument(target,document)){throw new OwlError("Cannot mount a component on a detached dom node");} 553return;}} 554throw new OwlError("Cannot mount component: the target is not a valid DOM element");} 555class EventBus extends EventTarget{trigger(name,payload){this.dispatchEvent(new CustomEvent(name,{detail:payload}));}} 556function whenReady(fn){return new Promise(function(resolve){if(document.readyState!=="loading"){resolve(true);}
557else{document.addEventListener("DOMContentLoaded",resolve,false);}}).then(fn||function(){});} 558async function loadFile(url){const result=await fetch(url);if(!result.ok){throw new OwlError("Error while fetching xml templates");} 559return await result.text();} 560class Markup extends String{} 561function htmlEscape(str){if(str instanceof Markup){return str;} 562if(str===undefined){return markup("");} 563if(typeof str==="number"){return markup(String(str));} 564[["&","&"],["<","<"],[">",">"],["'","'"],['"',"""],["`","`"],].forEach((pairs)=>{str=String(str).replace(new RegExp(pairs[0],"g"),pairs[1]);});return markup(str);} 565function markup(valueOrStrings,...placeholders){if(!Array.isArray(valueOrStrings)){return new Markup(valueOrStrings);} 566const strings=valueOrStrings;let acc="";let i=0;for(;i<placeholders.length;++i){acc+=strings[i]+htmlEscape(placeholders[i]);} 567acc+=strings[i];return new Markup(acc);} 568function createEventHandler(rawEvent){const eventName=rawEvent.split(".")[0];const capture=rawEvent.includes(".capture");if(rawEvent.includes(".synthetic")){return createSyntheticHandler(eventName,capture);} 569else{return createElementHandler(eventName,capture);}} 570let nextNativeEventId=1;function createElementHandler(evName,capture=false){let eventKey=`__event__${evName}_${nextNativeEventId++}`;
570if(capture){eventKey=`${eventKey}_capture`;} 571function listener(ev){const currentTarget=ev.currentTarget;if(!currentTarget||!inOwnerDocument(currentTarget)) 572return;const data=currentTarget[eventKey];if(!data) 573return;config.mainEventHandler(data,ev,currentTarget);} 574function setup(data){this[eventKey]=data;this.addEventListener(evName,listener,{capture});} 575function remove(){delete this[eventKey];this.removeEventListener(evName,listener,{capture});} 576function update(data){this[eventKey]=data;} 577return{setup,update,remove};} 578let nextSyntheticEventId=1;function createSyntheticHandler(evName,capture=false){let eventKey=`__event__synthetic_${evName}`;if(capture){eventKey=`${eventKey}_capture`;} 579setupSyntheticEvent(evName,eventKey,capture);const currentId=nextSyntheticEventId++;function setup(data){const _data=this[eventKey]||{};_data[currentId]=data;this[eventKey]=_data;} 580function remove(){delete this[eventKey];} 581return{setup,update:setup,remove};} 582function nativeToSyntheticEvent(eventKey,event){let dom=event.target;while(dom!==null){const _data=dom[eventKey];if(_data){for(const data of Object.values(_data)){const stopped=config.mainEventHandler(data,event,dom);if(stopped) 583return;}} 584dom=dom.parentNode;}} 585const CONFIGURED_SYNTHETIC_EVENTS={};function setupSyntheticEvent(evName,eventKey,capture=false){if(CONFIGURED_SYNTHETIC_EVENTS[eventKey]){return;} 586document.addEventListener(evName,(event)=>nativeToSyntheticEvent(eventKey,event),{capture,});CONFIGURED_SYNTHETIC_EVENTS[eventKey]=true;} 587const getDescriptor$3=(o,p)=>Object.getOwnPropertyDescriptor(o,p);let nodeInsertBefore$3;let nodeSetTextContent$1;let nodeRemoveChild$3;if(typeof Node!=="undefined"){const nodeProto=Node.prototype;nodeInsertBefore$3=nodeProto.insertBefore;nodeSetTextContent$1=getDescriptor$3(nodeProto,"textContent").set;nodeRemoveChild$3=nodeProto.removeChild;} 588class VMulti{constructor(children){this.children=children;} 589mount(parent,afterNode){const children=this.children;const l=children.length;const anchors=new Array(l);for(let i=0;i<l;i++){let child=children[i];if(child){child.mount(parent,afterNode);} 590else{const childAnchor=document.createTextNode("");anchors[i]=childAnchor;nodeInsertBefore$3.call(parent,childAnchor,afterNode);}} 591this.anchors=anchors;this.parentEl=parent;} 592moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;const children=this.children;const anchors=this.anchors;for(let i=0,l=children.length;i<l;i++){let child=children[i];if(child){child.moveBeforeDOMNode(node,parent);} 593else{const anchor=anchors[i];nodeInsertBefore$3.call(parent,anchor,node);}}} 594moveBeforeVNode(other,afterNode){if(other){const next=other.children[0];afterNode=(next?next.firstNode():other.anchors[0])||null;} 595const children=this.children;const parent=this.parentEl;const anchors=this.anchors;for(let i=0,l=children.length;i<l;i++){let child=children[i];if(child){child.moveBeforeVNode(null,afterNode);} 596else{const anchor=anchors[i];nodeInsertBefore$3.call(parent,anchor,afterNode);}}} 597patch(other,withBeforeRemove){if(this===other){return;} 598const children1=this.children;const children2=other.children;const anchors=this.anchors;const parentEl=this.parentEl;for(let i=0,l=children1.length;i<l;i++){const vn1=children1[i];const vn2=children2[i];if(vn1){if(vn2){vn1.patch(vn2,withBeforeRemove);} 599else{const afterNode=vn1.firstNode();const anchor=document.createTextNode("");anchors[i]=anchor;nodeInsertBefore$3.call(parentEl,anchor,afterNode);
599if(withBeforeRemove){vn1.beforeRemove();} 600vn1.remove();children1[i]=undefined;}} 601else if(vn2){children1[i]=vn2;const anchor=anchors[i];vn2.mount(parentEl,anchor);nodeRemoveChild$3.call(parentEl,anchor);}}} 602beforeRemove(){const children=this.children;for(let i=0,l=children.length;i<l;i++){const child=children[i];if(child){child.beforeRemove();}}} 603remove(){const parentEl=this.parentEl;if(this.isOnlyChild){nodeSetTextContent$1.call(parentEl,"");} 604else{const children=this.children;const anchors=this.anchors;for(let i=0,l=children.length;i<l;i++){const child=children[i];if(child){child.remove();} 605else{nodeRemoveChild$3.call(parentEl,anchors[i]);}}}} 606firstNode(){const child=this.children[0];return child?child.firstNode():this.anchors[0];} 607toString(){return this.children.map((c)=>(c?c.toString():"")).join("");}} 608function multi(children){return new VMulti(children);} 609const getDescriptor$2=(o,p)=>Object.getOwnPropertyDescriptor(o,p);let nodeInsertBefore$2;let characterDataSetData$1;let nodeRemoveChild$2;if(typeof Node!=="undefined"){const nodeProto=Node.prototype;nodeInsertBefore$2=nodeProto.insertBefore;nodeRemoveChild$2=nodeProto.removeChild;characterDataSetData$1=getDescriptor$2(CharacterData.prototype,"data").set;} 610class VSimpleNode{constructor(text){this.text=text;} 611mountNode(node,parent,afterNode){this.parentEl=parent;nodeInsertBefore$2.call(parent,node,afterNode);this.el=node;} 612moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;nodeInsertBefore$2.call(parent,this.el,node);} 613moveBeforeVNode(other,afterNode){nodeInsertBefore$2.call(this.parentEl,this.el,other?other.el:afterNode);} 614beforeRemove(){} 615remove(){nodeRemoveChild$2.call(this.parentEl,this.el);} 616firstNode(){return this.el;} 617toString(){return this.text;}} 618class VText$1 extends VSimpleNode{mount(parent,afterNode){this.mountNode(document.createTextNode(toText(this.text)),parent,afterNode);} 619patch(other){const text2=other.text;if(this.text!==text2){characterDataSetData$1.call(this.el,toText(text2));this.text=text2;}}} 620class VComment extends VSimpleNode{mount(parent,afterNode){this.mountNode(document.createComment(toText(this.text)),parent,afterNode);} 621patch(){}} 622function text(str){return new VText$1(str);} 623function comment(str){return new VComment(str);} 624function toText(value){switch(typeof value){case"string":return value;case"number":return String(value);case"boolean":return value?"true":"false";default:return value||"";}} 625const getDescriptor$1=(o,p)=>Object.getOwnPropertyDescriptor(o,p);let nodeProto;let elementProto;let characterDataSetData;let nodeGetFirstChild;let nodeGetNextSibling;if(typeof Node!=="undefined"){nodeProto=Node.prototype;elementProto=Element.prototype;characterDataSetData=getDescriptor$1(CharacterData.prototype,"data").set;nodeGetFirstChild=getDescriptor$1(nodeProto,"firstChild").get;nodeGetNextSibling=getDescriptor$1(nodeProto,"nextSibling").get;} 626const NO_OP$1=()=>{};function makePropSetter(name){return function setProp(value){this[name]=value===0?0:value?value.valueOf():"";};} 627const cache$1={};function createBlock(str){if(str in cache$1){return cache$1[str];} 628const doc=new DOMParser().parseFromString(`<t>${str}</t>`,"text/xml");const node=doc.firstChild.firstChild;if(config.shouldNormalizeDom){normalizeNode(node);} 629const tree=buildTree(node);const context=buildContext(tree);const template=tree.el;const Block=buildBlock(template,context);cache$1[str]=Block;return Block;} 630function normalizeNode(node){if(node.nodeType===Node.TEXT_NODE){if(!/\S/.test(node.textContent)){node.remove();return;}} 631if(node.nodeType===Node.ELEMENT_NODE){if(node.tagName==="pre"){return;}} 632for(let i=node.childNodes.length-1;i>=0;--i){normalizeNode(node.childNodes.item(i));}} 633function buildTree(node,parent=null,domParentTree=null){switch(node.nodeType){case Node.ELEMENT_NODE:{let currentNS=domParentTree&&domParentTree.currentNS;const tagName=node.tagName;let el=undefined;const info=[];if(tagName.startsWith("block-text-")){const index=parseInt(tagName.slice(11),10);info.push({type:"text",idx:index});el=document.createTextNode("");} 634if(tagName.startsWith("block-child-")){if(!domParentTree.isRef){addRef(domParentTree);}
635const index=parseInt(tagName.slice(12),10);info.push({type:"child",idx:index});el=document.createTextNode("");} 636currentNS||(currentNS=node.namespaceURI);if(!el){el=currentNS?document.createElementNS(currentNS,tagName):document.createElement(tagName);} 637if(el instanceof Element){if(!domParentTree){const fragment=document.createElement("template").content;fragment.appendChild(el);} 638const attrs=node.attributes;for(let i=0;i<attrs.length;i++){const attrName=attrs[i].name;const attrValue=attrs[i].value;if(attrName.startsWith("block-handler-")){const idx=parseInt(attrName.slice(14),10);info.push({type:"handler",idx,event:attrValue,});} 639else if(attrName.startsWith("block-attribute-")){const idx=parseInt(attrName.slice(16),10);info.push({type:"attribute",idx,name:attrValue,tag:tagName,});} 640else if(attrName.startsWith("block-property-")){const idx=parseInt(attrName.slice(15),10);info.push({type:"property",idx,name:attrValue,tag:tagName,});} 641else if(attrName==="block-attributes"){info.push({type:"attributes",idx:parseInt(attrValue,10),});} 642else if(attrName==="block-ref"){info.push({type:"ref",idx:parseInt(attrValue,10),});} 643else{el.setAttribute(attrs[i].name,attrValue);}}} 644const tree={parent,firstChild:null,nextSibling:null,el,info,refN:0,currentNS,};if(node.firstChild){const childNode=node.childNodes[0];if(node.childNodes.length===1&&childNode.nodeType===Node.ELEMENT_NODE&&childNode.tagName.startsWith("block-child-")){const tagName=childNode.tagName;const index=parseInt(tagName.slice(12),10);info.push({idx:index,type:"child",isOnlyChild:true});} 645else{tree.firstChild=buildTree(node.firstChild,tree,tree);el.appendChild(tree.firstChild.el);let curNode=node.firstChild;let curTree=tree.firstChild;while((curNode=curNode.nextSibling)){curTree.nextSibling=buildTree(curNode,curTree,tree);el.appendChild(curTree.nextSibling.el);curTree=curTree.nextSibling;}}} 646if(tree.info.length){addRef(tree);} 647return tree;} 648case Node.TEXT_NODE:case Node.COMMENT_NODE:{const el=node.nodeType===Node.TEXT_NODE?document.createTextNode(node.textContent):document.createComment(node.textContent);return{parent:parent,firstChild:null,nextSibling:null,el,info:[],refN:0,currentNS:null,};}} 649throw new OwlError("boom");} 650function addRef(tree){tree.isRef=true;do{tree.refN++;}while((tree=tree.parent));} 651function parentTree(tree){let parent=tree.parent;while(parent&&parent.nextSibling===tree){tree=parent;parent=parent.parent;} 652return parent;} 653function buildContext(tree,ctx,fromIdx){if(!ctx){const children=new Array(tree.info.filter((v)=>v.type==="child").length);ctx={collectors:[],locations:[],children,cbRefs:[],refN:tree.refN,refList:[]};fromIdx=0;} 654if(tree.refN){const initialIdx=fromIdx;const isRef=tree.isRef;const firstChild=tree.firstChild?tree.firstChild.refN:0;const nextSibling=tree.nextSibling?tree.nextSibling.refN:0;
654if(isRef){for(let info of tree.info){info.refIdx=initialIdx;} 655tree.refIdx=initialIdx;updateCtx(ctx,tree);fromIdx++;} 656if(nextSibling){const idx=fromIdx+firstChild;ctx.collectors.push({idx,prevIdx:initialIdx,getVal:nodeGetNextSibling});buildContext(tree.nextSibling,ctx,idx);} 657if(firstChild){ctx.collectors.push({idx:fromIdx,prevIdx:initialIdx,getVal:nodeGetFirstChild});buildContext(tree.firstChild,ctx,fromIdx);}} 658return ctx;} 659function updateCtx(ctx,tree){for(let info of tree.info){switch(info.type){case"text":ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:setText,updateData:setText,});break;case"child":if(info.isOnlyChild){ctx.children[info.idx]={parentRefIdx:info.refIdx,isOnlyChild:true,};} 660else{ctx.children[info.idx]={parentRefIdx:parentTree(tree).refIdx,afterRefIdx:info.refIdx,};} 661break;case"property":{const refIdx=info.refIdx;const setProp=makePropSetter(info.name);ctx.locations.push({idx:info.idx,refIdx,setData:setProp,updateData:setProp,});break;} 662case"attribute":{const refIdx=info.refIdx;let updater;let setter;if(info.name==="class"){setter=setClass;updater=updateClass;} 663else{setter=createAttrUpdater(info.name);updater=setter;} 664ctx.locations.push({idx:info.idx,refIdx,setData:setter,updateData:updater,});break;} 665case"attributes":ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:attrsSetter,updateData:attrsUpdater,});break;case"handler":{const{setup,update}=createEventHandler(info.event);ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:setup,updateData:update,});break;} 666case"ref":const index=ctx.cbRefs.push(info.idx)-1;ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:makeRefSetter(index,ctx.refList),updateData:NO_OP$1,});}}} 667function buildBlock(template,ctx){let B=createBlockClass(template,ctx);if(ctx.cbRefs.length){const cbRefs=ctx.cbRefs;const refList=ctx.refList;let cbRefsNumber=cbRefs.length;B=class extends B{mount(parent,afterNode){refList.push(new Array(cbRefsNumber));super.mount(parent,afterNode);for(let cbRef of refList.pop()){cbRef();}} 668remove(){super.remove();for(let cbRef of cbRefs){let fn=this.data[cbRef];fn(null);}}};} 669if(ctx.children.length){B=class extends B{constructor(data,children){super(data);this.children=children;}};B.prototype.beforeRemove=VMulti.prototype.beforeRemove;return(data,children=[])=>new B(data,children);} 670return(data)=>new B(data);} 671function createBlockClass(template,ctx){const{refN,collectors,children}=ctx;const colN=collectors.length;ctx.locations.sort((a,b)=>a.idx-b.idx);const locations=ctx.locations.map((loc)=>({refIdx:loc.refIdx,setData:loc.setData,updateData:loc.updateData,}));const locN=locations.length;const childN=children.length;const childrenLocs=children;const isDynamic=refN>0;const nodeCloneNode=nodeProto.cloneNode;const nodeInsertBefore=nodeProto.insertBefore;const elementRemove=elementProto.remove;class Block{constructor(data){this.data=data;} 672beforeRemove(){} 673remove(){elementRemove.call(this.el);} 674firstNode(){return this.el;} 675moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;nodeInsertBefore.call(parent,this.el,node);} 676moveBeforeVNode(other,afterNode){nodeInsertBefore.call(this.parentEl,this.el,other?other.el:afterNode);} 677toString(){const div=document.createElement("div");this.mount(div,null);return div.innerHTML;} 678mount(parent,afterNode){const el=nodeCloneNode.call(template,true);nodeInsertBefore.call(parent,el,afterNode);this.el=el;this.parentEl=parent;} 679patch(other,withBeforeRemove){}} 680if(isDynamic){Block.prototype.mount=function mount(parent,afterNode){const el=nodeCloneNode.call(template,true);const refs=new Array(refN);this.refs=refs;refs[0]=el;for(let i=0;i<colN;i++){const w=collectors[i];refs[w.idx]=w.getVal.call(refs[w.prevIdx]);} 681if(locN){const data=this.data;for(let i=0;i<locN;i++){const loc=locations[i];loc.setData.call(refs[loc.refIdx],data[i]);}} 682nodeInsertBefore.call(parent,el,afterNode);
682if(childN){const children=this.children;for(let i=0;i<childN;i++){const child=children[i];if(child){const loc=childrenLocs[i];const afterNode=loc.afterRefIdx?refs[loc.afterRefIdx]:null;child.isOnlyChild=loc.isOnlyChild;child.mount(refs[loc.parentRefIdx],afterNode);}}} 683this.el=el;this.parentEl=parent;};Block.prototype.patch=function patch(other,withBeforeRemove){if(this===other){return;} 684const refs=this.refs;if(locN){const data1=this.data;const data2=other.data;for(let i=0;i<locN;i++){const val1=data1[i];const val2=data2[i];if(val1!==val2){const loc=locations[i];loc.updateData.call(refs[loc.refIdx],val2,val1);}} 685this.data=data2;} 686if(childN){let children1=this.children;const children2=other.children;for(let i=0;i<childN;i++){const child1=children1[i];const child2=children2[i];if(child1){if(child2){child1.patch(child2,withBeforeRemove);} 687else{if(withBeforeRemove){child1.beforeRemove();} 688child1.remove();children1[i]=undefined;}} 689else if(child2){const loc=childrenLocs[i];const afterNode=loc.afterRefIdx?refs[loc.afterRefIdx]:null;child2.mount(refs[loc.parentRefIdx],afterNode);children1[i]=child2;}}}};} 690return Block;} 691function setText(value){characterDataSetData.call(this,toText(value));} 692function makeRefSetter(index,refs){return function setRef(fn){refs[refs.length-1][index]=()=>fn(this);};} 693const getDescriptor=(o,p)=>Object.getOwnPropertyDescriptor(o,p);let nodeInsertBefore$1;let nodeAppendChild;let nodeRemoveChild$1;let nodeSetTextContent;if(typeof Node!=="undefined"){const nodeProto=Node.prototype;nodeInsertBefore$1=nodeProto.insertBefore;nodeAppendChild=nodeProto.appendChild;nodeRemoveChild$1=nodeProto.removeChild;nodeSetTextContent=getDescriptor(nodeProto,"textContent").set;} 694class VList{constructor(children){this.children=children;} 695mount(parent,afterNode){const children=this.children;
695const _anchor=document.createTextNode("");this.anchor=_anchor;nodeInsertBefore$1.call(parent,_anchor,afterNode);const l=children.length;if(l){const mount=children[0].mount;for(let i=0;i<l;i++){mount.call(children[i],parent,_anchor);}} 696this.parentEl=parent;} 697moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;const children=this.children;for(let i=0,l=children.length;i<l;i++){children[i].moveBeforeDOMNode(node,parent);} 698parent.insertBefore(this.anchor,node);} 699moveBeforeVNode(other,afterNode){if(other){const next=other.children[0];afterNode=(next?next.firstNode():other.anchor)||null;} 700const children=this.children;for(let i=0,l=children.length;i<l;i++){children[i].moveBeforeVNode(null,afterNode);} 701this.parentEl.insertBefore(this.anchor,afterNode);} 702patch(other,withBeforeRemove){if(this===other){return;} 703const ch1=this.children;const ch2=other.children;if(ch2.length===0&&ch1.length===0){return;} 704this.children=ch2;const proto=ch2[0]||ch1[0];const{mount:cMount,patch:cPatch,remove:cRemove,beforeRemove,moveBeforeVNode:cMoveBefore,firstNode:cFirstNode,}=proto;const _anchor=this.anchor;const isOnlyChild=this.isOnlyChild;const parent=this.parentEl;if(ch2.length===0&&isOnlyChild){if(withBeforeRemove){for(let i=0,l=ch1.length;i<l;i++){beforeRemove.call(ch1[i]);}} 705nodeSetTextContent.call(parent,"");nodeAppendChild.call(parent,_anchor);return;} 706let startIdx1=0;let startIdx2=0;let startVn1=ch1[0];let startVn2=ch2[0];let endIdx1=ch1.length-1;let endIdx2=ch2.length-1;let endVn1=ch1[endIdx1];let endVn2=ch2[endIdx2];let mapping=undefined;while(startIdx1<=endIdx1&&startIdx2<=endIdx2){if(startVn1===null){startVn1=ch1[++startIdx1];continue;} 707if(endVn1===null){endVn1=ch1[--endIdx1];continue;} 708let startKey1=startVn1.key;let startKey2=startVn2.key;if(startKey1===startKey2){cPatch.call(startVn1,startVn2,withBeforeRemove);ch2[startIdx2]=startVn1;startVn1=ch1[++startIdx1];startVn2=ch2[++startIdx2];continue;} 709let endKey1=endVn1.key;let endKey2=endVn2.key;if(endKey1===endKey2){cPatch.call(endVn1,endVn2,withBeforeRemove);ch2[endIdx2]=endVn1;endVn1=ch1[--endIdx1];endVn2=ch2[--endIdx2];continue;} 710if(startKey1===endKey2){cPatch.call(startVn1,endVn2,withBeforeRemove);ch2[endIdx2]=startVn1;const nextChild=ch2[endIdx2+1];cMoveBefore.call(startVn1,nextChild,_anchor);startVn1=ch1[++startIdx1];endVn2=ch2[--endIdx2];continue;} 711if(endKey1===startKey2){cPatch.call(endVn1,startVn2,withBeforeRemove);ch2[startIdx2]=endVn1;const nextChild=ch1[startIdx1];cMoveBefore.call(endVn1,nextChild,_anchor);endVn1=ch1[--endIdx1];startVn2=ch2[++startIdx2];continue;} 712mapping=mapping||createMapping(ch1,startIdx1,endIdx1);let idxInOld=mapping[startKey2];if(idxInOld===undefined){cMount.call(startVn2,parent,cFirstNode.call(startVn1)||null);} 713else{const elmToMove=ch1[idxInOld];cMoveBefore.call(elmToMove,startVn1,null);cPatch.call(elmToMove,startVn2,withBeforeRemove);ch2[startIdx2]=elmToMove;ch1[idxInOld]=null;} 714startVn2=ch2[++startIdx2];} 715if(startIdx1<=endIdx1||startIdx2<=endIdx2){if(startIdx1>endIdx1){const nextChild=ch2[endIdx2+1];const anchor=nextChild?cFirstNode.call(nextChild)||null:_anchor;for(let i=startIdx2;i<=endIdx2;i++){cMount.call(ch2[i],parent,anchor);}} 716else{for(let i=startIdx1;i<=endIdx1;i++){let ch=ch1[i];if(ch){if(withBeforeRemove){beforeRemove.call(ch);} 717cRemove.call(ch);}}}}} 718beforeRemove(){const children=this.children;const l=children.length;if(l){const beforeRemove=children[0].beforeRemove;for(let i=0;i<l;i++){beforeRemove.call(children[i]);}}} 719remove(){const{parentEl,anchor}=this;if(this.isOnlyChild){nodeSetTextContent.call(parentEl,"");} 720else{const children=this.children;const l=children.length;if(l){const remove=children[0].remove;for(let i=0;i<l;i++){remove.call(children[i]);}} 721nodeRemoveChild$1.call(parentEl,anchor);}} 722firstNode(){const child=this.children[0];return child?child.firstNode():undefined;} 723toString(){return this.children.map((c)=>c.toString()).join("");}} 724function list(children){return new VList(children);} 725function createMapping(ch1,startIdx1,endIdx2){let mapping={};for(let i=startIdx1;i<=endIdx2;i++){mapping[ch1[i].key]=i;} 726return mapping;} 727let nodeInsertBefore;let nodeRemoveChild;if(typeof Node!=="undefined"){const nodeProto=Node.prototype;nodeInsertBefore=nodeProto.insertBefore;nodeRemoveChild=nodeProto.removeChild;} 728class VHtml{constructor(html){this.content=[];this.html=html;} 729mount(parent,afterNode){this.parentEl=parent;const template=document.createElement("template");template.innerHTML=this.html;this.content=[...template.content.childNodes];for(let elem of this.content){nodeInsertBefore.call(parent,elem,afterNode);} 730if(!this.content.length){const textNode=document.createTextNode("");this.content.push(textNode);nodeInsertBefore.call(parent,textNode,afterNode);}} 731moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;for(let elem of this.content){nodeInsertBefore.call(parent,elem,
731node);}} 732moveBeforeVNode(other,afterNode){const target=other?other.content[0]:afterNode;this.moveBeforeDOMNode(target);} 733patch(other){if(this===other){return;} 734const html2=other.html;if(this.html!==html2){const parent=this.parentEl;const afterNode=this.content[0];const template=document.createElement("template");template.innerHTML=html2;const content=[...template.content.childNodes];for(let elem of content){nodeInsertBefore.call(parent,elem,afterNode);} 735if(!content.length){const textNode=document.createTextNode("");content.push(textNode);nodeInsertBefore.call(parent,textNode,afterNode);} 736this.remove();this.content=content;this.html=other.html;}} 737beforeRemove(){} 738remove(){const parent=this.parentEl;for(let elem of this.content){nodeRemoveChild.call(parent,elem);}} 739firstNode(){return this.content[0];} 740toString(){return this.html;}} 741function html(str){return new VHtml(str);} 742function createCatcher(eventsSpec){const n=Object.keys(eventsSpec).length;class VCatcher{constructor(child,handlers){this.handlerFns=[];this.afterNode=null;this.child=child;this.handlerData=handlers;} 743mount(parent,afterNode){this.parentEl=parent;this.child.mount(parent,afterNode);this.afterNode=document.createTextNode("");parent.insertBefore(this.afterNode,afterNode);this.wrapHandlerData();for(let name in eventsSpec){const index=eventsSpec[name];const handler=createEventHandler(name);this.handlerFns[index]=handler;handler.setup.call(parent,this.handlerData[index]);}} 744wrapHandlerData(){for(let i=0;i<n;i++){let handler=this.handlerData[i];let idx=handler.length-2;let origFn=handler[idx];const self=this;handler[idx]=function(ev){const target=ev.target;let currentNode=self.child.firstNode();const afterNode=self.afterNode;while(currentNode&¤tNode!==afterNode){if(currentNode.contains(target)){return origFn.call(this,ev);} 745currentNode=currentNode.nextSibling;}};}} 746moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;this.child.moveBeforeDOMNode(node,parent);parent.insertBefore(this.afterNode,node);} 747moveBeforeVNode(other,afterNode){if(other){afterNode=other.firstNode()||afterNode;} 748this.child.moveBeforeVNode(other?other.child:null,afterNode);this.parentEl.insertBefore(this.afterNode,afterNode);} 749patch(other,withBeforeRemove){if(this===other){return;} 750this.handlerData=other.handlerData;this.wrapHandlerData();for(let i=0;i<n;i++){this.handlerFns[i].update.call(this.parentEl,this.handlerData[i]);} 751this.child.patch(other.child,withBeforeRemove);} 752beforeRemove(){this.child.beforeRemove();} 753remove(){for(let i=0;i<n;i++){this.handlerFns[i].remove.call(this.parentEl);} 754this.child.remove();this.afterNode.remove();} 755firstNode(){return this.child.firstNode();} 756toString(){return this.child.toString();}} 757return function(child,handlers){return new VCatcher(child,handlers);};} 758function mount$1(vnode,fixture,afterNode=null){vnode.mount(fixture,afterNode);} 759function patch(vnode1,vnode2,withBeforeRemove=false){vnode1.patch(vnode2,withBeforeRemove);} 760function remove(vnode,withBeforeRemove=false){if(withBeforeRemove){vnode.beforeRemove();} 761vnode.remove();} 762const fibersInError=new WeakMap();const nodeErrorHandlers=new WeakMap();function _handleError(node,error){if(!node){return false;} 763const fiber=node.fiber;if(fiber){fibersInError.set(fiber,error);} 764const errorHandlers=nodeErrorHandlers.get(node);if(errorHandlers){let handled=false;for(let i=errorHandlers.length-1;i>=0;i--){try{errorHandlers[i](error);handled=true;break;} 765catch(e){error=e;}} 766if(handled){return true;}} 767return _handleError(node.parent,error);} 768function handleError(params){let{error}=params;if(!(error instanceof OwlError)){error=Object.assign(new OwlError(`An error occured in the owl lifecycle (see this Error's "cause" property)`),{cause:error});} 769const node="node"in params?params.node:params.fiber.node;const fiber="fiber"in params?params.fiber:node.fiber;if(fiber){let current=fiber;do{current.node.fiber=current;fibersInError.set(current,error);current=current.parent;}while(current);fibersInError.set(fiber.root,error);} 770const handled=_handleError(node,error);if(!handled){console.warn(`[Owl] Unhandled error. Destroying the root component`);try{node.app.destroy();} 771catch(e){console.error(e);} 772throw error;}} 773function makeChildFiber(node,parent){let current=node.fiber;if(current){cancelFibers(current.children);current.root=null;} 774return new Fiber(node,parent);} 775function makeRootFiber(node){let current=node.fiber;if(current){let root=current.root;root.locked=true;root.setCounter(root.counter+1-cancelFibers(current.children));root.locked=false;current.children=[];current.childrenMap={};current.bdom=null;if(fibersInError.has(current)){fibersInError.delete(current);fibersInError.delete(root);current.appliedToDom=false;if(current instanceof RootFiber){current.mounted=current instanceof MountFiber?[current]:[];}} 776return current;} 777const fiber=new RootFiber(node,null);if(node.willPatch.length){fiber.willPatch.push(fiber);} 778if(node.patched.length){fiber.patched.push(fiber);} 779return fiber;} 780function throwOnRender(){throw new OwlError("Attempted to render cancelled fiber");} 781function cancelFibers(fibers){let result=0;for(let fiber of fibers){let node=fiber.node;fiber.render=throwOnRender;if(node.status===0){node.cancel();} 782node.fiber=null;if(fiber.bdom){node.forceNextRender=true;} 783else{result++;if(node.bdom){node.forceNextRender=true;}} 784result+=cancelFibers(fiber.children);} 785return result;} 786class Fiber{constructor(node,parent){this.bdom=null;this.children=[];this.appliedToDom=false;this.deep=false;this.childrenMap={};this.node=node;this.parent=parent;if(parent){this.deep=parent.deep;const root=parent.root;root.setCounter(root.counter+1);this.root=root;parent.children.push(this);} 787else{this.root=this;}} 788render(){let prev=this.root.node;
788let scheduler=prev.app.scheduler;let current=prev.parent;while(current){if(current.fiber){let root=current.fiber.root;if(root.counter===0&&prev.parentKey in current.fiber.childrenMap){current=root.node;} 789else{scheduler.delayedRenders.push(this);return;}} 790prev=current;current=current.parent;} 791this._render();} 792_render(){const node=this.node;const root=this.root;if(root){try{this.bdom=true;this.bdom=node.renderFn();} 793catch(e){node.app.handleError({node,error:e});} 794root.setCounter(root.counter-1);}}} 795class RootFiber extends Fiber{constructor(){super(...arguments);this.counter=1;this.willPatch=[];this.patched=[];this.mounted=[];this.locked=false;} 796complete(){const node=this.node;this.locked=true;let current=undefined;let mountedFibers=this.mounted;try{for(current of this.willPatch){let node=current.node;if(node.fiber===current){const component=node.component;for(let cb of node.willPatch){cb.call(component);}}} 797current=undefined;node._patch();this.locked=false;while((current=mountedFibers.pop())){current=current;if(current.appliedToDom){for(let cb of current.node.mounted){cb();}}} 798let patchedFibers=this.patched;while((current=patchedFibers.pop())){current=current;if(current.appliedToDom){for(let cb of current.node.patched){cb();}}}} 799catch(e){for(let fiber of mountedFibers){fiber.node.willUnmount=[];} 800this.locked=false;node.app.handleError({fiber:current||this,error:e});}} 801setCounter(newValue){this.counter=newValue;if(newValue===0){this.node.app.scheduler.flush();}}} 802class MountFiber extends RootFiber{constructor(node,target,options={}){super(node,null);this.target=target;this.position=options.position||"last-child";} 803complete(){let current=this;try{const node=this.node;node.children=this.childrenMap;node.app.constructor.validateTarget(this.target);if(node.bdom){node.updateDom();} 804else{node.bdom=this.bdom;if(this.position==="last-child"||this.target.childNodes.length===0){mount$1(node.bdom,this.target);} 805else{const firstChild=this.target.childNodes[0];mount$1(node.bdom,this.target,firstChild);}} 806node.fiber=null;node.status=1;this.appliedToDom=true;let mountedFibers=this.mounted;while((current=mountedFibers.pop())){if(current.appliedToDom){for(let cb of current.node.mounted){cb();}}}} 807catch(e){this.node.app.handleError({fiber:current,error:e});}}} 808const KEYCHANGES=Symbol("Key changes");const NO_CALLBACK=()=>{throw new Error("Called NO_CALLBACK. Owl is broken, please report this to the maintainers.");};const objectToString=Object.prototype.toString;const objectHasOwnProperty=Object.prototype.hasOwnProperty;const SUPPORTED_RAW_TYPES=["Object","Array","Set","Map","WeakMap"];const COLLECTION_RAW_TYPES=["Set","Map","WeakMap"];function rawType(obj){return objectToString.call(toRaw(obj)).slice(8,-1);} 809function canBeMadeReactive(value){if(typeof value!=="object"){return false;} 810return SUPPORTED_RAW_TYPES.includes(rawType(value));} 811function possiblyReactive(val,cb){return canBeMadeReactive(val)?reactive(val,cb):val;} 812const skipped=new WeakSet();function markRaw(value){skipped.add(value);return value;} 813function toRaw(value){return targets.has(value)?targets.get(value):value;} 814const targetToKeysToCallbacks=new WeakMap();function observeTargetKey(target,key,callback){if(callback===NO_CALLBACK){return;} 815if(!targetToKeysToCallbacks.get(target)){targetToKeysToCallbacks.set(target,new Map());} 816const keyToCallbacks=targetToKeysToCallbacks.get(target);if(!keyToCallbacks.get(key)){keyToCallbacks.set(key,new Set());} 817keyToCallbacks.get(key).add(callback);if(!callbacksToTargets.has(callback)){callbacksToTargets.set(callback,new Set());} 818callbacksToTargets.get(callback).add(target);} 819function notifyReactives(target,key){const keyToCallbacks=targetToKeysToCallbacks.get(target);if(!keyToCallbacks){return;} 820const callbacks=keyToCallbacks.get(key);if(!callbacks){return;} 821for(const callback of[...callbacks]){clearReactivesForCallback(callback);callback();}} 822const callbacksToTargets=new WeakMap();function clearReactivesForCallback(callback){const targetsToClear=callbacksToTargets.get(callback);if(!targetsToClear){return;} 823for(const target of targetsToClear){const observedKeys=targetToKeysToCallbacks.get(target);if(!observedKeys){continue;} 824for(const[key,callbacks]of observedKeys.entries()){callbacks.delete(callback);if(!callbacks.size){observedKeys.delete(key);}}} 825targetsToClear.clear();} 826function getSubscriptions(callback){const targets=callbacksToTargets.get(callback)||[];return[...targets].map((target)=>{const keysToCallbacks=targetToKeysToCallbacks.get(target);let keys=[];if(keysToCallbacks){for(const[key,cbs]of keysToCallbacks){if(cbs.has(callback)){keys.push(key);}}} 827return{target,keys};});} 828const targets=new WeakMap();const reactiveCache=new WeakMap();function reactive(target,callback=NO_CALLBACK){if(!canBeMadeReactive(target)){throw new OwlError(`Cannot make the given value reactive`);} 829if(skipped.has(target)){return target;} 830if(targets.has(target)){return reactive(targets.get(target),callback);} 831if(!reactiveCache.has(target)){reactiveCache.set(target,new WeakMap());} 832const reactivesForTarget=reactiveCache.get(target);if(!reactivesForTarget.has(callback)){const targetRawType=rawType(target);const handler=COLLECTION_RAW_TYPES.includes(targetRawType)?collectionsProxyHandler(target,callback,targetRawType):basicProxyHandler(callback);const proxy=new Proxy(target,handler);reactivesForTarget.set(callback,proxy);targets.set(proxy,target);} 833return reactivesForTarget.get(callback);} 834function basicProxyHandler(callback){return{get(target,key,receiver){const desc=Object.getOwnPropertyDescriptor(target,key);if(desc&&!desc.writable&&!desc.configurable){return Reflect.get(target,key,receiver);} 835observeTargetKey(target,key,callback);return possiblyReactive(Reflect.get(target,key,receiver),callback);},set(target,key,value,receiver){const hadKey=objectHasOwnProperty.call(target,key);const originalValue=Reflect.get(target,key,receiver);const ret=Reflect.set(target,key,toRaw(value),receiver);if(!hadKey&&objectHasOwnProperty.call(target,key)){notifyReactives(target,KEYCHANGES);} 836if(originalValue!==Reflect.get(target,key,receiver)||(key==="length"&&Array.isArray(target))){notifyReactives(target,key);} 837return ret;},deleteProperty(target,key){const ret=Reflect.deleteProperty(target,key);notifyReactives(target,KEYCHANGES);notifyReactives(target,key);return ret;},ownKeys(target){observeTargetKey(target,KEYCHANGES,callback);return Reflect.ownKeys(target);},has(target,key){observeTargetKey(target,KEYCHANGES,callback);return Reflect.has(target,key);},};} 838function makeKeyObserver(methodName,target,callback){return(key)=>{key=toRaw(key);observeTargetKey(target,key,callback);return possiblyReactive(target[methodName](key),callback);};} 839function makeIteratorObserver(methodName,target,callback){return function*(){observeTargetKey(target,KEYCHANGES,callback);const keys=target.keys();for(const item of target[methodName]()){const key=keys.next().value;observeTargetKey(target,key,callback);yield possiblyReactive(item,callback);}};} 840function makeForEachObserver(target,callback){return function forEach(forEachCb,thisArg){observeTargetKey(target,KEYCHANGES,callback);target.forEach(function(val,key,targetObj){observeTargetKey(target,key,callback);forEachCb.call(thisArg,possiblyReactive(val,callback),possiblyReactive(key,callback),possiblyReactive(targetObj,callback));},thisArg);};} 841function delegateAndNotify(setterName,getterName,target){return(key,value)=>{key=toRaw(key);const hadKey=target.has(key);const originalValue=target[getterName](key);const ret=target[setterName](key,value);const hasKey=target.has(key);if(hadKey!==hasKey){notifyReactives(target,KEYCHANGES);} 842if(originalValue!==target[getterName](key)){notifyReactives(target,key);} 843return ret;};} 844function makeClearNotifier(target){return()=>{const allKeys=[...target.keys()];target.clear();notifyReactives(target,KEYCHANGES);for(const key of allKeys){notifyReactives(target,key);}};} 845const rawTypeToFuncHandlers={Set:(target,callback)=>({has:makeKeyObserver("has",target,callback),add:delegateAndNotify("add","has",target),delete:delegateAndNotify("delete","has",target),keys:makeIteratorObserver("keys",target,callback),values:makeIteratorObserver("values",target,callback),entr
845ies:makeIteratorObserver("entries",target,callback),[Symbol.iterator]:makeIteratorObserver(Symbol.iterator,target,callback),forEach:makeForEachObserver(target,callback),clear:makeClearNotifier(target),get size(){observeTargetKey(target,KEYCHANGES,callback);return target.size;},}),Map:(target,callback)=>({has:makeKeyObserver("has",target,callback),get:makeKeyObserver("get",target,callback),set:delegateAndNotify("set","get",target),delete:delegateAndNotify("delete","has",target),keys:makeIteratorObserver("keys",target,callback),values:makeIteratorObserver("values",target,callback),entries:makeIteratorObserver("entries",target,callback),[Symbol.iterator]:makeIteratorObserver(Symbol.iterator,target,callback),forEach:makeForEachObserver(target,callback),clear:makeClearNotifier(target),get size(){observeTargetKey(target,KEYCHANGES,callback);return target.size;},}),WeakMap:(target,callback)=>({has:makeKeyObserver("has",target,callback),get:makeKeyObserver("get",target,callback),set:delegateAndNotify("set","get",target),delete:delegateAndNotify("delete","has",target),}),};function collectionsProxyHandler(target,callback,targetRawType){const specialHandlers=rawTypeToFuncHandlers[targetRawType](target,callback);return Object.assign(basicProxyHandler(callback),{get(target,key){if(objectHasOwnProperty.call(specialHandlers,key)){return specialHandlers[key];} 846observeTargetKey(target,key,callback);return possiblyReactive(target[key],callback);},});} 847let currentNode=null;function saveCurrent(){let n=currentNode;return()=>{currentNode=n;};} 848function getCurrent(){if(!currentNode){throw new OwlError("No active component (a hook function should only be called in 'setup')");} 849return currentNode;} 850function useComponent(){return currentNode.component;} 851function applyDefaultProps(props,defaultProps){for(let propName in defaultProps){if(props[propName]===undefined){props[propName]=defaultProps[propName];}}} 852const batchedRenderFunctions=new WeakMap();function useState(state){const node=getCurrent();let render=batchedRenderFunctions.get(node);if(!render){const wrapper={fn:batched(node.render.bind(node,false))};render=(...args)=>wrapper.fn(...args);batchedRenderFunctions.set(node,render);node.willDestroy.push(cleanupRenderAndReactives.bind(null,wrapper,render));} 853return reactive(state,render);} 854const NO_OP=()=>{};function cleanupRenderAndReactives(wrapper,render){wrapper.fn=NO_OP;clearReactivesForCallback(render);} 855class ComponentNode{constructor(C,props,app,parent,parentKey){this.fiber=null;this.bdom=null;this.status=0;this.forceNextRender=false;this.nextProps=null;this.children=Object.create(null);this.refs={};this.willStart=[];this.willUpdateProps=[];this.willUnmount=[];this.mounted=[];this.willPatch=[];this.patched=[];this.willDestroy=[];currentNode=this;this.app=app;this.parent=parent;this.props=props;this.parentKey=parentKey;const defaultProps=C.defaultProps;props=Object.assign({},props);if(defaultProps){applyDefaultProps(props,defaultProps);} 856const env=(parent&&parent.childEnv)||app.env;this.childEnv=env;for(const key in props){const prop=props[key];if(prop&&typeof prop==="object"&&targets.has(prop)){props[key]=useState(prop);}} 857this.component=new C(props,env,this);const ctx=Object.assign(Object.create(this.component),{this:this.component});this.renderFn=app.getTemplate(C.template).bind(this.component,ctx,this);this.component.setup();currentNode=null;} 858mountComponent(target,options){const fiber=new MountFiber(this,target,options);this.app.scheduler.addFiber(fiber);this.initiateRender(fiber);} 859async initiateRender(fiber){this.fiber=fiber;if(this.mounted.length){fiber.root.mounted.push(fiber);} 860const component=this.component;try{await Promise.all(this.willStart.map((f)=>f.call(component)));} 861catch(e){this.app.handleError({node:this,error:e});return;} 862if(this.status===0&&this.fiber===fiber){fiber.render();}} 863async render(deep){if(this.status>=2){return;} 864let current=this.fiber;if(current&&(current.root.locked||current.bdom===true)){await Promise.resolve();current=this.fiber;} 865if(current){if(!current.bdom&&!fibersInError.has(current)){if(deep){current.deep=deep;} 866return;} 867deep=deep||current.deep;} 868else if(!this.bdom){return;} 869const fiber=makeRootFiber(this);fiber.deep=deep;
869this.fiber=fiber;this.app.scheduler.addFiber(fiber);await Promise.resolve();if(this.status>=2){return;} 870if(this.fiber===fiber&&(current||!fiber.parent)){fiber.render();}} 871cancel(){this._cancel();delete this.parent.children[this.parentKey];this.app.scheduler.scheduleDestroy(this);} 872_cancel(){this.status=2;const children=this.children;for(let childKey in children){children[childKey]._cancel();}} 873destroy(){let shouldRemove=this.status===1;this._destroy();if(shouldRemove){this.bdom.remove();}} 874_destroy(){const component=this.component;if(this.status===1){for(let cb of this.willUnmount){cb.call(component);}} 875for(let child of Object.values(this.children)){child._destroy();} 876if(this.willDestroy.length){try{for(let cb of this.willDestroy){cb.call(component);}} 877catch(e){this.app.handleError({error:e,node:this});}} 878this.status=3;} 879async updateAndRender(props,parentFiber){this.nextProps=props;props=Object.assign({},props);const fiber=makeChildFiber(this,parentFiber);this.fiber=fiber;const component=this.component;const defaultProps=component.constructor.defaultProps;if(defaultProps){applyDefaultProps(props,defaultProps);} 880currentNode=this;for(const key in props){const prop=props[key];if(prop&&typeof prop==="object"&&targets.has(prop)){props[key]=useState(prop);}} 881currentNode=null;const prom=Promise.all(this.willUpdateProps.map((f)=>f.call(component,props)));await prom;if(fiber!==this.fiber){return;} 882component.props=props;fiber.render();const parentRoot=parentFiber.root;if(this.willPatch.length){parentRoot.willPatch.push(fiber);} 883if(this.patched.length){parentRoot.patched.push(fiber);}} 884updateDom(){if(!this.fiber){return;} 885if(this.bdom===this.fiber.bdom){for(let k in this.children){const child=this.children[k];child.updateDom();}} 886else{this.bdom.patch(this.fiber.bdom,false);this.fiber.appliedToDom=true;this.fiber=null;}} 887setRef(name,el){if(el){this.refs[name]=el;}} 888firstNode(){const bdom=this.bdom;return bdom?bdom.firstNode():undefined;} 889mount(parent,anchor){const bdom=this.fiber.bdom;this.bdom=bdom;bdom.mount(parent,anchor);this.status=1;this.fiber.appliedToDom=true;this.children=this.fiber.childrenMap;this.fiber=null;} 890moveBeforeDOMNode(node,parent){this.bdom.moveBeforeDOMNode(node,parent);} 891moveBeforeVNode(other,afterNode){this.bdom.moveBeforeVNode(other?other.bdom:null,afterNode);} 892patch(){if(this.fiber&&this.fiber.parent){this._patch();this.props=this.nextProps;}} 893_patch(){let hasChildren=false;for(let _k in this.children){hasChildren=true;break;} 894const fiber=this.fiber;this.children=fiber.childrenMap;this.bdom.patch(fiber.bdom,hasChildren);fiber.appliedToDom=true;this.fiber=null;} 895beforeRemove(){this._destroy();} 896remove(){this.bdom.remove();} 897get name(){return this.component.constructor.name;} 898get subscriptions(){const render=batchedRenderFunctions.get(this);return render?getSubscriptions(render):[];}} 899const TIMEOUT=Symbol("timeout");const HOOK_TIMEOUT={onWillStart:3000,onWillUpdateProps:3000,};function wrapError(fn,hookName){const error=new OwlError();const timeoutError=new OwlError();const node=getCurrent();return(...args)=>{const onError=(cause)=>{error.cause=cause;error.message=cause instanceof Error?`The following error occurred in ${hookName}: "${cause.message}"`:`Something that is not an Error was thrown in ${hookName} (see this Error's "cause" property)`;throw error;};let result;try{result=fn(...args);} 900catch(cause){onError(cause);} 901if(!(result instanceof Promise)){return result;} 902const timeout=HOOK_TIMEOUT[hookName];if(timeout){const fiber=node.fiber;Promise.race([result.catch(()=>{}),new Promise((resolve)=>setTimeout(()=>resolve(TIMEOUT),timeout)),]).then((res)=>{if(res===TIMEOUT&&node.fiber===fiber&&node.status<=2){timeoutError.message=`${hookName}'s promise hasn't resolved after ${timeout / 1000} seconds`;console.log(timeoutError);}});} 903return result.catch(onError);};} 904function onWillStart(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willStart.push(decorate(fn.bind(node.component),"onWillStart"));} 905function onWillUpdateProps(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willUpdateProps.push(decorate(fn.bind(node.component),"onWillUpdateProps"));} 906function onMounted(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.mounted.push(decorate(fn.bind(node.component),"onMounted"));} 907function onWillPatch(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willPatch.unshift(decorate(fn.bind(node.component),"onWillPatch"));} 908function onPatched(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.patched.push(decorate(fn.bind(node.component),"onPatched"));} 909function onWillUnmount(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willUnmount.unshift(decorate(fn.bind(node.component),"onWillUnmount"));} 910function onWillDestroy(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willDestroy.push(decorate(fn.bind(node.component),"onWillDestroy"));} 911function onWillRender(fn){const node=getCurrent();const renderFn=node.renderFn;const decorate=node.app.dev?wrapError:(fn)=>fn;fn=decorate(fn.bind(node.component),"onWillRender");node.renderFn=()=>{fn();return renderFn();};} 912function onRendered(fn){const node=getCurrent();const renderFn=node.renderFn;const decorate=node.app.dev?wrapError:(fn)=>fn;fn=decorate(fn.bind(node.component),"onRendered");node.renderFn=()=>{const result=renderFn();fn();return result;};} 913function onError(callback){const node=getCurrent();let handlers=nodeErrorHandlers.get(node);if(!handlers){handlers=[];nodeErrorHandlers.set(node,handlers);} 914handlers.push(callback.bind(node.component));} 915class Component{constructor(props,env,node){this.props=props;this.env=env;this.__owl__=node;} 916setup(){} 917render(deep=false){this.__owl__.render(deep===true);}} 918Component.template="";const VText=text("").constructor;class VPortal extends VText{constructor(selector,content){super("");this.target=null;this.selector=selector;this.content=content;} 919mount(parent,anchor){super.mount(parent,anchor);this.target=document.querySelector(this.selector);if(this.target){this.content.mount(this.target,null);} 920else{this.content.mount(parent,anchor);}} 921beforeRemove(){this.content.beforeRemove();} 922remove(){if(this.content){super.remove();this.content.remove();this.content=null;}} 923patch(other){super.patch(other);if(this.content){this.content.patch(other.content,true);} 924else{this.content=other.content;this.content.mount(this.target,null);}}} 925function portalTemplate(app,bdom,helpers){let{callSlot}=helpers;return function template(ctx,node,key=""){return new VPortal(ctx.props.target,callSlot(ctx,node,key,"default",false,null));};} 926class Portal extends Component{setup(){const node=this.__owl__;onMounted(()=>{const portal=node.bdom;if(!portal.target){const target=document.querySelector(this.props.target);if(target){portal.content.moveBeforeDOMNode(target.firstChild,target);} 927else{throw new OwlError("invalid portal target");}}});onWillUnmount(()=>{const portal=node.bdom;portal.remove();});}} 928Portal.template="__portal__";Portal.props={target:{type:String,},slots:true,};const isUnionType=(t)=>Array.isArray(t);const isBaseType=(t)=>typeof t!=="object";const isValueType=(t)=>typeof t==="object"&&t&&"value"in t;function isOptional(t){return typeof t==="object"&&"optional"in t?t.optional||false:false;} 929function describeType(type){return type==="*"||type===true?"value":type.name.toLowerCase();} 930function describe(info){if(isBaseType(info)){return describeType(info);} 931else if(isUnionType(info)){return info.map(describe).join(" or ");} 932else if(isValueType(info)){return String(info.value);} 933if("element"in info){return`list of ${describe({ type: info.element, optional: false })}s`;} 934if("shape"in info){return`object`;} 935return describe(info.type||"*");} 936function toSchema(spec){return Object.fromEntries(spec.map((e)=>
936e.endsWith("?")?[e.slice(0,-1),{optional:true}]:[e,{type:"*",optional:false}]));} 937function validate(obj,spec){let errors=validateSchema(obj,spec);if(errors.length){throw new OwlError("Invalid object: "+errors.join(", "));}} 938function validateSchema(obj,schema){if(Array.isArray(schema)){schema=toSchema(schema);} 939obj=toRaw(obj);let errors=[];for(let key in obj){if(key in schema){let result=validateType(key,obj[key],schema[key]);if(result){errors.push(result);}} 940else if(!("*"in schema)){errors.push(`unknown key '${key}'`);}} 941for(let key in schema){const spec=schema[key];if(key!=="*"&&!isOptional(spec)&&!(key in obj)){const isObj=typeof spec==="object"&&!Array.isArray(spec);const isAny=spec==="*"||(isObj&&"type"in spec?spec.type==="*":isObj);let detail=isAny?"":` (should be a ${describe(spec)})`;errors.push(`'${key}' is missing${detail}`);}} 942return errors;} 943function validateBaseType(key,value,type){if(typeof type==="function"){if(typeof value==="object"){if(!(value instanceof type)){return`'${key}' is not a ${describeType(type)}`;}} 944else if(typeof value!==type.name.toLowerCase()){return`'${key}' is not a ${describeType(type)}`;}} 945return null;} 946function validateArrayType(key,value,descr){if(!Array.isArray(value)){return`'${key}' is not a list of ${describe(descr)}s`;} 947for(let i=0;i<value.length;i++){const error=validateType(`${key}[${i}]`,value[i],descr);if(error){return error;}} 948return null;} 949function validateType(key,value,descr){if(value===undefined){return isOptional(descr)?null:`'${key}' is undefined (should be a ${describe(descr)})`;} 950else if(isBaseType(descr)){return validateBaseType(key,value,descr);} 951else if(isValueType(descr)){return value===descr.value?null:`'${key}' is not equal to '${descr.value}'`;} 952else if(isUnionType(descr)){let validDescr=descr.find((p)=>!validateType(key,value,p));return validDescr?null:`'${key}' is not a ${describe(descr)}`;} 953let result=null;if("element"in descr){result=validateArrayType(key,value,descr.element);} 954else if("shape"in descr){if(typeof value!=="object"||Array.isArray(value)){result=`'${key}' is not an object`;} 955else{const errors=validateSchema(value,descr.shape);if(errors.length){result=`'${key}' doesn't have the correct shape (${errors.join(", ")})`;}}} 956else if("values"in descr){if(typeof value!=="object"||Array.isArray(value)){result=`'${key}' is not an object`;} 957else{const errors=Object.entries(value).map(([key,value])=>validateType(key,value,descr.values)).filter(Boolean);if(errors.length){result=`some of the values in '${key}' are invalid (${errors.join(", ")})`;}}} 958if("type"in descr&&!result){result=validateType(key,value,descr.type);} 959if("validate"in descr&&!result){result=!descr.validate(value)?`'${key}' is not valid`:null;} 960return result;} 961const ObjectCreate=Object.create;function withDefault(value,defaultValue){return value===undefined||value===null||value===false?defaultValue:value;} 962function callSlot(ctx,parent,key,name,dynamic,extra,defaultContent){key=key+"__slot_"+name;const slots=ctx.props.slots||{};const{__render,__ctx,__scope}=slots[name]||{};const slotScope=ObjectCreate(__ctx||{});if(__scope){slotScope[__scope]=extra;} 963const slotBDom=__render?__render(slotScope,parent,key):null;if(defaultContent){let child1=undefined;let child2=undefined;if(slotBDom){child1=dynamic?toggler(name,slotBDom):slotBDom;} 964else{child2=defaultContent(ctx,parent,key);} 965return multi([child1,child2]);} 966return slotBDom||text("");} 967function capture(ctx){const result=ObjectCreate(ctx);for(let k in ctx){result[k]=ctx[k];} 968return result;} 969function withKey(elem,k){elem.key=k;return elem;} 970function prepareList(collection){let keys;let values;if(Array.isArray(collection)){keys=collection;values=collection;} 971else if(collection instanceof Map){keys=[...collection.keys()];values=[...collection.values()];} 972else if(Symbol.iterator in Object(collection)){keys=[...collection];values=keys;} 973else if(collection&&typeof collection==="object"){values=Object.values(collection);keys=Object.keys(collection);} 974else{throw new OwlError(`Invalid loop expression: "${collection}" is not iterable`);} 975const n=values.length;return[keys,values,n,new Array(n)];} 976const isBoundary=Symbol("isBoundary");function setContextValue(ctx,key,value){const ctx0=ctx;while(!ctx.hasOwnProperty(key)&&!ctx.hasOwnProperty(isBoundary)){const newCtx=ctx.__proto__;if(!newCtx){ctx=ctx0;break;} 977ctx=newCtx;} 978ctx[key]=value;} 979function toNumber(val){const n=parseFloat(val);return isNaN(n)?val:n;} 980function shallowEqual(l1,l2){for(let i=0,l=l1.length;i<l;i++){if(l1[i]!==l2[i]){return false;}} 981return true;} 982class LazyValue{constructor(fn,ctx,component,node,key){this.fn=fn;this.ctx=capture(ctx);this.component=component;this.node=node;this.key=key;} 983evaluate(){return this.fn.call(this.component,this.ctx,this.node,this.key);} 984toString(){return this.evaluate().toString();}} 985function safeOutput(value,defaultValue){if(value===undefined||value===null){return defaultValue?toggler("default",defaultValue):toggler("undefined",text(""));} 986let safeKey;let block;switch(typeof value){case"object":if(value instanceof Markup){safeKey=`string_safe`;block=html(value);} 987else if(value instanceof LazyValue){safeKey=`lazy_value`;block=value.evaluate();} 988else if(value instanceof String){safeKey="string_unsafe";block=text(value);} 989else{safeKey="block_safe";block=value;} 990break;case"string":safeKey="string_unsafe";block=text(value);break;default:safeKey="string_unsafe";block=text(String(value));} 991return toggler(safeKey,block);} 992function validateProps(name,props,comp){const ComponentClass=typeof name!=="string"?name:comp.constructor.components[name];if(!ComponentClass){return;} 993const schema=ComponentClass.props;if(!schema){if(comp.__owl__.app.warnIfNoStaticProps){console.warn(`Component '${ComponentClass.name}' does not have a static props description`);} 994return;} 995const defaultProps=ComponentClass.defaultProps;if(defaultProps){let isMandatory=(name)=>Array.isArray(schema)?schema.includes(name):name in schema&&!("*"in schema)&&!isOptional(schema[name]);for(let p in defaultProps){if(isMandatory(p)){throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);}}} 996const errors=validateSchema(props,schema);if(errors.length){throw new OwlError(`Invalid props for component '${ComponentClass.name}': `+errors.join(", "));}} 997function makeRefWrapper(node){let refNames=new Set();return(name,fn)=>{if(refNames.has(name)){throw new OwlError(`Cannot set the same ref more than once in the same component, ref "${name}" was set multiple times in ${node.name}`);} 998refNames.add(name);return fn;};} 999const helpers={withDefault,zero:Symbol("zero"),isBoundary,callSlot,capture,withKey,prepareList,setContextValue,shallowEqual,toNumber,validateProps,LazyValue,safeOutput,createCat
999cher,markRaw,OwlError,makeRefWrapper,};function parseXML(xml){const parser=new DOMParser();const doc=parser.parseFromString(xml,"text/xml");if(doc.getElementsByTagName("parsererror").length){let msg="Invalid XML in template.";const parsererrorText=doc.getElementsByTagName("parsererror")[0].textContent;if(parsererrorText){msg+="\nThe parser has produced the following error message:\n"+parsererrorText;const re=/\d+/g;const firstMatch=re.exec(parsererrorText);if(firstMatch){const lineNumber=Number(firstMatch[0]);const line=xml.split("\n")[lineNumber-1];const secondMatch=re.exec(parsererrorText);if(line&&secondMatch){const columnIndex=Number(secondMatch[0])-1;if(line[columnIndex]){msg+=`\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n`+`${line}\n${"-".repeat(columnIndex - 1)}^`;}}}} 1000throw new OwlError(msg);} 1001return doc;} 1002const bdom={text,createBlock,list,multi,html,toggler,comment};class TemplateSet{constructor(config={}){this.rawTemplates=Object.create(globalTemplates);this.templates={};this.Portal=Portal;this.dev=config.dev||false;this.translateFn=config.translateFn;this.translatableAttributes=config.translatableAttributes;if(config.templates){if(config.templates instanceof Document||typeof config.templates==="string"){this.addTemplates(config.templates);} 1003else{for(const name in config.templates){this.addTemplate(name,config.templates[name]);}}} 1004this.getRawTemplate=config.getTemplate;this.customDirectives=config.customDirectives||{};this.runtimeUtils={...helpers,__globals__:config.globalValues||{}};this.hasGlobalValues=Boolean(config.globalValues&&Object.keys(config.globalValues).length);} 1005static registerTemplate(name,fn){globalTemplates[name]=fn;} 1006addTemplate(name,template){if(name in this.rawTemplates){if(!this.dev){return;} 1007const rawTemplate=this.rawTemplates[name];const currentAsString=typeof rawTemplate==="string"?rawTemplate:rawTemplate instanceof Element?rawTemplate.outerHTML:rawTemplate.toString();const newAsString=typeof template==="string"?template:template.outerHTML;if(currentAsString===newAsString){return;} 1008throw new OwlError(`Template ${name} already defined with different content`);} 1009this.rawTemplates[name]=template;} 1010addTemplates(xml){if(!xml){return;} 1011xml=xml instanceof Document?xml:parseXML(xml);for(const template of xml.querySelectorAll("[t-name]")){const name=template.getAttribute("t-name");this.addTemplate(name,template);}} 1012getTemplate(name){var _a;if(!(name in this.templates)){const rawTemplate=((_a=this.getRawTemplate)===null||_a===void 0?void 0:_a.call(this,name))||this.rawTemplates[name];if(rawTemplate===undefined){let extraInfo="";try{const componentName=getCurrent().component.constructor.name;extraInfo=` (for component "${componentName}")`;} 1013catch{} 1014throw new OwlError(`Missing template: "${name}"${extraInfo}`);} 1015const isFn=typeof rawTemplate==="function"&&!(rawTemplate instanceof Element);const templateFn=isFn?rawTemplate:this._compileTemplate(name,rawTemplate);const templates=this.templates;this.templates[name]=function(context,parent){return templates[name].call(this,context,parent);};const template=templateFn(this,bdom,this.runtimeUtils);this.templates[name]=template;} 1016return this.templates[name];} 1017_compileTemplate(name,template){throw new OwlError(`Unable to compile a template. Please use owl full build instead`);} 1018callTemplate(owner,subTemplate,ctx,parent,key){const template=this.getTemplate(subTemplate);return toggler(subTemplate,template.call(owner,ctx,parent,key+subTemplate));}} 1019const globalTemplates={};function xml(...args){const name=`__template__${xml.nextId++}`;const value=String.raw(...args);globalTemplates[name]=value;return name;} 1020xml.nextId=1;TemplateSet.registerTemplate("__portal__",portalTemplate);const RESERVED_WORDS="true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date,__globals__".split(",");const WORD_REPLACEMENT=Object.assign(Object.create(null),{and:"&&",or:"||",gt:">",gte:">=",lt:"<",lte:"<=",});const STATIC_TOKEN_MAP=Object.assign(Object.create(null),{"{":"LEFT_BRACE","}":"RIGHT_BRACE","[":"LEFT_BRACKET","]":"RIGHT_BRACKET",":":"COLON",",":"COMMA","(":"LEFT_PAREN",")":"RIGHT_PAREN",});const OPERATORS="...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;,in ,new ,|,&,^,~".split(",");let tokenizeString=function(expr){let s=expr[0];let start=s;if(s!=="'"&&s!=='"'&&s!=="`"){return false;} 1021let i=1;let cur;while(expr[i]&&expr[i]!==start){cur=expr[i];s+=cur;if(cur==="\\"){i++;cur=expr[i];if(!cur){throw new OwlError("Invalid expression");} 1022s+=cur;} 1023i++;} 1024if(expr[i]!==start){throw new OwlError("Invalid expression");} 1025s+=start;if(start==="`"){return{type:"TEMPLATE_STRING",value:s,replace(replacer){return s.replace(/\$\{(.*?)\}/g,(match,group)=>{return"${"+replacer(group)+"}";});},};} 1026return{type:"VALUE",value:s};};let tokenizeNumber=function(expr){let s=expr[0];if(s&&s.match(/[0-9]/)){let i=1;while(expr[i]&&expr[i].match(/[0-9]|\./)){s+=expr[i];i++;} 1027return{type:"VALUE",value:s};} 1028else{return false;}};let tokenizeSymbol=function(expr){let s=expr[0];if(s&&s.match(/[a-zA-Z_\$]/)){let i=1;while(expr[i]&&expr[i].match(/\w/)){s+=expr[i];i++;} 1029if(s in WORD_REPLACEMENT){return{type:"OPERATOR",value:WORD_REPLACEMENT[s],size:s.length};} 1030return{type:"SYMBOL",value:s};} 1031else{return false;}};const tokenizeStatic=function(expr){const char=expr[0];if(char&&char in STATIC_TOKEN_MAP){return{type:STATIC_TOKEN_MAP[char],value:char};} 1032return false;};const tokenizeOperator=function(expr){for(let op of OPERATORS){if(expr.startsWith(op)){return{type:"OPERATOR",value:op};}} 1033return false;};const TOKENIZERS=[tokenizeString,tokenizeNumber,tokenizeOperator,tokenizeSymbol,tokenizeStatic,];function tokenize(expr){const result=[];let token=true;let error;let current=expr;try{while(token){current=current.trim();if(current){for(let tokenizer of TOKENIZERS){token=tokenizer(current);if(token){result.push(token);current=current.slice(token.size||token.value.length);break;}}} 1034else{token=false;}}} 1035catch(e){error=e;} 1036if(current.length||error){throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);} 1037return result;} 1038const isLeftSeparator=(token)=>token&&(token.type==="LEFT_BRACE"||token.type==="COMMA");const isRightSeparator=(token)=>token&&(token.type==="RIGHT_BRACE"||token.type==="COMMA");function compileExprToArray(expr){const localVars=new Set();const tokens=tokenize(expr);let i=0;let stack=[];while(i<tokens.length){let token=tokens[i];let prevToken=tokens[i-1];let nextToken=tokens[i+1];let groupType=stack[stack.length-1];switch(token.type){case"LEFT_BRACE":case"LEFT_BRACKET":case"LEFT_PAREN":stack.push(token.type);break;case"RIGHT_BRACE":case"RIGHT_BRACKET":case"RIGHT_PAREN":stack.pop();} 1039let isVar=token.type==="SYMBOL"&&!RESERVED_WORDS.includes(token.value);if(token.type==="SYMBOL"&&!RESERVED_WORDS.includes(token.value)){if(prevToken){if(groupType==="LEFT_BRACE"&&isLeftSeparator(prevToken)&&isRightSeparator(nextToken)){tokens.splice(i+1,0,{type:"COLON",value:":"},{...token});nextToken=tokens[i+1];} 1040if(prevToken.type==="OPERATOR"&&prevToken.value==="."){isVar=false;} 1041else if(prevToken.type==="LEFT_BRACE"||prevToken.type==="COMMA"){if(nextToken&&nextToken.type==="COLON"){isVar=false;}}}} 1042if(token.type==="TEMPLATE_STRING"){token.value=token.replace((expr)=>compileExpr(expr));} 1043if(nextToken&&nextToken.type==="OPERATOR"&&nextToken.value==="=>"){if(token.type==="RIGHT_PAREN"){let j=i-1;while(j>0&&tokens[j].type!=="LEFT_PAREN"){if(tokens[j].type==="SYMBOL"&&tokens[j].originalValue){tokens[j].value=tokens[j].originalValue;localVars.add(tokens[j].value);} 1044j--;}} 1045else{localVars.add(token.value);}} 1046if(isVar){token.varName=token.value;if(!localVars.has(token.value)){token.originalValue=token.value;token.value=`ctx['${token.value}']`;}} 1047i++;} 1048for(const token of tokens){if(token.type==="SYMBOL"&&token.varName&&localVars.has(token.value)){token.originalValue=token.value;token.value=`_${token.value}`;token.isLocal=true;}} 1049return tokens;} 1050const paddedValues=new Map([["in "," in "]]);function compileExpr(expr){return compileExprToArray(expr).map((t)=>paddedValues.get(t.value)||t.value).join("");} 1051const INTERP_REGEXP=/\{\{.*?\}\}|\#\{.*?\}/g;function replaceDynamicParts(s,replacer){let matches=s.match(INTERP_REGEXP);if(matches&&matches[0].length===s.length){return`(${replacer(s.slice(2, matches[0][0] === "{" ? -2 : -1))})`;} 1052let r=s.replace(INTERP_REGEXP,(s)=>"${"+replacer(s.slice(2,s[0]==="{"?-2:-1))+"}");return"`"+r+"`";} 1053function interpolate(s){return replaceDynamicParts(s,compileExpr);} 1054const whitespaceRE=/\s+/g;let xmlDoc;
1054if(typeof document!=="undefined"){xmlDoc=document.implementation.createDocument(null,null,null);} 1055const MODS=new Set(["stop","capture","prevent","self","synthetic"]);let nextDataIds={};function generateId(prefix=""){nextDataIds[prefix]=(nextDataIds[prefix]||0)+1;return prefix+nextDataIds[prefix];} 1056function isProp(tag,key){switch(tag){case"input":return(key==="checked"||key==="indeterminate"||key==="value"||key==="readonly"||key==="readOnly"||key==="disabled");case"option":return key==="selected"||key==="disabled";case"textarea":return key==="value"||key==="readonly"||key==="readOnly"||key==="disabled";case"select":return key==="value"||key==="disabled";case"button":case"optgroup":return key==="disabled";} 1057return false;} 1058function toStringExpression(str){return`\`${str.replace(/\\/g, "\\\\").replace(/`/g,"\\`").replace(/\$\{/,"\\${")}\``;} 1059class BlockDescription{constructor(target,type){this.dynamicTagName=null;this.isRoot=false;this.hasDynamicChildren=false;this.children=[];this.data=[];this.childNumber=0;this.parentVar="";this.id=BlockDescription.nextBlockId++;this.varName="b"+this.id;this.blockName="block"+this.id;this.target=target;this.type=type;} 1060insertData(str,prefix="d"){const id=generateId(prefix);this.target.addLine(`let ${id} = ${str};`);return this.data.push(id)-1;} 1061insert(dom){if(this.currentDom){this.currentDom.appendChild(dom);} 1062else{this.dom=dom;}} 1063generateExpr(expr){if(this.type==="block"){const hasChildren=this.children.length;let params=this.data.length?`[${this.data.join(", ")}]`:hasChildren?"[]":"";if(hasChildren){params+=", ["+this.children.map((c)=>c.varName).join(", ")+"]";} 1064if(this.dynamicTagName){return`toggler(${this.dynamicTagName}, ${this.blockName}(${this.dynamicTagName})(${params}))`;} 1065return`${this.blockName}(${params})`;} 1066else if(this.type==="list"){return`list(c_block${this.id})`;} 1067return expr;} 1068asXmlString(){const t=xmlDoc.createElement("t");t.appendChild(this.dom);return t.innerHTML;}} 1069BlockDescription.nextBlockId=1;function createContext(parentCtx,params){return Object.assign({block:null,index:0,forceNewBlock:true,translate:parentCtx.translate,translationCtx:parentCtx.translationCtx,tKeyExpr:null,nameSpace:parentCtx.nameSpace,tModelSelectedExpr:parentCtx.tModelSelectedExpr,},params);} 1070class CodeTarget{constructor(name,on){this.indentLevel=0;this.loopLevel=0;this.code=[];this.hasRoot=false;this.hasCache=false;this.shouldProtectScope=false;this.hasRefWrapper=false;this.name=name;this.on=on||null;} 1071addLine(line,idx){const prefix=new Array(this.indentLevel+2).join(" ");
1071if(idx===undefined){this.code.push(prefix+line);} 1072else{this.code.splice(idx,0,prefix+line);}} 1073generateCode(){let result=[];result.push(`function ${this.name}(ctx, node, key = "") {`);if(this.shouldProtectScope){result.push(` ctx = Object.create(ctx);`);result.push(` ctx[isBoundary] = 1`);} 1074if(this.hasRefWrapper){result.push(` let refWrapper = makeRefWrapper(this.__owl__);`);} 1075if(this.hasCache){result.push(` let cache = ctx.cache || {};`);result.push(` let nextCache = ctx.cache = {};`);} 1076for(let line of this.code){result.push(line);} 1077if(!this.hasRoot){result.push(`return text('');`);} 1078result.push(`}`);return result.join("\n ");} 1079currentKey(ctx){let key=this.loopLevel?`key${this.loopLevel}`:"key";if(ctx.tKeyExpr){key=`${ctx.tKeyExpr} + ${key}`;} 1080return key;}} 1081const TRANSLATABLE_ATTRS=["alt","aria-label","aria-placeholder","aria-roledescription","aria-valuetext","label","placeholder","title",];const translationRE=/^(\s*)([\s\S]+?)(\s*)$/;class CodeGenerator{constructor(ast,options){this.blocks=[];this.nextBlockId=1;this.isDebug=false;this.targets=[];this.target=new CodeTarget("template");this.translatableAttributes=TRANSLATABLE_ATTRS;this.staticDefs=[];this.slotNames=new Set();this.helpers=new Set();this.translateFn=options.translateFn||((s)=>s);if(options.translatableAttributes){const attrs=new Set(TRANSLATABLE_ATTRS);for(let attr of options.translatableAttributes){if(attr.startsWith("-")){attrs.delete(attr.slice(1));} 1082else{attrs.add(attr);}} 1083this.translatableAttributes=[...attrs];} 1084this.hasSafeContext=options.hasSafeContext||false;this.dev=options.dev||false;this.ast=ast;this.templateName=options.name;if(options.hasGlobalValues){this.helpers.add("__globals__");}} 1085generateCode(){const ast=this.ast;this.isDebug=ast.type===12;BlockDescription.nextBlockId=1;nextDataIds={};this.compileAST(ast,{block:null,index:0,forceNewBlock:false,isLast:true,translate:true,translationCtx:"",tKeyExpr:null,});let mainCode=[` let { text, createBlock, list, multi, html, toggler, comment } = bdom;`];if(this.helpers.size){mainCode.push(`let { ${[...this.helpers].join(", ")} } = helpers;`);} 1086if(this.templateName){mainCode.push(`// Template name: "${this.templateName}"`);} 1087for(let{id,expr}of this.staticDefs){mainCode.push(`const ${id} = ${expr};`);} 1088if(this.blocks.length){mainCode.push(``);for(let block of this.blocks){if(block.dom){let xmlString=toStringExpression(block.asXmlString());if(block.dynamicTagName){xmlString=xmlString.replace(/^`<\w+/,`\`<\${tag || '${block.dom.nodeName}'}`);xmlString=xmlString.replace(/\w+>`$/,`\${tag || '${block.dom.nodeName}'}>\``);mainCode.push(`let ${block.blockName} = tag => createBlock(${xmlString});`);} 1089else{mainCode.push(`let ${block.blockName} = createBlock(${xmlString});`);}}}} 1090if(this.targets.length){for(let fn of this.targets){mainCode.push("");mainCode=mainCode.concat(fn.generateCode());}} 1091mainCode.push("");mainCode=mainCode.concat("return "+this.target.generateCode());const code=mainCode.join("\n ");if(this.isDebug){const msg=`[Owl Debug]\n${code}`;console.log(msg);} 1092return code;} 1093compileInNewTarget(prefix,ast,ctx,on){const name=generateId(prefix);const initialTarget=this.target;const target=new CodeTarget(name,on);this.targets.push(target);this.target=target;this.compileAST(ast,createContext(ctx));this.target=initialTarget;return name;} 1094addLine(line,idx){this.target.addLine(line,idx);} 1095define(varName,expr){this.addLine(`const ${varName} = ${expr};`);} 1096insertAnchor(block,index=block.children.length){const tag=`block-child-${index}`;const anchor=xmlDoc.createElement(tag);block.insert(anchor);} 1097createBlock(parentBlock,type,ctx){const hasRoot=this.target.hasRoot;const block=new BlockDescription(this.target,type);if(!hasRoot){this.target.hasRoot=true;block.isRoot=true;} 1098if(parentBlock){parentBlock.children.push(block);if(parentBlock.type==="list"){block.parentVar=`c_block${parentBlock.id}`;}} 1099return block;} 1100insertBlock(expression,block,ctx){let blockExpr=block.generateExpr(expression);if(block.parentVar){let key=this.target.currentKey(ctx);this.helpers.add("withKey");this.addLine(`${block.parentVar}[${ctx.index}] = withKey(${blockExpr}, ${key});`);return;} 1101if(ctx.tKeyExpr){blockExpr=`toggler(${ctx.tKeyExpr}, ${blockExpr})`;} 1102if(block.isRoot){if(this.target.on){blockExpr=this.wrapWithEventCatcher(blockExpr,this.target.on);} 1103this.addLine(`return ${blockExpr};`);} 1104else{this.define(block.varName,blockExpr);}} 1105captureExpression(expr,forceCapture=false){if(!forceCapture&&!expr.includes("=>")){return compileExpr(expr);} 1106const tokens=compileExprToArray(expr);const mapping=new Map();return tokens.map((tok)=>
1106{if(tok.varName&&!tok.isLocal){if(!mapping.has(tok.varName)){const varId=generateId("v");mapping.set(tok.varName,varId);this.define(varId,tok.value);} 1107tok.value=mapping.get(tok.varName);} 1108return tok.value;}).join("");} 1109translate(str,translationCtx){const match=translationRE.exec(str);return match[1]+this.translateFn(match[2],translationCtx)+match[3];} 1110compileAST(ast,ctx){switch(ast.type){case 1:return this.compileComment(ast,ctx);case 0:return this.compileText(ast,ctx);case 2:return this.compileTDomNode(ast,ctx);case 4:return this.compileTEsc(ast,ctx);case 8:return this.compileTOut(ast,ctx);case 5:return this.compileTIf(ast,ctx);case 9:return this.compileTForeach(ast,ctx);case 10:return this.compileTKey(ast,ctx);case 3:return this.compileMulti(ast,ctx);case 7:return this.compileTCall(ast,ctx);case 15:return this.compileTCallBlock(ast,ctx);case 6:return this.compileTSet(ast,ctx);case 11:return this.compileComponent(ast,ctx);case 12:return this.compileDebug(ast,ctx);case 13:return this.compileLog(ast,ctx);case 14:return this.compileTSlot(ast,ctx);case 16:return this.compileTTranslation(ast,ctx);case 17:return this.compileTTranslationContext(ast,ctx);case 18:return this.compileTPortal(ast,ctx);}} 1111compileDebug(ast,ctx){this.addLine(`debugger;`);if(ast.content){return this.compileAST(ast.content,ctx);} 1112return null;} 1113compileLog(ast,ctx){this.addLine(`console.log(${compileExpr(ast.expr)});`);if(ast.content){return this.compileAST(ast.content,ctx);} 1114return null;} 1115compileComment(ast,ctx){let{block,forceNewBlock}=ctx;const isNewBlock=!block||forceNewBlock;if(isNewBlock){block=this.createBlock(block,"comment",ctx);this.insertBlock(`comment(${toStringExpression(ast.value)})`,block,{...ctx,forceNewBlock:forceNewBlock&&!block,});} 1116else{const text=xmlDoc.createComment(ast.value);block.insert(text);} 1117return block.varName;} 1118compileText(ast,ctx){let{block,forceNewBlock}=ctx;let value=ast.value;if(value&&ctx.translate!==false){value=this.translate(value,ctx.translationCtx);} 1119if(!ctx.inPreTag){value=value.replace(whitespaceRE," ");} 1120if(!block||forceNewBlock){block=this.createBlock(block,"text",ctx);this.insertBlock(`text(${toStringExpression(value)})`,block,{...ctx,forceNewBlock:forceNewBlock&&!block,});} 1121else{const createFn=ast.type===0?xmlDoc.createTextNode:xmlDoc.createComment;block.insert(createFn.call(xmlDoc,value));} 1122return block.varName;} 1123generateHandlerCode(rawEvent,handler){const modifiers=rawEvent.split(".").slice(1).map((m)=>{if(!MODS.has(m)){throw new OwlError(`Unknown event modifier: '${m}'`);} 1124return`"${m}"`;});let modifiersCode="";if(modifiers.length){modifiersCode=`${modifiers.join(",")}, `;} 1125return`[${modifiersCode}${this.captureExpression(handler)}, ctx]`;} 1126compileTDomNode(ast,ctx){var _a;let{block,forceNewBlock}=ctx;const isNewBlock=!block||forceNewBlock||ast.dynamicTag!==null||ast.ns;let codeIdx=this.target.code.length;if(isNewBlock){if((ast.dynamicTag||ctx.tKeyExpr||ast.ns)&&ctx.block){this.insertAnchor(ctx.block);} 1127block=this.createBlock(block,"block",ctx);this.blocks.push(block);if(ast.dynamicTag){const tagExpr=generateId("tag");this.define(tagExpr,compileExpr(ast.dynamicTag));block.dynamicTagName=tagExpr;}} 1128const attrs={};for(let key in ast.attrs){let expr,attrName;if(key.startsWith("t-attf")){expr=interpolate(ast.attrs[key]);const idx=block.insertData(expr,"attr");attrName=key.slice(7);attrs["block-attribute-"+idx]=attrName;} 1129else if(key.startsWith("t-att")){attrName=key==="t-att"?null:key.slice(6);expr=compileExpr(ast.attrs[key]);if(attrName&&isProp(ast.tag,attrName)){if(attrName==="readonly"){attrName="readOnly";} 1130if(attrName==="value"){expr=`new String((${expr}) === 0 ? 0 : ((${expr}) || ""))`;} 1131else{expr=`new Boolean(${expr})`;} 1132const idx=block.insertData(expr,"prop");attrs[`block-property-${idx}`]=attrName;} 1133else{const idx=block.insertData(expr,"attr");if(key==="t-att"){attrs[`block-attributes`]=String(idx);} 1134else{attrs[`block-attribute-${idx}`]=attrName;}}} 1135else if(this.translatableAttributes.includes(key)){const attrTranslationCtx=((_a=ast.attrsTranslationCtx)===null||_a===void 0?void 0:_a[key])||ctx.translationCtx;attrs[key]=this.translateFn(ast.attrs[key],attrTranslationCtx);} 1136else{expr=`"${ast.attrs[key]}"`;attrName=key;attrs[key]=ast.attrs[key];} 1137if(attrName==="value"&&ctx.tModelSelectedExpr){let selectedId=block.insertData(`${ctx.tModelSelectedExpr} === ${expr}`,"attr");attrs[`block-attribute-${selectedId}`]="selected";}} 1138let tModelSelectedExpr;if(ast.model){const{hasDynamicChildren,baseExpr,expr,eventType,shouldNumberize,
1138shouldTrim,targetAttr,specialInitTargetAttr,}=ast.model;const baseExpression=compileExpr(baseExpr);const bExprId=generateId("bExpr");this.define(bExprId,baseExpression);const expression=compileExpr(expr);const exprId=generateId("expr");this.define(exprId,expression);const fullExpression=`${bExprId}[${exprId}]`;let idx;if(specialInitTargetAttr){let targetExpr=targetAttr in attrs&&`'${attrs[targetAttr]}'`;if(!targetExpr&&ast.attrs){const dynamicTgExpr=ast.attrs[`t-att-${targetAttr}`];if(dynamicTgExpr){targetExpr=compileExpr(dynamicTgExpr);}} 1139idx=block.insertData(`${fullExpression} === ${targetExpr}`,"prop");attrs[`block-property-${idx}`]=specialInitTargetAttr;} 1140else if(hasDynamicChildren){const bValueId=generateId("bValue");tModelSelectedExpr=`${bValueId}`;this.define(tModelSelectedExpr,fullExpression);} 1141else{idx=block.insertData(`${fullExpression}`,"prop");attrs[`block-property-${idx}`]=targetAttr;} 1142this.helpers.add("toNumber");let valueCode=`ev.target.${targetAttr}`;valueCode=shouldTrim?`${valueCode}.trim()`:valueCode;valueCode=shouldNumberize?`toNumber(${valueCode})`:valueCode;const handler=`[(ev) => { ${fullExpression} = ${valueCode}; }]`;idx=block.insertData(handler,"hdlr");attrs[`block-handler-${idx}`]=eventType;} 1143for(let ev in ast.on){const name=this.generateHandlerCode(ev,ast.on[ev]);const idx=block.insertData(name,"hdlr");attrs[`block-handler-${idx}`]=ev;} 1144if(ast.ref){if(this.dev){this.helpers.add("makeRefWrapper");this.target.hasRefWrapper=true;} 1145const isDynamic=INTERP_REGEXP.test(ast.ref);let name=`\`${ast.ref}\``;if(isDynamic){name=replaceDynamicParts(ast.ref,(expr)=>this.captureExpression(expr,true));} 1146let setRefStr=`(el) => this.__owl__.setRef((${name}), el)`;if(this.dev){setRefStr=`refWrapper(${name}, ${setRefStr})`;} 1147const idx=block.insertData(setRefStr,"ref");attrs["block-ref"]=String(idx);} 1148const nameSpace=ast.ns||ctx.nameSpace;const dom=nameSpace?xmlDoc.createElementNS(nameSpace,ast.tag):xmlDoc.createElement(ast.tag);for(const[attr,val]of Object.entries(attrs)){if(!(attr==="class"&&val==="")){dom.setAttribute(attr,val);}} 1149block.insert(dom);if(ast.content.length){const initialDom=block.currentDom;block.currentDom=dom;const children=ast.content;for(let i=0;i<children.length;i++){const child=ast.content[i];const subCtx=createContext(ctx,{block,index:block.childNumber,forceNewBlock:false,isLast:ctx.isLast&&i===children.length-1,tKeyExpr:ctx.tKeyExpr,nameSpace,tModelSelectedExpr,inPreTag:ctx.inPreTag||ast.tag==="pre",});this.compileAST(child,subCtx);} 1150block.currentDom=initialDom;} 1151if(isNewBlock){this.insertBlock(`${block.blockName}(ddd)`,block,ctx);if(block.children.length&&block.hasDynamicChildren){const code=this.target.code;const children=block.children.slice();let current=children.shift();for(let i=codeIdx;i<code.length;i++){if(code[i].trimStart().startsWith(`const ${current.varName} `)){code[i]=code[i].replace(`const ${current.varName}`,current.varName);current=children.shift();if(!current) 1152break;}} 1153this.addLine(`let ${block.children.map((c) => c.varName).join(", ")};`,codeIdx);}} 1154return block.varName;} 1155compileTEsc(ast,ctx){let{block,forceNewBlock}=ctx;let expr;if(ast.expr==="0"){this.helpers.add("zero");expr=`ctx[zero]`;} 1156else{expr=compileExpr(ast.expr);if(ast.defaultValue){this.helpers.add("withDefault");expr=`withDefault(${expr}, ${toStringExpression(ast.defaultValue)})`;}} 1157if(!block||forceNewBlock){block=this.createBlock(block,"text",ctx);this.insertBlock(`text(${expr})`,block,{...ctx,forceNewBlock:forceNewBlock&&!block});} 1158else{const idx=block.insertData(expr,"txt");const text=xmlDoc.createElement(`block-text-${idx}`);block.insert(text);} 1159return block.varName;} 1160compileTOut(ast,ctx){let{block}=ctx;if(block){this.insertAnchor(block);} 1161block=this.createBlock(block,"html",ctx);let blockStr;if(ast.expr==="0"){this.helpers.add("zero");blockStr=`ctx[zero]`;} 1162else if(ast.body){let bodyValue=null;bodyValue=BlockDescription.nextBlockId;const subCtx=createContext(ctx);this.compileAST({type:3,content:ast.body},subCtx);this.helpers.add("safeOutput");blockStr=`safeOutput(${compileExpr(ast.expr)}, b${bodyValue})`;} 1163else{this.helpers.add("safeOutput");blockStr=`safeOutput(${compileExpr(ast.expr)})`;} 1164this.insertBlock(blockStr,block,ctx);return block.varName;} 1165compileTIfBranch(content,block,ctx){this.target.indentLevel++;let childN=block.children.length;this.compileAST(content,createContext(ctx,{block,index:ctx.index}));if(block.children.length>childN){this.insertAnchor(block,childN);} 1166this.target.indentLevel--;} 1167compileTIf(ast,ctx,nextNode){let{block,forceNewBlock}=ctx;const codeIdx=this.target.code.length;const isNewBlock=!block||(block.type!=="multi"&&forceNewBlock);if(block){block.hasDynamicChildren=true;} 1168if(!block||(block.type!=="multi"&&forceNewBlock)){block=this.createBlock(block,"multi",ctx);} 1169this.addLine(`if (${compileExpr(ast.condition)}) {`);this.compileTIfBranch(ast.content,block,ctx);if(ast.tElif){for(let clause of ast.tElif){this.addLine(`} else if (${compileExpr(clause.condition)}) {`);this.compileTIfBranch(clause.content,block,ctx);}} 1170if(ast.tElse){this.addLine(`} else {`);this.compileTIfBranch(ast.tElse,block,ctx);} 1171this.addLine("}");if(isNewBlock){if(block.children.length){const code=this.target.code;const children=block.children.slice();let current=children.shift();for(let i=codeIdx;i<code.length;i++){if(code[i].trimStart().startsWith(`const ${current.varName} `)){code[i]=code[i].replace(`const ${current.varName}`,current.varName);current=children.shift();if(!current) 1172break;}} 1173this.addLine(`let ${block.children.map((c) => c.varName).join(", ")};`,codeIdx);} 1174const args=block.children.map((c)=>c.varName).join(", ");this.insertBlock(`multi([${args}])`,block,ctx);} 1175return block.varName;} 1176compileTForeach(ast,ctx){let{block}=ctx;if(block){this.insertAnchor(block);} 1177block=this.createBlock(block,"list",ctx);this.target.loopLevel++;const loopVar=`i${this.target.loopLevel}`;this.addLine(`ctx = Object.create(ctx);`);const vals=`v_block${block.id}`;const keys=`k_block${block.id}`;const l=`l_block${block.id}`;const c=`c_block${block.id}`;this.helpers.add("prepareList");this.define(`[${keys}, ${vals}, ${l}, ${c}]`,`prepareList(${compileExpr(ast.collection)});`);if(this.dev){this.define(`keys${block.id}`,`new Set()`);} 1178this.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`);this.target.indentLevel++;this.addLine(`ctx[\`${ast.elem}\`] = ${keys}[${loopVar}];`);if(!ast.hasNoFirst){this.addLine(`ctx[\`${ast.elem}_first\`] = ${loopVar} === 0;`);} 1179if(!ast.hasNoLast){this.addLine(`ctx[\`${ast.elem}_last\`] = ${loopVar} === ${keys}.length - 1;`);} 1180if(!ast.hasNoIndex){this.addLine(`ctx[\`${ast.elem}_index\`] = ${loopVar};`);} 1181if(!ast.hasNoValue){this.addLine(`ctx[\`${ast.elem}_value\`] = ${vals}[${loopVar}];`);} 1182this.define(`key${this.target.loopLevel}`,ast.key?compileExpr(ast.key):loopVar);if(this.dev){this.helpers.add("OwlError");this.addLine(`if (keys${block.id}.has(String(key${this.target.loopLevel}))) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);this.addLine(`keys${block.id}.add(String(key${this.target.loopLevel}));`);} 1183let id;if(ast.memo){this.target.hasCache=true;id=generateId();this.define(`memo${id}`,compileExpr(ast.memo));this.define(`vnode${id}`,`cache[key${this.target.loopLevel}];`);this.addLine(`if (vnode${id}) {`);this.target.indentLevel++;this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`);this.target.indentLevel++;this.addLine(`${c}[${loopVar}] = vnode${id};`);this.addLine(`nextCache[key${this.target.loopLevel}] = vnode${id};`);this.addLine(`continue;`);this.target.indentLevel--;this.addLine("}");this.target.indentLevel--;this.addLine("}");} 1184const subCtx=createContext(ctx,{block,index:loopVar});this.compileAST(ast.body,subCtx);if(ast.memo){this.addLine(`nextCache[key${this.target.loopLevel}] = Object.assign(${c}[${loopVar}], {memo: memo${id}});`);} 1185this.target.indentLevel--;this.target.loopLevel--;this.addLine(`}`);if(!ctx.isLast){this.addLine(`ctx = ctx.__proto__;`);} 1186this.insertBlock("l",block,ctx);return block.varName;} 1187compileTKey(ast,ctx){const tKeyExpr=generateId("tKey_");this.define(tKeyExpr,compileExpr(ast.expr));ctx=createContext(ctx,{tKeyExpr,block:ctx.block,index:ctx.index,});return this.compileAST(ast.content,ctx);} 1188compileMulti(ast,ctx){let{block,forceNewBlock}=ctx;const isNewBlock=!block||forceNewBlock;let codeIdx=this.target.code.length;if(isNewBlock){const n=ast.content.filter((c)=>!c.hasNoRepresentation).length;let result=null;if(n<=1){for(let child of ast.content){const blockName=this.compileAST(child,ctx);result=result||blockName;} 1189return result;} 1190block=this.createBlock(block,"multi",ctx);} 1191let index=0;for(let i=0,l=ast.content.length;i<l;i++){const child=ast.content[i];const forceNewBlock=!child.hasNoRepresentation;const subCtx=createContext(ctx,{block,index,forceNewBlock,isLast:ctx.isLast&&i===l-1,});this.compileAST(child,subCtx);if(forceNewBlock){index++;}} 1192if(isNewBlock){if(block.hasDynamicChildren&&block.children.length){const code=this.target.code;const children=block.children.slice();let current=children.shift();for(let i=codeIdx;i<code.length;i++){if(code[i].trimStart().startsWith(`const ${current.varName} `)){code[i]=code[i].replace(`const ${current.varName}`,current.varName);current=children.shift();if(!current) 1193break;}} 1194this.addLine(`let ${block.children.map((c) => c.varName).join(", ")};`,codeIdx);} 1195const args=block.children.map((c)=>c.varName).join(", ");this.insertBlock(`multi([${args}])`,block,ctx);} 1196return block.varName;} 1197compileTCall(ast,ctx){let{block,forceNewBlock}=ctx;let ctxVar=ctx.ctxVar||"ctx";if(ast.context){ctxVar=generateId("ctx");this.addLine(`let ${ctxVar} = ${compileExpr(ast.context)};`);} 1198const isDynamic=INTERP_REGEXP.test(ast.name);const subTemplate=isDynamic?interpolate(ast.name):"`"+ast.name+"`";if(block&&!forceNewBlock){this.insertAnchor(block);} 1199block=this.createBlock(block,"multi",ctx);if(ast.body){this.addLine(`${ctxVar} = Object.create(${ctxVar});`);this.addLine(`${ctxVar}[isBoundary] = 1;`);this.helpers.add("isBoundary");const subCtx=createContext(ctx,{ctxVar});const bl=this.compileMulti({type:3,content:ast.body},subCtx);if(bl){this.helpers.add("zero");this.addLine(`${ctxVar}[zero] = ${bl};`);}} 1200const key=this.generateComponentKey();if(isDynamic){const templateVar=generateId("template");if(!this.staticDefs.find((d)=>d.id==="call")){this.staticDefs.push({id:"call",expr:`app.callTemplate.bind(app)`});} 1201this.define(templateVar,subTemplate);this.insertBlock(`call(this, ${templateVar}, ${ctxVar}, node, ${key})`,block,{...ctx,forceNewBlock:!block,});} 1202else{const id=generateId(`callTemplate_`);this.staticDefs.push({id,expr:`app.getTemplate(${subTemplate})`});this.insertBlock(`${id}.call(this, ${ctxVar}, node, ${key})`,block,{...ctx,forceNewBlock:!block,});} 1203if(ast.body&&!ctx.isLast){this.addLine(`${ctxVar} = ${ctxVar}.__proto__;`);} 1204return block.varName;} 1205compileTCallBlock(ast,ctx){let{block,forceNewBlock}=ctx;if(block){if(!forceNewBlock){this.insertAnchor(block);}} 1206block=this.createBlock(block,"multi",ctx);this.insertBlock(compileExpr(ast.name),block,{...ctx,forceNewBlock:!block});return block.varName;} 1207compileTSet(ast,ctx){this.target.shouldProtectScope=true;this.helpers.add("isBoundary").add("withDefault");const expr=ast.value?compileExpr(ast.value||""):"null";if(ast.body){this.helpers.add("LazyValue");const bodyAst={type:3,content:ast.body};const name=this.compileInNewTarget("value",bodyAst,ctx);let key=this.target.currentKey(ctx);let value=`new LazyValue(${name}, ctx, this, node, ${key})`;value=ast.value?(value?`withDefault(${expr}, ${value})`:expr):value;this.addLine(`ctx[\`${ast.name}\`] = ${value};`);} 1208else{let value;if(ast.defaultValue){const defaultValue=toStringExpression(ctx.translate?this.translate(ast.defaultValue,ctx.translationCtx):ast.defaultValue);if(ast.value){value=`withDefault(${expr}, ${defaultValue})`;} 1209else{value=defaultValue;}}
1210else{value=expr;} 1211this.helpers.add("setContextValue");this.addLine(`setContextValue(${ctx.ctxVar || "ctx"}, "${ast.name}", ${value});`);} 1212return null;} 1213generateComponentKey(currentKey="key"){const parts=[generateId("__")];for(let i=0;i<this.target.loopLevel;i++){parts.push(`\${key${i + 1}}`);} 1214return`${currentKey} + \`${parts.join("__")}\``;} 1215formatProp(name,value,attrsTranslationCtx,translationCtx){if(name.endsWith(".translate")){const attrTranslationCtx=(attrsTranslationCtx===null||attrsTranslationCtx===void 0?void 0:attrsTranslationCtx[name])||translationCtx;value=toStringExpression(this.translateFn(value,attrTranslationCtx));} 1216else{value=this.captureExpression(value);} 1217if(name.includes(".")){let[_name,suffix]=name.split(".");name=_name;switch(suffix){case"bind":value=`(${value}).bind(this)`;break;case"alike":case"translate":break;default:throw new OwlError(`Invalid prop suffix: ${suffix}`);}} 1218name=/^[a-z_]+$/i.test(name)?name:`'${name}'`;return`${name}: ${value || undefined}`;} 1219formatPropObject(obj,attrsTranslationCtx,translationCtx){return Object.entries(obj).map(([k,v])=>this.formatProp(k,v,attrsTranslationCtx,translationCtx));} 1220getPropString(props,dynProps){let propString=`{${props.join(",")}}`;if(dynProps){propString=`Object.assign({}, ${compileExpr(dynProps)}${props.length ? ", " + propString : ""})`;} 1221return propString;} 1222compileComponent(ast,ctx){let{block}=ctx;const hasSlotsProp="slots"in(ast.props||{});const props=ast.props?this.formatPropObject(ast.props,ast.propsTranslationCtx,ctx.translationCtx):[];let slotDef="";if(ast.slots){let ctxStr="ctx";if(this.target.loopLevel||!this.hasSafeContext){ctxStr=generateId("ctx");this.helpers.add("capture");this.define(ctxStr,`capture(ctx)`);} 1223let slotStr=[];for(let slotName in ast.slots){const slotAst=ast.slots[slotName];const params=[];if(slotAst.content){const name=this.compileInNewTarget("slot",slotAst.content,ctx,slotAst.on);params.push(`__render: ${name}.bind(this), __ctx: ${ctxStr}`);} 1224const scope=ast.slots[slotName].scope;if(scope){params.push(`__scope: "${scope}"`);} 1225if(ast.slots[slotName].attrs){params.push(...this.formatPropObject(ast.slots[slotName].attrs,ast.slots[slotName].attrsTranslationCtx,ctx.translationCtx));} 1226const slotInfo=`{${params.join(", ")}}`;slotStr.push(`'${slotName}': ${slotInfo}`);} 1227slotDef=`{${slotStr.join(", ")}}`;} 1228if(slotDef&&!(ast.dynamicProps||hasSlotsProp)){this.helpers.add("markRaw");props.push(`slots: markRaw(${slotDef})`);} 1229let propString=this.getPropString(props,ast.dynamicProps);let propVar;if((slotDef&&(ast.dynamicProps||hasSlotsProp))||this.dev){propVar=generateId("props");this.define(propVar,propString);propString=propVar;} 1230if(slotDef&&(ast.dynamicProps||hasSlotsProp)){this.helpers.add("markRaw");this.addLine(`${propVar}.slots = markRaw(Object.assign(${slotDef}, ${propVar}.slots))`);} 1231let expr;if(ast.isDynamic){expr=generateId("Comp");this.define(expr,compileExpr(ast.name));} 1232else{expr=`\`${ast.name}\``;} 1233if(this.dev){this.addLine(`helpers.validateProps(${expr}, ${propVar}, this);`);} 1234if(block&&(ctx.forceNewBlock===false||ctx.tKeyExpr)){this.insertAnchor(block);} 1235let keyArg=this.generateComponentKey();if(ctx.tKeyExpr){keyArg=`${ctx.tKeyExpr} + ${keyArg}`;} 1236let id=generateId("comp");const propList=[];for(let p in ast.props||{}){let[name,suffix]=p.split(".");if(!suffix){propList.push(`"${name}"`);}} 1237this.staticDefs.push({id,expr:`app.createComponent(${ast.isDynamic ? null : expr}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, [${propList}])`,});if(ast.isDynamic){keyArg=`(${expr}).name + ${keyArg}`;} 1238let blockExpr=`${id}(${propString}, ${keyArg}, node, this, ${ast.isDynamic ? expr : null})`;if(ast.isDynamic){blockExpr=`toggler(${expr}, ${blockExpr})`;} 1239if(ast.on){blockExpr=this.wrapWithEventCatcher(blockExpr,ast.on);} 1240block=this.createBlock(block,"multi",ctx);this.insertBlock(blockExpr,block,ctx);return block.varName;}
1241wrapWithEventCatcher(expr,on){this.helpers.add("createCatcher");let name=generateId("catcher");let spec={};let handlers=[];for(let ev in on){let handlerId=generateId("hdlr");let idx=handlers.push(handlerId)-1;spec[ev]=idx;const handler=this.generateHandlerCode(ev,on[ev]);this.define(handlerId,handler);} 1242this.staticDefs.push({id:name,expr:`createCatcher(${JSON.stringify(spec)})`});return`${name}(${expr}, [${handlers.join(",")}])`;} 1243compileTSlot(ast,ctx){this.helpers.add("callSlot");let{block}=ctx;let blockString;let slotName;let dynamic=false;let isMultiple=false;if(ast.name.match(INTERP_REGEXP)){dynamic=true;isMultiple=true;slotName=interpolate(ast.name);} 1244else{slotName="'"+ast.name+"'";isMultiple=isMultiple||this.slotNames.has(ast.name);this.slotNames.add(ast.name);} 1245const attrs={...ast.attrs};const dynProps=attrs["t-props"];delete attrs["t-props"];let key=this.target.loopLevel?`key${this.target.loopLevel}`:"key";if(isMultiple){key=this.generateComponentKey(key);} 1246const props=ast.attrs?this.formatPropObject(attrs,ast.attrsTranslationCtx,ctx.translationCtx):[];const scope=this.getPropString(props,dynProps);if(ast.defaultContent){const name=this.compileInNewTarget("defaultContent",ast.defaultContent,ctx);blockString=`callSlot(ctx, node, ${key}, ${slotName}, ${dynamic}, ${scope}, ${name}.bind(this))`;} 1247else{if(dynamic){let name=generateId("slot");this.define(name,slotName);blockString=`toggler(${name}, callSlot(ctx, node, ${key}, ${name}, ${dynamic}, ${scope}))`;} 1248else{blockString=`callSlot(ctx, node, ${key}, ${slotName}, ${dynamic}, ${scope})`;}} 1249if(ast.on){blockString=this.wrapWithEventCatcher(blockString,ast.on);} 1250if(block){this.insertAnchor(block);} 1251block=this.createBlock(block,"multi",ctx);this.insertBlock(blockString,block,{...ctx,forceNewBlock:false});return block.varName;} 1252compileTTranslation(ast,ctx){if(ast.content){return this.compileAST(ast.content,Object.assign({},ctx,{translate:false}));} 1253return null;} 1254compileTTranslationContext(ast,ctx){if(ast.content){return this.compileAST(ast.content,Object.assign({},ctx,{translationCtx:ast.translationCtx}));} 1255return null;} 1256compileTPortal(ast,ctx){if(!this.staticDefs.find((d)=>d.id==="Portal")){this.staticDefs.push({id:"Portal",expr:`app.Portal`});} 1257let{block}=ctx;const name=this.compileInNewTarget("slot",ast.content,ctx);let ctxStr="ctx";if(this.target.loopLevel||!this.hasSafeContext){ctxStr=generateId("ctx");this.helpers.add("capture");this.define(ctxStr,`capture(ctx)`);} 1258let id=generateId("comp");this.staticDefs.push({id,expr:`app.createComponent(null, false, true, false, false)`,});const target=compileExpr(ast.target);const key=this.generateComponentKey();const blockString=`${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, ${key}, node, ctx, Portal)`;if(block){this.insertAnchor(block);} 1259block=this.createBlock(block,"multi",ctx);this.insertBlock(blockString,block,{...ctx,forceNewBlock:false});return block.varName;}} 1260const cache=new WeakMap();function parse(xml,customDir){const ctx={inPreTag:false,customDirectives:customDir,};if(typeof xml==="string"){const elem=parseXML(`<t>${xml}</t>`).firstChild;return _parse(elem,ctx);} 1261let ast=cache.get(xml);if(!ast){ast=_parse(xml.cloneNode(true),ctx);cache.set(xml,ast);} 1262return ast;} 1263function _parse(xml,ctx){normalizeXML(xml);return parseNode(xml,ctx)||{type:0,value:""};} 1264function parseNode(node,ctx){if(!(node instanceof Element)){return parseTextCommentNode(node,ctx);} 1265return(parseTCustom(node,ctx)||parseTDebugLog(node,ctx)||parseTForEach(node,ctx)||parseTIf(node,ctx)||parseTPortal(node,ctx)||parseTCall(node,ctx)||parseTCallBlock(node)||parseTTranslation(node,ctx)||parseTTranslationContext(node,ctx)||parseTKey(node,ctx)||parseTEscNode(node,ctx)||parseTOutNode(node,ctx)||parseTSlot(node,ctx)||parseComponent(node,ctx)||parseDOMNode(node,ctx)||parseTSetNode(node,ctx)||parseTNode(node,ctx));} 1266function parseTNode(node,ctx){if(node.tagName!=="t"){return null;} 1267return parseChildNodes(node,ctx);} 1268const lineBreakRE=/[\r\n]/;function parseTextCommentNode(node,ctx){if(node.nodeType===Node.TEXT_NODE){let value=node.textContent||"";if(!ctx.inPreTag&&lineBreakRE.test(value)&&!value.trim()){return null;} 1269return{type:0,value};} 1270else if(node.nodeType===Node.COMMENT_NODE){return{type:1,value:node.textContent||""};} 1271return null;} 1272function parseTCustom(node,ctx){if(!ctx.customDirectives){return null;} 1273const nodeAttrsNames=node.getAttributeNames();
1273for(let attr of nodeAttrsNames){if(attr==="t-custom"||attr==="t-custom-"){throw new OwlError("Missing custom directive name with t-custom directive");} 1274if(attr.startsWith("t-custom-")){const directiveName=attr.split(".")[0].slice(9);const customDirective=ctx.customDirectives[directiveName];if(!customDirective){throw new OwlError(`Custom directive "${directiveName}" is not defined`);} 1275const value=node.getAttribute(attr);const modifiers=attr.split(".").slice(1);node.removeAttribute(attr);try{customDirective(node,value,modifiers);} 1276catch(error){throw new OwlError(`Custom directive "${directiveName}" throw the following error: ${error}`);} 1277return parseNode(node,ctx);}} 1278return null;} 1279function parseTDebugLog(node,ctx){if(node.hasAttribute("t-debug")){node.removeAttribute("t-debug");const content=parseNode(node,ctx);const ast={type:12,content,};if(content===null||content===void 0?void 0:content.hasNoRepresentation){ast.hasNoRepresentation=true;} 1280return ast;} 1281if(node.hasAttribute("t-log")){const expr=node.getAttribute("t-log");node.removeAttribute("t-log");const content=parseNode(node,ctx);const ast={type:13,expr,content,};if(content===null||content===void 0?void 0:content.hasNoRepresentation){ast.hasNoRepresentation=true;} 1282return ast;} 1283return null;} 1284const hasDotAtTheEnd=/\.[\w_]+\s*$/;const hasBracketsAtTheEnd=/\[[^\[]+\]\s*$/;const ROOT_SVG_TAGS=new Set(["svg","g","path"]);function parseDOMNode(node,ctx){const{tagName}=node;const dynamicTag=node.getAttribute("t-tag");node.removeAttribute("t-tag");if(tagName==="t"&&!dynamicTag){return null;} 1285if(tagName.startsWith("block-")){throw new OwlError(`Invalid tag name: '${tagName}'`);} 1286ctx=Object.assign({},ctx);if(tagName==="pre"){ctx.inPreTag=true;} 1287let ns=!ctx.nameSpace&&ROOT_SVG_TAGS.has(tagName)?"http://www.w3.org/2000/svg":null;const ref=node.getAttribute("t-ref");node.removeAttribute("t-ref");const nodeAttrsNames=node.getAttributeNames();let attrs=null;let attrsTranslationCtx=null;let on=null;let model=null;for(let attr of nodeAttrsNames){const value=node.getAttribute(attr);if(attr==="t-on"||attr==="t-on-"){throw new OwlError("Missing event name with t-on directive");} 1288if(attr.startsWith("t-on-")){on=on||{};on[attr.slice(5)]=value;} 1289else if(attr.startsWith("t-model")){if(!["input","select","textarea"].includes(tagName)){throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");} 1290let baseExpr,expr;if(hasDotAtTheEnd.test(value)){const index=value.lastIndexOf(".");baseExpr=value.slice(0,index);expr=`'${value.slice(index + 1)}'`;} 1291else if(hasBracketsAtTheEnd.test(value)){const index=value.lastIndexOf("[");baseExpr=value.slice(0,index);expr=value.slice(index+1,-1);} 1292else{throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);} 1293const typeAttr=node.getAttribute("type");const isInput=tagName==="input";const isSelect=tagName==="select";const isCheckboxInput=isInput&&typeAttr==="checkbox";const isRadioInput=isInput&&typeAttr==="radio";const hasTrimMod=attr.includes(".trim");const hasLazyMod=hasTrimMod||attr.includes(".lazy");const hasNumberMod=attr.includes(".number");const eventType=isRadioInput?"click":isSelect||hasLazyMod?"change":"input";model={baseExpr,expr,targetAttr:isCheckboxInput?"checked":"value",specialInitTargetAttr:isRadioInput?"checked":null,eventType,hasDynamicChildren:false,shouldTrim:hasTrimMod,shouldNumberize:hasNumberMod,};if(isSelect){ctx=Object.assign({},ctx);ctx.tModelInfo=model;}} 1294else if(attr.startsWith("block-")){throw new OwlError(`Invalid attribute: '${attr}'`);} 1295else if(attr==="xmlns"){ns=value;} 1296else if(attr.startsWith("t-translation-context-")){const attrName=attr.slice(22);attrsTranslationCtx=attrsTranslationCtx||{};attrsTranslationCtx[attrName]=value;} 1297else if(attr!=="t-name"){if(attr.startsWith("t-")&&!attr.startsWith("t-att")){throw new OwlError(`Unknown QWeb directive: '${attr}'`);} 1298const tModel=ctx.tModelInfo;if(tModel&&["t-att-value","t-attf-value"].includes(attr)){tModel.hasDynamicChildren=true;} 1299attrs=attrs||{};attrs[attr]=value;}} 1300if(ns){ctx.nameSpace=ns;} 1301const children=parseChildren(node,ctx);return{type:2,tag:tagName,dynamicTag,attrs,attrsTranslationCtx,on,ref,content:children,model,ns,};} 1302function parseTEscNode(node,ctx){if(!node.hasAttribute("t-esc")){return null;} 1303const escValue=node.getAttribute("t-esc");node.removeAttribute("t-esc");const tesc={type:4,expr:escValue,defaultValue:node.textContent||"",};let ref=node.getAttribute("t-ref");node.removeAttribute("t-ref");const ast=parseNode(node,ctx);if(!ast){return tesc;} 1304if(ast.type===2){return{...ast,ref,content:[tesc],};} 1305return tesc;} 1306function parseTOutNode(node,ctx){if(!node.hasAttribute("t-out")&&!node.hasAttribute("t-raw")){return null;} 1307if(node.hasAttribute("t-raw")){console.warn(`t-raw has been deprecated
1307in favor of t-out. If the value to render is not wrapped by the "markup" function, it will be escaped`);} 1308const expr=(node.getAttribute("t-out")||node.getAttribute("t-raw"));node.removeAttribute("t-out");node.removeAttribute("t-raw");const tOut={type:8,expr,body:null};const ref=node.getAttribute("t-ref");node.removeAttribute("t-ref");const ast=parseNode(node,ctx);if(!ast){return tOut;} 1309if(ast.type===2){tOut.body=ast.content.length?ast.content:null;return{...ast,ref,content:[tOut],};} 1310return tOut;} 1311function parseTForEach(node,ctx){if(!node.hasAttribute("t-foreach")){return null;} 1312const html=node.outerHTML;const collection=node.getAttribute("t-foreach");node.removeAttribute("t-foreach");const elem=node.getAttribute("t-as")||"";node.removeAttribute("t-as");const key=node.getAttribute("t-key");if(!key){throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);} 1313node.removeAttribute("t-key");const memo=node.getAttribute("t-memo")||"";node.removeAttribute("t-memo");const body=parseNode(node,ctx);if(!body){return null;} 1314const hasNoTCall=!html.includes("t-call");const hasNoFirst=hasNoTCall&&!html.includes(`${elem}_first`);const hasNoLast=hasNoTCall&&!html.includes(`${elem}_last`);const hasNoIndex=hasNoTCall&&!html.includes(`${elem}_index`);const hasNoValue=hasNoTCall&&!html.includes(`${elem}_value`);return{type:9,collection,elem,body,memo,key,hasNoFirst,hasNoLast,hasNoIndex,hasNoValue,};} 1315function parseTKey(node,ctx){if(!node.hasAttribute("t-key")){return null;} 1316const key=node.getAttribute("t-key");node.removeAttribute("t-key");const content=parseNode(node,ctx);if(!content){return null;} 1317const ast={type:10,expr:key,content,};if(content.hasNoRepresentation){ast.hasNoRepresentation=true;} 1318return ast;} 1319function parseTCall(node,ctx){if(!node.hasAttribute("t-call")){return null;} 1320const subTemplate=node.getAttribute("t-call");const context=node.getAttribute("t-call-context");node.removeAttribute("t-call");node.removeAttribute("t-call-context");if(node.tagName!=="t"){const ast=parseNode(node,ctx);const tcall={type:7,name:subTemplate,body:null,context};if(ast&&ast.type===2){ast.content=[tcall];return ast;} 1321if(ast&&ast.type===11){return{...ast,slots:{default:{content:tcall,scope:null,on:null,attrs:null,attrsTranslationCtx:null,},},};}} 1322const body=parseChildren(node,ctx);return{type:7,name:subTemplate,body:body.length?body:null,context,};} 1323function parseTCallBlock(node,ctx){if(!node.hasAttribute("t-call-block")){return null;} 1324const name=node.getAttribute("t-call-block");return{type:15,name,};} 1325function parseTIf(node,ctx){if(!node.hasAttribute("t-if")){return null;} 1326const condition=node.getAttribute("t-if");node.removeAttribute("t-if");const content=parseNode(node,ctx)||{type:0,value:""};let nextElement=node.nextElementSibling;const tElifs=[];while(nextElement&&nextElement.hasAttribute("t-elif")){const condition=nextElement.getAttribute("t-elif");nextElement.removeAttribute("t-elif");const tElif=parseNode(nextElement,ctx);const next=nextElement.nextElementSibling;nextElement.remove();nextElement=next;if(tElif){tElifs.push({condition,content:tElif});}} 1327let tElse=null;if(nextElement&&nextElement.hasAttribute("t-else")){nextElement.removeAttribute("t-else");tElse=parseNode(nextElement,ctx);nextElement.remove();} 1328return{type:5,condition,content,tElif:tElifs.length?tElifs:null,tElse,};} 1329function parseTSetNode(node,ctx){if(!node.hasAttribute("t-set")){return null;} 1330const name=node.getAttribute("t-set");const value=node.getAttribute("t-value")||null;const defaultValue=node.innerHTML===node.textContent?node.textContent||null:null;let body=null;if(node.textContent!==node.innerHTML){body=parseChildren(node,ctx);} 1331return{type:6,name,value,defaultValue,body,hasNoRepresentation:true};} 1332const directiveErrorMap=new Map([["t-ref","t-ref is no longer supported on components. Consider exposing only the public part of the component's API through a callback prop.",],["t-att","t-att makes no sense on component: props are already treated as expressions"],["t-attf","t-attf is not supported on components: use template strings for string interpolation in props",],]);function parseComponent(node,ctx){let name=node.tagName;const firstLetter=name[0];let isDynamic=node.hasAttribute("t-component");if(isDynamic&&name!=="t"){throw new OwlError(`Directive 't-component' can only be used on <t>
1332 nodes (used on a <${name}>)`);} 1333if(!(firstLetter===firstLetter.toUpperCase()||isDynamic)){return null;} 1334if(isDynamic){name=node.getAttribute("t-component");node.removeAttribute("t-component");} 1335const dynamicProps=node.getAttribute("t-props");node.removeAttribute("t-props");const defaultSlotScope=node.getAttribute("t-slot-scope");node.removeAttribute("t-slot-scope");let on=null;let props=null;let propsTranslationCtx=null;for(let name of node.getAttributeNames()){const value=node.getAttribute(name);if(name.startsWith("t-translation-context-")){const attrName=name.slice(22);propsTranslationCtx=propsTranslationCtx||{};propsTranslationCtx[attrName]=value;} 1336else if(name.startsWith("t-")){if(name.startsWith("t-on-")){on=on||{};on[name.slice(5)]=value;} 1337else{const message=directiveErrorMap.get(name.split("-").slice(0,2).join("-"));throw new OwlError(message||`unsupported directive on Component: ${name}`);}} 1338else{props=props||{};props[name]=value;}} 1339let slots=null;if(node.hasChildNodes()){const clone=node.cloneNode(true);const slotNodes=Array.from(clone.querySelectorAll("[t-set-slot]"));for(let slotNode of slotNodes){if(slotNode.tagName!=="t"){throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);} 1340const name=slotNode.getAttribute("t-set-slot");let el=slotNode.parentElement;let isInSubComponent=false;while(el&&el!==clone){if(el.hasAttribute("t-component")||el.tagName[0]===el.tagName[0].toUpperCase()){isInSubComponent=true;break;} 1341el=el.parentElement;} 1342if(isInSubComponent||!el){continue;} 1343slotNode.removeAttribute("t-set-slot");slotNode.remove();const slotAst=parseNode(slotNode,ctx);let on=null;let attrs=null;let attrsTranslationCtx=null;let scope=null;for(let attributeName of slotNode.getAttributeNames()){const value=slotNode.getAttribute(attributeName);if(attributeName==="t-slot-scope"){scope=value;continue;} 1344else if(attributeName.startsWith("t-translation-context-")){const attrName=attributeName.slice(22);attrsTranslationCtx=attrsTranslationCtx||{};attrsTranslationCtx[attrName]=value;} 1345else if(attributeName.startsWith("t-on-")){on=on||{};on[attributeName.slice(5)]=value;} 1346else{attrs=attrs||{};attrs[attributeName]=value;}} 1347slots=slots||{};slots[name]={content:slotAst,on,attrs,attrsTranslationCtx,scope};} 1348const defaultContent=parseChildNodes(clone,ctx);slots=slots||{};if(defaultContent&&!slots.default){slots.default={content:defaultContent,on,attrs:null,attrsTranslationCtx:null,scope:defaultSlotScope,};}} 1349return{type:11,name,isDynamic,dynamicProps,props,propsTranslationCtx,slots,on,};} 1350function parseTSlot(node,ctx){if(!node.hasAttribute("t-slot")){return null;} 1351const name=node.getAttribute("t-slot");node.removeAttribute("t-slot");let attrs=null;let attrsTranslationCtx=null;let on=null;for(let attributeName of node.getAttributeNames()){const value=node.getAttribute(attributeName);if(attributeName.startsWith("t-on-")){on=on||{};on[attributeName.slice(5)]=value;} 1352else if(attributeName.startsWith("t-translation-context-")){const attrName=attributeName.slice(22);attrsTranslationCtx=attrsTranslationCtx||{};attrsTranslationCtx[attrName]=value;} 1353else{attrs=attrs||{};attrs[attributeName]=value;}} 1354return{type:14,name,attrs,attrsTranslationCtx,on,defaultContent:parseChildNodes(node,ctx),};} 1355function wrapInTTranslationAST(r){const ast={type:16,content:r};if(r===null||r===void 0?void 0:r.hasNoRepresentation){ast.hasNoRepresentation=true;} 1356return ast;} 1357function parseTTranslation(node,ctx){if(node.getAttribute("t-translation")!=="off"){return null;} 1358node.removeAttribute("t-translation");const result=parseNode(node,ctx);if((result===null||result===void 0?void 0:result.type)===3){const children=result.content.map(wrapInTTranslationAST);return makeASTMulti(children);} 1359return wrapInTTranslationAST(result);} 1360function wrapInTTranslationContextAST(r,translationCtx){const ast={type:17,content:r,translationCtx,};if(r===null||r===void 0?void 0:r.hasNoRepresentation){ast.hasNoRepresentation=true;} 1361return ast;} 1362function parseTTranslationContext(node,ctx){const translationCtx=node.getAttribute("t-translation-context");if(!translationCtx){return null;} 1363node.removeAttribute("t-translation-context");const result=parseNode(node,ctx);if((result===null||result===void 0?void 0:result.type)===3){const children=result.content.map((c)=>wrapInTTranslationContextAST(c,translationCtx));return makeASTMulti(children);} 1364return wrapInTTranslationContextAST(result,translationCtx);} 1365function parseTPortal(node,ctx){if(!node.hasAttribute("t-portal")){return null;} 1366const target=node.getAttribute("t-portal");node.removeAttribute("t-portal");const content=parseNode(node,ctx);if(!content){return{type:0,value:"",};} 1367return{type:18,target,content,};} 1368function parseChildren(node,ctx){const children=[];for(let child of node.childNodes){const childAst=parseNode(child,ctx);if(childAst){if(childAst.type===3){children.push(...childAst.content);} 1369else{children.push(childAst);}}} 1370return children;} 1371function makeASTMulti(children){const ast={type:3,content:children};if(children.every((c)=>c.hasNoRepresentation)){ast.hasNoRepresentation=true;} 1372return ast;} 1373function parseChildNodes(node,ctx){const children=parseChildren(node,ctx);switch(children.length){case 0:return null;case 1:return children[0];default:return makeASTMulti(children);}} 1374function normalizeTIf(el){let tbranch=el.querySelectorAll("[t-elif], [t-else]");for(let i=0,ilen=tbranch.length;i<ilen;i++){let node=tbranch[i];let prevElem=node.previousElementSibling;let pattr=(name)=>prevElem.getAttribute(name);let nattr=(name)=>+!!node.getAttribute(name);if(prevElem&&(pattr("t-if")||pattr("t-elif"))){if(pattr("t-foreach")){throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");} 1375if(["t-if","t-elif","t-else"].map(nattr).reduce(function(a,b){return a+b;})>1){throw new OwlError("Only one conditional branching directive is allowed per node");} 1376let textNode;while((textNode=node.previousSibling)!==prevElem){if(textNode.nodeValue.trim().length&&textNode.nodeType!==8){throw new OwlError("text is not allowed between branching directives");} 1377textNode.remove();}} 1378else{throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");}}} 1379function normalizeTEscTOut(el){for(const d of["t-esc","t-out"]){const elements=[...el.querySelectorAll(`[${d}]`)].filter((el)=>el.tagName[0]===el.tagName[0].toUpperCase()||el.hasAttribute("t-component"));for(const el of elements){if(el.childNodes.length){throw new OwlError(`Cannot have ${d} on a component that already has content`);} 1380const value=el.getAttribute(d);el.removeAttribute(d);const t=el.ownerDocument.createElement("t");if(value!=null){t.setAttribute(d,value);} 1381el.appendChild(t);}}} 1382function normalizeXML(el){normalizeTIf(el);normalizeTEscTOut(el);} 1383function compile(template,options={hasGlobalValues:false,}){const ast=parse(template,options.customDirectives);const hasSafeContext=template instanceof Node?!(template instanceof Element)||template.querySelector("[t-set], [t-call]")===null:!template.includes("t-set")&&!template.includes("t-call");const codeGenerator=new CodeGenerator(ast,{...options,hasSafeContext});const code=codeGenerator.generateCode();try{return new Function("app, bdom, helpers",code);} 1384catch(originalError){const{name}=options;const nameStr=name?`template "${name}"`:"anonymous template";const err=new OwlError(`Failed to compile ${nameStr}: ${originalError.message}\n\ngenerated code:\nfunction(app, bdom, helpers) {\n${code}\n}`);err.cause=originalError;throw err;}} 1385const version="2.8.4";let requestAnimationFrame;if(typeof window!=="undefined"){requestAnimationFrame=window.requestAnimationFrame.bind(window);} 1386class Scheduler{constructor(){this.tasks=new Set();this.frame=0;this.delayedRenders=[];this.cancelledNodes=new Set();this.processing=false;this.requestAnimationFrame=Scheduler.requestAnimationFrame;} 1387addFiber(fiber){this.tasks.add(fiber.root);} 1388scheduleDestroy(node){this.cancelledNodes.add(node);if(this.frame===0){this.frame=this.requestAnimationFrame(()=>this.processTasks());}} 1389flush(){if(this.delayedRenders.length){let renders=this.delayedRenders;this.delayedRenders=[];for(let f of renders){if(f.root&&f.node.status!==3&&f.node.fiber===f){f.render();}}} 1390if(this.frame===0){this.frame=this.requestAnimationFrame(()=>this.processTasks());}} 1391processTasks(){if(this.processing){return;} 1392this.processing=true;this.frame=0;for(let node of this.cancelledNodes){node._destroy();} 1393this.cancelledNodes.clear();for(let task of this.tasks){this.processFiber(task);} 1394for(let task of this.tasks){if(task.node.status===3){this.tasks.delete(task);}} 1395this.processing=false;} 1396processFiber(fiber){if(fiber.root!==fiber){this.tasks.delete(fiber);return;} 1397const hasError=fibersInError.has(fiber);if(hasError&&fiber.counter!==0){this.tasks.delete(fiber);return;} 1398if(fiber.node.status===3){this.tasks.delete(fiber);return;} 1399if(fiber.counter===0){if(!hasError){fiber.complete();} 1400if(fiber.appliedToDom){this.tasks.delete(fiber);}}}} 1401Scheduler.requestAnimationFrame=requestAnimationFrame;let hasBeenLogged=false;const apps=new Set();if(typeof window!=="undefined"){window.__OWL_DEVTOOLS__||(window.__OWL_DEVTOOLS__={apps,Fiber,RootFiber,toRaw,reactive});} 1402class App extends TemplateSet{constructor(Root,config={}){super(config);
1402this.scheduler=new Scheduler();this.subRoots=new Set();this.root=null;this.name=config.name||"";this.Root=Root;apps.add(this);if(config.test){this.dev=true;} 1403this.warnIfNoStaticProps=config.warnIfNoStaticProps||false;if(this.dev&&!config.test&&!hasBeenLogged){console.info(`Owl is running in 'dev' mode.`);hasBeenLogged=true;} 1404const env=config.env||{};const descrs=Object.getOwnPropertyDescriptors(env);this.env=Object.freeze(Object.create(Object.getPrototypeOf(env),descrs));this.props=config.props||{};} 1405mount(target,options){const root=this.createRoot(this.Root,{props:this.props});this.root=root.node;this.subRoots.delete(root.node);return root.mount(target,options);} 1406createRoot(Root,config={}){const props=config.props||{};const env=this.env;if(config.env){this.env=config.env;} 1407const restore=saveCurrent();const node=this.makeNode(Root,props);restore();if(config.env){this.env=env;} 1408this.subRoots.add(node);return{node,mount:(target,options)=>{App.validateTarget(target);if(this.dev){validateProps(Root,props,{__owl__:{app:this}});} 1409const prom=this.mountNode(node,target,options);return prom;},destroy:()=>{this.subRoots.delete(node);node.destroy();this.scheduler.processTasks();},};} 1410makeNode(Component,props){return new ComponentNode(Component,props,this,null,null);} 1411mountNode(node,target,options){const promise=new Promise((resolve,reject)=>{let isResolved=false;node.mounted.push(()=>{resolve(node.component);isResolved=true;});let handlers=nodeErrorHandlers.get(node);if(!handlers){handlers=[];nodeErrorHandlers.set(node,handlers);} 1412handlers.unshift((e)=>{if(!isResolved){reject(e);} 1413throw e;});});node.mountComponent(target,options);return promise;} 1414destroy(){if(this.root){for(let subroot of this.subRoots){subroot.destroy();} 1415this.root.destroy();this.scheduler.processTasks();} 1416apps.delete(this);} 1417createComponent(name,isStatic,hasSlotsProp,hasDynamicPropList,propList){const isDynamic=!isStatic;let arePropsDifferent;const hasNoProp=propList.length===0;if(hasSlotsProp){arePropsDifferent=(_1,_2)=>true;} 1418else if(hasDynamicPropList){arePropsDifferent=function(props1,props2){for(let k in props1){if(props1[k]!==props2[k]){return true;}} 1419return Object.keys(props1).length!==Object.keys(props2).length;};} 1420else if(hasNoProp){arePropsDifferent=(_1,_2)=>false;} 1421else{arePropsDifferent=function(props1,props2){for(let p of propList){if(props1[p]!==props2[p]){return true;}} 1422return false;};} 1423const updateAndRender=ComponentNode.prototype.updateAndRender;const initiateRender=ComponentNode.prototype.initiateRender;return(props,key,ctx,parent,C)=>{let children=ctx.children;let node=children[key];if(isDynamic&&node&&node.component.constructor!==C){node=undefined;} 1424const parentFiber=ctx.fiber;if(node){if(arePropsDifferent(node.props,props)||parentFiber.deep||node.forceNextRender){node.forceNextRender=false;updateAndRender.call(node,props,parentFiber);}} 1425else{if(isStatic){const components=parent.constructor.components;if(!components){throw new OwlError(`Cannot find the definition of component "${name}", missing static components key in parent`);} 1426C=components[name];if(!C){throw new OwlError(`Cannot find the definition of component "${name}"`);} 1427else if(!(C.prototype instanceof Component)){throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);}} 1428node=new ComponentNode(C,props,this,ctx,key);children[key]=node;initiateRender.call(node,new Fiber(node,parentFiber));} 1429parentFiber.childrenMap[key]=node;return node;};} 1430handleError(...args){return handleError(...args);}} 1431App.validateTarget=validateTarget;App.apps=apps;App.version=version;async function mount(C,target,config={}){return new App(C,config).mount(target,config);} 1432const mainEventHandler=(data,ev,currentTarget)=>{const{data:_data,modifiers}=filterOutModifiersFromData(data);data=_data;let stopped=false;if(modifiers.length){let selfMode=false;const isSelf=ev.target===currentTarget;for(const mod of modifiers){switch(mod){case"self":selfMode=true;if(isSelf){continue;} 1433else{return stopped;} 1434case"prevent":if((selfMode&&isSelf)||!selfMode) 1435ev.preventDefault();continue;case"stop":if((selfMode&&isSelf)||!selfMode) 1436ev.stopPropagation();stopped=true;continue;}}} 1437if(Object.hasOwnProperty.call(data,0)){const handler=data[0];if(typeof handler!=="function"){throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);} 1438let node=data[1]?data[1].__owl__:null;if(node?node.status===1:true){handler.call(node?node.component:null,ev);}} 1439return stopped;};function status(component){switch(component.__owl__.status){case 0:return"new";case 2:return"cancelled";case 1:return"mounted";case 3:return"destroyed";}} 1440function useRef(name){const node=getCurrent();const refs=node.refs;return{get el(){const el=refs[name];return inOwnerDocument(el)?el:null;},};} 1441function useEnv(){return getCurrent().component.env;} 1442function extendEnv(currentEnv,extension){const env=Object.create(currentEnv);const descrs=Object.getOwnPropertyDescriptors(extension);return Object.freeze(Object.defineProperties(env,descrs));} 1443function useSubEnv(envExtension){const node=getCurrent();node.component.env=extendEnv(node.component.env,envExtension);useChildSubEnv(envExtension);} 1444function useChildSubEnv(envExtension){const node=getCurrent();node.childEnv=extendEnv(node.childEnv,envExtension);} 1445function useEffect(effect,computeDependencies=()=>[NaN]){let cleanup;let dependencies;onMounted(()=>{dependencies=computeDependencies();cleanup=effect(...dependencies);});onPatched(()=>{const newDeps=computeDependencies();const shouldReapply=newDeps.some((val,i)=>val!==dependencies[i]);if(shouldReapply){dependencies=newDeps;if(cleanup){cleanup();} 1446cleanup=effect(...dependencies);}});onWillUnmount(()=>cleanup&&cleanup());} 1447function useExternalListener(target,eventName,handler,eventParam
1447s){const node=getCurrent();const boundHandler=handler.bind(node.component);onMounted(()=>target.addEventListener(eventName,boundHandler,eventParams));onWillUnmount(()=>target.removeEventListener(eventName,boundHandler,eventParams));} 1448config.shouldNormalizeDom=false;config.mainEventHandler=mainEventHandler;const blockDom={config,mount:mount$1,patch,remove,list,multi,text,toggler,createBlock,html,comment,};const __info__={version:App.version,};TemplateSet.prototype._compileTemplate=function _compileTemplate(name,template){return compile(template,{name,dev:this.dev,translateFn:this.translateFn,translatableAttributes:this.translatableAttributes,customDirectives:this.customDirectives,hasGlobalValues:this.hasGlobalValues,});};exports.App=App;exports.Component=Component;exports.EventBus=EventBus;exports.OwlError=OwlError;exports.__info__=__info__;exports.batched=batched;exports.blockDom=blockDom;exports.htmlEscape=htmlEscape;exports.loadFile=loadFile;exports.markRaw=markRaw;exports.markup=markup;exports.mount=mount;exports.onError=onError;exports.onMounted=onMounted;exports.onPatched=onPatched;exports.onRendered=onRendered;exports.onWillDestroy=onWillDestroy;exports.onWillPatch=onWillPatch;exports.onWillRender=onWillRender;exports.onWillStart=onWillStart;exports.onWillUnmount=onWillUnmount;exports.onWillUpdateProps=onWillUpdateProps;exports.reactive=reactive;exports.status=status;exports.toRaw=toRaw;exports.useChildSubEnv=useChildSubEnv;exports.useComponent=useComponent;exports.useEffect=useEffect;exports.useEnv=useEnv;exports.useExternalListener=useExternalListener;exports.useRef=useRef;exports.useState=useState;exports.useSubEnv=useSubEnv;exports.validate=validate;exports.validateType=validateType;exports.whenReady=whenReady;exports.xml=xml;Object.defineProperty(exports,'__esModule',{value:true});__info__.date='2026-07-10T09:10:50.283Z';__info__.hash='5093c0b';__info__.url='https://github.com/odoo/owl';})(this.owl=this.owl||{});; 1449 1450/* /web/static/lib/owl/odoo_module.js */ 1451odoo.define("@odoo/owl",[],function(){"use strict";return owl;});; 1452 1453/* /web/static/src/env.js */ 1454odoo.define('@web/env',['@odoo/owl','@web/core/utils/hooks','@web/core/registry','@web/core/templates','@web/core/l10n/translation','@web/session','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{App,EventBus}=require("@odoo/owl");const{SERVICES_METADATA}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const{getTemplate}=require("@web/core/templates");const{appTranslateFn}=require("@web/core/l10n/translation");const{session}=require("@web/session");const{isMacOS}=require("@web/core/browser/feature_detection");__exports.makeEnv=makeEnv;function makeEnv(){const bus=new EventBus();const prom=new Promise((resolve)=>{bus.addEventListener("SERVICES-LOADED",resolve,{once:true});});return{bus,isReady:prom,services:{},debug:odoo.debug,get isSmall(){throw new Error("UI service not initialized!");},};} 1455const serviceRegistry=registry.category("services");serviceRegistry.addValidation({start:Function,dependencies:{type:Array,element:String,optional:true},async:{type:[{type:Array,element:String},{value:true}],optional:true},"*":true,});let startServicesPromise=null;__exports.startServices=startServices;async function startServices(env){await Promise.resolve();const toStart=new Map();serviceRegistry.addEventListener("UPDATE",async(ev)=>{await Promise.resolve();const{operation,key:name,value:service}=ev.detail;if(operation==="delete"){return;} 1456if(toStart.size){const namedService=Object.assign(Object.create(service),{name});toStart.set(name,namedService);}else{await _startServices(env,toStart);}});await _startServices(env,toStart);} 1457async function _startServices(env,toStart){if(startServicesPromise){return startServicesPromise.then(()=>_startServices(env,toStart));} 1458const services=env.services;for(const[name,service]of serviceRegistry.getEntries()){if(!(name in services)){const namedService=Object.assign(Object.create(service),{name});toStart.set(name,namedService);}} 1459async function start(){let service=null;const proms=[];
1459while((service=findNext())){const name=service.name;toStart.delete(name);const entries=(service.dependencies||[]).map((dep)=>[dep,services[dep]]);const dependencies=Object.fromEntries(entries);if(name in services){continue;} 1460const value=service.start(env,dependencies);if("async"in service){SERVICES_METADATA[name]=service.async;} 1461proms.push(Promise.resolve(value).then((val)=>{services[name]=val||null;}));} 1462await Promise.all(proms);if(proms.length){return start();}} 1463startServicesPromise=start().finally(()=>{startServicesPromise=null;});await startServicesPromise;env.bus.trigger("SERVICES-LOADED");if(toStart.size){const missingDeps=new Set();for(const service of toStart.values()){for(const dependency of service.dependencies){if(!(dependency in services)&&!toStart.has(dependency)){missingDeps.add(dependency);}}} 1464const depNames=[...missingDeps].join(", ");throw new Error(`Some services could not be started: ${[ 1465 ...toStart.keys(), 1466 ]}. Missing dependencies: ${depNames}`);} 1467function findNext(){for(const s of toStart.values()){if(s.dependencies){if(s.dependencies.every((d)=>d in services)){return s;}}else{return s;}} 1468return null;}} 1469const customDirectives=__exports.customDirectives={click:(node,value,modifiers)=>{let mods="";if(modifiers.includes("synthetic")){mods+=".synthetic";} 1470if(modifiers.includes("capture")){mods+=".capture";} 1471const handlerFunction=`(ev) => __globals__.click(ev, (${value}).bind(this), '${JSON.stringify( 1472 modifiers 1473 )}')`;node.setAttribute(`t-on-click${mods}`,handlerFunction);node.setAttribute(`t-on-auxclick${mods}`,handlerFunction);},};const globalValues=__exports.globalValues={click:(ev,value,modifiers)=>{if(ev.button===0||ev.button===1){modifiers=JSON.parse(modifiers);for(const modifier of modifiers){if(modifier==="stop"){ev.stopPropagation();} 1474if(modifier==="prevent"){ev.preventDefault();}} 1475const ctrlKey=isMacOS()?ev.metaKey:ev.ctrlKey;const isMiddleClick=(ctrlKey&&ev.button===0)||ev.button===1;value(ev,isMiddleClick);}},};__exports.mountComponent=mountComponent;async function mountComponent(component,target,appConfig={}){let{env}=appConfig;const isRoot=!env;if(isRoot){env=await makeEnv();await startServices(env);} 1476const app=new App(component,{env,getTemplate,dev:env.debug||session.test_mode,warnIfNoStaticProps:!session.test_mode,name:component.constructor.name,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,customDirectives,globalValues,...appConfig,});const root=await app.mount(target);if(isRoot){odoo.__WOWL_DEBUG__={root};} 1477return app;} 1478return __exports;});; 1479 1480/* /web/static/src/session.js */ 1481odoo.define('@web/session',[],function(require){'use strict';let __exports={};const session=__exports.session=odoo.__session_info__||{};delete odoo.__session_info__;return __exports;});; 1482 1483/* /web/static/src/core/action_swiper/action_swiper.js */ 1484odoo.define('@web/core/action_swiper/action_swiper',['@web/core/browser/browser','@web/core/l10n/localization','@web/core/utils/numbers','@odoo/owl','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{localization}=require("@web/core/l10n/localization");const{clamp}=require("@web/core/utils/numbers");const{Component,onMounted,onWillUnmount,useRef,useState}=require("@odoo/owl");const{Deferred}=require("@web/core/utils/concurrency");const isScrollSwipable=(scrollables)=>{return{left:!scrollables.filter((e)=>e.scrollLeft!==0).length,right:!scrollables.filter((e)=>e.scrollLeft+Math.round(e.getBoundingClientRect().width)!==e.scrollWidth).length,};};const ActionSwiper=__exports.ActionSwiper=class ActionSwiper extends Component{static template="web.ActionSwiper";static props={onLeftSwipe:{type:Object,args:{action:Function,icon:String,bgColor:String,},optional:true,},onRightSwipe:{type:Object,args:{action:Function,icon:String,bgColor:String,},optional:true,},slots:Object,animationOnMove:{type:Boolean,optional:true},animationType:{type:String,optional:true},swipeDistanceRatio:{type:Number,optional:true},swipeInvalid:{type:Function,optional:true},};static defaultProps={onLeftSwipe:undefined,onRightSwipe:undefined,animationOnMove:true,animationType:"bounce",swipeDistanceRatio:2,};setup(){this.actionTimeoutId=null;this.resetTimeoutId=null;this.defaultState={containerStyle:"",isSwiping:false,width:undefined,};this.root=useRef("root");this.targetContainer=useRef("targetContainer");this.state=useState({...this.defaultState});this.scrollables=undefined;this.startX=undefined;this.swipedDistance=0;this.isScrollValidated=false;onMounted(()=>
1484{if(this.targetContainer.el){this.state.width=this.targetContainer.el.getBoundingClientRect().width;} 1485if(this.props.onLeftSwipe||this.props.onRightSwipe){const classes=new Set(this.root.el.classList);classes.delete("o_actionswiper");for(const className of classes){this.targetContainer.el.firstChild.classList.add(className);this.root.el.classList.remove(className);}}});onWillUnmount(()=>{browser.clearTimeout(this.actionTimeoutId);browser.clearTimeout(this.resetTimeoutId);});} 1486get localizedProps(){return{onLeftSwipe:localization.direction==="rtl"?this.props.onRightSwipe:this.props.onLeftSwipe,onRightSwipe:localization.direction==="rtl"?this.props.onLeftSwipe:this.props.onRightSwipe,};} 1487_onTouchEndSwipe(){if(this.state.isSwiping){this.state.isSwiping=false;if(this.localizedProps.onRightSwipe&&this.swipedDistance>this.state.width/this.props.swipeDistanceRatio){this.swipedDistance=this.state.width;this.handleSwipe(this.localizedProps.onRightSwipe.action);}else if(this.localizedProps.onLeftSwipe&&this.swipedDistance<-this.state.width/this.props.swipeDistanceRatio){this.swipedDistance=-this.state.width;this.handleSwipe(this.localizedProps.onLeftSwipe.action);}else{this.state.containerStyle="";}}} 1488_onTouchMoveSwipe(ev){if(this.state.isSwiping){if(this.props.swipeInvalid&&this.props.swipeInvalid()){this.state.isSwiping=false;return;} 1489const{onLeftSwipe,onRightSwipe}=this.localizedProps;this.swipedDistance=clamp(ev.touches[0].clientX-this.startX,onLeftSwipe?-this.state.width:0,onRightSwipe?this.state.width:0);if(Math.abs(this.swipedDistance)>40){ev.preventDefault();} 1490if(!this.isScrollValidated&&this.scrollables&&!isScrollSwipable(this.scrollables)[this.swipedDistance>0?"left":"right"]){return this._reset();} 1491this.isScrollValidated=true;if(this.props.animationOnMove){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;}}} 1492_onTouchStartSwipe(ev){this.scrollables=ev.composedPath().filter((e)=>e.nodeType===1&&this.targetContainer.el.contains(e)&&e.scrollWidth>e.getBoundingClientRect().width&&["auto","scroll"].includes(window.getComputedStyle(e)["overflow-x"]));if(!this.state.width){this.state.width=this.targetContainer&&this.targetContainer.el.getBoundingClientRect().width;} 1493this.state.isSwiping=true;this.isScrollValidated=false;this.startX=ev.touches[0].clientX;} 1494_reset(){Object.assign(this.state,{...this.defaultState});this.scrollables=undefined;this.startX=undefined;this.swipedDistance=0;this.isScrollValidated=false;} 1495handleSwipe(action){if(this.props.animationType==="bounce"){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;this.actionTimeoutId=browser.setTimeout(async()=>{await action(Promise.resolve());this._reset();},500);}else if(this.props.animationType==="forwards"){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;this.actionTimeoutId=browser.setTimeout(async()=>{const prom=new Deferred();await action(prom);this.state.isSwiping=true;this.state.containerStyle=`transform: translateX(${-this.swipedDistance}px)`;this.resetTimeoutId=browser.setTimeout(()=>{prom.resolve();this._reset();},100);},100);}else{return action(Promise.resolve());}}} 1496return __exports;});; 1497 1498/* /web/static/src/core/anchor_scroll_prevention.js */ 1499odoo.define('@web/core/anchor_scroll_prevention',['@web/core/browser/browser'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");browser.addEventListener("click",(ev)=>{const href=ev.target.closest("a")?.getAttribute("href");if(href&&href==="#"){ev.preventDefault();return;}});return __exports;});; 1500 1501/* /web/static/src/core/assets.js */ 1502odoo.define('@web/core/assets',['@odoo/owl','@web/session','@web/core/registry'],function(require){'use strict';let __exports={};const{Component,onWillStart,whenReady,xml}=require("@odoo/owl");const{session}=require("@web/session");const{registry}=require("@web/core/registry");const globalBundleCache=__exports.globalBundleCache=new Map();const assetCacheByDocument=__exports.assetCacheByDocument=new WeakMap();function getGlobalBundleCache(){return globalBundleCache;} 1503function getAssetCache(targetDoc){if(!assetCacheByDocument.has(targetDoc)){assetCacheByDocument.set(targetDoc,new Map());} 1504return assetCacheByDocument.get(targetDoc);} 1505__exports.computeBundleCacheMap=computeBundleCacheMap;function computeBundleCacheMap(targetDoc){const cacheMap=getGlobalBundleCache();for(const script of targetDoc.head.querySelectorAll("script[src]")){cacheMap.set(script.getAttribute("src"),Promise.resolve());} 1506for(const link of targetDoc.head.querySelectorAll("link[rel=stylesheet][href]")){cacheMap.set(link.getAttribute("href"),Promise.resolve());}} 1507whenReady(()=>computeBundleCacheMap(document));const onLoadAndError=(el,onLoad,onError)=>{const onLoadListener=(event)=>{removeListeners();onLoad(event);};const onErrorListener=(error)=>{removeListeners();onError(error);};const removeListeners=()=>{el.removeEventListener("load",onLoadListener);el.removeEventListener("error",onErrorListener);};el.addEventListener("load",onLoadListener);el.addEventListener("error",onErrorListener);window.addEventListener("pagehide",()=>{removeListeners();});};
1507__exports.getBundle=getBundle;function getBundle(){return assets.getBundle(...arguments);} 1508__exports.loadBundle=loadBundle;function loadBundle(){return assets.loadBundle(...arguments);} 1509__exports.loadJS=loadJS;function loadJS(){return assets.loadJS(...arguments);} 1510__exports.loadCSS=loadCSS;function loadCSS(){return assets.loadCSS(...arguments);} 1511const AssetsLoadingError=__exports.AssetsLoadingError=class AssetsLoadingError extends Error{} 1512const LazyComponent=__exports.LazyComponent=class LazyComponent extends Component{static template=xml`<t t-component="Component" t-props="componentProps"/>`;static props={Component:String,bundle:String,props:{type:[Object,Function],optional:true},};setup(){onWillStart(async()=>{await loadBundle(this.props.bundle);this.Component=registry.category("lazy_components").get(this.props.Component);});} 1513get componentProps(){return typeof this.props.props==="function"?this.props.props():this.props.props;}} 1514const assets=__exports.assets={retries:{count:3,delay:5000,extraDelay:2500,},getBundle(bundleName){const cacheMap=getGlobalBundleCache();if(cacheMap.has(bundleName)){return cacheMap.get(bundleName);} 1515const url=new URL(`/web/bundle/${bundleName}`,location.origin);for(const[key,value]of Object.entries(session.bundle_params||{})){url.searchParams.set(key,value);} 1516const promise=fetch(url).then(async(response)=>{const cssLibs=[];const jsLibs=[];if(!response.bodyUsed){const result=await response.json();for(const{src,type}of Object.values(result)){if(type==="link"&&src){cssLibs.push(src);}else if(type==="script"&&src){jsLibs.push(src);}}} 1517return{cssLibs,jsLibs};}).catch((reason)=>{cacheMap.delete(bundleName);throw new AssetsLoadingError(`The loading of ${url} failed`,{cause:reason});});cacheMap.set(bundleName,promise);return promise;},loadBundle(bundleName,{targetDoc=document,css=true,js=true}={}){if(typeof bundleName!=="string"){throw new Error(`loadBundle(bundleName:string) accepts only bundleName argument as a string ! Not ${JSON.stringify( 1518 bundleName 1519 )} as ${typeof bundleName}`);} 1520return getBundle(bundleName).then(({cssLibs,jsLibs})=>{const promises=[];if(css&&cssLibs){promises.push(...cssLibs.map((url)=>assets.loadCSS(url,{targetDoc})));} 1521if(js&&jsLibs){promises.push(...jsLibs.map((url)=>assets.loadJS(url,{targetDoc})));} 1522return Promise.all(promises);});},loadCSS(url,{retryCount=0,targetDoc=document}={}){const cacheMap=getAssetCache(targetDoc);if(cacheMap.has(url)){return cacheMap.get(url);} 1523const linkEl=targetDoc.createElement("link");linkEl.setAttribute("href",url);linkEl.type="text/css";linkEl.rel="stylesheet";const promise=new Promise((resolve,reject)=>onLoadAndError(linkEl,resolve,async(error)=>{cacheMap.delete(url);if(retryCount<assets.retries.count){const delay=assets.retries.delay+assets.retries.extraDelay*retryCount;await new Promise((res)=>setTimeout(res,delay));linkEl.remove();loadCSS(url,{retryCount:retryCount+1,targetDoc}).then(resolve).catch((reason)=>{cacheMap.delete(url);reject(reason);});}else{reject(new AssetsLoadingError(`The loading of ${url} failed`,{cause:error}));}}));cacheMap.set(url,promise);targetDoc.head.appendChild(linkEl);return promise;},loadJS(url,{targetDoc=document}={}){const cacheMap=getAssetCache(targetDoc);if(cacheMap.has(url)){return cacheMap.get(url);} 1524const scriptEl=targetDoc.createElement("script");scriptEl.setAttribute("src",url);scriptEl.type=url.includes("web/static/lib/pdfjs/")?"module":"text/javascript";
1524const promise=new Promise((resolve,reject)=>onLoadAndError(scriptEl,resolve,(error)=>{cacheMap.delete(url);reject(new AssetsLoadingError(`The loading of ${url} failed`,{cause:error}));}));cacheMap.set(url,promise);targetDoc.head.appendChild(scriptEl);return promise;},};return __exports;});; 1525 1526/* /web/static/src/core/autocomplete/autocomplete.js */ 1527odoo.define('@web/core/autocomplete/autocomplete',['@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/timing','@web/core/hotkeys/hotkey_service','@web/core/position/position_hook','@odoo/owl','@web/core/utils/classname'],function(require){'use strict';let __exports={};const{Deferred}=require("@web/core/utils/concurrency");const{useAutofocus,useForwardRefToParent,useService}=require("@web/core/utils/hooks");const{isScrollableY,scrollTo}=require("@web/core/utils/scrolling");const{useDebounced}=require("@web/core/utils/timing");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{usePosition}=require("@web/core/position/position_hook");const{Component,onWillUpdateProps,useExternalListener,useRef,useState}=require("@odoo/owl");const{mergeClasses}=require("@web/core/utils/classname");const AutoComplete=__exports.AutoComplete=class AutoComplete extends Component{static template="web.AutoComplete";static props={value:{type:String,optional:true},id:{type:String,optional:true},sources:{type:Array,element:{type:Object,shape:{placeholder:{type:String,optional:true},options:[Array,Function],optionSlot:{type:String,optional:true},},},},placeholder:{type:String,optional:true},title:{type:String,optional:true},autocomplete:{type:String,optional:true},autoSelect:{type:Boolean,optional:true},resetOnSelect:{type:Boolean,optional:true},onInput:{type:Function,optional:true},onCancel:{type:Function,optional:true},onChange:{type:Function,optional:true},onBlur:{type:Function,optional:true},onFocus:{type:Function,optional:true},searchOnInputClick:{type:Boolean,optional:true},input:{type:Function,optional:true},inputDebounceDelay:{type:Number,optional:true},dropdown:{type:Boolean,optional:true},autofocus:{type:Boolean,optional:true},class:{type:String,optional:true},slots:{type:Object,optional:true},menuPositionOptions:{type:Object,optional:true},menuCssClass:{type:[String,Array,Object],optional:true},selectOnBlur:{type:Boolean,optional:true},};static defaultProps={value:"",placeholder:"",title:"",autocomplete:"off",autoSelect:false,dropdown:true,onInput:()=>{},onCancel:()=>{},onChange:()=>{},onBlur:()=>{},onFocus:()=>{},searchOnInputClick:true,inputDebounceDelay:250,menuPositionOptions:{},menuCssClass:{},};get timeout(){return this.props.inputDebounceDelay;} 1528setup(){this.nextSourceId=0;this.nextOptionId=0;this.sources=[];this.inEdition=false;this.mouseSelectionActive=false;this.isOptionSelected=false;this.state=useState({navigationRev:0,optionsRev:0,open:false,activeSourceOption:null,value:this.props.value,});this.inputRef=useForwardRefToParent("input");this.listRef=useRef("sourcesList");if(this.props.autofocus){useAutofocus({refName:"input"});} 1529this.root=useRef("root");this.debouncedProcessInput=useDebounced(async()=>{const currentPromise=this.pendingPromise;this.pendingPromise=null;this.props.onInput({inputValue:this.inputRef.el.value,});try{await this.open(true);currentPromise.resolve();}catch{currentPromise.reject();}finally{if(currentPromise===this.loadingPromise){this.loadingPromise=null;}}},this.timeout);useExternalListener(window,"scroll",this.externalClose,true);useExternalListener(window,"pointerdown",this.externalClose,true);useExternalListener(window,"mousemove",()=>(this.mouseSelectionActive=true),true);this.hotkey=useService("hotkey");this.hotkeysToRemove=[];onWillUpdateProps((nextProps)=>{if(this.props.value!==nextProps.value||this.forceValFromProp){this.forceValFromProp=false;if(!this.inEdition){this.state.value=nextProps.value;this.inputRef.el.value=nextProps.value;}}});if(this.props.dropdown){usePosition("sourcesList",()=>this.targetDropdown,this.dropdownOptions);}else{this.open(false);}} 1530get targetDropdown(){return this.inputRef.el;} 1531get activeSourceOptionId(){if(!this.isOpened||!this.state.activeSourceOption){return undefined;} 1532const[sourceIndex,optionIndex]=this.state.activeSourceOption;const source=this.sources[sourceIndex];return`${this.props.id || "autocomplete"}_${sourceIndex}_${ 1533 source.isLoading ? "loading" : optionIndex 1534 }`;} 1535get dropdownOptions(){return{position:"bottom-start",...this.props.menuPositionOptions,};} 1536get isOpened(){return this.state.open;} 1537get hasOptions(){for(const source of this.sources){if(source.isLoading||source.options.length){return true;}} 1538return false;} 1539get activeOption(){if(!this.state.activeSourceOption){return null;} 1540const[sourceIndex,optionIndex]=this.state.activeSourceOption;return this.sources[sourceIndex].options[optionIndex];} 1541open(useInput=false){this.state.open=true;return this.loadSources(useInput);} 1542close(){this.state.open=false;this.state.activeSourceOption=null;this.mouseSelectionActive=false;} 1543cancel(){if(this.inputRef.el.value.length){if(this.props.autoSelect){this.inputRef.el.value=this.props.value;this.props.onCancel();}} 1544this.close();} 1545async loadSources(useInput){this.sources=[];this.state.activeSourceOption=null;const proms=[];for(const pSource of this.props.sources){const source=this.makeSource(pSource);this.sources.push(source);const options=this.loadOptions(pSource.options,useInput?this.inputRef.el.value.trim():"");if(options instanceof Promise){source.isLoading=true;const prom=options.then((options)=>{source.options=options.map((option)=>this.makeOption(option));source.isLoading=false;this.state.optionsRev++;});proms.push(prom);}else{source.options=options.map((option)=>this.makeOption(option));}} 1546await Promise.all(proms);this.navigate(0);this.scroll();} 1547get displayOptions(){return!this.props.dropdown||(this.isOpened&&this.hasOptions);} 1548loadOptions(options,request){if(typeof options==="function"){return options(request);}else{return options;}} 1549makeOption(option){return{cssClass:"",data:{},...option,id:++this.nextOptionId,unselectable:!option.onSelect,};} 1550makeSource(source){return{id:++this.nextSourceId,options:[],isLoading:false,placeholder:source.placeholder,optionSlot:source.optionSlot,};} 1551isActiveSourceOption([sourceIndex,optionIndex]){return(this.state.activeSourceOption&&this.state.activeSourceOption[0]===sourceIndex&&this.state.activeSourceOption[1]===optionIndex);} 1552selectOption(option){this.inEdition=false;if(option.unselectable){return;} 1553if(this.props.resetOnSelect){this.inputRef.el.value="";} 1554this.isOptionSelected=true;this.forceValFromProp=true;option.onSelect();this.close();} 1555navigate(direction){let step=Math.sign(direction);if(!step){this.state.activeSourceOption=null;step=1;}else{this.state.navigationRev++;}
1556do{if(this.state.activeSourceOption){let[sourceIndex,optionIndex]=this.state.activeSourceOption;let source=this.sources[sourceIndex];optionIndex+=step;if(0>optionIndex||optionIndex>=source.options.length){sourceIndex+=step;source=this.sources[sourceIndex];while(source&&source.isLoading){sourceIndex+=step;source=this.sources[sourceIndex];} 1557if(source){optionIndex=step<0?source.options.length-1:0;}} 1558this.state.activeSourceOption=source?[sourceIndex,optionIndex]:null;}else{let sourceIndex=step<0?this.sources.length-1:0;let source=this.sources[sourceIndex];while(source&&source.isLoading){sourceIndex+=step;source=this.sources[sourceIndex];} 1559if(source){const optionIndex=step<0?source.options.length-1:0;if(optionIndex<source.options.length){this.state.activeSourceOption=[sourceIndex,optionIndex];}}}}while(this.activeOption?.unselectable);} 1560onInputBlur(){if(this.ignoreBlur){this.ignoreBlur=false;return;} 1561if(this.props.selectOnBlur&&!this.isOptionSelected&&this.sources[0]){const firstOption=this.sources[0].options[0];if(firstOption){this.state.activeSourceOption=firstOption.unselectable?null:[0,0];this.selectOption(this.activeOption);}} 1562this.props.onBlur({inputValue:this.inputRef.el.value,});this.inEdition=false;this.isOptionSelected=false;} 1563onInputClick(){if(!this.isOpened&&this.props.searchOnInputClick){this.open(this.inputRef.el.value.trim()!==this.props.value.trim());}else{this.close();}} 1564onInputChange(ev){if(this.ignoreBlur){ev.stopImmediatePropagation();} 1565this.props.onChange({inputValue:this.inputRef.el.value,isOptionSelected:this.ignoreBlur,});} 1566async onInput(){this.inEdition=true;this.pendingPromise=this.pendingPromise||new Deferred();this.loadingPromise=this.pendingPromise;this.debouncedProcessInput();} 1567onInputFocus(ev){this.inputRef.el.setSelectionRange(0,this.inputRef.el.value.length);this.props.onFocus(ev);} 1568get autoCompleteRootClass(){let classList="";if(this.props.class){classList+=this.props.class;} 1569if(this.props.dropdown){classList+=" dropdown";} 1570return classList;} 1571get ulDropdownClass(){return mergeClasses(this.props.menuCssClass,{"dropdown-menu ui-autocomplete":this.props.dropdown,"list-group":!this.props.dropdown,});} 1572async onInputKeydown(ev){const hotkey=getActiveHotkey(ev);const isSelectKey=hotkey==="enter"||hotkey==="tab";if(this.loadingPromise&&isSelectKey){if(hotkey==="enter"){ev.stopPropagation();ev.preventDefault();} 1573await this.loadingPromise;} 1574switch(hotkey){case"enter":if(!this.isOpened||!this.state.activeSourceOption){return;} 1575this.selectOption(this.activeOption);break;case"escape":if(!this.isOpened){return;} 1576this.cancel();break;case"tab":case"shift+tab":if(!this.isOpened){return;} 1577if(this.props.autoSelect&&this.state.activeSourceOption&&(this.state.navigationRev>0||this.inputRef.el.value.length>0)){this.selectOption(this.activeOption);} 1578this.close();return;case"arrowup":this.navigate(-1);if(!this.isOpened){this.open(true);} 1579this.scroll();break;case"arrowdown":this.navigate(+1);if(!this.isOpened){this.open(true);} 1580this.scroll();break;default:return;} 1581ev.stopPropagation();ev.preventDefault();} 1582onOptionMouseEnter(indices){if(!this.mouseSelectionActive){return;} 1583const[sourceIndex,optionIndex]=indices;if(this.sources[sourceIndex].options[optionIndex]?.unselectable){this.state.activeSourceOption=null;}else{this.state.activeSourceOption=indices;}} 1584onOptionMouseLeave(){this.state.activeSourceOption=null;} 1585onOptionClick(option){this.selectOption(option);this.inputRef.el.focus();} 1586onOptionPointerDown(option,ev){this.ignoreBlur=true;if(option.unselectable){ev.preventDefault();}} 1587externalClose(ev){if(this.isOpened&&!this.root.el.contains(ev.target)){this.cancel();}} 1588scroll(){if(!this.activeSourceOptionId){return;} 1589if(isScrollableY(this.listRef.el)){const element=this.listRef.el.querySelector(`#${this.activeSourceOptionId}`);if(element){scrollTo(element);}}}} 1590return __exports;});; 1591 1592/* /web/static/src/core/barcode/ZXingBarcodeDetector.js */ 1593odoo.define('@web/core/barcode/ZXingBarcodeDetector',[],function(require){'use strict';let __exports={};__exports.buildZXingBarcodeDetector=buildZXingBarcodeDetector;function buildZXingBarcodeDetector(ZXing){const ZXingFormats=new Map([["aztec",ZXing.BarcodeFormat.AZTEC],["code_39",ZXing.BarcodeFormat.CODE_39],["code_128",ZXing.BarcodeFormat.CODE_128],["data_matrix",ZXing.BarcodeFormat.DATA_MATRIX],["ean_8",ZXing.BarcodeFormat.EAN_8],["ean_13",ZXing.BarcodeFormat.EAN_13],["itf",ZXing.BarcodeFormat.ITF],["pdf417",ZXing.BarcodeFormat.PDF_417],["qr_code",ZXing.BarcodeFormat.QR_CODE],["upc_a",ZXing.BarcodeFormat.UPC_A],["upc_e",ZXing.BarcodeFormat.UPC_E],]);const allSupportedFormats=Array.from(ZXingFormats.keys());class ZXingBarcodeDetector{constructor(opts={}){const formats=opts.formats||allSupportedFormats;const hints=new Map([[ZXing.DecodeHintType.POSSIBLE_FORMATS,formats.map((format)=>ZXingFormats.get(format)),],[ZXing.DecodeHintType.TRY_HARDER,true],]);this.reader=new ZXing.MultiFormatReader();this.reader.setHints(hints);} 1594async detect(video){if(!(video instanceof HTMLVideoElement)){throw new DOMException("imageDataFrom() requires an HTMLVideoElement","InvalidArgumentError");} 1595if(!isVideoElementReady(video)){throw new DOMException("HTMLVideoElement is not ready","InvalidStateError");} 1596const canvas=document.createElement("canvas");let barcodeArea;if(this.cropArea&&(this.cropArea.x||this.cropArea.y)){barcodeArea=this.cropArea;}else{barcodeArea={x:0,y:0,width:video.videoWidth,height:video.videoHeight,};} 1597canvas.width=barcodeArea.width;
1597canvas.height=barcodeArea.height;const ctx=canvas.getContext("2d");ctx.drawImage(video,barcodeArea.x,barcodeArea.y,barcodeArea.width,barcodeArea.height,0,0,barcodeArea.width,barcodeArea.height);const luminanceSource=new ZXing.HTMLCanvasElementLuminanceSource(canvas);const binaryBitmap=new ZXing.BinaryBitmap(new ZXing.HybridBinarizer(luminanceSource));try{const result=this.reader.decodeWithState(binaryBitmap);const{resultPoints}=result;const boundingBox=DOMRectReadOnly.fromRect({x:resultPoints[0].x,y:resultPoints[0].y,height:Math.max(1,Math.abs(resultPoints[1].y-resultPoints[0].y)),width:Math.max(1,Math.abs(resultPoints[1].x-resultPoints[0].x)),});const cornerPoints=resultPoints;const format=Array.from(ZXingFormats).find(([k,val])=>val===result.getBarcodeFormat());const rawValue=result.getText();return[{boundingBox,cornerPoints,format,rawValue,},];}catch(err){if(err.name==="NotFoundException"){return[];} 1598throw err;}} 1599setCropArea(cropArea){this.cropArea=cropArea;}} 1600ZXingBarcodeDetector.getSupportedFormats=async()=>allSupportedFormats;return ZXingBarcodeDetector;} 1601const HAVE_NOTHING=0;const HAVE_METADATA=1;__exports.isVideoElementReady=isVideoElementReady;function isVideoElementReady(video){return![HAVE_NOTHING,HAVE_METADATA].includes(video.readyState);} 1602return __exports;});; 1603 1604/* /web/static/src/core/barcode/barcode_dialog.js */ 1605odoo.define('@web/core/barcode/barcode_dialog',['@web/core/l10n/translation','@web/core/dialog/dialog','@odoo/owl','@web/core/barcode/barcode_video_scanner'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{Dialog}=require("@web/core/dialog/dialog");const{Component,useState}=require("@odoo/owl");const{BarcodeVideoScanner,isBarcodeScannerSupported}=require("@web/core/barcode/barcode_video_scanner");const BarcodeDialog=__exports.BarcodeDialog=class BarcodeDialog extends Component{static template="web.BarcodeDialog";static components={BarcodeVideoScanner,Dialog,};static props=["facingMode","close","onResult","onError"];setup(){this.state=useState({barcodeScannerSupported:isBarcodeScannerSupported(),errorMessage:_t("Check your browser permissions"),});} 1606onResult(result){this.props.close();this.props.onResult(result);} 1607onError(error){this.state.barcodeScannerSupported=false;this.state.errorMessage=error.message;}} 1608__exports.scanBarcode=scanBarcode;async function scanBarcode(env,facingMode="environment"){let res;let rej;const promise=new Promise((resolve,reject)=>{res=resolve;rej=reject;});env.services.dialog.add(BarcodeDialog,{facingMode,onResult:(result)=>res(result),onError:(error)=>rej(error),});return promise;} 1609return __exports;});; 1610 1611/* /web/static/src/core/barcode/barcode_video_scanner.js */ 1612odoo.define('@web/core/barcode/barcode_video_scanner',['@web/core/browser/browser','@web/core/utils/concurrency','@web/core/assets','@web/core/barcode/ZXingBarcodeDetector','@web/core/barcode/crop_overlay','@odoo/owl','@web/core/l10n/translation','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{delay}=require("@web/core/utils/concurrency");const{loadJS}=require("@web/core/assets");const{isVideoElementReady,buildZXingBarcodeDetector}=require("@web/core/barcode/ZXingBarcodeDetector");const{CropOverlay}=require("@web/core/barcode/crop_overlay");const{Component,onMounted,onWillStart,onWillUnmount,status,useRef,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{pick}=require("@web/core/utils/objects");const BarcodeVideoScanner=__exports.BarcodeVideoScanner=class BarcodeVideoScanner extends Component{static template="web.BarcodeVideoScanner";static components={CropOverlay,};static props={cssClass:{type:String,optional:true},facingMode:{type:String,validate:(fm)=>["environment","left","right","user"].includes(fm),},close:{type:Function,optional:true},onReady:{type:Function,optional:true},onResult:Function,onError:Function,placeholder:{type:String,optional:true},delayBetweenScan:{type:Number,optional:true},};static defaultProps={cssClass:"w-100 h-100",};setup(){this.videoPreviewRef=useRef("videoPreview");this.detectorTimeout=null;this.stream=null;this.detector=null;this.overlayInfo={};this.zoomRatio=1;this.scanPaused=false;this.state=useState({isReady:false,});onWillStart(async()=>{let DetectorClass;if("BarcodeDetector"in window){DetectorClass=BarcodeDetector;}else{await loadJS("/web/static/lib/zxing-library/zxing-library.js");DetectorClass=buildZXingBarcodeDetector(window.ZXing);} 1613const formats=await DetectorClass.getSupportedFormats();this.detector=new DetectorClass({formats});});onMounted(async()=>{const constraints={video:{facingMode:this.props.facingMode},audio:false,};try{this.stream=await browser.navigator.mediaDevices.getUserMedia(constraints);}catch(err){const errors={NotFoundError:_t("No device can be found."),NotAllowedError:_t("Odoo needs your authorization first."),};const errorMessage=_t("Could not start scanning. %(message)s",{message:errors[err.name]||err.message,});this.props.onError(new Error(errorMessage));return;} 1614if(!this.videoPreviewRef.el){this.cleanStreamAndTimeout();const errorMessage=_t("Barcode Video Scanner could not be mounted properly.");this.props.onError(new Error(errorMessage));return;} 1615this.videoPreviewRef.el.srcObject=this.stream;const ready=await this.isVideoReady();if(!ready){return;} 1616if(this.videoPreviewRef.el.paused){await this.videoPreviewRef.el.play();} 1617const{height,width}=getComputedStyle(this.videoPreviewRef.el);const divWidth=width.slice(0,-2);const divHeight=height.slice(0,-2);const tracks=this.stream.getVideoTracks();if(tracks.length){const[track]=tracks;const settings=track.getSettings();this.zoomRatio=Math.min(divWidth/settings.width,divHeight/settings.height);this.addZoomSlider(track,settings);} 1618this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);});onWillUnmount(()=>this.cleanStreamAndTimeout());} 1619cleanStreamAndTimeout(){clearTimeout(this.detectorTimeout);this.detectorTimeout=null;
1619if(this.stream){this.stream.getTracks().forEach((track)=>track.stop());this.stream=null;}} 1620isZXingBarcodeDetector(){return this.detector&&this.detector.__proto__.constructor.name==="ZXingBarcodeDetector";} 1621async isVideoReady(){while(!isVideoElementReady(this.videoPreviewRef.el)){await delay(10);if(status(this)==="destroyed"){return false;}} 1622this.state.isReady=true;if(this.props.onReady){this.props.onReady();} 1623return true;} 1624onResize(overlayInfo){this.overlayInfo=overlayInfo;if(this.isZXingBarcodeDetector()){this.detector.setCropArea(this.adaptValuesWithRatio(this.overlayInfo,true));}} 1625async detectCode(){let barcodeDetected=false;let codes=[];try{codes=await this.detector.detect(this.videoPreviewRef.el);}catch(err){this.props.onError(err);} 1626for(const code of codes){if(!this.isZXingBarcodeDetector()&&this.overlayInfo.x!==undefined&&this.overlayInfo.y!==undefined){const{x,y,width,height}=this.adaptValuesWithRatio(code.boundingBox);if(x<this.overlayInfo.x||x+width>this.overlayInfo.x+this.overlayInfo.width||y<this.overlayInfo.y||y+height>this.overlayInfo.y+this.overlayInfo.height){continue;}} 1627barcodeDetected=true;this.barcodeDetected(code.rawValue);break;} 1628if(this.stream&&(!barcodeDetected||!this.props.delayBetweenScan)){this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);}} 1629barcodeDetected(barcode){if(this.props.delayBetweenScan&&!this.scanPaused){this.scanPaused=true;this.detectorTimeout=setTimeout(()=>{this.scanPaused=false;this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);},this.props.delayBetweenScan);} 1630this.props.onResult(barcode);} 1631adaptValuesWithRatio(domRect,dividerRatio=false){const newObject=pick(domRect,"x","y","width","height");for(const key of Object.keys(newObject)){if(dividerRatio){newObject[key]/=this.zoomRatio;}else{newObject[key]*=this.zoomRatio;}} 1632return newObject;} 1633addZoomSlider(track,settings){const zoom=track.getCapabilities().zoom;if(zoom?.min!==undefined&&zoom?.max!==undefined){const inputElement=document.createElement("input");inputElement.type="range";inputElement.min=zoom.min;inputElement.max=zoom.max;inputElement.step=zoom.step||1;inputElement.value=settings.zoom;inputElement.classList.add("align-self-end","m-5","z-1");inputElement.addEventListener("input",async(event)=>{await track?.applyConstraints({advanced:[{zoom:inputElement.value}]});});this.videoPreviewRef.el.parentElement.appendChild(inputElement);}}} 1634__exports.isBarcodeScannerSupported=isBarcodeScannerSupported;function isBarcodeScannerSupported(){return Boolean(browser.navigator.mediaDevices&&browser.navigator.mediaDevices.getUserMedia);} 1635return __exports;});; 1636 1637/* /web/static/src/core/barcode/crop_overlay.js */ 1638odoo.define('@web/core/barcode/crop_overlay',['@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/utils/numbers'],function(require){'use strict';let __exports={};const{Component,useRef,onPatched}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isIOS}=require("@web/core/browser/feature_detection");const{clamp}=require("@web/core/utils/numbers");const CropOverlay=__exports.CropOverlay=class CropOverlay extends Component{static template="web.CropOverlay";static props={onResize:Function,isReady:Boolean,slots:{type:Object,shape:{default:{},},},};setup(){this.localStorageKey="o-barcode-scanner-overlay";this.cropContainerRef=useRef("crop-container");this.isMoving=false;this.boundaryOverlay={};this.relativePosition={x:0,y:0,};onPatched(()=>{this.setupCropRect();});this.isIOS=isIOS();} 1639setupCropRect(){if(!this.props.isReady){return;} 1640this.computeDefaultPoint();this.computeOverlayPosition();this.calculateAndSetTransparentRect();this.executeOnResizeCallback();} 1641boundPoint(pointValue,boundaryRect){return{x:clamp(pointValue.x,boundaryRect.left,boundaryRect.left+boundaryRect.width),y:clamp(pointValue.y,boundaryRect.top,boundaryRect.top+boundaryRect.height),};} 1642calculateAndSetTransparentRect(){const cropTransparentRect=this.getTransparentRec(this.relativePosition,this.boundaryOverlay);this.setCropValue(cropTransparentRect,this.relativePosition);} 1643computeOverlayPosition(){const cropOverlayElement=this.cropContainerRef.el.querySelector(".o_crop_overlay");this.boundaryOverlay=cropOverlayElement.getBoundingClientRect();} 1644executeOnResizeCallback(){const transparentRec=this.getTransparentRec(this.relativePosition,this.boundaryOverlay);browser.localStorage.setItem(this.localStorageKey,JSON.stringify(transparentRec));this.props.onResize({...transparentRec,width:this.boundaryOverlay.width-2*transparentRec.x,height:this.boundaryOverlay.height-2*trans
1644parentRec.y,});} 1645computeDefaultPoint(){const firstChildComputedStyle=getComputedStyle(this.cropContainerRef.el.firstChild);const elementWidth=firstChildComputedStyle.width.slice(0,-2);const elementHeight=firstChildComputedStyle.height.slice(0,-2);const stringSavedPoint=browser.localStorage.getItem(this.localStorageKey);if(stringSavedPoint){const savedPoint=JSON.parse(stringSavedPoint);this.relativePosition={x:clamp(savedPoint.x,0,elementWidth),y:clamp(savedPoint.y,0,elementHeight),};}else{const stepWidth=elementWidth/10;const width=stepWidth*8;const height=width/4;const startY=elementHeight/2-height/2;this.relativePosition={x:stepWidth+width,y:startY+height,};}} 1646getTransparentRec(point,rect){const middleX=rect.width/2;const middleY=rect.height/2;const newDeltaX=Math.abs(point.x-middleX);const newDeltaY=Math.abs(point.y-middleY);return{x:middleX-newDeltaX,y:middleY-newDeltaY,};} 1647setCropValue(point,iconPoint){if(!iconPoint){iconPoint=point;} 1648this.cropContainerRef.el.style.setProperty("--o-crop-x",`${point.x}px`);this.cropContainerRef.el.style.setProperty("--o-crop-y",`${point.y}px`);this.cropContainerRef.el.style.setProperty("--o-crop-icon-x",`${iconPoint.x}px`);this.cropContainerRef.el.style.setProperty("--o-crop-icon-y",`${iconPoint.y}px`);} 1649pointerDown(event){if(event.target.matches("input")){return;} 1650event.preventDefault();if(event.target.matches(".o_crop_icon")){this.computeOverlayPosition();this.isMoving=true;}} 1651pointerMove(event){if(!this.isMoving){return;} 1652let eventPosition;if(event.touches&&event.touches.length){eventPosition=event.touches[0];}else{eventPosition=event;} 1653const{clientX,clientY}=eventPosition;const restrictedPosition=this.boundPoint({x:clientX,y:clientY,},this.boundaryOverlay);this.relativePosition={x:restrictedPosition.x-this.boundaryOverlay.left,y:restrictedPosition.y-this.boundaryOverlay.top,};this.calculateAndSetTransparentRect(this.relativePosition);} 1654pointerUp(event){this.isMoving=false;this.executeOnResizeCallback();}} 1655return __exports;});; 1656 1657/* /web/static/src/core/bottom_sheet/bottom_sheet.js */ 1658odoo.define('@web/core/bottom_sheet/bottom_sheet',['@odoo/owl','@web/core/h
1658otkeys/hotkey_hook','@web/core/utils/hooks','@web/core/utils/timing','@web/core/utils/scrolling','@web/core/utils/dvu','@web/core/utils/numbers','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{Component,useState,useRef,onMounted,useExternalListener}=require("@odoo/owl");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{useForwardRefToParent}=require("@web/core/utils/hooks");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{compensateScrollbar}=require("@web/core/utils/scrolling");const{getViewportDimensions,useViewportChange}=require("@web/core/utils/dvu");const{clamp}=require("@web/core/utils/numbers");const{browser}=require("@web/core/browser/browser");const BottomSheet=__exports.BottomSheet=class BottomSheet extends Component{static template="web.BottomSheet";static defaultProps={class:"",};static props={component:{type:Function},componentProps:{optional:true,type:Object},close:{type:Function},class:{optional:true},role:{optional:true,type:String},ref:{optional:true,type:Function},slots:{optional:true,type:Object},};setup(){this.maxHeightPercent=90;this.state=useState({isPositionedReady:false,isSnappingEnabled:false,isDismissing:false,progress:0,});this.measurements={viewportHeight:0,naturalHeight:0,maxHeight:0,dismissThreshold:0,};useForwardRefToParent("ref");this.containerRef=useRef("container");this.scrollRailRef=useRef("scrollRail");this.sheetRef=useRef("sheet");this.sheetBodyRef=useRef("ref");this.throttledOnScroll=useThrottleForAnimation(this.onScroll.bind(this));useViewportChange(()=>{if(this.state.isPositionedReady&&!this.state.isDismissing){this.updateDimensions();}});useHotkey("escape",()=>this.slideOut());window.history.pushState({bottomSheet:true},"");this.handlePopState=()=>{if(this.state.isPositionedReady&&!this.state.isDismissing){window.history.pushState({bottomSheet:true},"");this.slideOut();}};useExternalListener(window,"popstate",this.handlePopState);onMounted(()=>{const isReduced=browser.matchMedia(`(prefers-reduced-motion: reduce)`)===true||browser.matchMedia(`(prefers-reduced-motion: reduce)`).matches===true;this.prefersReducedMotion=isReduced||getComputedStyle(this.containerRef.el).animationName==="none";this.initializeSheet();compensateScrollbar(this.scrollRailRef.el,true,true,"padding-right");});} 1659initializeSheet(){if(!this.containerRef.el||!this.scrollRailRef.el||!this.sheetRef.el){return;} 1660this.measureDimensions();this.applyDimensions();this.positionSheet();this.setupEventHandlers();this.state.isPositionedReady=true;if(this.prefersReducedMotion){this.state.isSnappingEnabled=true;}else{this.sheetRef.el?.addEventListener("animationend",()=>(this.state.isSnappingEnabled=true),{once:true,});this.sheetRef.el?.addEventListener("animationcancel",()=>(this.state.isSnappingEnabled=true),{once:true,});}} 1661updateDimensions(){this.state.isSnappingEnabled=false;this.measureDimensions();this.applyDimensions();const scrollTop=this.scrollRailRef.el.scrollTop;this.updateProgressValue(scrollTop);} 1662measureDimensions(){const viewportHeight=getViewportDimensions().height;const maxHeightPx=(this.maxHeightPercent/100)*viewportHeight;const sheet=this.sheetRef.el;sheet.style.removeProperty("min-height");sheet.style.removeProperty("height");const naturalHeight=sheet.offsetHeight;const initialHeightPx=Math.min(naturalHeight,maxHeightPx);this.measurements={viewportHeight,naturalHeight,initialHeight:initialHeightPx,maxHeight:maxHeightPx,dismissThreshold:Math.min(initialHeightPx*0.3,100),};} 1663applyDimensions(){const rail=this.scrollRailRef.el;const heightPercent=Math.min((this.measurements.initialHeight/this.measurements.viewportHeight)*100,this.maxHeightPercent);rail.style.setProperty("--sheet-height",`${heightPercent}dvh`);rail.style.setProperty("--sheet-max-height",`${this.measurements.viewportHeight}px`);rail.style.setProperty("--dismiss-height",`${this.measurements.initialHeight || 0}px`);} 1664positionSheet(){const scrollRail=this.scrollRailRef.el;const bodyContent=this.sheetBodyRef.el;const scrollValue=this.measurements.maxHeight;if(bodyContent){bodyContent.style.overflowY="auto";} 1665scrollRail.scrollTop=scrollValue||0;scrollRail.style.containerType="scroll-state size";} 1666setupEventHandlers(){const scrollRail=this.scrollRailRef.el;scrollRail.addEventListener("scroll",this.throttledOnScroll);} 1667onScroll(){if(!this.scrollRailRef.el){return;} 1668const scrollTop=this.scrollRailRef.el.scrollTop;this.updateProgressValue(scrollTop);if(scrollTop<this.measurements.dismissThreshold){this.slideOut();}} 1669updateProgressValue(scrollTop){const initialPosition=this.measurements.naturalHeight;const progress=clamp(scrollTop/initialPosition,0,1);if(Math.abs(this.state.progress-progress)>0.01){this.state.progress=progress;}}
1670slideOut(){if(this.state.isDismissing){return;} 1671if(this.prefersReducedMotion){this.props.close?.();}else{this.sheetRef.el?.addEventListener("animationend",()=>this.props.close?.(),{once:true,});this.sheetRef.el?.addEventListener("animationcancel",()=>this.props.close?.(),{once:true,});} 1672this.state.isDismissing=true;this.state.isSnappingEnabled=false;} 1673close(){this.slideOut();} 1674back(){if(this.props.onBack){this.props.onBack();}else{this.slideOut();}}} 1675return __exports;});; 1676 1677/* /web/static/src/core/bottom_sheet/bottom_sheet_service.js */ 1678odoo.define('@web/core/bottom_sheet/bottom_sheet_service',['@odoo/owl','@web/core/bottom_sheet/bottom_sheet','@web/core/registry'],function(require){'use strict';let __exports={};const{markRaw}=require("@odoo/owl");const{BottomSheet}=require("@web/core/bottom_sheet/bottom_sheet");const{registry}=require("@web/core/registry");const popoverService=__exports.popoverService={dependencies:["overlay"],start(_,{overlay}){let bottomSheetCount=0;const add=(target,component,props={},options={})=>{function removeAndUpdateCount(){_remove();bottomSheetCount--;if(bottomSheetCount===0){document.body.classList.remove("bottom-sheet-open");}else if(bottomSheetCount===1){document.body.classList.remove("bottom-sheet-open-multiple");}} 1679const _remove=overlay.add(BottomSheet,{close:removeAndUpdateCount,component,componentProps:markRaw(props),ref:options.ref,class:options.class,role:options.role,},{env:options.env,onRemove:options.onClose,rootId:target.getRootNode()?.host?.id,});bottomSheetCount++;if(bottomSheetCount===1){document.body.classList.add("bottom-sheet-open");}else if(bottomSheetCount>1){document.body.classList.add("bottom-sheet-open-multiple");} 1680return removeAndUpdateCount;};return{add};},};registry.category("services").add("bottom_sheet",popoverService);return __exports;});; 1681 1682/* /web/static/src/core/browser/browser.js */ 1683odoo.define('@web/core/browser/browser',[],function(require){'use strict';let __exports={};let sessionStorage;let localStorage;try{sessionStorage=window.sessionStorage;localStorage=window.localStorage;localStorage.setItem("__localStorage__","true");localStorage.removeItem("__localStorage__");}catch{localStorage=makeRAMLocalStorage();sessionStorage=makeRAMLocalStorage();} 1684const browser=__exports.browser={addEventListener:window.addEventListener.bind(window),dispatchEvent:window.dispatchEvent.bind(window),AnalyserNode:window.AnalyserNode,Audio:window.Audio,AudioBufferSourceNode:window.AudioBufferSourceNode,AudioContext:window.AudioContext,AudioWorkletNode:window.AudioWorkletNode,BeforeInstallPromptEvent:window.BeforeInstallPromptEvent?.bind(window),GainNode:window.GainNode,MediaStreamAudioSourceNode:window.MediaStreamAudioSourceNode,removeEventListener:window.removeEventListener.bind(window),setTimeout:window.setTimeout.bind(window),clearTimeout:window.clearTimeout.bind(window),setInterval:window.setInterval.bind(window),clearInterval:window.clearInterval.bind(window),performance:window.performance,requestAnimationFrame:window.requestAnimationFrame.bind(window),cancelAnimationFrame:window.cancelAnimationFrame.bind(window),console:window.console,history:window.history,matchMedia:window.matchMedia.bind(window),navigator,Notification:window.Notification,open:window.open.bind(window),SharedWorker:window.SharedWorker,Worker:window.Worker,XMLHttpRequest:window.XMLHttpRequest,localStorage,sessionStorage,fetch:window.fetch.bind(window),innerHeight:window.innerHeight,innerWidth:window.innerWidth,ontouchstart:window.ontouchstart,BroadcastChannel:window.BroadcastChannel,visualViewport:window.visualViewport,};Object.defineProperty(browser,"location",{set(val){window.location=val;},get(){return window.location;},configurable:true,});Object.defineProperty(browser,"innerHeight",{get:()=>window.innerHeight,configurable:true,});Object.defineProperty(browser,"innerWidth",{get:()=>window.innerWidth,configurable:true,});__exports.makeRAMLocalStorage=makeRAMLocalStorage;function makeRAMLocalStorage(){let store={};return{setItem(key,value){const newValue=String(value);store[key]=newValue;window.dispatchEvent(new StorageEvent("storage",{key,newValue}));},getItem(key){return store[key]??null;},clear(){store={};},removeItem(key){delete store[key];window.dispatchEvent(new StorageEvent("storage",{key,newValue:null}));},get length(){return Object.keys(store).length;},key(){return"";},};} 1685return __exports;});; 1686 1687/* /web/static/src/core/browser/cookie.js */ 1688odoo.define('@web/core/browser/cookie',[],function(require){'use strict';let __exports={};const COOKIE_TTL=24*60*60*365;const cookie=__exports.cookie={get _cookieMonster(){return document.cookie;},set _cookieMonster(value){document.cookie=value;},get(str){const parts=this._cookieMonster.split("; ");for(const part of parts){const[key,value]=part.split(/=(.*)/);if(key===str){return value||"";}}},set(key,value,ttl=COOKIE_TTL){let fullCookie=[];if(value!==undefined){fullCookie.push(`${key}=${value}`);} 1689fullCookie=fullCookie.concat(["path=/",`max-age=${Math.floor(ttl)}`]);this._cookieMonster=fullCookie.join("; ");},delete(key){this.set(key,"kill",0);},};return __exports;});; 1690 1691/* /web/static/src/core/browser/feature_detection.js */ 1692odoo.define('@web/core/browser/feature_detection',['@web/core/browser/browser'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");__exports.isBrowserChrome=isBrowserChrome;function isBrowserChrome(){return/Chrome/i.test(browser.navigator.userAgent);} 1693__exports.isBrowserFirefox=isBrowserFirefox;function isBrowserFirefox(){return/Firefox/i.test(browser.navigator.userAgent);} 1694__exports.isBrowserMicrosoftEdge=isBrowserMicrosoftEdge;function isBrowserMicrosoftEdge(){return/Edg/i.test(browser.navigator.userAgent);} 1695__exports.isBrowserSafari=isBrowserSafari;function isBrowserSafari(){return!isBrowserChrome()&&browser.navigator.userAgent?.includes("Safari");} 1696__exports.isAndroid=isAndroid;function isAndroid(){return/Android/i.test(browser.navigator.userAgent);} 1697__exports.isIOS=isIOS;function isIOS(){let isIOSPlatform=false;if("platform"in browser.navigator){isIOSPlatform=browser.navigator.platform==="MacIntel";} 1698return(/(iPad|iPhone|iPod)/i.test(browser.navigator.userAgent)||(isIOSPlatform&&maxTouchPoints()>1));} 1699__exports.isOtherMobileOS=isOtherMobileOS;
1699function isOtherMobileOS(){return/(webOS|BlackBerry|Windows Phone)/i.test(browser.navigator.userAgent);} 1700__exports.isMacOS=isMacOS;function isMacOS(){return/Mac/i.test(browser.navigator.userAgent);} 1701__exports.isMobileOS=isMobileOS;function isMobileOS(){return isAndroid()||isIOS()||isOtherMobileOS();} 1702__exports.isIosApp=isIosApp;function isIosApp(){return/OdooMobile \(iOS\)/i.test(browser.navigator.userAgent);} 1703__exports.isAndroidApp=isAndroidApp;function isAndroidApp(){return/OdooMobile.+Android/i.test(browser.navigator.userAgent);} 1704__exports.isDisplayStandalone=isDisplayStandalone;function isDisplayStandalone(){return browser.matchMedia("(display-mode: standalone)").matches;} 1705__exports.hasTouch=hasTouch;function hasTouch(){return browser.ontouchstart!==undefined||browser.matchMedia("(pointer:coarse)").matches;} 1706__exports.maxTouchPoints=maxTouchPoints;function maxTouchPoints(){return browser.navigator.maxTouchPoints||1;} 1707__exports.isVirtualKeyboardSupported=isVirtualKeyboardSupported;function isVirtualKeyboardSupported(){return"virtualKeyboard"in browser.navigator;} 1708return __exports;});; 1709 1710/* /web/static/src/core/browser/router.js */ 1711odoo.define('@web/core/browser/router',['@odoo/owl','@web/core/utils/objects','@web/core/utils/urls','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/utils/arrays','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{EventBus}=require("@odoo/owl");const{omit,pick}=require("@web/core/utils/objects");const{compareUrls,objectToUrlEncodedString}=require("@web/core/utils/urls");const{browser}=require("@web/core/browser/browser");const{isDisplayStandalone}=require("@web/core/browser/feature_detection");const{slidingWindow}=require("@web/core/utils/arrays");const{isNumeric}=require("@web/core/utils/strings");const PATH_KEYS=__exports.PATH_KEYS=["resId","action","active_id","model"];const routerBus=__exports.routerBus=new EventBus();function isScopedApp(){return browser.location.href.includes("/scoped_app")&&isDisplayStandalone();} 1712function cast(value){return!value||isNaN(value)?value:Number(value);} 1713function parseString(str){const parts=str.split("&");const result={};for(const part of parts){const[key,value]=part.split("=");const decoded=decodeURIComponent(value||"");result[key]=cast(decoded);} 1714return result;} 1715function computeNextState(values,replace){const nextState=replace?pick(state,..._lockedKeys):{...state};Object.assign(nextState,values);if(nextState.actionStack?.length){Object.assign(nextState.actionStack.at(-1),pick(nextState,...PATH_KEYS));} 1716return sanitizeSearch(nextState);} 1717function sanitize(obj,valueToRemove){return Object.fromEntries(Object.entries(obj).filter(([,v])=>v!==valueToRemove).map(([k,v])=>[k,cast(v)]));} 1718function sanitizeSearch(search){return sanitize(search);} 1719function sanitizeHash(hash){return sanitize(hash,"");} 1720__exports.parseHash=parseHash;function parseHash(hash){return hash&&hash!=="#"?parseString(hash.slice(1)):{};} 1721__exports.parseSearchQuery=parseSearchQuery;function parseSearchQuery(search){return search?parseString(search.slice(1)):{};} 1722function pathFromActionState(state){const path=[];const{action,model,active_id,resId}=state;if(active_id&&typeof active_id==="number"){path.push(active_id);} 1723if(action){if(typeof action==="number"||action.includes(".")){path.push(`action-${action}`);}else{path.push(action);}}else if(model){if(model.includes(".")){path.push(model);}else{path.push(`m-${model}`);}} 1724if(resId&&(typeof resId==="number"||resId==="new")){path.push(resId);} 1725return path.join("/");} 1726__exports.startUrl=startUrl;function startUrl(){return isScopedApp()?"scoped_app":"odoo";} 1727function stateToUrl(state){let path="";const pathKeysToOmit=[..._hiddenKeysFromUrl];const actionStack=(state.actionStack||[state]).map((a)=>({...a}));if(actionStack.at(-1)?.action!=="menu"){for(const[prevAct,currentAct]of slidingWindow(actionStack,2).reverse()){const{action:prevAction,resId:prevResId,active_id:prevActiveId}=prevAct;const{action:currentAction,active_id:currentActiveId}=currentAct;if(currentActiveId===prevResId){delete currentAct.active_id;} 1728if(prevAction===currentAction&&!prevResId&¤tActiveId===prevActiveId){delete currentAct.action;delete currentAct.active_id;}}
1729const pathSegments=actionStack.map(pathFromActionState).filter(Boolean);if(pathSegments.length){path=`/${pathSegments.join("/")}`;}} 1730if(state.active_id&&typeof state.active_id!=="number"){pathKeysToOmit.splice(pathKeysToOmit.indexOf("active_id"),1);} 1731if(state.resId&&typeof state.resId!=="number"&&state.resId!=="new"){pathKeysToOmit.splice(pathKeysToOmit.indexOf("resId"),1);} 1732const search=objectToUrlEncodedString(omit(state,...pathKeysToOmit));const start_url=startUrl();return`/${start_url}${path}${search ? `?${search}` : ""}`;} 1733function urlToState(urlObj){const{pathname,hash,search}=urlObj;const state=parseSearchQuery(search);if(pathname==="/web"){const sanitizedHash=sanitizeHash(parseHash(hash));if(sanitizedHash.id){sanitizedHash.resId=sanitizedHash.id;delete sanitizedHash.id;delete sanitizedHash.view_type;}else if(sanitizedHash.view_type==="form"){sanitizedHash.resId="new";delete sanitizedHash.view_type;} 1734Object.assign(state,sanitizedHash);const url=browser.location.origin+router.stateToUrl(state);urlObj.href=url;} 1735const[prefix,...splitPath]=urlObj.pathname.split("/").filter(Boolean);if(["odoo","scoped_app"].includes(prefix)){const actionParts=[...splitPath.entries()].filter(([_,part])=>!isNumeric(part)&&part!=="new");const actions=[];for(const[i,part]of actionParts){const action={};const[left,right]=[splitPath[i-1],splitPath[i+1]];if(isNumeric(left)){action.active_id=parseInt(left);} 1736if(right==="new"){action.resId="new";}else if(isNumeric(right)){action.resId=parseInt(right);} 1737if(part.startsWith("action-")){const actionId=part.slice(7);action.action=isNumeric(actionId)?parseInt(actionId):actionId;}else if(part.startsWith("m-")){action.model=part.slice(2);}else if(part.includes(".")){action.model=part;}else{action.action=part;} 1738if(action.resId&&action.action){actions.push(omit(action,"resId"));} 1739if(action.action||action.resId||i===splitPath.length-1){actions.push(action);}} 1740const activeAction=actions.at(-1);if(activeAction){Object.assign(state,activeAction);state.actionStack=actions;} 1741if(prefix==="scoped_app"&&!isDisplayStandalone()){const url=browser.location.origin+router.stateToUrl(state);urlObj.href=url;}} 1742return state;} 1743let state;let pushTimeout;let pushArgs;let _lockedKeys;let _hiddenKeysFromUrl=new Set();__exports.startRouter=startRouter;function startRouter(){const url=new URL(browser.location);state=router.urlToState(url);if(browser.location.pathname==="/web"){browser.history.replaceState(browser.history.state,null,url.href);} 1744pushTimeout=null;pushArgs={replace:false,reload:false,state:{},};_lockedKeys=new Set(["debug","lang"]);_hiddenKeysFromUrl=new Set([...PATH_KEYS,"actionStack"]);} 1745browser.addEventListener("popstate",(ev)=>{browser.clearTimeout(pushTimeout);if(!ev.state){browser.history.replaceState({nextState:state},"",browser.location.href);return;} 1746state=ev.state?.nextState||router.urlToState(new URL(browser.location));if(!ev.state?.skipRouteChange&&!router.skipLoad){routerBus.trigger("ROUTE_CHANGE");} 1747router.skipLoad=false;});browser.addEventListener("pageshow",(ev)=>{if(ev.persisted){browser.clearTimeout(pushTimeout);routerBus.trigger("ROUTE_CHANGE");}});browser.addEventListener("click",(ev)=>{if(ev.defaultPrevented||ev.target.closest("[contenteditable]")){return;} 1748const a=ev.target.closest("a");const href=a?.getAttribute("href");if(href&&!href.startsWith("#")){let url;try{url=new URL(a.href);}catch{return;} 1749if(browser.location.host===url.host&&browser.location.pathname.startsWith("/odoo")&&(["/web","/odoo"].includes(url.pathname)||url.pathname.startsWith("/odoo/"))&&a.target!=="_blank"){ev.preventDefault();state=router.urlToState(url);if(url.pathname.startsWith("/odoo")&&url.hash){browser.history.pushState({},"",url.href);} 1750new Promise((res)=>setTimeout(res,0)).then(()=>routerBus.trigger("ROUTE_CHANGE"));}}});function makeDebouncedPush(mode){function doPush(){const nextState=computeNextState(pushArgs.state,pushArgs.replace);const url=browser.location.origin+router.stateToUrl(nextState);if(!compareUrls(url+browser.location.hash,browser.location.href)){if(mode==="push"){const originalTitle=document.title;document.title=pushArgs.title;browser.history.pushState({nextState},"",url);document.title=originalTitle;}else{browser.history.replaceState({nextState},"",url);}}else{browser.history.replaceState({nextState},"",browser.location.href);} 1751state=nextState;if(pushArgs.reload){browser.location.reload();}} 1752return function pushOrReplaceState(state,options={}){pushArgs.replace||=options.replace;pushArgs.reload||=options.reload;pushArgs.title=document.title;Object.assign(pushArgs.state,state);browser.clearTimeout(pushTimeout);const push=()=>{try{doPush();}catch(e){if(e.name==="NS_ERROR_ILLEGAL_VALUE"||e.name==="DataCloneError"){console.error(e);}else{throw e;}}finally{pushTimeout=null;pushArgs={replace:false,reload:false,state:{},};}};if(options.sync){push();}else{pushTimeout=browser.setTimeout(()=>{push();});}};} 1753const router=__exports.router={get current(){return state;},stateToUrl,urlToState,pushState:makeDebouncedPush("push"),replaceState:makeDebouncedPush("replace"),cancelPushes:()=>browser.clearTimeout(pushTimeout),addLockedKey:(key)=>_lockedKeys.add(key),hideKeyFromUrl:(key)=>_hiddenKeysFromUrl.add(key),skipLoad:false,};startRouter();__exports.objectToQuery=objectToQuery;function objectToQuery(obj){const query={};
1753Object.entries(obj).forEach(([k,v])=>{query[k]=v?String(v):v;});return query;} 1754return __exports;});; 1755 1756/* /web/static/src/core/checkbox/checkbox.js */ 1757odoo.define('@web/core/checkbox/checkbox',['@web/core/hotkeys/hotkey_hook','@odoo/owl'],function(require){'use strict';let __exports={};const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{Component,useRef}=require("@odoo/owl");const CheckBox=__exports.CheckBox=class CheckBox extends Component{static template="web.CheckBox";static nextId=1;static defaultProps={onChange:()=>{},};static props={id:{type:true,optional:true,},disabled:{type:Boolean,optional:true,},value:{type:Boolean,optional:true,},slots:{type:Object,optional:true,},onChange:{type:Function,optional:true,},className:{type:String,optional:true,},name:{type:String,optional:true,},indeterminate:{type:Boolean,optional:true,},};setup(){this.id=`checkbox-comp-${CheckBox.nextId++}`;this.rootRef=useRef("root");useHotkey("Enter",({area})=>{const oldValue=area.querySelector("input").checked;this.props.onChange(!oldValue);},{area:()=>this.rootRef.el,bypassEditableProtection:true});} 1758onClick(ev){if(ev.composedPath().find((el)=>["INPUT","LABEL"].includes(el.tagName))){ev.stopPropagation();return;} 1759const input=this.rootRef.el.querySelector("input");input.focus();if(!this.props.disabled){ev.stopPropagation();input.checked=!input.checked;this.props.onChange(input.checked);}} 1760onChange(ev){if(!this.props.disabled){this.props.onChange(ev.target.checked);}}} 1761return __exports;});; 1762 1763/* /web/static/src/core/code_editor/code_editor.js */ 1764odoo.define('@web/core/code_editor/code_editor',['@odoo/owl','@web/core/assets'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillStart,useEffect,useRef,useState,status}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const CodeEditor=__exports.CodeEditor=class CodeEditor extends Component{static template="web.CodeEditor";static components={};static props={mode:{type:String,optional:true,validate:(mode)=>CodeEditor.MODES.includes(mode),},value:{validate:(v)=>typeof v==="string",optional:true},readonly:{type:Boolean,optional:true},onChange:{type:Function,optional:true},onBlur:{type:Function,optional:true},class:{type:String,optional:true},theme:{type:String,optional:true,validate:(theme)=>CodeEditor.THEMES.includes(theme),},maxLines:{type:Number,optional:true},sessionId:{type:[Number,String],optional:true},initialCursorPosition:{type:Object,optional:true},showLineNumbers:{type:Boolean,optional:true},};static defaultProps={readonly:false,value:"",onChange:()=>{},class:"",theme:"",sessionId:1,showLineNumbers:true,};static MODES=["javascript","xml","qweb","scss","python"];static THEMES=["","monokai"];setup(){this.editorRef=useRef("editorRef");this.state=useState({activeMode:undefined,});onWillStart(async()=>await loadBundle("web.ace_lib"));const sessions={};let ignoredAceChange=false;useEffect((el)=>{if(!el){return;} 1765const aceEditor=window.ace.edit(el);this.aceEditor=aceEditor;this.aceEditor.setOptions({maxLines:this.props.maxLines,showPrintMargin:false,useWorker:false,});this.aceEditor.$blockScrolling=true;this.aceEditor.on("changeMode",()=>{this.state.activeMode=this.aceEditor.getSession().$modeId.split("/").at(-1);});const session=aceEditor.getSession();if(!sessions[this.props.sessionId]){sessions[this.props.sessionId]=session;} 1766session.setValue(this.props.value);session.on("change",()=>{if(this.props.onChange&&!ignoredAceChange){this.props.onChange(this.aceEditor.getValue(),this.aceEditor.getCursorPosition());}});this.aceEditor.on("blur",()=>{if(this.props.onBlur){this.props.onBlur();}});return()=>{aceEditor.destroy();};},()=>[this.editorRef.el]);useEffect((theme)=>this.aceEditor.setTheme(theme?`ace/theme/${theme}`:""),()=>[this.props.theme]);useEffect((readonly,showLineNumbers)=>{this.aceEditor.setOptions({readOnly:readonly,highlightActiveLine:!readonly,highlightGutterLine:!readonly,});this.aceEditor.renderer.setOptions({displayIndentGuides:!readonly,showGutter:!readonly&&showLineNumbers,});this.aceEditor.renderer.$cursorLayer.element.style.display=readonly?"none":"block";},()=>[this.props.readonly,this.props.showLineNumbers]);useEffect((sessionId,mode,value)=>{let session=sessions[sessionId];if(session){if(session.getValue()!==value){ignoredAceChange=true;session.setValue(value);ignoredAceChange=false;}}else{session=new window.ace.EditSession(value);session.setUndoManager(new window.ace.UndoManager());session.setOptions({useWorker:false,tabSize:2,useSoftTabs:true,});session.on("change",()=>{if(this.props.onChange&&!ignoredAceChange){this.props.onChange(this.aceEditor.getValue(),this.aceEditor.getCursorPosition());}});sessions[sessionId]=session;} 1767session.setMode(mode?`ace/mode/${mode}`:"");this.aceEditor.setSession(session);},()=>[this.props.sessionId,this.props.mode,this.props.value]);const initialCursorPosition=this.props.initialCursorPosition;if(initialCursorPosition){onMounted(()=>{window.requestAnimationFrame(()=>{if(status(this)!="destroyed"&&this.aceEditor){this.aceEditor.focus();const{row,column}=initialCursorPosition;const pos={row:row||0,column:column||0,};this.aceEditor.selection.moveToPosition(pos);this.aceEditor.renderer.scrollCursorIntoView(pos,0.5);}});});}}} 1768return __exports;});; 1769 1770/* /web/static/src/core/color_picker/color_picker.js */ 1771odoo.define('@web/core/color_picker/color_picker',['@odoo/owl','@web/core/color_picker/custom_color_picker/custom_color_picker','@web/core/popover/popover_hook','@web/core/utils/colors','@web/core/browser/cookie','@web/core/position/position_hook','@web/core/registry'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef,useState}=require("@odoo/owl");const{CustomColorPicker}=require("@web/core/color_picker/custom_color_picker/custom_color_picker");const{usePopover}=require("@web/core/popover/popover_hook");const{isCSSColor,isColorGradient,normalizeCSSColor}=require("@web/core/utils/colors");const{cookie}=require("@web/core/browser/cookie");const{POSITION_BUS}=require("@web/core/position/position_hook");const{registry}=require("@web/core/registry");const DEFAULT_COLORS=__exports.DEFAULT_COLORS=[["#000000","#424242","#636363","#9C9C94","#CEC6CE","#EFEFEF","#F7F7F7","#FFFFFF"],["#FF0000","#FF9C00","#FFFF00","#00FF00","#00FFFF","#0000FF","#9C00FF","#FF00FF"],["#F7C6CE","#FFE7CE","#FFEFC6","#D6EFD6","#CEDEE7","#CEE7F7","#D6D6E7","#E7D6DE"],["#E79C9C","#FFC69C","#FFE79C","#B5D6A5","#A5C6CE","#9CC6EF","#B5A5D6","#D6A5BD"],["#E76363","#F7AD6B","#FFD663","#94BD7B","#73A5AD","#6BADDE","#8C7BC6","#C67BA5"],["#CE0000","#E79439","#EFC631","#6BA54A","#4A7B8C","#3984C6","#634AA5","#A54A7B"],["#9C0000","#B56308","#BD9400","#397B21","#104A5A","#085294","#311873","#731842"],["#630000","#7B3900","#846300","#295218","#083139","#003163","#21104A","#4A1031"],];const DEFAULT_GRAYSCALES=__exports.DEFAULT_GRAYSCALES={solid:["black","900","800","600","400","200","100","white"],};const DEFAULT_THEME_COLOR_VARS=__exports.DEFAULT_THEME_COLOR_VARS=["o-color-1","o-color-2","o-color-3","o-color-4","o-color-5",];const ColorPicker=__exports.ColorPicker=class ColorPicker extends Component{static template="web.ColorPicker";static components={CustomColorPicker};static props={state:{type:Object,shape:{selectedColor:String,selectedColorCombination:{type:String,optional:true},getTargetedElements:{type:Function,optional:true},defaultTab:String,selectedTab:{type:String,optional:true},mode:{type:String,optional:true},},},getUsedCustomColors:Function,applyColor:Function,applyColorPreview:Function,applyColorResetPreview:Function,editColorCombination:{type:Function,optional:true},setOnCloseCallback:{type:Function,optional:true},setOperationCallbacks:{type:Function,optional:true},enabledTabs:{type:Array,optional:true},colorPrefix:{type:String},cssVarColorPrefix:{type:String,optional:true},defaultOpacity:{type:Number,optional:true},grayscales:{type:Object,optional:true},noTransparency:{type:Boolean,optional:true},close:{type:Function,optional:true},className:{type:String,optional:true},useDefaultThemeColors:{type:Boolean,optional:true},};static defaultProps={close:()=>{},defaultOpacity:100,enabledTabs:["solid","custom"],cssVarColorPrefix:"",setOnCloseCallback:()=>{},useDefaultThemeColors:true,};setup(){this.tabs=registry.category("color_picker_tabs").getAll().filter((tab)=>this.props.enabledTabs.includes(tab.id));this.root=useRef("root");this.DEFAULT_COLORS=DEFAULT_COLORS;this.grayscales=Object.assign({},DEFAULT_GRAYSCALES,this.props.grayscales);this.DEFAULT_THEME_COLOR_VARS=this.props.useDefaultThemeColors?DEFAULT_THEME_COLOR_VARS:[];this.defaultColorSet=this.getDefaultColorSet();this.defaultColor=this.props.state.selectedColor;this.focusedBtn=null;this.onApplyCallback=()=>{};this.onPreviewRevertCallback=()=>{};this.getPreviewColor=()=>{};this.state=useState({activeTab:this.props.state.selectedTab||this.getDefaultTab(),currentCustomColor:this.props.state.selectedColor,currentColorPreview:undefined,showGradientPicker:false,});this.usedCustomColors=this.props.getUsedCustomColors();useEffect(()=>{this.env[POSITION_BUS]?.trigger("update");},()=>[this.state.activeTab]);} 1772getDefaultTab(){if(this.props.enabledTabs.includes(this.props.state.defaultTab)){return this.props.state.defaultTab;} 1773return this.props.enabledTabs[0];} 1774get selectedColor(){return this.props.state.selectedColor;}
1775get isDarkTheme(){return cookie.get("color_scheme")==="dark";} 1776setTab(tab){this.state.activeTab=tab;this.setOperationCallbacks({onPreviewRevertCallback:()=>{}});this.applyColorResetPreview();} 1777processColorFromEvent(ev){const target=this.getTarget(ev);let color=target.dataset.color||"";if(color&&isColorCombination(color)){return color;} 1778if(color&&!isCSSColor(color)&&!isColorGradient(color)){color=this.props.colorPrefix+color;} 1779return color;} 1780setOperationCallbacks(cbs){if(this.props.setOperationCallbacks){this.props.setOperationCallbacks(cbs);} 1781if(cbs.onApplyCallback){this.onApplyCallback=cbs.onApplyCallback;} 1782if(cbs.onPreviewRevertCallback){this.onPreviewRevertCallback=cbs.onPreviewRevertCallback;} 1783if(cbs.getPreviewColor){this.getPreviewColor=cbs.getPreviewColor;}} 1784applyColor(color){this.state.currentCustomColor=color;this.props.applyColor(color);this.defaultColorSet=this.getDefaultColorSet();this.onApplyCallback();} 1785onColorApply(ev){if(!this.isColorButton(this.getTarget(ev))){return;} 1786const color=this.processColorFromEvent(ev);this.applyColor(color);this.props.close();} 1787applyColorResetPreview(){this.props.applyColorResetPreview();this.state.currentColorPreview=undefined;this.onPreviewRevertCallback();} 1788onColorPreview(ev){const color=ev.hex||ev.gradient||this.processColorFromEvent(ev);this.props.applyColorPreview(color);this.state.currentColorPreview=this.getPreviewColor();} 1789onColorHover(ev){if(!this.isColorButton(this.getTarget(ev))){return;} 1790this.onColorPreview(ev);} 1791onColorHoverOut(ev){if(!this.isColorButton(this.getTarget(ev))){return;} 1792this.applyColorResetPreview();} 1793getTarget(ev){const target=ev.target.closest(`[data-color]`);return this.root.el.contains(target)?target:ev.target;} 1794onColorFocusin(ev){if(this.focusedBtn===ev.target){this.focusedBtn=null;return;} 1795this.focusedBtn=ev.target;this.onColorHover(ev);if(document.activeElement!==ev.target){ev.target.focus();}} 1796onColorFocusout(ev){if(!ev.relatedTarget||!this.isColorButton(ev.relatedTarget)){return;} 1797const activeEl=document.activeElement;this.applyColorResetPreview();if(document.activeElement!==activeEl){ev.relatedTarget.focus();}} 1798getDefaultColorSet(){if(!this.props.state.selectedColor){return;} 1799let defaultColors=this.props.enabledTabs.includes("solid")?this.DEFAULT_THEME_COLOR_VARS:[];for(const grayscale of Object.values(this.grayscales)){defaultColors=defaultColors.concat(grayscale);} 1800const targetedElement=this.props.state.getTargetedElements?.()[0]||document.documentElement;const selectedColor=this.props.state.selectedColor.toUpperCase();const htmlStyle=targetedElement.ownerDocument.defaultView.getComputedStyle(targetedElement);for(const color of defaultColors){const cssVar=normalizeCSSColor(htmlStyle.getPropertyValue(`--${color}`));if(cssVar?.toUpperCase()===selectedColor){return color;}} 1801return false;} 1802colorPickerNavigation(ev){const{target,key}=ev;if(!target.classList.contains("o_color_button")){return;} 1803if(!["ArrowRight","ArrowLeft","ArrowUp","ArrowDown"].includes(key)){return;} 1804let targetBtn;if(key==="ArrowRight"){targetBtn=target.nextElementSibling;}else if(key==="ArrowLeft"){targetBtn=target.previousElementSibling;}else if(key==="ArrowUp"||key==="ArrowDown"){const buttonIndex=[...target.parentElement.children].indexOf(target);const nbColumns=getComputedStyle(target).getPropertyValue("--o-color-picker-grid-columns");targetBtn=target.parentElement.children[buttonIndex+(key==="ArrowUp"?-1:1)*nbColumns];if(!targetBtn){const row=key==="ArrowUp"?target.parentElement.previousElementSibling:target.parentElement.nextElementSibling;if(row?.matches(".o_color_section, .o_colorpicker_section")){targetBtn=row.children[buttonIndex];}}} 1805if(targetBtn&&targetBtn.classList.contains("o_color_button")){targetBtn.focus();}} 1806isColorButton(targetEl){return targetEl.tagName==="BUTTON"&&!targetEl.matches(".o_colorpicker_ignore");}} 1807__exports.useColorPicker=useColorPicker;function useColorPicker(refName,props,options={}){let onCloseCallback=()=>{};const setOnCloseCallback=(cb)=>{onCloseCallback=cb;};props.setOnCloseCallback=setOnCloseCallback;if(options.onClose){const onClose=options.onClose;options.onClose=()=>{onCloseCallback();onClose();};} 1808const colorPicker=usePopover(ColorPicker,options);const root=useRef(refName);function onClick(){if(colorPicker.isOpen){colorPicker.close();}else{colorPicker.open(root.el,props);options.onOpen?.();}} 1809useEffect((el)=>{if(!el){return;} 1810el.addEventListener("click",onClick);return()=>{el.removeEventListener("click",onClick);};},()=>[root.el]);return colorPicker;} 1811function isColorCombination(color){return color.startsWith("o_cc");} 1812return __exports;});; 1813 1814/* /web/static/src/core/color_picker/custom_color_picker/custom_color_picker.js */ 1815odoo.define('@web/core/color_picker/custom_color_picker/custom_color_picker',['@web/core/h
1815otkeys/hotkey_service','@web/core/l10n/translation','@web/core/utils/colors','@web/core/utils/functions','@web/core/utils/numbers','@web/core/utils/timing','@odoo/owl'],function(require){'use strict';let __exports={};const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{convertCSSColorToRgba,convertHslToRgb,convertRgbaToCSSColor,convertRgbToHsl,normalizeCSSColor,}=require("@web/core/utils/colors");const{uniqueId}=require("@web/core/utils/functions");const{clamp}=require("@web/core/utils/numbers");const{debounce,useThrottleForAnimation}=require("@web/core/utils/timing");const{Component,onMounted,onWillUpdateProps,useExternalListener,useRef}=require("@odoo/owl");const ARROW_KEYS=["arrowup","arrowdown","arrowleft","arrowright"];const SLIDER_KEYS=[...ARROW_KEYS,"pageup","pagedown","home","end"];const DEFAULT_COLOR="#FF0000";const CustomColorPicker=__exports.CustomColorPicker=class CustomColorPicker extends Component{static template="web.CustomColorPicker";static props={document:{type:true,optional:true},defaultColor:{type:String,optional:true},selectedColor:{type:String,optional:true},noTransparency:{type:Boolean,optional:true},stopClickPropagation:{type:Boolean,optional:true},onColorSelect:{type:Function,optional:true},onColorPreview:{type:Function,optional:true},onInputEnter:{type:Function,optional:true},defaultOpacity:{type:Number,optional:true},setOnCloseCallback:{type:Function,optional:true},setOperationCallbacks:{type:Function,optional:true},};static defaultProps={document:window.document,defaultColor:DEFAULT_COLOR,defaultOpacity:100,noTransparency:false,stopClickPropagation:false,onColorSelect:()=>{},onColorPreview:()=>{},onInputEnter:()=>{},};setup(){this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;if(this.props.defaultOpacity>0&&this.props.defaultOpacity<=1){this.props.defaultOpacity*=100;} 1816if(this.props.defaultColor.length<=7){const opacityHex=Math.round((this.props.defaultOpacity/100)*255).toString(16).padStart(2,"0");this.props.defaultColor+=opacityHex;} 1817this.colorComponents={};this.uniqueId=uniqueId("colorpicker");this.selectedHexValue="";this.shouldSetSelectedColor=false;this.lastFocusedSliderEl=undefined;if(!this.props.selectedColor){this.props.selectedColor=this.props.defaultColor;} 1818this.debouncedOnChangeInputs=debounce(this.onChangeInputs.bind(this),10,true);this.elRef=useRef("el");this.colorPickerAreaRef=useRef("colorPickerArea");this.colorPickerPointerRef=useRef("colorPickerPointer");this.colorSliderRef=useRef("colorSlider");this.colorSliderPointerRef=useRef("colorSliderPointer");this.opacitySliderRef=useRef("opacitySlider");this.opacitySliderPointerRef=useRef("opacitySliderPointer");const documents=[window.top,...Array.from(window.top.frames).filter((frame)=>{try{const document=frame.document;return!!document;}catch{return false;}}),].map((w)=>w.document);this.throttleOnPointerMove=useThrottleForAnimation((ev)=>{this.onPointerMovePicker(ev);this.onPointerMoveSlider(ev);this.onPointerMoveOpacitySlider(ev);});for(const doc of documents){useExternalListener(doc,"pointermove",this.throttleOnPointerMove);useExternalListener(doc,"pointerup",this.onPointerUp.bind(this));useExternalListener(doc,"keydown",this.onEscapeKeydown.bind(this),{capture:true});} 1819this.props.setOnCloseCallback?.(()=>{if(this.shouldSetSelectedColor){this._colorSelected();}});this.props.setOperationCallbacks?.({getPreviewColor:()=>{if(this.shouldSetSelectedColor){return this.colorComponents.hex;}},onApplyCallback:()=>{this.shouldSetSelectedColor=false;},onPreviewRevertCallback:()=>{if(this.previewActive&&this.shouldSetSelectedColor){this.props.onColorPreview(this.colorComponents);}},});onMounted(async()=>{const rgba=convertCSSColorToRgba(this.props.selectedColor)||convertCSSColorToRgba(this.props.defaultColor);if(rgba){this._updateRgba(rgba.red,rgba.green,rgba.blue,rgba.opacity);} 1820this.previewActive=true;this._updateUI();});onWillUpdateProps((newProps)=>{const newSelectedColor=newProps.selectedColor?newProps.selectedColor:newProps.defaultColor;if(normalizeCSSColor(newSelectedColor)!==this.colorComponents.cssColor){this.setSelectedColor(newSelectedColor);}});} 1821setSelectedColor(color){const rgba=convertCSSColorToRgba(color);if(rgba){const oldPreviewActive=this.previewActive;this.previewActive=false;this._updateRgba(rgba.red,rgba.green,rgba.blue,rgba.opacity);this.previewActive=oldPreviewActive;this._updateUI();}} 1822getAllowedHotkeys(allowedKeys){return allowedKeys.flatMap((key)=>[key,`control+${key}`]);} 1823setLastFocusedSliderEl(el){this.lastFocusedSliderEl=el;document.activeElement.blur();} 1824get el(){return this.elRef.el;} 1825handleRangeKeydownValue(hotkey,value,{min=0,max=100,defaultStep=10,modifierStep=1,leap=20}={}){let step=defaultStep;if(hotkey.startsWith("control+")){step=modifierStep;} 1826const mainKey=hotkey.replace("control+","");if(mainKey==="pageup"||mainKey==="pagedown"){step=leap;} 1827if(["arrowup","arrowright","pageup"].includes(mainKey)){value+=step;}else if(["arrowdown","arrowleft","pagedown"].includes(mainKey)){value-=step;}else if(mainKey==="home"){value=min;}else if(mainKey==="end"){value=max;} 1828return clamp(value,min,max);} 1829selectColorOnEnter(hotkey){if(hotkey==="enter"&&this.shouldSetSelectedColor){this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;this._colorSelected();}} 1830_updateUI(){for(const[color,value]of Object.entries(this.colorComponents)){const input=this.el.querySelector(`.o_${color}_input`);if(input){input.value=value;}} 1831const colorPickerArea=this.colorPickerAreaRef.el;colorPickerArea.style.backgroundColor=`hsl(${this.colorComponents.hue}, 100%, 50%)`;const top=((100-this.colorComponents.lightness)*colorPickerArea.clientHeight)/100;const left=(this.colorComponents.saturation*colorPickerArea.clientWidth)/100;const colorpickerPointer=this.colorPickerPointerRef.el;colorpickerPointer.style.top=top-5+"px";colorpickerPointer.style.left=left-5+"px";colorpickerPointer.setAttribute("aria-label",_t("Saturation: %(saturationLvl)s %. Brightness: %(brightnessLvl)s %",{saturationLvl:this.colorComponents.saturation?.toFixed(2)||"0",brightnessLvl:this.colorComponents.lightness?.toFixed(2)||"0",}));const colorSlider=this.colorSliderRef.el;const height=colorSlider.clientHeight;const y=(this.colorComponents.hue*height)/360;this.colorSliderPointerRef.el.style.bottom=`${Math.round(y - 4)}px`;this.colorSliderPointerRef.el.setAttribute("aria-valuenow",this.colorComponents.hue.toFixed(2));if(!this.props.noTransparency){const opacitySlider=this.opacitySliderRef.el;const heightOpacity=opacitySlider.clientHeight;const z=heightOpacity*(1-this.colorComponents.opacity/100.0);this.opacitySliderPointerRef.el.style.top=`${Math.round(z - 2)}px`;this.opacitySliderPointerRef.el.setAttribute("aria-valuenow",this.colorComponents.opacity.toFixed(2));const sliderColor=this.colorComponents.hex.slice(0,7);opacitySlider.style.background=`linear-gradient(${sliderColor} 0%, transparent 100%)`;}} 1832_updateHex(hex){const rgb=convertCSSColorToRgba(hex);if(!rgb){return;} 1833Object.assign(this.colorComponents,{hex:hex},rgb,convertRgbToHsl(rgb.red,rgb.green,rgb.blue));this._updateCssColor();} 1834_updateRgba(r,g,b,a){const opacity=a||this.colorComponents.opacity;if(opacity<0.1&&(r>0.1||g>0.1||b>0.1)){a=this.props.defaultOpacity;} 1835const hex=convertRgbaToCSSColor(r,g,b,a);if(!hex){return;} 1836Object.assign(this.colorComponents,{red:r,green:g,blue:b},a===undefined?{}:{opacity:a},{hex:hex},convertRgbToHsl(r,g,b));this._updateCssColor();} 1837_updateHsl(h,s,l){if(0.1<Math.abs(h-this.colorComponents.hue)){if(l<0.1||99.9<l){l=50;} 1838if(s<0.1){s=100;}} 1839let a=this.colorComponents.opacity;if(a<0.1&&l>0.1){a=this.props.defaultOpacity;} 1840const rgb=convertHslToRgb(h,s,l);if(!rgb){return;} 1841const hex=convertRgbaToCSSColor(rgb.red,rgb.green,rgb.blue,a);Object.assign(this.colorComponents,{hue:h,saturation:s,lightness:l},rgb,{hex:hex},{opacity:a});this._updateCssColor();} 1842_updateOpacity(a){if(a<0||a>100){return;} 1843Object.assign(this.colorComponents,{opacity:a});const r=this.colorComponents.red;const g=this.colorComponents.green;const b=this.colorComponents.blue;Object.assign(this.colorComponents,{hex:convertRgbaToCSSColor(r,g,b,a)});this._updateCssColor();} 1844_colorSelected(){this.props.onColorSelect(this.colorComponents);} 1845_updateCssColor(){const r=this.colorComponents.red;const g=this.colorComponents.green;const b=this.colorComponents.blue;const a=this.colorComponents.opacity;Object.assign(this.colorComponents,{cssColor:convertRgbaToCSSColor(r,g,b,a)});if(this.previewActive){this.props.onColorPreview(this.colorComponents);}} 1846onKeydown(ev){if(ev.key==="Enter"){if(ev.target.tagName==="INPUT"){this.onChangeInputs(ev);} 1847ev.preventDefault();this.props.onInputEnter(ev);}} 1848onClick(ev){if(this.props.stopClickPropagation){ev.stopPropagation();} 1849ev.__isColorpickerClick=true;if(ev.target.dataset.colorMethod==="hex"&&!this.selectedHexValue){ev.target.select();this.selectedHexValue=ev.target.value;return;} 1850this.selectedHexValue="";} 1851onPointerUp(){if(this.pickerFlag||this.sliderFlag||this.opacitySliderFlag){this.shouldSetSelectedColor=true;this._updateCssColor();} 1852this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;if(this.lastFocusedSliderEl){this.lastFocusedSliderEl.focus();this.lastFocusedSliderEl=undefined;}}
1853onEscapeKeydown(ev){const hotkey=getActiveHotkey(ev);if(hotkey==="escape"){this.props.setOnCloseCallback?.(()=>{});}} 1854onPointerDownPicker(ev){this.pickerFlag=true;ev.preventDefault();this.onPointerMovePicker(ev);this.setLastFocusedSliderEl(this.colorPickerPointerRef.el);} 1855onPointerMovePicker(ev){if(!this.pickerFlag){return;} 1856const colorPickerArea=this.colorPickerAreaRef.el;const rect=colorPickerArea.getClientRects()[0];const top=ev.pageY-rect.top;const left=ev.pageX-rect.left;let saturation=Math.round((100*left)/colorPickerArea.clientWidth);let lightness=Math.round((100*(colorPickerArea.clientHeight-top))/colorPickerArea.clientHeight);saturation=clamp(saturation,0,100);lightness=clamp(lightness,0,100);this._updateHsl(this.colorComponents.hue,saturation,lightness);this._updateUI();} 1857onPickerKeydown(ev){const hotkey=getActiveHotkey(ev);this.selectColorOnEnter(hotkey);if(!this.getAllowedHotkeys(ARROW_KEYS).includes(hotkey)){return;} 1858let saturation=this.colorComponents.saturation;let lightness=this.colorComponents.lightness;let step=10;if(hotkey.startsWith("control+")){step=1;} 1859const mainKey=hotkey.replace("control+","");if(mainKey==="arrowup"){lightness+=step;}else if(mainKey==="arrowdown"){lightness-=step;}else if(mainKey==="arrowright"){saturation+=step;}else if(mainKey==="arrowleft"){saturation-=step;} 1860lightness=clamp(lightness,0,100);saturation=clamp(saturation,0,100);this._updateHsl(this.colorComponents.hue,saturation,lightness);this._updateUI();this.shouldSetSelectedColor=true;} 1861onPointerDownSlider(ev){this.sliderFlag=true;ev.preventDefault();this.onPointerMoveSlider(ev);this.setLastFocusedSliderEl(this.colorSliderPointerRef.el);} 1862onPointerMoveSlider(ev){if(!this.sliderFlag){return;} 1863const colorSlider=this.colorSliderRef.el;const colorSliderRects=colorSlider.getClientRects();const y=colorSliderRects[0].height-(ev.pageY-colorSliderRects[0].top);let hue=Math.round((360*y)/colorSlider.clientHeight);hue=clamp(hue,0,360);this._updateHsl(hue,this.colorComponents.saturation,this.colorComponents.lightness);this._updateUI();} 1864onSliderKeydown(ev){const hotkey=getActiveHotkey(ev);this.selectColorOnEnter(hotkey);if(!this.getAllowedHotkeys(SLIDER_KEYS).includes(hotkey)){return;} 1865const hue=this.handleRangeKeydownValue(hotkey,this.colorComponents.hue,{min:0,max:360,leap:30,});this._updateHsl(hue,this.colorComponents.saturation,this.colorComponents.lightness);this._updateUI();this.shouldSetSelectedColor=true;} 1866onPointerDownOpacitySlider(ev){this.opacitySliderFlag=true;ev.preventDefault();this.onPointerMoveOpacitySlider(ev);this.setLastFocusedSliderEl(this.opacitySliderPointerRef.el);} 1867onPointerMoveOpacitySlider(ev){if(!this.opacitySliderFlag||this.props.noTransparency){return;} 1868const opacitySlider=this.opacitySliderRef.el;const y=ev.pageY-opacitySlider.getClientRects()[0].top;let opacity=Math.round(100*(1-y/opacitySlider.clientHeight));opacity=clamp(opacity,0,100);this._updateOpacity(opacity);this._updateUI();} 1869onOpacitySliderKeydown(ev){const hotkey=getActiveHotkey(ev);this.selectColorOnEnter(hotkey);if(!this.getAllowedHotkeys(SLIDER_KEYS).includes(hotkey)){return;} 1870const opacity=this.handleRangeKeydownValue(hotkey,this.colorComponents.opacity);this._updateOpacity(opacity);this._updateUI();this.shouldSetSelectedColor=true;} 1871onChangeInputs(ev){switch(ev.target.dataset.colorMethod){case"hex":return;case"hsl":this._updateHsl(parseInt(this.el.querySelector(".o_hue_input").value),parseInt(this.el.querySelector(".o_saturation_input").value),parseInt(this.el.querySelector(".o_lightness_input").value));break;} 1872this._updateUI();this._colorSelected();} 1873onHexColorInput(ev){const hexColorValue=ev.target.value.replaceAll("#","");if(hexColorValue.length===6||hexColorValue.length===8){this._updateHex(`#${hexColorValue}`);this._updateUI();this._colorSelected();}}} 1874return __exports;});; 1875 1876/* /web/static/src/core/color_picker/tabs/color_picker_custom_tab.js */ 1877odoo.define('@web/core/color_picker/tabs/color_picker_custom_tab',['@odoo/owl','@web/core/l10n/translation','@web/core/registry','@web/core/utils/colors','@web/core/color_picker/custom_color_picker/custom_color_picker'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{isColorGradient}=require("@web/core/utils/colors");const{CustomColorPicker}=require("@web/core/color_picker/custom_color_picker/custom_color_picker");const ColorPickerCustomTab=__exports.ColorPickerCustomTab=class ColorPickerCustomTab extends Component{static template="web.ColorPickerCustomTab";static components={CustomColorPicker};static props={applyColor:Function,colorPickerNavigation:Function,onColorClick:Function,onColorPreview:Function,onColorPointerOver:Function,onColorPointerOut:Function,onFocusin:Function,onFocusout:Function,getUsedCustomColors:{type:Function,optional:true},currentColorPreview:{type:String,optional:true},currentCustomColor:{type:String,optional:true}
1877,defaultColorSet:{type:String|Boolean,optional:true},defaultOpacity:{type:Number,optional:true},grayscales:{type:Object,optional:true},cssVarColorPrefix:{type:String,optional:true},noTransparency:{type:Boolean,optional:true},setOnCloseCallback:{type:Function,optional:true},setOperationCallbacks:{type:Function,optional:true},"*":{optional:true},};setup(){this.usedCustomColors=this.props.getUsedCustomColors();} 1878isValidCustomColor(color){return color&&color.slice(7,9)!=="00"&&!isColorGradient(color);}} 1879registry.category("color_picker_tabs").add("web.custom",{id:"custom",name:_t("Custom"),component:ColorPickerCustomTab,});return __exports;});; 1880 1881/* /web/static/src/core/color_picker/tabs/color_picker_solid_tab.js */ 1882odoo.define('@web/core/color_picker/tabs/color_picker_solid_tab',['@odoo/owl','@web/core/l10n/translation','@web/core/registry'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const ColorPickerSolidTab=__exports.ColorPickerSolidTab=class ColorPickerSolidTab extends Component{static template="web.ColorPickerSolidTab";static props={colorPickerNavigation:Function,onColorClick:Function,onColorPointerOver:Function,onColorPointerOut:Function,onFocusin:Function,onFocusout:Function,currentCustomColor:{type:String,optional:true},defaultColorSet:{type:String|Boolean,optional:true},cssVarColorPrefix:{type:String,optional:true},defaultColors:Array,defaultThemeColorVars:Array,"*":{optional:true},};} 1883registry.category("color_picker_tabs").add("web.solid",{id:"solid",name:_t("Solid"),component:ColorPickerSolidTab,});return __exports;});; 1884 1885/* /web/static/src/core/colorlist/colorlist.js */ 1886odoo.define('@web/core/colorlist/colorlist',['@web/core/l10n/translation','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{Component,useRef,useState,useExternalListener}=require("@odoo/owl");const ColorList=__exports.ColorList=class ColorList extends Component{static COLORS=[_t("No color"),_t("Red"),_t("Orange"),_t("Yellow"),_t("Cyan"),_t("Purple"),_t("Almond"),_t("Teal"),_t("Blue"),_t("Raspberry"),_t("Green"),_t("Violet"),];static template="web.ColorList";static defaultProps={forceExpanded:false,isExpanded:false,};static props={canToggle:{type:Boolean,optional:true},colors:Array,forceExpanded:{type:Boolean,optional:true},isExpanded:{type:Boolean,optional:true},onColorSelected:Function,selectedColor:{type:Number,optional:true},};setup(){this.colorlistRef=useRef("colorlist");this.state=useState({isExpanded:this.props.isExpanded});useExternalListener(window,"click",this.onOutsideClick);} 1887get colors(){return this.constructor.COLORS;} 1888onColorSelected(id){this.props.onColorSelected(id);if(!this.props.forceExpanded){this.state.isExpanded=false;}} 1889onOutsideClick(ev){if(this.colorlistRef.el.contains(ev.target)||this.props.forceExpanded){return;} 1890this.state.isExpanded=false;} 1891onToggle(ev){if(this.props.canToggle){ev.preventDefault();ev.stopPropagation();this.state.isExpanded=!this.state.isExpanded;this.colorlistRef.el.firstElementChild.focus();}}} 1892return __exports;});; 1893 1894/* /web/static/src/core/colors/colors.js */ 1895odoo.define('@web/core/colors/colors',['@web/core/utils/numbers'],function(require){'use strict';let __exports={};const{clamp}=require("@web/core/utils/numbers");const COLORS_ENT_BRIGHT=["#875A7B","#A5D8D7","#DCD0D9"];const COLORS_ENT_DARK=["#6B3E66","#147875","#5A395A"];const COLORS_SM=["#4EA7F2","#EA6175","#43C5B1","#F4A261","#8481DD","#FFD86D",];const COLORS_MD=["#4EA7F2","#3188E6","#43C5B1","#00A78D","#EA6175","#CE4257","#F4A261","#F48935","#8481DD","#5752D1","#FFD86D","#FFBC2C",];const COLORS_LG=["#4EA7F2","#3188E6","#056BD9","#A76DBC","#7F4295","#6D2387","#EA6175","#CE4257","#982738","#43C5B1","#00A78D","#0E8270","#F4A261","#F48935","#BE5D10","#8481DD","#5752D1","#3A3580","#A4A8B6","#7E8290","#545B70","#FFD86D","#FFBC2C","#C08A16",];const COLORS_XL=["#4EA7F2","#3188E6","#056BD9","#155193","#A76DBC","#7F4295","#6D2387","#4F1565","#EA6175","#CE4257","#982738","#791B29","#43C5B1","#00A78D","#0E8270","#105F53","#F4A261","#F48935","#BE5D10","#7D380D","#8481DD","#5752D1","#3A3580","#26235F","#A4A8B6","#7E8290","#545B70","#3F4250","#FFD86D","#FFBC2C","#C08A16","#936A12",];__exports.getColors=getColors;function getColors(colorScheme,paletteName){switch(paletteName){case"odoo":return colorScheme==="dark"?COLORS_ENT_DARK:COLORS_ENT_BRIGHT;case"sm":return COLORS_SM;case"md":return COLORS_MD;case"lg":return COLORS_LG;default:return COLORS_XL;}} 1896__exports.getColor=getColor;function getColor(index,colorScheme,paletteSizeOrName){let paletteName;if(paletteSizeOrName==="odoo"){paletteName="odoo";}else if(paletteSizeOrName<=6||paletteSizeOrName==="sm"){paletteName="sm";}else if(paletteSizeOrName<=12||paletteSizeOrName==="md"){paletteName="md";}else if(paletteSizeOrName<=24||paletteSizeOrName==="lg"){paletteName="lg";}else{paletteName="xl";} 1897const colors=getColors(colorScheme,paletteName);return colors[index%colors.length];} 1898const DEFAULT_BG=__exports.DEFAULT_BG="#d3d3d3";__exports.getBorderWhite=getBorderWhite;function getBorderWhite(colorScheme){return colorScheme==="dark"?"rgba(38, 42, 54, .2)":"rgba(249,250,251, .2)";} 1899const RGB_REGEX=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;__exports.hexToRGBA=hexToRGBA;function hexToRGBA(hex,opacity){const rgb=RGB_REGEX.exec(hex).slice(1,4).map((n)=>parseInt(n,16)).join(",");return`rgba(${rgb},${opacity})`;} 1900__exports.getCustomColor=getCustomColor;function getCustomColor(colorScheme,brightModeColor,darkModeColor){if(darkModeColor===undefined){return brightModeColor;}else{return colorScheme==="dark"?darkModeColor:brightModeColor;}} 1901__exports.lightenColor=lightenColor;function lightenColor(color,factor){factor=clamp(factor,0,1);let r=parseInt(color.substring(1,3),16);let g=parseInt(color.substring(3,5),16);let b=parseInt(color.substring(5,7),16);r=Math.round(r+(255-r)*factor);g=Math.round(g+(255-g)*factor);b=Math.round(b+(255-b)*factor);r=r.toString(16).padStart(2,"0");g=g.toString(16).padStart(2,"0");b=b.toString(16).padStart(2,"0");return`#${r}${g}${b}`;} 1902__exports.darkenColor=darkenColor;
1902function darkenColor(color,factor){factor=clamp(factor,0,1);let r=parseInt(color.substring(1,3),16);let g=parseInt(color.substring(3,5),16);let b=parseInt(color.substring(5,7),16);r=Math.round(r*(1-factor));g=Math.round(g*(1-factor));b=Math.round(b*(1-factor));r=r.toString(16).padStart(2,"0");g=g.toString(16).padStart(2,"0");b=b.toString(16).padStart(2,"0");return`#${r}${g}${b}`;} 1903return __exports;});; 1904 1905/* /web/static/src/core/commands/command_category.js */ 1906odoo.define('@web/core/commands/command_category',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const commandCategoryRegistry=registry.category("command_categories");commandCategoryRegistry.add("app",{},{sequence:10}).add("smart_action",{},{sequence:15}).add("actions",{},{sequence:30}).add("default",{},{sequence:50}).add("view_switcher",{},{sequence:100}).add("debug",{},{sequence:110}).add("disabled",{});return __exports;});; 1907 1908/* /web/static/src/core/commands/command_hook.js */ 1909odoo.define('@web/core/commands/command_hook',['@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{useEffect}=require("@odoo/owl");__exports.useCommand=useCommand;function useCommand(name,action,options={}){const commandService=useService("command");useEffect(()=>commandService.add(name,action,options),()=>[]);} 1910return __exports;});; 1911 1912/* /web/static/src/core/commands/command_palette.js */ 1913odoo.define('@web/core/commands/command_palette',['@web/core/dialog/dialog','@web/core/h
1913otkeys/hotkey_hook','@web/core/l10n/translation','@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/search','@web/core/utils/timing','@web/core/browser/feature_detection','@web/core/utils/html','@odoo/owl'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{KeepLast,Race}=require("@web/core/utils/concurrency");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{scrollTo}=require("@web/core/utils/scrolling");const{fuzzyLookup}=require("@web/core/utils/search");const{debounce}=require("@web/core/utils/timing");const{isMacOS,isMobileOS}=require("@web/core/browser/feature_detection");const{highlightText}=require("@web/core/utils/html");const{Component,onWillStart,onWillDestroy,EventBus,useRef,useState,markRaw,useExternalListener,}=require("@odoo/owl");const DEFAULT_PLACEHOLDER=_t("Search...");const DEFAULT_EMPTY_MESSAGE=_t("No result found");const FUZZY_NAMESPACES=["default"];function commandsWithinCategory(categoryName,categories){return(cmd)=>{const inCurrentCategory=categoryName===cmd.category;const fallbackCategory=categoryName==="default"&&!categories.includes(cmd.category);return inCurrentCategory||fallbackCategory;};} 1914const DefaultCommandItem=__exports.DefaultCommandItem=class DefaultCommandItem extends Component{static template="web.DefaultCommandItem";static props={slots:{type:Object,optional:true},hotkey:{type:String,optional:true},hotkeyOptions:{type:String,optional:true},name:{type:String,optional:true},searchValue:{type:String,optional:true},executeCommand:{type:Function,optional:true},};} 1915const CommandPalette=__exports.CommandPalette=class CommandPalette extends Component{static template="web.CommandPalette";static components={Dialog};static lastSessionId=0;static props={bus:{type:EventBus,optional:true},close:Function,config:Object,closeMe:{type:Function,optional:true},};setup(){if(this.props.bus){const setConfig=({detail})=>this.setCommandPaletteConfig(detail);this.props.bus.addEventListener(`SET-CONFIG`,setConfig);onWillDestroy(()=>this.props.bus.removeEventListener(`SET-CONFIG`,setConfig));} 1916this.keyId=1;this.race=new Race();this.keepLast=new KeepLast();this._sessionId=CommandPalette.lastSessionId++;this.DefaultCommandItem=DefaultCommandItem;this.activeElement=useService("ui").activeElement;this.inputRef=useAutofocus();useHotkey("Enter",()=>this.executeSelectedCommand(),{bypassEditableProtection:true});useHotkey("Control+Enter",()=>this.executeSelectedCommand(true),{bypassEditableProtection:true,});useHotkey("ArrowUp",()=>this.selectCommandAndScrollTo("PREV"),{bypassEditableProtection:true,allowRepeat:true,});useHotkey("ArrowDown",()=>this.selectCommandAndScrollTo("NEXT"),{bypassEditableProtection:true,allowRepeat:true,});useExternalListener(window,"mousedown",this.onWindowMouseDown);this.state=useState({});this.root=useRef("root");this.listboxRef=useRef("listbox");onWillStart(()=>this.setCommandPaletteConfig(this.props.config));} 1917get commandsByCategory(){const categories=[];for(const category of this.categoryKeys){const commands=this.state.commands.filter(commandsWithinCategory(category,this.categoryKeys));if(commands.length){categories.push({commands,name:this.categoryNames[category],keyId:category,});}} 1918return categories;} 1919async setCommandPaletteConfig(config){this.configByNamespace=config.configByNamespace||{};this.state.FooterComponent=config.FooterComponent;this.providersByNamespace={default:[]};for(const provider of config.providers){const namespace=provider.namespace||"default";if(namespace in this.providersByNamespace){this.providersByNamespace[namespace].push(provider);}else{this.providersByNamespace[namespace]=[provider];}} 1920const{namespace,searchValue}=this.processSearchValue(config.searchValue||"");this.switchNamespace(namespace);this.state.searchValue=searchValue;await this.race.add(this.search(searchValue));} 1921async setCommands(namespace,options={}){this.categoryKeys=["default"];this.categoryNames={};const proms=this.providersByNamespace[namespace].map((provider)=>{const{provide}=provider;const result=provide(this.env,options);return result;});let commands=(await this.keepLast.add(Promise.all(proms))).flat();const namespaceConfig=this.configByNamespace[namespace]||{};if(options.searchValue&&FUZZY_NAMESPACES.includes(namespace)){commands=fuzzyLookup(options.searchValue,commands,(c)=>c.name);}else{if(namespaceConfig.categories){let commandsSorted=[];this.categoryKeys=namespaceConfig.categories;this.categoryNames=namespaceConfig.categoryNames||{};if(!this.categoryKeys.includes("default")){this.categoryKeys.push("default");} 1922for(const category of this.categoryKeys){commandsSorted=commandsSorted.concat(commands.filter(commandsWithinCategory(category,this.categoryKeys)));} 1923commands=commandsSorted;}} 1924this.state.commands=markRaw(commands.slice(0,100).map((command)=>({...command,keyId:this.keyId++,text:highlightText(options.searchValue,command.name,"fw-bolder text-primary"),})));this.selectCommand(this.state.commands.length?0:-1);this.mouseSelectionActive=false;this.state.emptyMessage=(namespaceConfig.emptyMessage||DEFAULT_EMPTY_MESSAGE).toString();}
1925selectCommand(index){if(index===-1||index>=this.state.commands.length){this.state.selectedCommand=null;return;} 1926this.state.selectedCommand=markRaw(this.state.commands[index]);} 1927selectCommandAndScrollTo(type){this.mouseSelectionActive=false;const index=this.state.commands.indexOf(this.state.selectedCommand);if(index===-1){return;} 1928let nextIndex;if(type==="NEXT"){nextIndex=index<this.state.commands.length-1?index+1:0;}else if(type==="PREV"){nextIndex=index>0?index-1:this.state.commands.length-1;} 1929this.selectCommand(nextIndex);const command=this.listboxRef.el.querySelector(`#o_command_${nextIndex}`);scrollTo(command,{scrollable:this.listboxRef.el});} 1930onCommandClicked(event,index){event.preventDefault();this.selectCommand(index);const ctrlKey=isMacOS()?event.metaKey:event.ctrlKey;this.executeSelectedCommand(ctrlKey);} 1931async executeCommand(command){const config=await command.action();if(config){this.setCommandPaletteConfig(config);}else{this.props.close();}} 1932async executeSelectedCommand(ctrlKey){await this.searchValuePromise;const selectedCommand=this.state.selectedCommand;if(selectedCommand){if(!ctrlKey){this.executeCommand(selectedCommand);}else if(selectedCommand.href){window.open(selectedCommand.href,"_blank");}}} 1933onCommandMouseEnter(index){if(this.mouseSelectionActive){this.selectCommand(index);}else{this.mouseSelectionActive=true;}} 1934async search(searchValue){this.state.isLoading=true;try{await this.setCommands(this.state.namespace,{searchValue,activeElement:this.activeElement,sessionId:this._sessionId,});}finally{this.state.isLoading=false;} 1935if(this.inputRef.el){this.inputRef.el.focus();}} 1936debounceSearch(value){const{namespace,searchValue}=this.processSearchValue(value);if(namespace!=="default"&&this.state.namespace!==namespace){this.switchNamespace(namespace);} 1937this.state.searchValue=searchValue;this.searchValuePromise=this.lastDebounceSearch(searchValue).catch(()=>{this.searchValuePromise=null;});} 1938onSearchInput(ev){this.debounceSearch(ev.target.value);} 1939onKeyDown(ev){if(ev.key.toLowerCase()==="backspace"&&!ev.target.value.length&&!ev.repeat){this.switchNamespace("default");this.state.searchValue="";this.searchValuePromise=this.lastDebounceSearch("").catch(()=>{this.searchValuePromise=null;});}} 1940onWindowMouseDown(ev){if(!this.root.el.contains(ev.target)){this.props.close();}} 1941switchNamespace(namespace){if(this.lastDebounceSearch){this.lastDebounceSearch.cancel();} 1942const namespaceConfig=this.configByNamespace[namespace]||{};this.lastDebounceSearch=debounce((value)=>this.search(value),namespaceConfig.debounceDelay||0);this.state.namespace=namespace;this.state.placeholder=namespaceConfig.placeholder||DEFAULT_PLACEHOLDER.toString();} 1943processSearchValue(searchValue){let namespace="default";if(searchValue.length&&this.providersByNamespace[searchValue[0]]){namespace=searchValue[0];searchValue=searchValue.slice(1);} 1944return{namespace,searchValue};} 1945get isMacOS(){return isMacOS();} 1946get isMobileOS(){return isMobileOS();}} 1947return __exports;});; 1948 1949/* /web/static/src/core/commands/command_service.js */ 1950odoo.define('@web/core/commands/command_service',['@web/core/registry','@web/core/commands/command_palette','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{CommandPalette}=require("@web/core/commands/command_palette");const{Component,EventBus}=require("@odoo/owl");const commandCategoryRegistry=registry.category("command_categories");
1950const commandProviderRegistry=registry.category("command_provider");const commandSetupRegistry=registry.category("command_setup");class DefaultFooter extends Component{static template="web.DefaultFooter";static props={switchNamespace:{type:Function},};setup(){this.elements=commandSetupRegistry.getEntries().map((el)=>({namespace:el[0],name:el[1].name})).filter((el)=>el.name);} 1951onClick(namespace){this.props.switchNamespace(namespace);}} 1952const commandService=__exports.commandService={dependencies:["dialog","hotkey","ui"],start(env,{dialog,hotkey:hotkeyService,ui}){const registeredCommands=new Map();let nextToken=0;let isPaletteOpened=false;const bus=new EventBus();hotkeyService.add("control+k",openMainPalette,{bypassEditableProtection:true,global:true,});function openMainPalette(config={},onClose){const configByNamespace={};for(const provider of commandProviderRegistry.getAll()){const namespace=provider.namespace||"default";if(!configByNamespace[namespace]){configByNamespace[namespace]={categories:[],categoryNames:{},};}} 1953for(const[category,el]of commandCategoryRegistry.getEntries()){const namespace=el.namespace||"default";const name=el.name;if(namespace in configByNamespace){configByNamespace[namespace].categories.push(category);configByNamespace[namespace].categoryNames[category]=name;}} 1954for(const[namespace,{emptyMessage,debounceDelay,placeholder},]of commandSetupRegistry.getEntries()){if(namespace in configByNamespace){if(emptyMessage){configByNamespace[namespace].emptyMessage=emptyMessage;} 1955if(debounceDelay!==undefined){configByNamespace[namespace].debounceDelay=debounceDelay;} 1956if(placeholder){configByNamespace[namespace].placeholder=placeholder;}}} 1957config=Object.assign({configByNamespace,FooterComponent:DefaultFooter,providers:commandProviderRegistry.getAll(),},config);return openPalette(config,onClose);} 1958function openPalette(config,onClose){if(isPaletteOpened){bus.trigger("SET-CONFIG",config);return;} 1959isPaletteOpened=true;dialog.add(CommandPalette,{config,bus,},{onClose:()=>{isPaletteOpened=false;if(onClose){onClose();}},});} 1960function registerCommand(command,options){if(!command.name||!command.action||typeof command.action!=="function"){throw new Error("A Command must have a name and an action function.");} 1961const registration=Object.assign({},command,options);if(registration.identifier){const commandsArray=Array.from(registeredCommands.values());const sameName=commandsArray.find((com)=>com.name===registration.name);if(sameName){if(registration.identifier!==sameName.identifier){registration.name+=` (${registration.identifier})`;sameName.name+=` (${sameName.identifier})`;}}else{const sameFullName=commandsArray.find((com)=>com.name===registration.name+`(${registration.identifier})`);if(sameFullName){registration.name+=` (${registration.identifier})`;}}} 1962if(registration.hotkey){const action=async()=>{const commandService=env.services.command;const config=await command.action();if(!isPaletteOpened&&config){commandService.openPalette(config);}};registration.removeHotkey=hotkeyService.add(registration.hotkey,action,{...options.hotkeyOptions,global:registration.global,isAvailable:(...args)=>{let available=true;if(registration.isAvailable){available=registration.isAvailable(...args);} 1963if(available&&options.hotkeyOptions?.isAvailable){available=options.hotkeyOptions?.isAvailable(...args);} 1964return available;},});} 1965const token=nextToken++;registeredCommands.set(token,registration);if(!options.activeElement){Promise.resolve().then(()=>{registration.activeElement=ui.activeElement;});} 1966return token;} 1967function unregisterCommand(token){const cmd=registeredCommands.get(token);if(cmd&&cmd.removeHotkey){cmd.removeHotkey();} 1968registeredCommands.delete(token);} 1969return{add(name,action,options={}){const token=registerCommand({name,action},options);return()=>{unregisterCommand(token);};},getCommands(activeElement){return[...registeredCommands.values()].filter((command)=>command.activeElement===activeElement||command.global);},openMainPalette,openPalette,};},};registry.category("services").add("command",commandService);return __exports;});; 1970 1971/* /web/static/src/core/commands/default_providers.js */ 1972odoo.define('@web/core/commands/default_providers',['@web/core/browser/feature_detection','@web/core/h
1972otkeys/hotkey_hook','@web/core/l10n/translation','@web/core/registry','@web/core/utils/strings','@web/core/utils/ui','@web/core/commands/command_palette','@odoo/owl'],function(require){'use strict';let __exports={};const{isMacOS}=require("@web/core/browser/feature_detection");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{capitalize}=require("@web/core/utils/strings");const{getVisibleElements}=require("@web/core/utils/ui");const{DefaultCommandItem}=require("@web/core/commands/command_palette");const{Component}=require("@odoo/owl");const commandSetupRegistry=registry.category("command_setup");commandSetupRegistry.add("default",{emptyMessage:_t("No command found"),placeholder:_t("Search for a command..."),});const HotkeyCommandItem=__exports.HotkeyCommandItem=class HotkeyCommandItem extends Component{static template="web.HotkeyCommandItem";static props=["hotkey","hotkeyOptions?","name?","searchValue?","executeCommand","slots"];setup(){useHotkey(this.props.hotkey,this.props.executeCommand);} 1973getKeysToPress(command){const{hotkey}=command;let result=hotkey.split("+");if(isMacOS()){result=result.map((x)=>x.replace("control","command")).map((x)=>x.replace("alt","control"));} 1974return result.map((key)=>key.toUpperCase());}} 1975const commandCategoryRegistry=registry.category("command_categories");
1975const commandProviderRegistry=registry.category("command_provider");commandProviderRegistry.add("command",{provide:(env,options={})=>{const commands=env.services.command.getCommands(options.activeElement).map((cmd)=>{cmd.category=commandCategoryRegistry.contains(cmd.category)?cmd.category:"default";return cmd;}).filter((command)=>command.isAvailable===undefined||command.isAvailable());const uniqueCommands=commands.filter((obj,index)=>{return(index===commands.findIndex((o)=>obj.name===o.name&&obj.category===o.category));});return uniqueCommands.map((command)=>({Component:command.hotkey?HotkeyCommandItem:DefaultCommandItem,action:command.action,category:command.category,name:command.name,props:{hotkey:command.hotkey,hotkeyOptions:command.hotkeyOptions,},}));},});commandProviderRegistry.add("data-hotkeys",{provide:(env,options={})=>{const commands=[];const overlayModifier=registry.category("services").get("hotkey").overlayModifier;for(const el of getVisibleElements(options.activeElement,"[data-hotkey]:not(:disabled)")){const closest=el.closest("[data-command-category]");const category=closest?closest.dataset.commandCategory:"default";if(category==="disabled"){continue;} 1976const description=el.title||el.dataset.bsOriginalTitle||el.dataset.tooltip||el.placeholder||(el.innerText&&`${el.innerText.slice(0, 50)}${el.innerText.length > 50 ? "..." : ""}`)||_t("no description provided");commands.push({Component:HotkeyCommandItem,action:()=>{el.focus();el.click();},category,name:capitalize(description.trim().toLowerCase()),props:{hotkey:`${overlayModifier}+${el.dataset.hotkey}`,},});} 1977return commands;},});return __exports;});; 1978 1979/* /web/static/src/core/confirmation_dialog/confirmation_dialog.js */ 1980odoo.define('@web/core/confirmation_dialog/confirmation_dialog',['@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{useChildRef}=require("@web/core/utils/hooks");const{Component}=require("@odoo/owl");const deleteConfirmationMessage=__exports.deleteConfirmationMessage=_t(`Ready to make your record disappear into thin air? Are you sure? 1981It will be gone forever! 1982 1983Think twice before you click that 'Delete' button!`);const ConfirmationDialog=__exports.ConfirmationDialog=class ConfirmationDialog extends Component{static template="web.ConfirmationDialog";static components={Dialog};static props={close:Function,title:{validate:(m)=>{return(typeof m==="string"||(typeof m==="object"&&typeof m.toString==="function"));},optional:true,},body:{type:String,optional:true},confirm:{type:Function,optional:true},confirmLabel:{type:String,optional:true},confirmClass:{type:String,optional:true},cancel:{type:Function,optional:true},cancelLabel:{type:String,optional:true},dismiss:{type:Function,optional:true},};static defaultProps={confirmLabel:_t("Ok"),cancelLabel:_t("Cancel"),confirmClass:"btn-primary",title:_t("Confirmation"),};setup(){this.env.dialogData.dismiss=()=>this._dismiss();this.modalRef=useChildRef();this.isProcess=false;} 1984async _cancel(){return this.execButton(this.props.cancel);} 1985async _confirm(){return this.execButton(this.props.confirm);} 1986async _dismiss(){return this.execButton(this.props.dismiss||this.props.cancel);} 1987setButtonsDisabled(disabled){this.isProcess=disabled;if(!this.modalRef.el){return;} 1988for(const button of[...this.modalRef.el.querySelectorAll(".modal-footer button")]){button.disabled=disabled;}} 1989async execButton(callback){if(this.isProcess){return;} 1990this.setButtonsDisabled(true);if(callback){let shouldClose;try{shouldClose=await callback();}catch(e){this.props.close();throw e;} 1991if(shouldClose===false){this.setButtonsDisabled(false);return;}} 1992this.props.close();}} 1993const AlertDialog=__exports.AlertDialog=class AlertDialog extends ConfirmationDialog{static template="web.AlertDialog";static props={...ConfirmationDialog.props,contentClass:{type:String,optional:true},};static defaultProps={...ConfirmationDialog.defaultProps,title:_t("Alert"),};} 1994return __exports;});; 1995 1996/* /web/static/src/core/context.js */ 1997odoo.define('@web/core/context',['@web/core/py_js/py','@web/core/py_js/py_builtin','@web/core/py_js/py_interpreter'],function(require){'use strict';let __exports={};const{evaluateExpr,parseExpr}=require("@web/core/py_js/py");const{BUILTINS}=require("@web/core/py_js/py_builtin");const{evaluate}=require("@web/core/py_js/py_interpreter");__exports.makeContext=makeContext;function makeContext(contexts,initialEvaluationContext){const evaluationContext=Object.assign({},initialEvaluationContext);const context={};for(let ctx of contexts){if(ctx!==""){ctx=typeof ctx==="string"?evaluateExpr(ctx,evaluationContext):ctx;Object.assign(context,ctx);Object.assign(evaluationContext,context);}} 1998return context;} 1999function getPartialNames(ast){if(ast.type===5){return[ast.value];} 2000if(ast.type===6){return getPartialNames(ast.right);} 2001if(ast.type===14||ast.type===7){return getPartialNames(ast.left).concat(getPartialNames(ast.right));} 2002if(ast.type===15){return getPartialNames(ast.obj);} 2003return[];} 2004__exports.evalPartialContext=evalPartialContext;function evalPartialContext(_context,evaluationContext={}){const ast=parseExpr(_context);const context={};for(const key in ast.value){const value=ast.value[key];if(getPartialNames(value).some((name)=>!(name in evaluationContext||name in BUILTINS))){continue;} 2005try{context[key]=evaluate(value,evaluationContext);}catch{}} 2006return context;} 2007return __exports;});; 2008 2009/* /web/static/src/core/copy_button/copy_button.js */ 2010odoo.define('@web/core/copy_button/copy_button',['@web/core/browser/browser','@web/core/tooltip/tooltip','@web/core/popover/popover_hook','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Tooltip}=require("@web/core/tooltip/tooltip");const{usePopover}=require("@web/core/popover/popover_hook");const{Component,useRef}=require("@odoo/owl");const CopyButton=__exports.CopyButton=class CopyButton extends Component{static template="web.CopyButton";static props={className:{type:String,optional:true},copyText:{type:String,optional:true},disabled:{type:Boolean,optional:true},successText:{type:String,optional:true},icon:{type:String,optional:true},content:{type:[String,Object,Function],optional:true},};setup(){this.button=useRef("button");this.popover=usePopover(Tooltip);} 2011showTooltip(){this.popover.open(this.button.el,{tooltip:this.props.successText});browser.setTimeout(this.popover.close,800);} 2012async onClick(){let write,content;if(typeof this.props.content==="function"){content=this.props.content();}else{content=this.props.content;} 2013if(typeof content==="string"||content instanceof String){write=(value)=>browser.navigator.clipboard.writeText(value);}else{write=(value)=>browser.navigator.clipboard.write(value);} 2014try{await write(content);}catch(error){return browser.console.warn(error);} 2015this.showTooltip();}} 2016return __exports;});; 2017 2018/* /web/static/src/core/currency.js */ 2019odoo.define('@web/core/currency',['@odoo/owl','@web/core/network/rpc','@web/core/user','@web/core/utils/numbers','@web/core/utils/strings','@web/session'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{rpc}=require("@web/core/network/rpc");const{user}=require("@web/core/user");const{formatFloat,humanNumber}=require("@web/core/utils/numbers");const{nbsp}=require("@web/core/utils/strings");const{session}=require("@web/session");const currencies=__exports.currencies=session.currencies||{};delete session.currencies;__exports.getCurrency=getCurrency;function getCurrency(id){return currencies[id];} 2020__exports.getCurrencyRates=getCurrencyRates;async function getCurrencyRates(){const rates=reactive({});function recordsToRates(records){return Object.fromEntries(records.map((r)=>[r.id,r.inverse_rate]));} 2021const model="res.currency";const method="read";const url=`/web/dataset/call_kw/${model}/${method}`;const context={...user.context,to_currency:user.activeCompany.currency_id,};const params={model,method,args:[Object.keys(currencies).map(Number),["inverse_rate"]],kwargs:{context},};const records=await rpc(url,params,{cache:{type:"disk",update:"once",callback:(records,hasChanged)=>
2021{if(hasChanged){Object.assign(rates,recordsToRates(records));}},},});Object.assign(rates,recordsToRates(records));return rates;} 2022__exports.formatCurrency=formatCurrency;function formatCurrency(amount,currencyId,options={}){const currency=getCurrency(currencyId);const digits=(options.digits!==undefined)?options.digits:(currency&¤cy.digits) 2023let formattedAmount;if(options.humanReadable){formattedAmount=humanNumber(amount,{decimals:digits?digits[1]:2,minDigits:options.minDigits,});}else{formattedAmount=formatFloat(amount,{digits,minDigits:options.minDigits,trailingZeros:options.trailingZeros});} 2024if(!currency||options.noSymbol){return formattedAmount;} 2025const formatted=[currency.symbol,formattedAmount];if(currency.position==="after"){formatted.reverse();} 2026return formatted.join(nbsp);} 2027return __exports;});; 2028 2029/* /web/static/src/core/datetime/datetime_input.js */ 2030odoo.define('@web/core/datetime/datetime_input',['@odoo/owl','@web/core/utils/objects','@web/core/datetime/datetime_picker','@web/core/datetime/datetime_picker_hook'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{omit}=require("@web/core/utils/objects");const{DateTimePicker}=require("@web/core/datetime/datetime_picker");const{useDateTimePicker}=require("@web/core/datetime/datetime_picker_hook");const dateTimeInputOwnProps={format:{type:String,optional:true},id:{type:String,optional:true},class:{type:String,optional:true},onChange:{type:Function,optional:true},onApply:{type:Function,optional:true},placeholder:{type:String,optional:true},disabled:{type:Boolean,optional:true},};const DateTimeInput=__exports.DateTimeInput=class DateTimeInput extends Component{static props={...DateTimePicker.props,...dateTimeInputOwnProps,};static template="web.DateTimeInput";setup(){const getPickerProps=()=>omit(this.props,...Object.keys(dateTimeInputOwnProps));useDateTimePicker({format:this.props.format,showSeconds:this.props.rounding<=0,get pickerProps(){return getPickerProps();},onApply:(...args)=>this.props.onApply?.(...args),onChange:(...args)=>this.props.onChange?.(...args),});}} 2031return __exports;});; 2032 2033/* /web/static/src/core/datetime/datetime_picker.js */ 2034odoo.define('@web/core/datetime/datetime_picker',['@odoo/owl','@web/core/l10n/translation','@web/core/l10n/dates','@web/core/l10n/localization','@web/core/utils/arrays','@web/core/time_picker/time_picker','@web/core/l10n/time'],function(require){'use strict';let __exports={};const{Component,onWillRender,onWillUpdateProps,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{MAX_VALID_DATE,MIN_VALID_DATE,clampDate,isInRange,today}=require("@web/core/l10n/dates");const{localization}=require("@web/core/l10n/localization");const{ensureArray}=require("@web/core/utils/arrays");const{TimePicker}=require("@web/core/time_picker/time_picker");const{Time}=require("@web/core/l10n/time");const{DateTime,Info}=luxon;const getStartOfDecade=(date)=>Math.floor(date.year/10)*10;const getStartOfCentury=(date)=>Math.floor(date.year/100)*100;const getStartOfWeek=(date)=>{const{weekStart}=localization;return date.set({weekday:date.weekday<weekStart?weekStart-7:weekStart});};const numberRange=(min,max)=>[...Array(max-min)].map((_,i)=>i+min);const parseLimitDate=(value,defaultValue)=>clampDate(value==="today"?today():value||defaultValue,MIN_VALID_DATE,MAX_VALID_DATE);const toDateItem=({isOutOfRange=false,isValid=true,label,range,extraClass})=>({id:range[0].toISODate(),includesToday:isInRange(today(),range),isOutOfRange,isValid,label:String(range[0][label]),range,extraClass,});const toWeekItem=(weekDayItems)=>({number:weekDayItems[3].range[0].weekNumber,days:weekDayItems,});const PRECISION_LEVELS=new Map().set("days",{mainTitle:_t("Select month"),nextTitle:_t("Next month"),prevTitle:_t("Previous month"),step:{month:1},getTitle:(date)=>`${date.monthLong} ${date.year}`,getItems:(date,{maxDate,minDate,showWeekNumbers,isDateValid,dayCellClass})=>{const startDates=[date];const lastWeeks=[];let shouldAddLastWeek=false;const dayItems=startDates.map((date,i)=>{const monthRange=[date.startOf("month"),date.endOf("month")];const weeks=[];let startOfNextWeek=getStartOfWeek(monthRange[0]);for(let w=0;w<WEEKS_PER_MONTH;
2034w++){const weekDayItems=[];for(let d=0;d<DAYS_PER_WEEK;d++){const day=startOfNextWeek.plus({day:d});const range=[day,day.endOf("day")];const dayItem=toDateItem({isOutOfRange:!isInRange(day,monthRange),isValid:isInRange(range,[minDate,maxDate])&&isDateValid?.(day),label:"day",range,extraClass:dayCellClass?.(day)||"",});weekDayItems.push(dayItem);if(d===DAYS_PER_WEEK-1){startOfNextWeek=day.plus({day:1});} 2035if(w===WEEKS_PER_MONTH-1){shouldAddLastWeek=true;}} 2036const weekItem=toWeekItem(weekDayItems);if(w===WEEKS_PER_MONTH-1){lastWeeks.push(weekItem);}else{weeks.push(weekItem);}} 2037const daysOfWeek=weeks[0].days.map((d)=>[d.range[0].weekdayShort,d.range[0].weekdayLong,Info.weekdays("narrow",{locale:d.range[0].locale})[d.range[0].weekday-1],]);if(showWeekNumbers){daysOfWeek.unshift(["",_t("Week numbers"),""]);} 2038return{id:`__month__${i}`,number:monthRange[0].month,daysOfWeek,weeks,};});if(shouldAddLastWeek){for(let i=0;i<dayItems.length;i++){dayItems[i].weeks.push(lastWeeks[i]);}} 2039return dayItems;},}).set("months",{mainTitle:_t("Select year"),nextTitle:_t("Next year"),prevTitle:_t("Previous year"),step:{year:1},getTitle:(date)=>String(date.year),getItems:(date,{maxDate,minDate})=>{const startOfYear=date.startOf("year");return numberRange(0,12).map((i)=>{const startOfMonth=startOfYear.plus({month:i});const range=[startOfMonth,startOfMonth.endOf("month")];return toDateItem({isValid:isInRange(range,[minDate,maxDate]),label:"monthShort",range,});});},}).set("years",{mainTitle:_t("Select decade"),nextTitle:_t("Next decade"),prevTitle:_t("Previous decade"),step:{year:10},getTitle:(date)=>`${getStartOfDecade(date) - 1} - ${getStartOfDecade(date) + 10}`,getItems:(date,{maxDate,minDate})=>{const startOfDecade=date.startOf("year").set({year:getStartOfDecade(date)});return numberRange(-GRID_MARGIN,GRID_COUNT+GRID_MARGIN).map((i)=>{const startOfYear=startOfDecade.plus({year:i});const range=[startOfYear,startOfYear.endOf("year")];return toDateItem({isOutOfRange:i<0||i>=GRID_COUNT,isValid:isInRange(range,[minDate,maxDate]),label:"year",range,});});},}).set("decades",{mainTitle:_t("Select century"),nextTitle:_t("Next century"),prevTitle:_t("Previous century"),step:{year:100},getTitle:(date)=>`${getStartOfCentury(date) - 10} - ${getStartOfCentury(date) + 100}`,getItems:(date,{maxDate,minDate})=>{const startOfCentury=date.startOf("year").set({year:getStartOfCentury(date)});return numberRange(-GRID_MARGIN,GRID_COUNT+GRID_MARGIN).map((i)=>{const startOfDecade=startOfCentury.plus({year:i*10});const range=[startOfDecade,startOfDecade.plus({year:10,millisecond:-1})];return toDateItem({label:"year",isOutOfRange:i<0||i>=GRID_COUNT,isValid:isInRange(range,[minDate,maxDate]),range,});});},});const GRID_COUNT=10;const GRID_MARGIN=1;const NULLABLE_DATETIME_PROPERTY=[DateTime,{value:false},{value:null}];const DAYS_PER_WEEK=7;const WEEKS_PER_MONTH=6;const DateTimePicker=__exports.DateTimePicker=class DateTimePicker extends Component{static props={focusedDateIndex:{type:Number,optional:true},showWeekNumbers:{type:Boolean,optional:true},daysOfWeekFormat:{type:String,optional:true},maxDate:{type:[NULLABLE_DATETIME_PROPERTY,{value:"today"}],optional:true},maxPrecision:{type:[...PRECISION_LEVELS.keys()].map((value)=>({value})),optional:true,},minDate:{type:[NULLABLE_DATETIME_PROPERTY,{value:"today"}],optional:true},minPrecision:{type:[...PRECISION_LEVELS.keys()].map((value)=>({value})),optional:true,},onReset:{type:Function,optional:true},onSelect:{type:Function,optional:true},onToggleRange:{type:Function,optional:true},range:{type:Boolean,optional:true},rounding:{type:Number,optional:true},showRangeToggler:{type:Boolean,optional:true},slots:{type:Object,shape:{buttons:{type:Object,optional:true}},optional:true,},type:{type:[{value:"date"},{value:"datetime"}],optional:true},value:{type:[NULLABLE_DATETIME_PROPERTY,{type:Array,element:NULLABLE_DATETIME_PROPERTY},],optional:true,},isDateValid:{type:Function,optional:true},dayCellClass:{type:Function,optional:true},tz:{type:String,optional:true},};static defaultProps={focusedDateIndex:0,daysOfWeekFormat:"narrow",maxPrecision:"decades",minPrecision:"days",rounding:5,showWeekNumbers:true,type:"datetime",};static template="web.DateTimePicker";static components={TimePicker};get activePrecisionLevel(){return PRECISION_LEVELS.get(this.state.precision);} 2040get isLastPrecisionLevel(){return(this.allowedPrecisionLevels.indexOf(this.state.precision)===this.allowedPrecisionLevels.length-1);} 2041get titles(){return ensureArray(this.title);} 2042setup(){this.allowedPrecisionLevels=[];this.items=[];this.title="";this.shouldAdjustFocusDate=false;this.state=useState({focusDate:null,hoveredDate:null,timeValues:[],precision:this.props.minPrecision,});this.onPropsUpdated(this.props);onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));onWillRender(()=>this.onWillRender());}
2043onPropsUpdated(props){this.values=ensureArray(props.value).map((value)=>value&&!value.isValid?null:value);this.allowedPrecisionLevels=this.filterPrecisionLevels(props.minPrecision,props.maxPrecision);this.maxDate=parseLimitDate(props.maxDate,MAX_VALID_DATE);this.minDate=parseLimitDate(props.minDate,MIN_VALID_DATE);if(this.props.type==="date"){this.maxDate=this.maxDate.endOf("day");this.minDate=this.minDate.startOf("day");} 2044if(this.maxDate<this.minDate){throw new Error(`DateTimePicker error: given "maxDate" comes before "minDate".`);} 2045this.state.timeValues=this.getTimeValues(props);this.shouldAdjustFocusDate=!props.range;this.adjustFocus(this.values,props.focusedDateIndex);} 2046onWillRender(){const{dayCellClass,focusedDateIndex,isDateValid,range,showWeekNumbers}=this.props;const{focusDate,hoveredDate}=this.state;const precision=this.activePrecisionLevel;const getterParams={maxDate:this.maxDate,minDate:this.minDate,showWeekNumbers:showWeekNumbers??!range,isDateValid,dayCellClass,};this.title=precision.getTitle(focusDate);this.items=precision.getItems(focusDate,getterParams);this.selectedRange=[...this.values];if(range&&focusedDateIndex>0&&(!this.values[1]||hoveredDate>this.values[0])){this.selectedRange[1]=hoveredDate;}} 2047adjustFocus(values,focusedDateIndex){if(!this.shouldAdjustFocusDate&&this.state.focusDate){return;} 2048const dateToFocus=values[focusedDateIndex]||values[focusedDateIndex===1?0:1]||today();this.shouldAdjustFocusDate=false;this.state.focusDate=this.clamp(dateToFocus.startOf("month"));} 2049clamp(value){return clampDate(value,this.minDate,this.maxDate);} 2050filterPrecisionLevels(minPrecision,maxPrecision){const levels=[...PRECISION_LEVELS.keys()];return levels.slice(levels.indexOf(minPrecision),levels.indexOf(maxPrecision)+1);} 2051getActiveRangeInfo({range}){const result={isSelected:isInRange(this.selectedRange,range),isSelectStart:false,isSelectEnd:false,isHighlighted:isInRange(this.state.hoveredDate,range),};if(this.props.range){if(result.isSelected){const[selectStart,selectEnd]=this.selectedRange.sort();result.isSelectStart=!selectStart||isInRange(selectStart,range);result.isSelectEnd=!selectEnd||isInRange(selectEnd,range);}}else{result.isSelectStart=result.isSelectEnd=result.isSelected;} 2052return result;} 2053getTimeValues(props){const timeValues=this.values.map((val,index)=>new Time({hour:index===1&&!this.values[1]?(val||DateTime.local()).hour+1:(val||DateTime.local()).hour,minute:val?.minute||0,second:val?.second||0,}));if(props.range){return timeValues;}else{const values=[];values[props.focusedDateIndex]=timeValues[props.focusedDateIndex];return values;}} 2054isSelectedDate({range}){return this.values.some((value)=>isInRange(value,range));} 2055next(ev){ev.preventDefault();const{step}=this.activePrecisionLevel;this.state.focusDate=this.clamp(this.state.focusDate.plus(step));} 2056previous(ev){ev.preventDefault();const{step}=this.activePrecisionLevel;this.state.focusDate=this.clamp(this.state.focusDate.minus(step));} 2057onTimeChange(valueIndex,newTime){this.state.timeValues[valueIndex]=newTime;const value=this.values[valueIndex]||today();this.validateAndSelect(value,valueIndex,"time");} 2058validateAndSelect(value,valueIndex,unit){if(!this.props.onSelect){return false;} 2059const result=[...this.values];result[valueIndex]=value;if(this.props.type==="datetime"){const{hour,minute,second}=this.state.timeValues[valueIndex];result[valueIndex]=result[valueIndex].set({hour,minute,second});} 2060if(!isInRange(result[valueIndex],[this.minDate,this.maxDate])){return false;} 2061this.props.onSelect(result.length===2?result:result[0],unit);return true;} 2062zoomIn(date){const index=this.allowedPrecisionLevels.indexOf(this.state.precision)-1;if(index in this.allowedPrecisionLevels){this.state.focusDate=this.clamp(date);this.state.precision=this.allowedPrecisionLevels[index];return true;} 2063return false;} 2064zoomOut(){const index=this.allowedPrecisionLevels.indexOf(this.state.precision)+1;if(index in this.allowedPrecisionLevels){this.state.precision=this.allowedPrecisionLevels[index];return true;} 2065return false;} 2066zoomOrSelect(dateItem){if(!dateItem.isValid){return;} 2067if(this.zoomIn(dateItem.range[0])){return;} 2068const[value]=dateItem.range;const valueIndex=this.props.focusedDateIndex;const isValid=this.validateAndSelect(value,valueIndex,"date");this.shouldAdjustFocusDate=isValid&&!this.props.range;}} 2069return __exports;});; 2070 2071/* /web/static/src/core/datetime/datetime_picker_hook.js */ 2072odoo.define('@web/core/datetime/datetime_picker_hook',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{onWillDestroy,useRef}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");__exports.useDateTimePicker=useDateTimePicker;function useDateTimePicker(params){function getInputs(){return inputRefs.map((ref)=>ref.el);} 2073const inputRefs=[useRef(params.startDateRefName||"start-date"),useRef(params.endDateRefName||"end-date"),];const serviceParams=Object.assign(Object.create(params),{getInputs,useOwlHooks:true,});const picker=useService("datetime_picker").create(serviceParams);onWillDestroy(()=>{picker.disable();});return picker;} 2074return __exports;});; 2075 2076/* /web/static/src/core/datetime/datetime_picker_popover.js */ 2077odoo.define('@web/core/datetime/datetime_picker_popover',['@odoo/owl','@web/core/h
2077otkeys/hotkey_hook','@web/core/datetime/datetime_picker'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{DateTimePicker}=require("@web/core/datetime/datetime_picker");const DateTimePickerPopover=__exports.DateTimePickerPopover=class DateTimePickerPopover extends Component{static components={DateTimePicker};static props={close:Function,pickerProps:{type:Object,shape:DateTimePicker.props},};static template="web.DateTimePickerPopover";setup(){useHotkey("enter",()=>this.props.close());}} 2078return __exports;});; 2079 2080/* /web/static/src/core/datetime/datetimepicker_service.js */ 2081odoo.define('@web/core/datetime/datetimepicker_service',['@odoo/owl','@web/core/l10n/dates','@web/core/popover/popover_hook','@web/core/registry','@web/core/utils/arrays','@web/core/utils/objects','@web/core/datetime/datetime_picker','@web/core/datetime/datetime_picker_popover'],function(require){'use strict';let __exports={};const{markRaw,onPatched,onWillRender,reactive,useEffect,useRef}=require("@odoo/owl");const{areDatesEqual,formatDate,formatDateTime,parseDate,parseDateTime}=require("@web/core/l10n/dates");const{makePopover}=require("@web/core/popover/popover_hook");const{registry}=require("@web/core/registry");const{ensureArray,zip,zipWith}=require("@web/core/utils/arrays");const{shallowEqual}=require("@web/core/utils/objects");const{DateTimePicker}=require("@web/core/datetime/datetime_picker");const{DateTimePickerPopover}=require("@web/core/datetime/datetime_picker_popover");function markValuesRaw(obj){const copy={};for(const[key,value]of Object.entries(obj)){if(value&&typeof value==="object"){copy[key]=markRaw(value);}else{copy[key]=value;}} 2082return copy;} 2083function stringifyProps(props){const copy={};for(const[key,value]of Object.entries(props)){copy[key]=JSON.stringify(value);} 2084return copy;} 2085const FOCUS_CLASSNAME="text-primary";const formatters={date:formatDate,datetime:formatDateTime,};const listenedElements=new WeakSet();const parsers={date:parseDate,datetime:parseDateTime,};const datetimePickerService=__exports.datetimePickerService={dependencies:["popover"],start(env,{popover:popoverService}){const dateTimePickerList=new Set();return{create(params={}){async function apply(){const{value}=pickerProps;const stringValue=JSON.stringify(value);if(stringValue===lastAppliedStringValue||stringValue===stringProps.value){return;} 2086lastAppliedStringValue=stringValue;inputsChanged=ensureArray(value).map(()=>false);await params.onApply?.(value);stringProps.value=stringValue;} 2087function enable(){for(const[el,value]of zip(getInputs(),ensureArray(pickerProps.value),true)){updateInput(el,value);if(el&&!el.disabled&&!el.readOnly&&!listenedElements.has(el)){listenedElements.add(el);el.addEventListener("change",onInputChange);el.addEventListener("click",onInputClick);el.addEventListener("focus",onInputFocus);el.addEventListener("keydown",onInputKeydown);}} 2088const calendarIconGroupEl=getInput(0)?.parentElement.querySelector(".o_input_group_date_icon");if(calendarIconGroupEl){calendarIconGroupEl.classList.add("cursor-pointer");calendarIconGroupEl.addEventListener("click",()=>open(0));} 2089return()=>{};} 2090function focusActiveInput(){const inputEl=getInput(pickerProps.focusedDateIndex);if(!inputEl){shouldFocus=true;return;} 2091const{activeElement}=inputEl.ownerDocument;if(activeElement!==inputEl){inputEl.focus();} 2092setInputFocus(inputEl);} 2093function getInput(valueIndex){const el=getInputs()[valueIndex];if(el?.isConnected){return el;} 2094return null;} 2095function getPopoverTarget(){const target=getTarget();if(target){return target;} 2096if(pickerProps.range){let parentElement=getInput(0).parentElement;const inputEls=getInputs();while(parentElement&&!inputEls.every((inputEl)=>parentElement.contains(inputEl))){parentElement=parentElement.parentElement;} 2097return parentElement||getInput(0);}else{return getInput(0);}} 2098function getTarget(){return targetRef?targetRef.el:params.target;} 2099function isOpen(){return popover.isOpen;} 2100function onInputChange(ev){updateValueFromInputs();inputsChanged[ev.target===getInput(1)?1:0]=true;if(!isOpen()||inputsChanged.every(Boolean)){saveAndClose();}} 2101function onInputClick({target}){open(target===getInput(1)?1:0);} 2102function onInputFocus({target}){pickerProps.focusedDateIndex=target===getInput(1)?1:0;setInputFocus(target);} 2103function onInputKeydown(ev){if(ev.key=="Enter"&&ev.ctrlKey){ev.preventDefault();updateValueFromInputs();return open(ev.target===getInput(1)?1:0);} 2104switch(ev.key){case"Enter":case"Escape":{return saveAndClose();}
2105case"Tab":{if(!getInput(0)||!getInput(1)||ev.target!==getInput(ev.shiftKey?1:0)){return saveAndClose();}}}} 2106function open(inputIndex){pickerProps.focusedDateIndex=inputIndex;if(!isOpen()){const popoverTarget=getPopoverTarget();if(ensureVisibility()){const{marginBottom}=popoverTarget.style;popoverTarget.style.marginBottom=`100vh`;popoverTarget.scrollIntoView(true);restoreTargetMargin=async()=>{popoverTarget.style.marginBottom=marginBottom;};} 2107for(const picker of dateTimePickerList){picker.close();} 2108popover.open(popoverTarget,{pickerProps});} 2109focusActiveInput();} 2110function safeConvert(operation,value){const{type}=pickerProps;const convertFn=(operation==="format"?formatters:parsers)[type];const options={tz:pickerProps.tz,format:params.format};if(operation==="format"){options.showSeconds=params.showSeconds??true;} 2111try{return[convertFn(value,options),null];}catch(error){if(error?.name==="ConversionError"){return[null,error];}else{throw error;}}} 2112function saveAndClose(){if(isOpen()){popover.close();}else{apply();}} 2113function setFocusClass(input){for(const el of getInputs()){if(el){el.classList.toggle(FOCUS_CLASSNAME,isOpen()&&el===input);}}} 2114function setInputFocus(inputEl){inputEl.selectionStart=0;inputEl.selectionEnd=inputEl.value.length;setFocusClass(inputEl);shouldFocus=false;} 2115function updateInput(el,value){if(!el){return;} 2116const[formattedValue]=safeConvert("format",value);el.value=formattedValue||"";} 2117function updateValue(value,unit,source){if(source==="input"&&areDatesEqual(pickerProps.value,value)){return;} 2118pickerProps.value=value;if(pickerProps.range&&unit!=="time"&&source==="picker"){if(!value[0]){pickerProps.focusedDateIndex=0;}else if(pickerProps.focusedDateIndex===0||(value[0]&&value[1]&&value[1]<value[0])){const{year,month,day}=value[pickerProps.focusedDateIndex];for(let i=0;i<value.length;i++){value[i]=value[i]&&value[i].set({year,month,day});} 2119pickerProps.focusedDateIndex=1;}else{pickerProps.focusedDateIndex=pickerProps.focusedDateIndex===1?0:1;}} 2120params.onChange?.(value);} 2121function updateValueFromInputs(){const values=zipWith(getInputs(),ensureArray(pickerProps.value),(el,currentValue)=>{if(!el||el.tagName?.toLowerCase()!=="input"){return currentValue;} 2122const[parsedValue,error]=safeConvert("parse",el.value);if(error){updateInput(el,currentValue);return currentValue;}else{return parsedValue;}});updateValue(values.length===2?values:values[0],"date","input");} 2123const createPopover=params.createPopover||function defaultCreatePopover(...args){return makePopover(popoverService.add,...args);};const ensureVisibility=params.ensureVisibility||function defaultEnsureVisibility(){return env.isSmall;};const getInputs=params.getInputs||function defaultGetInputs(){return[getTarget(),null];};const rawPickerProps={...DateTimePicker.defaultProps,onReset:()=>{updateValue(ensureArray(pickerProps.value).length===2?[false,false]:false,"date","picker");saveAndClose();},onSelect:(value,unit)=>{value&&=markRaw(value);updateValue(value,unit,"picker");if(!pickerProps.range&&pickerProps.type==="date"){saveAndClose();}},...markValuesRaw(params.pickerProps),};const pickerProps=reactive(rawPickerProps,()=>{for(const[el,value]of zip(getInputs(),ensureArray(pickerProps.value),true)){if(el){updateInput(el,value);if(!isOpen()){apply();}}} 2124shouldFocus=true;});const popover=createPopover(DateTimePickerPopover,{async onClose(){updateValueFromInputs();setFocusClass(null);restoreTargetMargin?.();restoreTargetMargin=null;await apply();params.onClose?.();},});let inputsChanged=[];let lastAppliedStringValue="";let restoreTargetMargin=null;let shouldFocus=false;let stringProps={};let targetRef=null;if(params.useOwlHooks){if(typeof params.target==="string"){targetRef=useRef(params.target);} 2125onWillRender(function computeBasePickerProps(){const nextProps=markValuesRaw(params.pickerProps);const oldStringProps=stringProps;stringProps=stringifyProps(nextProps);lastAppliedStringValue=stringProps.value;if(shallowEqual(oldStringProps,stringProps)){return;} 2126inputsChanged=ensureArray(nextProps.value).map(()=>false);for(const[key,value]of Object.entries(nextProps)){if(!areDatesEqual(pickerProps[key],value)){pickerProps[key]=value;}}});
2126useEffect(enable,getInputs);onPatched(function focusIfNeeded(){if(isOpen()&&shouldFocus){focusActiveInput();}});}else if(typeof params.target==="string"){throw new Error(`datetime picker service error: cannot use target as ref name when not using Owl hooks`);} 2127const picker={enable,disable:()=>dateTimePickerList.delete(picker),isOpen,open,close:()=>popover.close(),state:pickerProps,};dateTimePickerList.add(picker);return picker;},};},};registry.category("services").add("datetime_picker",datetimePickerService);return __exports;});; 2128 2129/* /web/static/src/core/debug/debug_context.js */ 2130odoo.define('@web/core/debug/debug_context',['@web/core/user','@web/core/registry','@odoo/owl'],function(require){'use strict';let __exports={};const{user}=require("@web/core/user");const{registry}=require("@web/core/registry");const{useEffect,useEnv,useSubEnv}=require("@odoo/owl");const debugRegistry=registry.category("debug");const getAccessRights=async()=>{const rightsToCheck={"ir.ui.view":"write","ir.rule":"read","ir.model.access":"read",};const proms=Object.entries(rightsToCheck).map(([model,operation])=>{return user.checkAccessRight(model,operation);});const[canEditView,canSeeRecordRules,canSeeModelAccess]=await Promise.all(proms);const accessRights={canEditView,canSeeRecordRules,canSeeModelAccess};return accessRights;};class DebugContext{constructor(defaultCategories){this.categories=new Map(defaultCategories.map((cat)=>[cat,[{}]]));} 2131activateCategory(category,context){const contexts=this.categories.get(category)||new Set();contexts.add(context);this.categories.set(category,contexts);return()=>{contexts.delete(context);if(contexts.size===0){this.categories.delete(category);}};} 2132async getItems(env){const accessRights=await getAccessRights();return[...this.categories.entries()].flatMap(([category,contexts])=>{return debugRegistry.category(category).getAll().map((factory)=>factory(Object.assign({env,accessRights},...contexts)));}).filter(Boolean).sort((x,y)=>{const xSeq=x.sequence||1000;const ySeq=y.sequence||1000;return xSeq-ySeq;});}} 2133const debugContextSymbol=Symbol("debugContext");__exports.createDebugContext=createDebugContext;function createDebugContext({categories=[]}={}){return{[debugContextSymbol]:new DebugContext(categories)};} 2134__exports.useOwnDebugContext=useOwnDebugContext;function useOwnDebugContext({categories=[]}={}){useSubEnv(createDebugContext({categories}));} 2135__exports.useEnvDebugContext=useEnvDebugContext;function useEnvDebugContext(){const debugContext=useEnv()[debugContextSymbol];if(!debugContext){throw new Error("There is no debug context available in the current environment.");} 2136return debugContext;} 2137__exports.useDebugCategory=useDebugCategory;function useDebugCategory(category,context={}){const env=useEnv();if(env.debug){const debugContext=useEnvDebugContext();useEffect(()=>debugContext.activateCategory(category,context),()=>[]);}} 2138return __exports;});; 2139 2140/* /web/static/src/core/debug/debug_menu.js */ 2141odoo.define('@web/core/debug/debug_menu',['@web/core/l10n/translation','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/debug/debug_menu_basic','@web/core/commands/command_hook','@web/core/utils/hooks','@web/core/debug/debug_context'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{DebugMenuBasic}=require("@web/core/debug/debug_menu_basic");const{useCommand}=require("@web/core/commands/command_hook");const{useService}=require("@web/core/utils/hooks");const{useEnvDebugContext}=require("@web/core/debug/debug_context");const DebugMenu=__exports.DebugMenu=class DebugMenu extends DebugMenuBasic{static components={Dropdown,DropdownItem};static props={};setup(){super.setup();const debugContext=useEnvDebugContext();this.command=useService("command");useCommand(_t("Debug tools..."),async()=>{const items=await debugContext.getItems(this.env);let index=0;const defaultCategories=items.filter((item)=>item.type==="separator").map(()=>(index+=1));const provider={async provide(){const categories=[...defaultCategories];let category=categories.shift();const result=[];
2141items.forEach((item)=>{if(item.type==="item"){result.push({name:item.description.toString(),action:item.callback,category,});}else if(item.type==="separator"){category=categories.shift();}});return result;},};const configByNamespace={default:{categories:defaultCategories,emptyMessage:_t("No debug command found"),placeholder:_t("Choose a debug command..."),},};const commandPaletteConfig={configByNamespace,providers:[provider],};return commandPaletteConfig;},{category:"debug",});}} 2142return __exports;});; 2143 2144/* /web/static/src/core/debug/debug_menu_basic.js */ 2145odoo.define('@web/core/debug/debug_menu_basic',['@web/core/debug/debug_context','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/l10n/translation','@web/core/utils/arrays','@odoo/owl','@web/core/registry'],function(require){'use strict';let __exports={};const{useEnvDebugContext}=require("@web/core/debug/debug_context");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{groupBy,sortBy}=require("@web/core/utils/arrays");const{Component}=require("@odoo/owl");const{registry}=require("@web/core/registry");const debugSectionRegistry=registry.category("debug_section");debugSectionRegistry.add("record",{label:_t("Record"),sequence:10}).add("records",{label:_t("Records"),sequence:10}).add("ui",{label:_t("User Interface"),sequence:20}).add("security",{label:_t("Security"),sequence:30}).add("testing",{label:_t("Tours & Testing"),sequence:40}).add("tools",{label:_t("Tools"),sequence:50});const DebugMenuBasic=__exports.DebugMenuBasic=class DebugMenuBasic extends Component{static template="web.DebugMenu";static components={Dropdown,DropdownItem,};static props={};setup(){this.debugContext=useEnvDebugContext();} 2146async loadGroupedItems(){const items=await this.debugContext.getItems(this.env);const sections=groupBy(items,(item)=>item.section||"");this.sectionEntries=sortBy(Object.entries(sections),([section])=>debugSectionRegistry.get(section,{sequence:50}).sequence);} 2147getSectionLabel(section){return debugSectionRegistry.get(section,{label:section}).label;}} 2148return __exports;});; 2149 2150/* /web/static/src/core/debug/debug_menu_items.js */ 2151odoo.define('@web/core/debug/debug_menu_items',['@web/core/l10n/translation','@web/core/browser/browser','@web/core/browser/router','@web/core/registry','@web/core/user'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{browser}=require("@web/core/browser/browser");const{router}=require("@web/core/browser/router");const{registry}=require("@web/core/registry");const{user}=require("@web/core/user");function activateTestsAssetsDebugging({env}){if(String(router.current.debug).includes("tests")){return;} 2152return{type:"item",description:_t("Activate Test Mode"),callback:()=>{router.pushState({debug:"assets,tests"},{reload:true});},sequence:580,section:"tools",};} 2153__exports.regenerateAssets=regenerateAssets;function regenerateAssets({env}){return{type:"item",description:_t("Regenerate Assets"),callback:async()=>{await env.services.orm.call("ir.attachment","regenerate_assets_bundles");browser.location.reload();},sequence:550,section:"tools",};} 2154__exports.becomeSuperuser=becomeSuperuser;function becomeSuperuser({env}){const becomeSuperuserURL=browser.location.origin+"/web/become";if(!user.isAdmin){return false;} 2155return{type:"item",description:_t("Become Superuser"),href:becomeSuperuserURL,callback:()=>{browser.open(becomeSuperuserURL,"_self");},sequence:560,section:"tools",};} 2156function leaveDebugMode(){return{type:"item",description:_t("Leave Debug Mode"),callback:()=>{router.pushState({debug:0},{reload:true});},sequence:650,};} 2157registry.category("debug").category("default").add("regenerateAssets",regenerateAssets).add("becomeSuperuser",becomeSuperuser).add("activateTestsAssetsDebugging",activateTestsAssetsDebugging).add("leaveDebugMode",leaveDebugMode);return __exports;});; 2158 2159/* /web/static/src/core/debug/debug_providers.js */ 2160odoo.define('@web/core/debug/debug_providers',['@web/core/l10n/translation','@web/core/registry','@web/core/browser/browser','@web/core/browser/router'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{browser}=require("@web/core/browser/browser");const{router}=require("@web/core/browser/router");
2160const commandProviderRegistry=registry.category("command_provider");commandProviderRegistry.add("debug",{provide:(env,options)=>{const result=[];if(env.debug){if(!env.debug.includes("assets")){result.push({action(){router.pushState({debug:"assets"},{reload:true});},category:"debug",name:_t("Activate debug mode (with assets)"),});} 2161result.push({action(){router.pushState({debug:0},{reload:true});},category:"debug",name:_t("Deactivate debug mode"),});result.push({action(){browser.open("/web/tests?debug=assets");},category:"debug",name:_t("Run Unit Tests"),});}else{const debugKey="debug";if(options.searchValue.toLowerCase()===debugKey){result.push({action(){router.pushState({debug:"1"},{reload:true});},category:"debug",name:`${_t("Activate debug mode")} (${debugKey})`,});result.push({action(){router.pushState({debug:"assets"},{reload:true});},category:"debug",name:`${_t("Activate debug mode (with assets)")} (${debugKey})`,});}} 2162return result;},});return __exports;});; 2163 2164/* /web/static/src/core/debug/debug_utils.js */ 2165odoo.define('@web/core/debug/debug_utils',[],function(require){'use strict';let __exports={};__exports.editModelDebug=editModelDebug;function editModelDebug(env,title,model,id){return env.services.action.doAction({res_model:model,res_id:id,name:title,type:"ir.actions.act_window",views:[[false,"form"]],view_mode:"form",target:"current",});} 2166return __exports;});; 2167 2168/* /web/static/src/core/dialog/dialog.js */
2169odoo.define('@web/core/dialog/dialog',['@web/core/hotkeys/hotkey_hook','@web/core/ui/ui_service','@web/core/utils/hooks','@odoo/owl','@web/core/utils/timing','@web/core/utils/draggable_hook_builder_owl','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{useActiveElement}=require("@web/core/ui/ui_service");const{useForwardRefToParent}=require("@web/core/utils/hooks");const{Component,onWillDestroy,useChildSubEnv,useExternalListener,useState}=require("@odoo/owl");const{throttleForAnimation}=require("@web/core/utils/timing");const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const{hasTouch}=require("@web/core/browser/feature_detection");const useDialogDraggable=makeDraggableHook({name:"useDialogDraggable",onWillStartDrag({ctx,addCleanup,addStyle,getRect}){const{height,width}=getRect(ctx.current.element);ctx.current.container=document.createElement("div");addStyle(ctx.current.container,{position:"fixed",top:"0",bottom:`${70 - height}px`,left:`${70 - width}px`,right:`${70 - width}px`,});ctx.current.element.after(ctx.current.container);addCleanup(()=>ctx.current.container.remove());},onDrop({ctx,getRect}){const{top,left}=getRect(ctx.current.element);return{left:left-ctx.current.elementRect.left,top:top-ctx.current.elementRect.top,};},});const Dialog=__exports.Dialog=class Dialog extends Component{static template="web.Dialog";static props={contentClass:{type:String,optional:true},bodyClass:{type:String,optional:true},fullscreen:{type:Boolean,optional:true},footer:{type:Boolean,optional:true},header:{type:Boolean,optional:true},size:{type:String,optional:true,validate:(s)=>["sm","md","lg","xl","fs","fullscreen"].includes(s),},technical:{type:Boolean,optional:true},title:{type:String,optional:true},modalRef:{type:Function,optional:true},slots:{type:Object,shape:{default:Object,header:{type:Object,optional:true},footer:{type:Object,optional:true},},},withBodyPadding:{type:Boolean,optional:true},onExpand:{type:Function,optional:true},};static defaultProps={contentClass:"",bodyClass:"",fullscreen:false,footer:true,header:true,size:"lg",technical:true,title:"Odoo",withBodyPadding:true,};setup(){this.modalRef=useForwardRefToParent("modalRef");useActiveElement("modalRef");this.data=useState(this.env.dialogData);useHotkey("escape",()=>this.onEscape());useHotkey("control+enter",()=>{const btns=document.querySelectorAll(".o_dialog:not(.o_inactive_modal) .modal-footer button");const firstVisibleBtn=Array.from(btns).find((btn)=>{const styles=getComputedStyle(btn);return styles.display!=="none";});if(firstVisibleBtn){firstVisibleBtn.click();}},{bypassEditableProtection:true});this.id=`dialog_${this.data.id}`;useChildSubEnv({inDialog:true,dialogId:this.id});this.isMovable=this.props.header;if(this.isMovable){this.position=useState({left:0,top:0});useDialogDraggable({enable:()=>!this.env.isSmall,ref:this.modalRef,elements:".modal-content",handle:".modal-header",ignore:"button, input",edgeScrolling:{enabled:false},onDrop:({top,left})=>{this.position.left+=left;this.position.top+=top;},});const throttledResize=throttleForAnimation(this.onResize.bind(this));useExternalListener(window,"resize",throttledResize);} 2170onWillDestroy(()=>{if(this.env.isSmall){this.data.scrollToOrigin();}});this.bodyTabIndex=hasTouch()?"0":undefined;} 2171get isFullscreen(){return this.props.fullscreen||this.env.isSmall;} 2172get contentStyle(){if(this.isMovable){return`top: ${this.position.top}px; left: ${this.position.left}px;`;} 2173return"";} 2174onResize(){this.position.left=0;this.position.top=0;} 2175onEscape(){return this.dismiss();} 2176async dismiss(){if(this.data.dismiss){await this.data.dismiss();} 2177return this.data.close({dismiss:true});}} 2178return __exports;});; 2179 2180/* /web/static/src/core/dialog/dialog_service.js */ 2181odoo.define('@web/core/dialog/dialog_service',['@odoo/owl','@web/core/registry'],function(require){'use strict';let __exports={};const{Component,markRaw,reactive,useChildSubEnv,xml}=require("@odoo/owl");const{registry}=require("@web/core/registry");class DialogWrapper extends Component{static template=xml`<t t-component="props.subComponent" t-props="props.subProps" />`;static props=["*"];setup(){useChildSubEnv({dialogData:this.props.subEnv});}} 2182const dialogService=__exports.dialogService={dependencies:["overlay"],start(env,{overlay}){const stack=[];let nextId=0;const deactivate=()=>{for(const subEnv of stack){subEnv.isActive=false;}};const add=(dialogClass,props,options={})=>{const id=nextId++;const close=(params)=>remove(params);const subEnv=reactive({id,close,isActive:true,});deactivate();stack.push(subEnv);document.body.classList.add("modal-open");let isBeingClosed=false;const scrollOrigin={top:window.scrollY,left:window.scrollX};subEnv.scrollToOrigin=()=>
2182{if(!stack.length){window.scrollTo(scrollOrigin);}};const remove=overlay.add(DialogWrapper,{subComponent:dialogClass,subProps:markRaw({...props,close}),subEnv,},{onRemove:async(closeParams)=>{if(isBeingClosed){return;} 2183isBeingClosed=true;await options.onClose?.(closeParams);stack.splice(stack.findIndex((d)=>d.id===id),1);deactivate();if(stack.length){stack.at(-1).isActive=true;}else{document.body.classList.remove("modal-open");}},rootId:options.context?.root?.el?.getRootNode()?.host?.id,});return remove;};function closeAll(params){for(const dialog of[...stack].reverse()){dialog.close(params);}} 2184return{add,closeAll};},};registry.category("services").add("dialog",dialogService);return __exports;});; 2185 2186/* /web/static/src/core/domain.js */ 2187odoo.define('@web/core/domain',['@web/core/utils/arrays','@web/core/py_js/py','@web/core/py_js/py_utils','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{shallowEqual}=require("@web/core/utils/arrays");const{evaluate,formatAST,parseExpr}=require("@web/core/py_js/py");const{toPyValue}=require("@web/core/py_js/py_utils");const{escapeRegExp}=require("@web/core/utils/strings");const InvalidDomainError=__exports.InvalidDomainError=class InvalidDomainError extends Error{} 2188const Domain=__exports.Domain=class Domain{static combine(domains,operator){if(domains.length===0){return new Domain([]);} 2189const domain1=domains[0]instanceof Domain?domains[0]:new Domain(domains[0]);if(domains.length===1){return domain1;} 2190const domain2=Domain.combine(domains.slice(1),operator);const result=new Domain([]);const astValues1=domain1.ast.value;const astValues2=domain2.ast.value;const op=operator==="AND"?"&":"|";const combinedAST={type:4,value:astValues1.concat(astValues2)};result.ast=normalizeDomainAST(combinedAST,op);return result;} 2191static and(domains){return Domain.combine(domains,"AND");} 2192static or(domains){return Domain.combine(domains,"OR");} 2193static not(domain){const result=new Domain(domain);result.ast.value.unshift({type:1,value:"!"});return result;} 2194static removeDomainLeaves(domain,keysToRemove){function processLeaf(elements,idx,operatorCtx,newDomain){const leaf=elements[idx];if(leaf.type===10){if(keysToRemove.includes(leaf.value[0].value)){if(operatorCtx==="&"){newDomain.ast.value.push(...Domain.TRUE.ast.value);}else if(operatorCtx==="|"){newDomain.ast.value.push(...Domain.FALSE.ast.value);}}else{newDomain.ast.value.push(leaf);} 2195return 1;}else if(leaf.type===1){if(leaf.value==="|"&&elements[idx+1].type===10&&elements[idx+2].type===10&&keysToRemove.includes(elements[idx+1].value[0].value)&&keysToRemove.includes(elements[idx+2].value[0].value)){newDomain.ast.value.push(...Domain.TRUE.ast.value);return 3;} 2196newDomain.ast.value.push(leaf);if(leaf.value==="!"){return 1+processLeaf(elements,idx+1,"&",newDomain);} 2197const firstLeafSkip=processLeaf(elements,idx+1,leaf.value,newDomain);const secondLeafSkip=processLeaf(elements,idx+1+firstLeafSkip,leaf.value,newDomain);return 1+firstLeafSkip+secondLeafSkip;} 2198return 0;} 2199domain=new Domain(domain);if(domain.ast.value.length===0){return domain;} 2200const newDomain=new Domain([]);processLeaf(domain.ast.value,0,"&",newDomain);return newDomain;} 2201constructor(descr=[]){if(descr instanceof Domain){return new Domain(descr.toString());}else{let rawAST;try{rawAST=typeof descr==="string"?parseExpr(descr):toAST(descr);}catch(error){throw new InvalidDomainError(`Invalid domain representation: ${descr.toString()}`,{cause:error,});} 2202this.ast=normalizeDomainAST(rawAST);}} 2203contains(record){const expr=evaluate(this.ast,record);return matchDomain(record,expr);} 2204toString(){return formatAST(this.ast);} 2205toList(context){return evaluate(this.ast,context);} 2206toJson(){try{const evaluatedAsList=this.toList({});const evaluatedDomain=new Domain(evaluatedAsList);if(evaluatedDomain.toString()===this.toString()){return evaluatedAsList;} 2207return this.toString();}catch{return this.toString();}}} 2208const TRUE_LEAF=[1,"=",1];const FALSE_LEAF=[0,"=",1];const TRUE_DOMAIN=new Domain([TRUE_LEAF]);const FALSE_DOMAIN=new Domain([FALSE_LEAF]);Domain.TRUE=TRUE_DOMAIN;Domain.FALSE=FALSE_DOMAIN;function toAST(domain){const elems=domain.map((elem)=>{switch(elem){case"!":case"&":case"|":return{type:1,value:elem};default:return{type:10,value:elem.map(toPyValue),};}});return{type:4,value:elems};}
2209function normalizeDomainAST(domain,op="&"){if(domain.type!==4){if(domain.type===10){const value=domain.value;if(value.findIndex((e)=>e.type===10)===-1||!value.every((e)=>e.type===10||e.type===1)){throw new InvalidDomainError("Invalid domain AST");}}else{throw new InvalidDomainError("Invalid domain AST");}} 2210if(domain.value.length===0){return domain;} 2211let expected=1;for(const child of domain.value){switch(child.type){case 1:if(child.value==="&"||child.value==="|"){expected++;}else if(child.value!=="!"){throw new InvalidDomainError("Invalid domain AST");} 2212break;case 4:case 10:if(child.value.length===3){expected--;break;} 2213throw new InvalidDomainError("Invalid domain AST");default:throw new InvalidDomainError("Invalid domain AST");}} 2214const values=domain.value.slice();while(expected<0){expected++;values.unshift({type:1,value:op});} 2215if(expected>0){throw new InvalidDomainError(`invalid domain ${formatAST(domain)} (missing ${expected} segment(s))`);} 2216return{type:4,value:values};} 2217function matchCondition(record,condition){if(typeof condition==="boolean"){return condition;} 2218const[field,operator,value]=condition;if(typeof field==="string"){const names=field.split(".");if(names.length>=2){return matchCondition(record[names[0]],[names.slice(1).join("."),operator,value]);}} 2219let likeRegexp,ilikeRegexp;if(["like","not like","ilike","not ilike"].includes(operator)){likeRegexp=new RegExp(`(.*)${escapeRegExp(value).replaceAll("%", "(.*)")}(.*)`,"g");ilikeRegexp=new RegExp(`(.*)${escapeRegExp(value).replaceAll("%", "(.*)")}(.*)`,"gi");} 2220const fieldValue=typeof field==="number"?field:record[field];const isNot=operator.startsWith("not ");switch(operator){case"=?":if([false,null].includes(value)){return true;} 2221case"=":case"==":if(Array.isArray(fieldValue)&&Array.isArray(value)){return shallowEqual(fieldValue,value);} 2222return fieldValue===value;case"!=":case"<>":return!matchCondition(record,[field,"=",value]);case"<":return fieldValue<value;case"<=":return fieldValue<=value;case">":return fieldValue>value;case">=":return fieldValue>=value;case"in":case"not in":{const val=Array.isArray(value)?value:[value];const fieldVal=Array.isArray(fieldValue)?fieldValue:[fieldValue];return Boolean(fieldVal.some((fv)=>val.includes(fv)))!=isNot;} 2223case"like":case"not like":if(fieldValue===false){return isNot;} 2224return Boolean(fieldValue.match(likeRegexp))!=isNot;case"=like":case"not =like":if(fieldValue===false){return isNot;} 2225return(Boolean(new RegExp(escapeRegExp(value).replace(/%/g,".*")).test(fieldValue))!=isNot);case"ilike":case"not ilike":if(fieldValue===false){return isNot;} 2226return Boolean(fieldValue.match(ilikeRegexp))!=isNot;case"=ilike":case"not =ilike":if(fieldValue===false){return isNot;} 2227return(Boolean(new RegExp(escapeRegExp(value).replace(/%/g,".*"),"i").test(fieldValue))!=isNot);case"any":case"not any":return true;case"child_of":case"parent_of":return true;} 2228throw new InvalidDomainError("could not match domain");} 2229function makeOperators(record){const match=matchCondition.bind(null,record);return{"!":(x)=>!match(x),"&":(a,b)=>match(a)&&match(b),"|":(a,b)=>match(a)||match(b),};} 2230function matchDomain(record,domain){if(domain.length===0){return true;} 2231const operators=makeOperators(record);const reversedDomain=Array.from(domain).reverse();const condStack=[];for(const item of reversedDomain){const operator=typeof item==="string"&&operators[item];if(operator){const operands=condStack.splice(-operator.length);condStack.push(operator(...operands));}else{condStack.push(item);}} 2232return matchCondition(record,condStack.pop());} 2233return __exports;});; 2234 2235/* /web/static/src/core/domain_selector/domain_selector.js */ 2236odoo.define('@web/core/domain_selector/domain_selector',['@odoo/owl','@web/core/checkbox/checkbox','@web/core/domain','@web/core/domain_selector/domain_selector_operator_editor','@web/core/l10n/translation','@web/core/model_field_selector/model_field_selector','@web/core/tree_editor/condition_tree','@web/core/tree_editor/domain_from_tree','@web/core/tree_editor/tree_editor','@web/core/tree_editor/tree_editor_operator_editor','@web/core/utils/hooks','@web/core/domain_selector/utils'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{CheckBox}=require("@web/core/checkbox/checkbox");const{Domain}=require("@web/core/domain");const{getDomainDisplayedOperators}=require("@web/core/domain_selector/domain_selector_operator_editor");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{ModelFieldSelector}=require("@web/core/model_field_selector/model_field_selector");const{areEqualTrees,condition,connector,formatValue,}=require("@web/core/tree_editor/condition_tree");const{domainFromTree}=require("@web/core/tree_editor/domain_from_tree");const{TreeEditor}=require("@web/core/tree_editor/tree_editor");const{getOperatorEditorInfo}=require("@web/core/tree_editor/tree_editor_operator_editor");const{useService}=require("@web/core/utils/hooks");const{getDefaultCondition}=require("@web/core/domain_selector/utils");const ARCHIVED_CONDITION=condition("active","in",[true,false]);const ARCHIVED_DOMAIN=`[("active", "in", [True, False])]`;const DomainSelector=__exports.DomainSelector=class DomainSelector extends Component{static template="web.DomainSelector";static components={TreeEditor,CheckBox};static props={domain:String,resModel:String,className:{type:String,optional:true},defaultConnector:{type:[{value:"&"},{value:"|"}],optional:true},isDebugMode:{type:Boolean,optional:true},readonly:{type:Boolean,optional:true},update:{type:Function,optional:true},debugUpdate:{type:Function,optional:true},};static defaultProps={isDebugMode:false,readonly:true,update:()=>{},};setup(){this.fieldService=useService("field");this.treeProcessor=useService("tree_processor");this.tree=null;this.showArchivedCheckbox=false;this.includeArchived=false;onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((np)=>this.onPropsUpdated(np));} 2237async onPropsUpdated(p){let domain;let isSupported=true;try{domain=new Domain(p.domain);}catch{isSupported=false;} 2238if(!isSupported){this.tree=null;this.showArchivedCheckbox=false;this.includeArchived=false;return;} 2239const[tree,{fieldDef:activeFieldDef}]=await Promise.all([this.treeProcessor.treeFromDomain(p.resModel,domain,!p.isDebugMode),this.fieldService.loadFieldInfo(p.resModel,"active"),]);this.tree=tree;this.showArchivedCheckbox=this.getShowArchivedCheckBox(Boolean(activeFieldDef),p);this.includeArchived=false;if(this.showArchivedCheckbox){if(this.tree.type==="connector"&&this.tree.value==="&"){this.tree.children=this.tree.children.filter((child)=>
2239{if(areEqualTrees(child,ARCHIVED_CONDITION)){this.includeArchived=true;return false;} 2240return true;});if(this.tree.children.length===1){this.tree=this.tree.children[0];}}else if(areEqualTrees(this.tree,ARCHIVED_CONDITION)){this.includeArchived=true;this.tree=connector("&");}}} 2241getShowArchivedCheckBox(hasActiveField,props){return hasActiveField;} 2242getDefaultCondition(fieldDefs){return getDefaultCondition(fieldDefs);} 2243getDefaultOperator(fieldDef){return getDomainDisplayedOperators(fieldDef)[0];} 2244getOperatorEditorInfo(fieldDef){const operators=getDomainDisplayedOperators(fieldDef);return getOperatorEditorInfo(operators,fieldDef);} 2245getPathEditorInfo(resModel,defaultCondition){const{isDebugMode}=this.props;return{component:ModelFieldSelector,extractProps:({update,value:path})=>({path,update,resModel,isDebugMode,readonly:false,}),isSupported:(path)=>[0,1].includes(path)||typeof path==="string",defaultValue:()=>defaultCondition.path,stringify:(path)=>formatValue(path),message:_t("Invalid field chain"),};} 2246toggleIncludeArchived(){this.includeArchived=!this.includeArchived;this.update(this.tree);} 2247resetDomain(){this.props.update("[]");} 2248onDomainInput(domain){if(this.props.debugUpdate){this.props.debugUpdate(domain);}} 2249onDomainChange(domain){this.props.update(domain,true);} 2250update(tree){const archiveDomain=this.includeArchived?ARCHIVED_DOMAIN:`[]`;const domain=tree?Domain.and([domainFromTree(tree),archiveDomain]).toString():archiveDomain;this.props.update(domain);}} 2251return __exports;});; 2252 2253/* /web/static/src/core/domain_selector/domain_selector_operator_editor.js */ 2254odoo.define('@web/core/domain_selector/domain_selector_operator_editor',[],function(require){'use strict';let __exports={};__exports.getDomainDisplayedOperators=getDomainDisplayedOperators;function getDomainDisplayedOperators(fieldDef){if(!fieldDef){fieldDef={};} 2255const{type,is_property}=fieldDef;if(is_property){switch(type){case"many2many":case"tags":return["in","not in","set","not set"];case"many2one":case"selection":return["=","!=","set","not set"];}} 2256switch(type){case"boolean":return["set","not set"];case"selection":return["=","!=","in","not in","set","not set"];case"char":case"text":case"html":return["=","!=","ilike","not ilike","starts with","set","not set"];case"date":case"datetime":return["in range","=","<",">","set","not set"];case"integer":case"float":case"monetary":return["=","!=","<",">","between"];case"many2one":case"many2many":case"one2many":return["in","not in","ilike","not ilike","set","not set"];case"json":return["=","!=","ilike","not ilike","set","not set"];case"binary":case"properties":return["set","not set"];case undefined:return["="];default:return["=","!=","<",">","ilike","not ilike","like","not like","=like","=ilike","in","not in","set","not set",];}} 2257return __exports;});; 2258 2259/* /web/static/src/core/domain_selector/utils.js */ 2260odoo.define('@web/core/domain_selector/utils',['@web/core/domain_selector/domain_selector_operator_editor','@web/core/tree_editor/condition_tree','@web/core/tree_editor/domain_from_tree','@web/core/tree_editor/tree_editor_value_editors','@web/core/tree_editor/utils','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{getDomainDisplayedOperators}=require("@web/core/domain_selector/domain_selector_operator_editor");const{condition}=require("@web/core/tree_editor/condition_tree");const{domainFromTree}=require("@web/core/tree_editor/domain_from_tree");const{getDefaultValue}=require("@web/core/tree_editor/tree_editor_value_editors");const{getDefaultPath}=require("@web/core/tree_editor/utils");const{useService}=require("@web/core/utils/hooks");__exports.getDefaultCondition=getDefaultCondition;function getDefaultCondition(fieldDefs){const defaultPath=getDefaultPath(fieldDefs);const fieldDef=fieldDefs[defaultPath];const operator=getDomainDisplayedOperators(fieldDef)[0];const value=getDefaultValue(fieldDef,operator);return condition(fieldDef.name,operator,value);} 2261__exports.getDefaultDomain=getDefaultDomain;function getDefaultDomain(fieldDefs){return domainFromTree(getDefaultCondition(fieldDefs));} 2262__exports.useGetDefaultLeafDomain=useGetDefaultLeafDomain;function useGetDefaultLeafDomain(){const fieldService=useService("field");return async(resModel)=>{const fieldDefs=await fieldService.loadFields(resModel);return getDefaultDomain(fieldDefs);};} 2263return __exports;});; 2264 2265/* /web/static/src/core/domain_selector_dialog/domain_selector_dialog.js */ 2266odoo.define('@web/core/domain_selector_dialog/domain_selector_dialog',['@web/core/l10n/translation','@odoo/owl','@web/core/dialog/dialog','@web/core/domain','@web/core/domain_selector/domain_selector','@web/core/network/rpc','@web/core/utils/hooks','@web/core/user'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{Component,useRef,useState}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{Domain}=require("@web/core/domain");const{DomainSelector}=require("@web/core/domain_selector/domain_selector");const{rpc}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const{user}=require("@web/core/user");const DomainSelectorDialog=__exports.DomainSelectorDialog=class DomainSelectorDialog extends Component{static template="web.DomainSelectorDialog";static components={Dialog,DomainSelector,};static props={close:Function,onConfirm:Function,resModel:String,className:{type:String,optional:true},defaultConnector:{type:[{value:"&"},{value:"|"}],optional:true},domain:String,isDebugMode:{type:Boolean,optional:true},readonly:{type:Boolean,optional:true},text:{type:String,optional:true},confirmButtonText:{type:String,optional:true},disableConfirmButton:{type:Function,optional:true},discardButtonText:{type:String,optional:true},title:{type:String,optional:true},context:{type:Object,optional:true},};static defaultProps={isDebugMode:false,readonly:false,context:{},};setup(){this.notification=useService("notification");this.orm=useService("orm");this.state=useState({domain:this.props.domain});this.confirmButtonRef=useRef("confirm");} 2267get confirmButtonText(){return this.props.confirmButtonText||_t("Confirm");} 2268get dialogTitle(){return this.props.title||_t("Domain");} 2269get disabled(){if(this.props.disableConfirmButton){return this.props.disableConfirmButton(this.state.domain);} 2270return false;} 2271get discardButtonText(){return this.props.discardButtonText||_t("Discard");} 2272get domainSelectorProps(){return{className:this.props.className,resModel:this.props.resModel,readonly:this.props.readonly,isDebugMode:this.props.isDebugMode,defaultConnector:this.props.defaultConnector,domain:this.state.domain,update:(domain)=>{this.state.domain=domain;},};} 2273async onConfirm(){this.confirmButtonRef.el.disabled=true;let domain;let isValid;try{const evalContext={...user.context,...this.props.context};domain=new Domain(this.state.domain).toList(evalContext);}catch{isValid=false;}
2274if(isValid===undefined){isValid=await rpc("/web/domain/validate",{model:this.props.resModel,domain,});} 2275if(!isValid){if(this.confirmButtonRef.el){this.confirmButtonRef.el.disabled=false;} 2276this.notification.add(_t("Domain is invalid. Please correct it"),{type:"danger",});return;} 2277this.props.onConfirm(this.state.domain);this.props.close();} 2278onDiscard(){this.props.close();}} 2279return __exports;});; 2280 2281/* /web/static/src/core/dropdown/_behaviours/dropdown_group_hook.js */ 2282odoo.define('@web/core/dropdown/_behaviours/dropdown_group_hook',['@odoo/owl','@web/core/dropdown/dropdown_group'],function(require){'use strict';let __exports={};const{useComponent,useEffect,useEnv}=require("@odoo/owl");const{DROPDOWN_GROUP}=require("@web/core/dropdown/dropdown_group");__exports.useDropdownGroup=useDropdownGroup;function useDropdownGroup(){const env=useEnv();const group={isInGroup:DROPDOWN_GROUP in env,get isOpen(){return this.isInGroup&&[...env[DROPDOWN_GROUP]].some((dropdown)=>dropdown.isOpen);},};if(group.isInGroup){const dropdown=useComponent();useEffect(()=>{env[DROPDOWN_GROUP].add(dropdown.state);return()=>env[DROPDOWN_GROUP].delete(dropdown.state);});} 2283return group;} 2284return __exports;});; 2285 2286/* /web/static/src/core/dropdown/_behaviours/dropdown_nesting.js */ 2287odoo.define('@web/core/dropdown/_behaviours/dropdown_nesting',['@odoo/owl','@web/core/l10n/localization','@web/core/utils/hooks','@web/core/utils/reactive'],function(require){'use strict';let __exports={};const{EventBus,onWillDestroy,useChildSubEnv,useEffect,useEnv}=require("@odoo/owl");const{localization}=require("@web/core/l10n/localization");const{useBus,useService}=require("@web/core/utils/hooks");const{effect}=require("@web/core/utils/reactive");const DROPDOWN_NESTING=__exports.DROPDOWN_NESTING=Symbol("dropdownNesting");const BUS=new EventBus();class DropdownNestingState{constructor({parent,close}){this._isOpen=false;this.parent=parent;this.children=new Set();this.close=close;parent?.children.add(this);} 2288set isOpen(value){this._isOpen=value;if(this._isOpen){BUS.trigger("dropdown-opened",this);}} 2289get isOpen(){return this._isOpen;} 2290remove(){this.parent?.children.delete(this);} 2291closeAllParents(){this.close();if(this.parent){this.parent.closeAllParents();}} 2292closeChildren(){this.children.forEach((child)=>child.close());} 2293shouldIgnoreChanges(other){return(other===this||other.activeEl!==this.activeEl||[...this.children].some((child)=>child.shouldIgnoreChanges(other)));} 2294handleChange(other){if(this.shouldIgnoreChanges(other)){return;} 2295if(other.isOpen&&this.isOpen){this.close();}}} 2296__exports.useDropdownNesting=useDropdownNesting;function useDropdownNesting(state){const env=useEnv();const current=new DropdownNestingState({parent:env[DROPDOWN_NESTING],close:()=>state.close(),});const uiService=useService("ui");useEffect(()=>{Promise.resolve().then(()=>{current.activeEl=uiService.activeElement;});},()=>[]);useChildSubEnv({[DROPDOWN_NESTING]:current});useBus(BUS,"dropdown-opened",({detail:other})=>current.handleChange(other));effect((state)=>{current.isOpen=state.isOpen;},[state]);onWillDestroy(()=>{current.remove();});const isDropdown=(target)=>target&&target.classList.contains("o-dropdown");const isRTL=()=>localization.direction==="rtl";return{get hasParent(){return Boolean(current.parent);},navigationOptions:{onUpdated:(navigator)=>{if(current.parent&&!navigator.activeItem){navigator.items[0]?.setActive();}},hotkeys:{escape:()=>current.close(),arrowleft:{isAvailable:()=>true,callback:(navigator)=>{if(isRTL()&&isDropdown(navigator.activeItem?.target)){navigator.activeItem?.select();}else if(current.parent){current.close();}},},arrowright:{isAvailable:()=>true,callback:(navigator)=>{if(isRTL()&¤t.parent){current.close();}else if(isDropdown(navigator.activeItem?.target)){navigator.activeItem?.select();}},},},},};} 2297return __exports;});; 2298 2299/* /web/static/src/core/dropdown/_behaviours/dropdown_popover.js */ 2300odoo.define('@web/core/dropdown/_behaviours/dropdown_popover',['@odoo/owl','@web/core/dropdown/dropdown_item'],function(require){'use strict';let __exports={};const{Component,onMounted,onRendered,onWillDestroy,onWillStart,xml}=require("@odoo/owl");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");
2300const DropdownPopover=__exports.DropdownPopover=class DropdownPopover extends Component{static components={DropdownItem};static template=xml` 2301 <t t-if="this.props.items"> 2302 <t t-foreach="this.props.items" t-as="item" t-key="this.getKey(item, item_index)"> 2303 <DropdownItem class="item.class" onSelected="() => item.onSelected()" t-out="item.label"/> 2304 </t> 2305 </t> 2306 <t t-slot="content" /> 2307 `;static props={close:{type:Function,optional:true},beforeOpen:{type:Function,optional:true},onOpened:{type:Function,optional:true},onClosed:{type:Function,optional:true},refresher:Object,slots:Object,items:{type:Array,optional:true},};setup(){onRendered(()=>{this.props.refresher.token;});onWillStart(async()=>{await this.props.beforeOpen?.();});onMounted(()=>{this.props.onOpened?.();});onWillDestroy(()=>{this.props.onClosed?.();});} 2308getKey(item,index){return"id"in item?item.id:index;}} 2309return __exports;});; 2310 2311/* /web/static/src/core/dropdown/accordion_item.js */ 2312odoo.define('@web/core/dropdown/accordion_item',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onPatched,useState}=require("@odoo/owl");const ACCORDION=__exports.ACCORDION=Symbol("Accordion");const AccordionItem=__exports.AccordionItem=class AccordionItem extends Component{static template="web.AccordionItem";static components={};static props={slots:{type:Object,shape:{default:{},},},description:String,selected:{type:Boolean,optional:true,},class:{type:String,optional:true,},};static defaultProps={class:"",selected:false,};setup(){this.state=useState({open:false,});this.parentComponent=this.env[ACCORDION];onPatched(()=>{this.parentComponent?.accordionStateChanged?.();});}} 2313return __exports;});; 2314 2315/* /web/static/src/core/dropdown/checkbox_item.js */ 2316odoo.define('@web/core/dropdown/checkbox_item',['@web/core/dropdown/dropdown_item'],function(require){'use strict';let __exports={};const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const CheckboxItem=__exports.CheckboxItem=class CheckboxItem extends DropdownItem{static template="web.CheckboxItem";static props={...DropdownItem.props,checked:{type:Boolean,optional:false,},};} 2317return __exports;});; 2318 2319/* /web/static/src/core/dropdown/dropdown.js */ 2320odoo.define('@web/core/dropdown/dropdown',['@odoo/owl','@web/core/dropdown/_behaviours/dropdown_group_hook','@web/core/dropdown/_behaviours/dropdown_nesting','@web/core/dropdown/_behaviours/dropdown_popover','@web/core/dropdown/dropdown_hooks','@web/core/navigation/navigation','@web/core/popover/popover_hook','@web/core/utils/classname','@web/core/utils/hooks','@web/core/utils/objects','@web/core/utils/reactive','@web/core/ui/ui_service','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component,onMounted,onRendered,onWillUpdateProps,reactive,status,useEffect,xml,}=require("@odoo/owl");const{useDropdownGroup}=require("@web/core/dropdown/_behaviours/dropdown_group_hook");const{useDropdownNesting}=require("@web/core/dropdown/_behaviours/dropdown_nesting");const{DropdownPopover}=require("@web/core/dropdown/_behaviours/dropdown_popover");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{useNavigation}=require("@web/core/navigation/navigation");const{usePopover}=require("@web/core/popover/popover_hook");const{mergeClasses}=require("@web/core/utils/classname");const{useChildRef,useService}=require("@web/core/utils/hooks");const{deepMerge}=require("@web/core/utils/objects");const{effect}=require("@web/core/utils/reactive");const{utils}=require("@web/core/ui/ui_service");const{hasTouch}=require("@web/core/browser/feature_detection");__exports.getFirstElementOfNode=getFirstElementOfNode;function getFirstElementOfNode(node){if(!node){return null;} 2321if(node.el){return node.el.nodeType===Node.ELEMENT_NODE?node.el:null;} 2322if(node.bdom||node.child){return getFirstElementOfNode(node.bdom||node.child);} 2323if(node.children){for(const child of node.children){const el=getFirstElementOfNode(child);if(el){return el;}}} 2324return null;} 2325const Dropdown=__exports.Dropdown=class Dropdown extends Component{static template=xml`<t t-slot="default"/>`;static components={};static props={menuClass:{optional:true},position:{type:String,optional:true},slots:{type:Object,shape:{default:{optional:true},content:{optional:true},},},items:{optional:true,type:Array,elements:{type:Object,shape:{label:String,onSelected:Function,class:{optional:true},"*":true,},},},menuRef:{type:Function,optional:true},disabled:{type:Boolean,optional:true},holdOnHover:{type:Boolean,optional:true},focusToggleOnClosed:{type:Boolean,optional:true},beforeOpen:{type:Function,optional:true},onOpened:{type:Function,optional:true},onStateChanged:{type:Function,optional:true},state:{type:Object,shape:{isOpen:Boolean,close:Function,open:Function,"*":true,},optional:true,},manual:{type:Boolean,optional:true},noClasses:{type:Boolean,optional:true},navigationOptions:{type:Object,optional:true},bottomSheet:{type:Boolean,optional:true},};static defaultProps={disabled:false,holdOnHover:false,focusToggleOnClosed:true,menuClass:"",state:undefined,noClasses:false,navigationOptions:{},bottomSheet:true,};setup(){this.menuRef=this.props.menuRef||useChildRef();this.state=this.props.state||useDropdownState();this.nesting=useDropdownNesting(this.state);this.group=useDropdownGroup();this.navigation=useNavigation(this.menuRef,{shouldRegisterHotkeys:false,isNavigationAvailable:()=>this.state.isOpen,getItems:()=>
2325{if(this.state.isOpen&&this.menuRef.el){return this.menuRef.el.querySelectorAll(":scope .o-navigable, :scope .o-dropdown");}else{return[];}},...deepMerge(this.nesting.navigationOptions,this.props.navigationOptions),});this.uiService=useService("ui");const getPosition=()=>this.position;const options={animation:false,arrow:false,closeOnClickAway:(target)=>this.popoverCloseOnClickAway(target),closeOnEscape:false,env:this.__owl__.childEnv,holdOnHover:this.props.holdOnHover,onClose:()=>this.state.close(),onPositioned:(el,{direction})=>this.setTargetDirectionClass(direction),popoverClass:mergeClasses("o-dropdown--menu dropdown-menu mx-0",{"o-dropdown--menu-submenu":this.hasParent},this.props.menuClass),role:"menu",get position(){return getPosition();},ref:this.menuRef,setActiveElement:false,};if(this.isBottomSheet){Object.assign(options,{useBottomSheet:true,class:mergeClasses("o-dropdown--menu dropdown-menu show",this.props.menuClass),});} 2326this.popover=usePopover(DropdownPopover,options);onRendered(()=>(this.popoverRefresher?this.popoverRefresher.token++:null));onMounted(()=>this.onStateChanged(this.state));effect((state)=>this.onStateChanged(state),[this.state]);useEffect((target)=>this.setTargetElement(target),()=>[this.target]);onWillUpdateProps(({disabled})=>{if(disabled){this.closePopover();}});} 2327get isBottomSheet(){return utils.isSmall()&&hasTouch()&&this.props.bottomSheet;} 2328get position(){return this.props.position||(this.hasParent?"right-start":"bottom-start");} 2329get hasParent(){return this.nesting.hasParent;} 2330get target(){const target=getFirstElementOfNode(this.__owl__.bdom);if(!target){throw new Error("Could not find a valid dropdown toggler, prefer a single html element and put any dynamic content inside of it.");} 2331return target;} 2332handleClick(event){if(this.props.disabled){return;} 2333event.stopPropagation();if(this.state.isOpen&&!this.hasParent){this.state.close();}else{this.state.open();}} 2334handleMouseEnter(){if(this.props.disabled){return;} 2335if(this.hasParent||this.group.isOpen){this.target.focus();this.state.open();}} 2336onStateChanged(state){if(state.isOpen){this.openPopover();}else{this.closePopover();}} 2337popoverCloseOnClickAway(target){const rootNode=target.getRootNode();if(rootNode instanceof ShadowRoot){target=rootNode.host;} 2338return this.uiService.getActiveElementOf(target)===this.activeEl;} 2339setTargetElement(target){if(!target){return;} 2340target.ariaExpanded=false;const optionalClasses=[];const requiredClasses=[];optionalClasses.push("o-dropdown");if(this.hasParent){requiredClasses.push("o-dropdown--has-parent");} 2341const tagName=target.tagName.toLowerCase();if(!["input","textarea","table","thead","tbody","tr","th","td"].includes(tagName)){optionalClasses.push("dropdown-toggle");if(this.hasParent){optionalClasses.push("o-dropdown-item","dropdown-item");requiredClasses.push("o-navigable");if(!target.classList.contains("o-dropdown--no-caret")){requiredClasses.push("o-dropdown-caret");}}} 2342target.classList.add(...requiredClasses);if(!this.props.noClasses){target.classList.add(...optionalClasses);} 2343this.defaultDirection=this.position.split("-")[0];this.setTargetDirectionClass(this.defaultDirection);if(!this.props.manual){target.addEventListener("click",this.handleClick.bind(this));target.addEventListener("mouseenter",this.handleMouseEnter.bind(this));return()=>{target.removeEventListener("click",this.handleClick.bind(this));target.removeEventListener("mouseenter",this.handleMouseEnter.bind(this));};}} 2344setTargetDirectionClass(direction){if(!this.target||this.props.noClasses){return;} 2345const directionClasses={bottom:"dropdown",top:"dropup",left:"dropstart",right:"dropend",};this.target.classList.remove(...Object.values(directionClasses));this.target.classList.add(directionClasses[direction]);} 2346openPopover(){if(this.popover.isOpen||status(this)!=="mounted"){return;} 2347if(!this.target||!this.target.isConnected){this.state.close();return;} 2348this.popoverRefresher=reactive({token:0});const props={beforeOpen:()=>this.props.beforeOpen?.(),onOpened:()=>this.onOpened(),onClosed:()=>this.onClosed(),refresher:this.popoverRefresher,items:this.props.items,slots:this.props.slots,};this.popover.open(this.target,props);} 2349closePopover(){this.popover.close();if(this.props.focusToggleOnClosed&&!this.group.isInGroup){this._focusedElBeforeOpen?.focus();this._focusedElBeforeOpen=undefined;}} 2350onOpened(){this._focusedElBeforeOpen=document.activeElement;this.activeEl=this.uiService.activeElement;this.navigation.registerHotkeys();this.navigation.update();this.props.onOpened?.();this.props.onStateChanged?.(true);if(this.target){this.target.ariaExpanded=true;this.target.classList.add("show");} 2351const menuEl=this.menuRef.el;if(menuEl){this.observer=new MutationObserver(()=>this.navigation.update());this.observer.observe(menuEl,{childList:true,subtree:true,});}} 2352onClosed(){this.navigation.unregisterHotkeys();this.navigation.update();this.props.onStateChanged?.(false);delete this.activeEl;if(this.target){this.target.ariaExpanded=false;this.target.classList.remove("show");this.setTargetDirectionClass(this.defaultDirection);} 2353if(this.observer){this.observer.disconnect();this.observer=null;}}} 2354return __exports;});; 2355 2356/* /web/static/src/core/dropdown/dropdown_group.js */ 2357odoo.define('@web/core/dropdown/dropdown_group',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,useChildSubEnv,xml}=require("@odoo/owl");const GROUPS=new Map();function getGroup(id){if(!GROUPS.has(id)){GROUPS.set(id,{group:new Set(),c
2357ount:0,});} 2358GROUPS.get(id).count++;return GROUPS.get(id).group;} 2359function removeGroup(id){const groupData=GROUPS.get(id);groupData.count--;if(groupData.count<=0){GROUPS.delete(id);}} 2360const DROPDOWN_GROUP=__exports.DROPDOWN_GROUP=Symbol("dropdownGroup");const DropdownGroup=__exports.DropdownGroup=class DropdownGroup extends Component{static template=xml`<t t-slot="default"/>`;static props={group:{type:String,optional:true},slots:Object,};setup(){if(this.props.group){const group=getGroup(this.props.group);onWillDestroy(()=>removeGroup(this.props.group));useChildSubEnv({[DROPDOWN_GROUP]:group});}else{useChildSubEnv({[DROPDOWN_GROUP]:new Set()});}}} 2361return __exports;});; 2362 2363/* /web/static/src/core/dropdown/dropdown_hooks.js */ 2364odoo.define('@web/core/dropdown/dropdown_hooks',['@odoo/owl','@web/core/dropdown/_behaviours/dropdown_nesting','@web/core/utils/reactive'],function(require){'use strict';let __exports={};const{useEnv,useState}=require("@odoo/owl");const{DROPDOWN_NESTING}=require("@web/core/dropdown/_behaviours/dropdown_nesting");const{Reactive}=require("@web/core/utils/reactive");const DropdownState=__exports.DropdownState=class DropdownState extends Reactive{isOpen=false;constructor({onOpen,onClose}={}){super();this._onOpen=onOpen;this._onClose=onClose;} 2365open(){this.isOpen=true;this._onOpen?.();} 2366close(){this.isOpen=false;this._onClose?.();}} 2367__exports.useDropdownState=useDropdownState;function useDropdownState({onOpen,onClose}={}){return useState(new DropdownState({onOpen,onClose}));} 2368__exports.useDropdownCloser=useDropdownCloser;function useDropdownCloser(){const env=useEnv();const dropdown=env[DROPDOWN_NESTING];return{close:()=>dropdown?.close(),closeChildren:()=>dropdown?.closeChildren(),closeAll:()=>dropdown?.closeAllParents(),};} 2369return __exports;});; 2370 2371/* /web/static/src/core/dropdown/dropdown_item.js */ 2372odoo.define('@web/core/dropdown/dropdown_item',['@odoo/owl','@web/core/dropdown/dropdown_hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useDropdownCloser}=require("@web/core/dropdown/dropdown_hooks");const ClosingMode={None:"none",ClosestParent:"closest",AllParents:"all",};const DropdownItem=__exports.DropdownItem=class DropdownItem extends Component{static template="web.DropdownItem";static props={tag:{type:String,optional:true,},class:{type:[String,Object],optional:true,},onSelected:{type:Function,optional:true,},closingMode:{type:ClosingMode,optional:true,},attrs:{type:Object,optional:true,},slots:{Object,optional:true},};static defaultProps={closingMode:ClosingMode.AllParents,attrs:{},};setup(){this.dropdownControl=useDropdownCloser();} 2373onClick(ev){if(this.props.attrs&&this.props.attrs.href){ev.preventDefault();} 2374this.props.onSelected?.(ev);switch(this.props.closingMode){case ClosingMode.ClosestParent:this.dropdownControl.close();break;case ClosingMode.AllParents:this.dropdownControl.closeAll();break;}}} 2375return __exports;});; 2376 2377/* /web/static/src/core/dropzone/dropzone.js */ 2378odoo.define('@web/core/dropzone/dropzone',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef,useState}=require("@odoo/owl");const Dropzone=__exports.Dropzone=class Dropzone extends Component{static props={extraClass:{type:String,optional:true},onDrop:{type:Function,optional:true},ref:[Object,Function],slots:{type:Object,optional:true},};static template="web.Dropzone";setup(){super.setup();this.root=useRef("root");this.state=useState({isDraggingInside:false,});useEffect(()=>{const{top,left,width,height}=this.props.ref.el.getBoundingClientRect();this.root.el.style=`top:${top}px;left:${left}px;width:${width}px;height:${height}px;`;});}} 2379return __exports;});; 2380 2381/* /web/static/src/core/dropzone/dropzone_hook.js */ 2382odoo.define('@web/core/dropzone/dropzone_hook',['@web/core/dropzone/dropzone','@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Dropzone}=require("@web/core/dropzone/dropzone");const{useEffect,useExternalListener}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");__exports.useCustomDropzone=useCustomDropzone;function useCustomDropzone(targetRef,dropzoneComponent,dropzoneComponentProps,isDropzoneEnabled=()=>true){const overlayService=useService("overlay");const uiService=useService("ui");let dragCount=0;let hasTarget=false;let removeDropzone=false;useExternalListener(document,"dragenter",onDragEnter,{capture:true});useExternalListener(document,"dragleave",onDragLeave,{capture:true});useExternalListener(window,"dragover",(ev)=>{if(ev.dataTransfer&&ev.dataTransfer.types.includes("Files")){ev.preventDefault();}});useExternalListener(window,"drop",(ev)=>{if(ev.dataTransfer&&ev.dataTransfer.types.includes("Files")){ev.preventDefault();} 2383dragCount=0;updateDropzone();},{capture:true});function updateDropzone(){const hasDropzone=!!removeDropzone;const isTargetInActiveElement=uiService.activeElement.contains(targetRef.el);const shouldDisplayDropzone=dragCount&&hasTarget&&isTargetInActiveElement&&isDropzoneEnabled();if(shouldDisplayDropzone&&!hasDropzone){removeDropzone=overlayService.add(dropzoneComponent,{ref:targetRef,...dropzoneComponentProps});} 2384if(!shouldDisplayDropzone&&hasDropzone){removeDropzone();removeDropzone=false;}} 2385function onDragEnter(ev){if(dragCount||(ev.dataTransfer&&ev.dataTransfer.types.includes("Files"))){dragCount++;updateDropzone();}}
2385 2386function onDragLeave(){if(dragCount){dragCount--;updateDropzone();}} 2387useEffect((el)=>{hasTarget=!!el;updateDropzone();},()=>[targetRef.el]);} 2388__exports.useDropzone=useDropzone;function useDropzone(targetRef,onDrop,extraClass,isDropzoneEnabled=()=>true){const dropzoneComponent=Dropzone;const dropzoneComponentProps={extraClass,onDrop};useCustomDropzone(targetRef,dropzoneComponent,dropzoneComponentProps,isDropzoneEnabled);} 2389return __exports;});; 2390 2391/* /web/static/src/core/effects/effect_service.js */ 2392odoo.define('@web/core/effects/effect_service',['@web/core/l10n/translation','@web/core/registry','@web/core/user','@web/core/effects/rainbow_man'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{user}=require("@web/core/user");const{RainbowMan}=require("@web/core/effects/rainbow_man");const effectRegistry=registry.category("effects");function rainbowMan(env,params={}){let message=params.message;if(message instanceof Element){console.log("Providing an HTML element to an effect is deprecated. Note that all event handlers will be lost.");message=message.outerHTML;}else if(!message){message=_t("Well Done!");} 2393if(user.showEffect){const props={imgUrl:params.img_url||"/web/static/img/smile.svg",fadeout:params.fadeout||"medium",message,Component:params.Component,props:params.props,};return{Component:RainbowMan,props};} 2394env.services.notification.add(message);} 2395effectRegistry.add("rainbow_man",rainbowMan);const effectService=__exports.effectService={dependencies:["overlay"],start(env,{overlay}){const add=(params={})=>{const type=params.type||"rainbow_man";const effect=effectRegistry.get(type);const{Component,props}=effect(env,params)||{};if(Component){const remove=overlay.add(Component,{...props,close:()=>remove(),});}};return{add};},};registry.category("services").add("effect",effectService);return __exports;});; 2396 2397/* /web/static/src/core/effects/rainbow_man.js */ 2398odoo.define('@web/core/effects/rainbow_man',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Component,useEffect,useExternalListener,useState}=require("@odoo/owl");const RainbowMan=__exports.RainbowMan=class RainbowMan extends Component{static template="web.RainbowMan";static rainbowFadeouts={slow:4500,medium:3500,fast:2000,no:false};static props={fadeout:String,close:Function,message:String,imgUrl:String,Component:{type:Function,optional:true},props:{type:Object,optional:true},};setup(){useExternalListener(document.body,"click",this.closeRainbowMan);this.state=useState({isFading:false});this.delay=RainbowMan.rainbowFadeouts[this.props.fadeout];if(this.delay){useEffect(()=>{const timeout=browser.setTimeout(()=>{this.state.isFading=true;},this.delay);return()=>browser.clearTimeout(timeout);},()=>[]);}} 2399onAnimationEnd(ev){if(this.delay&&ev.animationName==="reward-fading-reverse"){ev.stopPropagation();this.closeRainbowMan();}} 2400closeRainbowMan(){this.props.close();}} 2401return __exports;});; 2402 2403/* /web/static/src/core/emoji_picker/emoji_picker.js */ 2404odoo.define('@web/core/emoji_picker/emoji_picker',['@web/core/utils/misc','@odoo/owl','@web/core/assets','@web/core/l10n/translation','@web/core/popover/popover_hook','@web/core/utils/search','@web/core/utils/hooks','@web/core/browser/feature_detection','@web/core/utils/concurrency','@web/core/dialog/dialog','@web/core/templates'],function(require){'use strict';let __exports={};const{markEventHandled}=require("@web/core/utils/misc");const{App,Component,onMounted,onPatched,onWillPatch,onWillStart,onWillUnmount,reactive,useComponent,useEffect,useExternalListener,useRef,useState,xml,}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const{__not_defined__,appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{usePopover}=require("@web/core/popover/popover_hook");const{fuzzyLookup}=require("@web/core/utils/search");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{isMobileOS}=require("@web/core/browser/feature_detection");const{Deferred}=require("@web/core/utils/concurrency");const{Dialog}=require("@web/core/dialog/dialog");const{getTemplate}=require("@web/core/templates");__exports.useEmojiPicker=useEmojiPicker;function useEmojiPicker(...args){return usePicker(EmojiPicker,...args);} 2405const loader=__exports.loader=reactive({loadEmoji:()=>
2405loadBundle("web.assets_emoji"),loaded:undefined,});__exports.loadEmoji=loadEmoji;async function loadEmoji(){const res={categories:[],emojis:[]};try{await loader.loadEmoji();const{getCategories,getEmojis}=odoo.loader.modules.get("@web/core/emoji_picker/emoji_data");res.categories=getCategories();res.emojis=getEmojis();return res;}catch{return res;}finally{if(!loader.loaded){const emojiValueToShortcodes={};for(const emoji of res.emojis){emojiValueToShortcodes[emoji.codepoints]=emoji.shortcodes;} 2406loader.loaded={emojiValueToShortcodes,emojiRegex:new RegExp(Object.keys(emojiValueToShortcodes).length?Object.keys(emojiValueToShortcodes).map((c)=>c.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")).sort((a,b)=>b.length-a.length).join("|"):/(?!)/,"gu"),};}}} 2407const PICKER_PROPS=__exports.PICKER_PROPS=["PickerComponent?","close?","onClose?","onSelect","state?","storeScroll?","mobile?",];const EmojiPicker=__exports.EmojiPicker=class EmojiPicker extends Component{static props=[...PICKER_PROPS,"class?","initialSearchTerm?"];static template="web.EmojiPicker";categories=null;emojis=null;shouldScrollElem=null;lastSearchTerm;keyboardNavigated=false;setup(){this.gridRef=useRef("emoji-grid");this.navbarRef=useRef("navbar");this.ui=useService("ui");this.isMobileOS=isMobileOS();this.state=useState({activeEmojiIndex:0,categoryId:null,searchTerm:this.props.initialSearchTerm??"",hoveredEmoji:undefined,});this.frequentEmojiService=useService("web.frequent.emoji");useAutofocus();onWillStart(async()=>{const{categories,emojis}=await loadEmoji();this.categories=categories;this.emojis=emojis;this.emojiByCodepoints=Object.fromEntries(this.emojis.map((emoji)=>[emoji.codepoints,emoji]));this.recentSnapshot=Object.entries(this.frequentEmojiService.all).sort(([,usage_1],[,usage_2])=>usage_2-usage_1).map(([codepoints])=>this.emojiByCodepoints[codepoints]);this.recentCategory={name:"Frequently used",displayName:_t("Frequently used"),title:"ð",sortId:0,};this.state.categoryId=this.recentEmojis.length?this.recentCategory.sortId:this.categories[0].sortId;});onMounted(()=>{if(this.emojis.length===0){return;} 2408this.navbarResizeObserver=new ResizeObserver(()=>this.adaptNavbar());this.navbarResizeObserver.observe(this.navbarRef.el);this.adaptNavbar();this.highlightActiveCategory();if(this.props.storeScroll){this.gridRef.el.scrollTop=this.props.storeScroll.get();} 2409this.state.hoveredEmoji=this.activeEmoji;});onPatched(()=>{if(this.emojis.length===0){return;} 2410if(this.shouldScrollElem){this.shouldScrollElem=false;const getElement=()=>this.gridRef.el.querySelector(`.o-EmojiPicker-category[data-category="${this.state.categoryId}"`);const elem=getElement();if(elem){elem.scrollIntoView();}else{this.shouldScrollElem=getElement;}}});useEffect(()=>this.updateEmojiPickerRepr(),()=>[this.state.categoryId,this.state.searchTerm]);useEffect((el)=>{const gridEl=this.gridRef.el;const activeEl=gridEl?.querySelector(".o-Emoji.o-active");if(!gridEl){return;} 2411if(activeEl&&this.keyboardNavigated&&!isElementVisible(activeEl,gridEl)){activeEl.scrollIntoView({block:"center",behavior:"instant"});this.keyboardNavigated=false;} 2412this.state.hoveredEmoji=this.activeEmoji;},()=>[this.state.activeEmojiIndex,this.gridRef.el]);useEffect(()=>{if(!this.gridRef.el){return;} 2413if(this.searchTerm){this.gridRef.el.scrollTop=0;this.state.categoryId=null;}else{if(this.lastSearchTerm){this.gridRef.el.scrollTop=0;} 2414this.highlightActiveCategory();} 2415this.lastSearchTerm=this.searchTerm;},()=>[this.searchTerm]);onWillUnmount(()=>{this.navbarResizeObserver?.disconnect();if(!this.gridRef.el){return;} 2416if(this.props.storeScroll){this.props.storeScroll.set(this.gridRef.el.scrollTop);}});} 2417adaptNavbar(){if(!this.navbarRef.el){return;} 2418const computedStyle=getComputedStyle(this.navbarRef.el);const availableWidth=this.navbarRef.el.getBoundingClientRect().width- 2419parseInt(computedStyle.paddingLeft)- 2420parseInt(computedStyle.marginLeft)- 2421parseInt(computedStyle.paddingLeft)- 2422parseInt(computedStyle.marginLeft);const itemWidth=this.navbarRef.el.querySelector(".o-Emoji").getBoundingClientRect().width;const gapWidth=parseInt(computedStyle.gap);const maxAvailableNavbarItemAmountAtOnce=Math.floor(availableWidth/(itemWidth+gapWidth));const repr=[];let panel=[];const allCategories=this.getAllCategories();for(const category of allCategories){if(panel.length===maxAvailableNavbarItemAmountAtOnce-1&&category!==allCategories.at(-1)){panel.push("next");repr.push(panel);panel=[];panel.push("previous");} 2423panel.push(category.sortId);} 2424if(panel.length>0){if(repr.length>0){panel.push(...[...Array(maxAvailableNavbarItemAmountAtOnce-panel.length)].map((_,idx)=>"empty_"+idx));} 2425repr.push(panel);} 2426this.state.emojiNavbarRepr=repr;} 2427get currentNavbarPanel(){if(!this.state.emojiNavbarRepr){return this.getAllCategories().map((c)=>c.sortId);} 2428if(this.state.categoryId===null||Number.isNaN(this.state.categoryId)){return this.state.emojiNavbarRepr[0];} 2429return this.state.emojiNavbarRepr.find((panel)=>panel.includes(this.state.categoryId));} 2430get searchTerm(){return this.props.state?this.props.state.searchTerm:this.state.searchTerm;} 2431set searchTerm(value){if(this.props.state){this.props.state.searchTerm=value;}else{this.state.searchTerm=value;}} 2432get itemsNumber(){return this.recentEmojis.length+this.getEmojis().length;} 2433get recentEmojis(){const recent=this.recentSnapshot??[];if(this.searchTerm&&recent.length>0){return fuzzyLookup(this.searchTerm,recent,(emoji)=>[emoji.name,...emoji.keywords,...emoji.emoticons,...emoji.shortcodes,]);} 2434return recent.slice(0,42);} 2435get placeholder(){return this.state.hoveredEmoji?.shortcodes.join(" ")??_t("Search emoji");} 2436onMouseenterEmoji(ev,emoji){this.state.hoveredEmoji=emoji;} 2437onMouseleaveEmoji(ev,emoji){this.state.hoveredEmoji=this.activeEmoji;} 2438onClick(ev){markEventHandled(ev,"emoji.selectEmoji");} 2439onClickToNextCategories(){const panelIndex=this.state.emojiNavbarRepr.findIndex((p)=>p.includes(this.state.categoryId));this.selectCategory(this.state.emojiNavbarRepr[panelIndex+1][1]);} 2440onClickToPreviousCategories(){const panelIndex=this.state.emojiNavbarRepr.findIndex((p)=>p.includes(this.state.categoryId));this.selectCategory(this.state.emojiNavbarRepr[panelIndex-1].at(-2));} 2441updateEmojiPickerRepr(){if(this.emojis.length===0){return;}
2442const emojiEls=Array.from(this.gridRef.el.querySelectorAll(".o-Emoji"));const emojiRects=emojiEls.map((el)=>el.getBoundingClientRect());this.emojiMatrix=[];for(const[index,pos]of emojiRects.entries()){const emojiIndex=emojiEls[index].dataset.index;if(this.emojiMatrix.length===0||pos.top>emojiRects[index-1].top){this.emojiMatrix.push([]);} 2443this.emojiMatrix.at(-1).push(parseInt(emojiIndex));}} 2444handleNavigation(key){const currentIdx=this.state.activeEmojiIndex;let currentRow=-1;let currentCol=-1;const rowIdx=this.emojiMatrix.findIndex((row)=>row.includes(currentIdx));if(rowIdx!==-1){currentRow=rowIdx;currentCol=this.emojiMatrix[currentRow].indexOf(currentIdx);} 2445let newIdx;switch(key){case"ArrowDown":{const rowBelow=this.emojiMatrix[currentRow+1];const rowBelowBelow=this.emojiMatrix[currentRow+2];if(rowBelow?.length<=currentCol&&rowBelowBelow?.length>=currentCol){newIdx=rowBelowBelow?.[currentCol];}else{newIdx=rowBelow?.[Math.min(currentCol,rowBelow.length-1)];} 2446break;} 2447case"ArrowUp":{const rowAbove=this.emojiMatrix[currentRow-1];const rowAboveAbove=this.emojiMatrix[currentRow-2];if(rowAbove?.length<=currentCol&&rowAboveAbove?.length>=currentCol){newIdx=rowAboveAbove?.[currentCol];}else{newIdx=rowAbove?.[Math.min(currentCol,rowAbove.length-1)];} 2448break;} 2449case"ArrowRight":{const colRight=currentCol+1;if(colRight===this.emojiMatrix[currentRow]?.length){const rowBelowRight=this.emojiMatrix[currentRow+1];newIdx=rowBelowRight?.[0];}else{newIdx=this.emojiMatrix[currentRow]?.[colRight];} 2450break;} 2451case"ArrowLeft":{const colLeft=currentCol-1;if(colLeft<0){const rowAboveLeft=this.emojiMatrix[currentRow-1];newIdx=rowAboveLeft?.[rowAboveLeft.length-1]??this.state.activeEmojiIndex;}else{newIdx=this.emojiMatrix[currentRow][colLeft];} 2452break;}} 2453this.state.activeEmojiIndex=newIdx??this.state.activeEmojiIndex;} 2454get activeEmoji(){const activeCodepoints=this.gridRef.el.querySelector(`.o-EmojiPicker-content .o-Emoji[data-index="${this.state.activeEmojiIndex}"]`)?.dataset.codepoints;return activeCodepoints?this.emojiByCodepoints[activeCodepoints]:u
2454ndefined;} 2455onKeydown(ev){switch(ev.key){case"ArrowDown":case"ArrowUp":case"ArrowRight":case"ArrowLeft":this.handleNavigation(ev.key);this.keyboardNavigated=true;break;case"Enter":ev.preventDefault();this.gridRef.el?.querySelector(`.o-EmojiPicker-content .o-Emoji[data-index="${this.state.activeEmojiIndex}"]`)?.click();break;case"Escape":this.props.close?.();this.props.onClose?.();ev.stopPropagation();}} 2456getAllCategories(){const res=[...this.categories];if(this.recentEmojis.length>0){res.unshift(this.recentCategory);} 2457return res;} 2458getEmojis(){let emojisToDisplay=[...this.emojis];const recentEmojis=this.recentEmojis;if(recentEmojis.length>0&&this.searchTerm){emojisToDisplay=emojisToDisplay.filter((emoji)=>!recentEmojis.includes(emoji));} 2459if(this.searchTerm.length>0){return fuzzyLookup(this.searchTerm,emojisToDisplay,(emoji)=>[emoji.name,...emoji.keywords,...emoji.emoticons,...emoji.shortcodes,]);} 2460return emojisToDisplay;} 2461getEmojisFromSearch(){return[...this.recentEmojis,...this.getEmojis()];} 2462selectCategory(categoryId){this.searchTerm="";this.state.categoryId=categoryId;this.shouldScrollElem=true;} 2463selectEmoji(ev){const codepoints=ev.currentTarget.dataset.codepoints;let resetOnSelect=!ev.shiftKey;const res=this.props.onSelect(codepoints,resetOnSelect);if(res===false){resetOnSelect=false;} 2464this.frequentEmojiService.incrementEmojiUsage(codepoints);if(resetOnSelect){this.gridRef.el.scrollTop=0;this.props.close?.();this.props.onClose?.();}} 2465highlightActiveCategory(){if(!this.gridRef||!this.gridRef.el){return;} 2466const coords=this.gridRef.el.getBoundingClientRect();const res=document.elementFromPoint(coords.x+10,coords.y+10);if(!res){return;} 2467this.state.categoryId=parseInt(res.dataset.category);}} 2468__exports.usePicker=usePicker;function usePicker(PickerComponent,ref,props,options={}){const component=useComponent();const targets=[];const state=useState({isOpen:false});const ui=useService("ui");const dialog=useService("dialog");let remove;const newOptions={...options,onClose:()=>{state.isOpen=false;props.onClose?.();},};const popover=usePopover(PickerComponent,{...newOptions,animation:false,popoverClass:options.popoverClass??""+" bg-100 border border-secondary",});props.storeScroll={scrollValue:0,set:(value)=>{props.storeScroll.scrollValue=value;},get:()=>props.storeScroll.scrollValue,};function add(ref,onSelect,{show=false}={}){const toggler=()=>toggle(isMobileOS()?undefined:ref,onSelect);targets.push([ref,toggler]);if(!ref.el){return;} 2469ref.el.addEventListener("click",toggler);ref.el.addEventListener("mouseenter",loadEmoji);if(show){ref.el.click();}} 2470function open(ref,openProps){state.isOpen=true;if(ui.isSmall||isMobileOS()){const def=new Deferred();const pickerMobileProps={PickerComponent,onSelect:(...args)=>{const func=openProps?.onSelect??props?.onSelect;const res=func?.(...args);def.resolve(true);return res;},};if(ref?.el){pickerMobileProps.close=()=>remove();const app=new App(PickerMobile,{name:"Popout",env:component.env,props:pickerMobileProps,getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,});app.mount(ref.el);remove=()=>{state.isOpen=false;props.onClose?.();app.destroy();};}else{remove=dialog.add(PickerMobileInDialog,pickerMobileProps,{context:component,onClose:()=>{state.isOpen=false;props.onClose?.();return def.resolve(false);},});} 2471return def;} 2472return popover.open(ref.el,{...props,...openProps});} 2473function close(){remove?.();popover.close?.();} 2474function toggle(ref,onSelect=props.onSelect){if(state.isOpen){close();}else{open(ref,{...props,onSelect});}} 2475if(ref){add(ref);} 2476onMounted(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;} 2477ref.el.addEventListener("click",toggle);ref.el.addEventListener("mouseenter",loadEmoji);}});onWillPatch(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;} 2478ref.el.removeEventListener("click",toggle);ref.el.removeEventListener("mouseenter",loadEmoji);}});onPatched(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;} 2479ref.el.addEventListener("click",toggle);ref.el.addEventListener("mouseenter",loadEmoji);}});Object.assign(state,{open,close,toggle});return state;} 2480class PickerMobile extends Component{static props=[...PICKER_PROPS,"onClose?"];static template=xml` 2481 <t t-component="props.PickerComponent" t-props="pickerProps"/> 2482 `;get pickerProps(){return{...this.props,onSelect:(...args)=>this.props.onSelect(...args),mobile:true,};}} 2483class PickerMobileInDialog extends PickerMobile{static components={Dialog};static props=[...PICKER_PROPS,"onClose?"];static template=xml` 2484 <Dialog size="'lg'" header="false" footer="false" contentClass="'o-discuss-mobileContextMenu d-flex position-absolute bottom-0 rounded-0 h-50 bg-100'" bodyClass="'p-1'"> 2485 <div class="h-100" t-ref="root"> 2486 <t t-component="props.PickerComponent" t-props="pickerProps"/> 2487 </div> 2488 </Dialog> 2489 `;setup(){super.setup();this.root=useRef("root");useExternalListener(window,"click",(ev)=>{if(ev.target!==this.root.el&&!this.root.el.contains(ev.target)){this.props.close?.();}},{capture:true});}} 2490function isElementVisible(el,holder){const offset=20;holder=holder||document.body;const{top,bottom,height}=el.getBoundingClientRect();let{top:holderTop,bottom:holderBottom}=holder.getBoundingClientRect();holderTop+=offset*2;holderBottom-=offset;return top-offset<=holderTop?holderTop-top<=height:bottom-holderBottom<=height;} 2491return __exports;});; 2492 2493/* /web/static/src/core/emoji_picker/frequent_emoji_service.js */ 2494odoo.define('@web/core/emoji_picker/frequent_emoji_service',['@odoo/owl','@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const frequentEmojiService=__exports.frequentEmojiService={start(){const state=reactive({all:JSON.parse(browser.localStorage.getItem("web.emoji.frequent")||"{}"),incrementEmojiUsage(codepoints){state.all[codepoints]??=0;state.all[codepoints]++;browser.localStorage.setItem("web.emoji.frequent",JSON.stringify(state.all));},getMostFrequent(limit){return Object.entries(state.all).sort(([,usage_1],[,usage_2])=>usage_2-usage_1).slice(0,limit??Infinity).map(([codepoints])=>codepoints);},});browser.addEventListener("storage",(ev)=>{if(ev.key==="web.emoji.frequent"){state.all=ev.newValue?JSON.parse(ev.newValue):{};}else if(ev.key===null){state.all={};}});return state;},};registry.category("services").add("web.frequent.emoji",frequentEmojiService);return __exports;});; 2495 2496/* /web/static/src/core/ensure_jquery.js */ 2497odoo.define('@web/core/ensure_jquery',['@web/core/assets'],function(require){'use strict';let __exports={};const{loadBundle,loadJS}=require("@web/core/assets");__exports.ensureJQuery=ensureJQuery;async function ensureJQuery(){if(!window.jQuery){await loadBundle("web._assets_jquery");const BTS_CLASSES=["Carousel","Dropdown","Modal","Popover","Tooltip","Collapse"];const $=window.jQuery;for(const CLS of BTS_CLASSES){const plugin=window[CLS];if(plugin){const name=plugin.NAME;const JQUERY_NO_CONFLICT=$.fn[name];$.fn[name]=plugin.jQueryInterface;$.fn[name].Constructor=plugin;$.fn[name].noConflict=()=>{$.fn[name]=JQUERY_NO_CONFLICT;return plugin.jQueryInterface;};}}}else if(!window.jQuery.fn.getScrollingElement){await loadJS("/web/static/src/legacy/js/libs/jquery.js");}} 2498return __exports;});; 2499 2500/* /web/static/src/core/errors/error_dialogs.js */ 2501odoo.define('@web/core/errors/error_dialogs',['@web/core/browser/browser','@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/registry','@web/core/tooltip/tooltip','@web/core/popover/popover_hook','@web/core/utils/hooks','@web/core/utils/strings','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Dialog}=require("@web/core/dialog/dialog");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{Tooltip}=require("@web/core/tooltip/tooltip");const{usePopover}=require("@web/core/popover/popover_hook");const{useService}=require("@web/core/utils/hooks");const{capitalize}=require("@web/core/utils/strings");const{Component,useRef,useState,markup}=require("@odoo/owl");const{DateTime}=luxon;const standardErrorDialogProps=__exports.standardErrorDialogProps={traceback:{type:[String,{value:null}],optional:true},message:{type:String,optional:true},name:{type:String,optional:true},exceptionName:{type:[String,{value:null}],optional:true},data:{type:[Object,{value:null}],optional:true},subType:{type:[String,{value:null}],optional:true},code:{type:[Number,String,{value:null}],optional:true},type:{type:[String,{value:null}],optional:true},serverHost:{type:[String,{value:null}],optional:true},id:{type:[Number,{value:null}],optional:true},model:{type:[String,{value:null}],optional:true},close:Function,};const odooExceptionTitleMap=__exports.odooExceptionTitleMap=new Map(Object.entries({"odoo.addons.base.models.ir_mail_server.MailDeliveryException":_t("MailDeliveryException"),"odoo.exceptions.Acce
2501ssDenied":_t("Access Denied"),"odoo.exceptions.MissingError":_t("Missing Record"),"odoo.addons.web.controllers.action.MissingActionError":_t("Missing Action"),"odoo.addons.base.models.ir_actions.ServerActionWithWarningsError":_t("Invalid Operation"),"odoo.exceptions.UserError":_t("Invalid Operation"),"odoo.exceptions.ValidationError":_t("Validation Error"),"odoo.exceptions.AccessError":_t("Access Error"),"odoo.exceptions.Warning":_t("Warning"),}));const ErrorDialog=__exports.ErrorDialog=class ErrorDialog extends Component{static template="web.ErrorDialog";static components={Dialog};static title=_t("Odoo Error");static showTracebackButtonText=_t("See technical details");static hideTracebackButtonText=_t("Hide technical details");static props={...standardErrorDialogProps};setup(){this.state=useState({showTraceback:false,});this.copyButtonRef=useRef("copyButton");this.popover=usePopover(Tooltip);this.contextDetails="Occured ";if(this.props.serverHost){this.contextDetails+=`on ${this.props.serverHost} `;} 2502if(this.props.model){this.contextDetails+=`on model ${this.props.model} `;} 2503this.contextDetails+=`on ${DateTime.now() 2504 .setZone("UTC") 2505 .toFormat("yyyy-MM-dd HH:mm:ss")} GMT`;} 2506showTooltip(){this.popover.open(this.copyButtonRef.el,{tooltip:_t("Copied")});browser.setTimeout(this.popover.close,800);} 2507onClickClipboard(){browser.navigator.clipboard.writeText(`${this.props.name}\n\n${this.props.message}\n\n${this.contextDetails}\n\n${this.props.traceback}`);this.showTooltip();}} 2508const ClientErrorDialog=__exports.ClientErrorDialog=class ClientErrorDialog extends ErrorDialog{} 2509ClientErrorDialog.title=_t("Odoo Client Error");const NetworkErrorDialog=__exports.NetworkErrorDialog=class NetworkErrorDialog extends ErrorDialog{} 2510NetworkErrorDialog.title=_t("Odoo Network Error");const RequestEntityTooLargeErrorDialog=__exports.RequestEntityTooLargeErrorDialog=class RequestEntityTooLargeErrorDialog extends ErrorDialog{} 2511RequestEntityTooLargeErrorDialog.title=_t("The request sent to the server was too large");const RPCErrorDialog=__exports.RPCErrorDialog=class RPCErrorDialog extends ErrorDialog{setup(){super.setup();this.inferTitle();this.traceback=this.props.traceback;if(this.props.data&&this.props.data.debug){this.traceback=`${this.props.data.debug}\nThe above server error caused the following client error:\n${this.traceback}`;}} 2512inferTitle(){if(this.props.exceptionName&&odooExceptionTitleMap.has(this.props.exceptionName)){this.title=odooExceptionTitleMap.get(this.props.exceptionName).toString();return;} 2513if(!this.props.type){return;} 2514switch(this.props.type){case"server":this.title=_t("Odoo Server Error");break;case"script":this.title=_t("Odoo Client Error");break;case"network":this.title=_t("Odoo Network Error");break;}} 2515onClickClipboard(){browser.navigator.clipboard.writeText(`${this.props.name}\n\n${this.props.message}\n\n${this.contextDetails}\n\n${this.traceback}`);this.showTooltip();}} 2516const WarningDialog=__exports.WarningDialog=class WarningDialog extends Component{static template="web.WarningDialog";static components={Dialog};static props={...standardErrorDialogProps,title:{type:String,optional:true},};setup(){this.title=this.inferTitle();const{data,message}=this.props;if(data&&data.arguments&&data.arguments.length>0){this.message=data.arguments[0];}else{this.message=message;}} 2517inferTitle(){if(this.props.exceptionName&&odooExceptionTitleMap.has(this.props.exceptionName)){return odooExceptionTitleMap.get(this.props.exceptionName).toString();} 2518return this.props.title||_t("Odoo Warning");}} 2519const RedirectWarningDialog=__exports.RedirectWarningDialog=class RedirectWarningDialog extends Component{static template="web.RedirectWarningDialog";static components={Dialog};static props={...standardErrorDialogProps};setup(){this.actionService=useService("action");const{data,subType}=this.props;const[message,actionId,buttonText,additionalContext]=data.arguments;this.title=capitalize(subType)||_t("Odoo Warning");this.message=message;this.actionId=actionId;this.buttonText=buttonText;this.additionalContext=additionalContext;} 2520async onClick(){const options={forceLeave:true};if(this.additionalContext){options.additionalContext=this.additionalContext;} 2521if(this.actionId.help){this.actionId.help=markup(this.actionId.help);} 2522await this.actionService.doAction(this.actionId,options);this.props.close();}} 2523const Error504Dialog=__exports.Error504Dialog=class Error504Dialog extends Component{static template="web.Error504Dialog";static components={Dialog};static props={...standardErrorDialogProps};} 2524const SessionExpiredDialog=__exports.SessionExpiredDialog=class SessionExpiredDialog extends Component{static template="web.SessionExpiredDialog";static components={Dialog};static props={...standardErrorDialogProps};onClick(){browser.location.reload();}}
2525registry.category("error_dialogs").add("odoo.exceptions.AccessDenied",WarningDialog).add("odoo.exceptions.AccessError",WarningDialog).add("odoo.exceptions.MissingError",WarningDialog).add("odoo.addons.web.controllers.action.MissingActionError",WarningDialog).add("odoo.addons.base.models.ir_actions.ServerActionWithWarningsError",WarningDialog).add("odoo.exceptions.UserError",WarningDialog).add("odoo.exceptions.ValidationError",WarningDialog).add("odoo.exceptions.RedirectWarning",RedirectWarningDialog).add("odoo.http.SessionExpiredException",SessionExpiredDialog).add("werkzeug.exceptions.Forbidden",SessionExpiredDialog).add("504",Error504Dialog);return __exports;});; 2526 2527/* /web/static/src/core/errors/error_handlers.js */ 2528odoo.define('@web/core/errors/error_handlers',['@web/core/l10n/translation','@web/core/browser/browser','@web/core/network/rpc','@web/core/registry','@web/session','@web/core/user','@web/core/errors/error_dialogs','@web/core/errors/error_service'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{browser}=require("@web/core/browser/browser");const{ConnectionLostError,RPCError,RequestEntityTooLargeError,rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const{session}=require("@web/session");const{user}=require("@web/core/user");const{ClientErrorDialog,ErrorDialog,NetworkErrorDialog,RequestEntityTooLargeErrorDialog,RPCErrorDialog,}=require("@web/core/errors/error_dialogs");const{UncaughtClientError,ThirdPartyScriptError,UncaughtPromiseError}=require("@web/core/errors/error_service");const errorHandlerRegistry=registry.category("error_handlers");const errorDialogRegistry=registry.category("error_dialogs");const errorNotificationRegistry=registry.category("error_notifications");__exports.rpcErrorHandler=rpcErrorHandler;function rpcErrorHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;} 2529if(originalError instanceof RPCError){error.unhandledRejectionEvent.preventDefault();const exceptionName=originalError.exceptionName;let ErrorComponent=originalError.Component;if(!ErrorComponent&&exceptionName){if(errorNotificationRegistry.contains(exceptionName)){const notif=errorNotificationRegistry.get(exceptionName);env.services.notification.add(notif.message||originalError.data.message,notif);return true;} 2530if(errorDialogRegistry.contains(exceptionName)){ErrorComponent=errorDialogRegistry.get(exceptionName);}} 2531if(!ErrorComponent&&originalError.data.context){const exceptionClass=originalError.data.context.exception_class;if(errorDialogRegistry.contains(exceptionClass)){ErrorComponent=errorDialogRegistry.get(exceptionClass);}} 2532env.services.dialog.add(ErrorComponent||RPCErrorDialog,{traceback:error.traceback,message:originalError.message,name:originalError.name,exceptionName:originalError.exceptionName,data:originalError.data,subType:originalError.subType,code:originalError.code,type:originalError.type,serverHost:error.event?.target?.location.host,model:originalError.model,});return true;}} 2533errorHandlerRegistry.add("rpcErrorHandler",rpcErrorHandler,{sequence:97});let connectionLostNotifRemove=null;__exports.lostConnectionHandler=lostConnectionHandler;function lostConnectionHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;} 2534if(originalError instanceof ConnectionLostError){if(connectionLostNotifRemove){return true;} 2535connectionLostNotifRemove=env.services.notification.add(_t("Connection lost. Trying to reconnect..."),{sticky:true});let delay=2000;browser.setTimeout(function checkConnection(){rpc("/web/webclient/version_info",{}).then(function(){if(connectionLostNotifRemove){connectionLostNotifRemove();connectionLostNotifRemove=null;} 2536env.services.notification.add(_t("Connection restored. You are back online."),{type:"info",});}).catch(()=>{delay=delay*1.5+500*Math.random();browser.setTimeout(checkConnection,delay);});},delay);return true;}} 2537errorHandlerRegistry.add("lostConnectionHandler",lostConnectionHandler,{sequence:98});__exports.requestEntityTooLargeHandler=requestEntityTooLargeHandler;function requestEntityTooLargeHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;} 2538if(originalError instanceof RequestEntityTooLargeError){env.services.dialog.add(RequestEntityTooLargeErrorDialog);return true;}} 2539errorHandlerRegistry.add("requestEntityTooLargeHandler",requestEntityTooLargeHandler,{sequence:99});const defaultDialogs=new Map([[UncaughtClientError,ClientErrorDialog],[UncaughtPromiseError,ClientErrorDialog],[ThirdPartyScriptError,NetworkErrorDialog],]);__exports.defaultHandler=defaultHandler;function defaultHandler(env,error){const DialogComponent=defaultDialogs.get(error.constructor)||ErrorDialog;env.services.dialog.add(DialogComponent,{traceback:error.traceback,message:error.message,name:error.name,serverHost:error.event?.target?.location.host,});return true;} 2540errorHandlerRegistry.add("defaultHandler",defaultHandler,{sequence:100});__exports.swallowAllVisitorErrors=swallowAllVisitorErrors;function swallowAllVisitorErrors(env,error,originalError){if(!user.isInternalUser&&!odoo.debug&&!session.test_mode){return true;}} 2541if(user.isInternalUser===undefined){if(session.is_frontend){console.warn("isInternalUser information is required for this handler to work. It must be available in the page.");}}else{registry.category("error_handlers").add("swallowAllVisitorErrors",swallowAllVisitorErrors,{sequence:0});} 2542return __exports;});; 2543 2544/* /web/static/src/core/errors/error_service.js */ 2545odoo.define('@web/core/errors/error_service',['@web/core/browser/browser','@web/core/registry','@web/core/errors/error_utils','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{completeUncaughtError,getErrorTechnicalName}=require("@web/core/errors/error_utils");const{isBrowserFirefox,isBrowserChrome}=require("@web/core/browser/feature_detection");const HTMLElementLoadingError=__exports.HTMLElementLoadingError=class HTMLElementLoadingError extends
2545Error{static message="Error loading an HTML Element";constructor(message=HTMLElementLoadingError.message,event){super(message);this.event=event;}} 2546const UncaughtError=__exports.UncaughtError=class UncaughtError extends Error{constructor(message){super(message);this.name=getErrorTechnicalName(this);this.traceback=null;}} 2547const UncaughtClientError=__exports.UncaughtClientError=class UncaughtClientError extends UncaughtError{constructor(message="Uncaught Javascript Error"){super(message);}} 2548const UncaughtPromiseError=__exports.UncaughtPromiseError=class UncaughtPromiseError extends UncaughtError{constructor(message="Uncaught Promise"){super(message);this.unhandledRejectionEvent=null;}} 2549const ThirdPartyScriptError=__exports.ThirdPartyScriptError=class ThirdPartyScriptError extends UncaughtError{constructor(message="Third-Party Script Error"){super(message);}} 2550const errorService=__exports.errorService={start(env){function handleError(uncaughtError,retry=true){function shouldLogError(){return(uncaughtError.event&&!uncaughtError.event.defaultPrevented&&uncaughtError.traceback);} 2551let originalError=uncaughtError;while(originalError instanceof Error&&"cause"in originalError){originalError=originalError.cause;} 2552for(const[name,handler]of registry.category("error_handlers").getEntries()){try{if(handler(env,uncaughtError,originalError)){break;}}catch(e){if(shouldLogError()){uncaughtError.event.preventDefault();console.error(`@web/core/error_service: handler "${name}" failed with "${ 2553 e.cause || e 2554 }" while trying to handle:\n`+uncaughtError.traceback);} 2555return;}} 2556if(shouldLogError()){uncaughtError.event.preventDefault();console.error(uncaughtError.traceback);}} 2557browser.addEventListener("error",async(ev)=>{const{colno,error,filename,lineno,message}=ev;const resizeObserverError="ResizeObserver loop completed with undelivered notifications.";if(!(error instanceof Error)&&message===resizeObserverError){ev.preventDefault();return;} 2558const isRedactedError=!filename&&!lineno&&!colno;const isThirdPartyScriptError=isRedactedError||(isBrowserFirefox()&&new URL(filename).origin!==window.location.origin);if(isThirdPartyScriptError&&!odoo.debug){return;} 2559let uncaughtError;if(isRedactedError){uncaughtError=new ThirdPartyScriptError();uncaughtError.traceback=`An error whose details cannot be accessed by the Odoo framework has occurred.\n`+`The error probably originates from a JavaScript file served from a different origin.\n`+`The full error is available in the browser console.`;}else{uncaughtError=new UncaughtClientError();uncaughtError.event=ev;if(error instanceof Error){error.errorEvent=ev;const annotated=env.debug&&env.debug.includes("assets");await completeUncaughtError(uncaughtError,error,annotated);}} 2560uncaughtError.cause=error;handleError(uncaughtError);});browser.addEventListener("unhandledrejection",async(ev)=>{let error=ev.reason;if(error&&error.type==="error"&&"eventPhase"in error){if(!error.bubbles){ev.preventDefault();return;} 2561let message;if(error.target){message=`${HTMLElementLoadingError.message}: ${error.target.nodeName}`;} 2562error=new HTMLElementLoadingError(message,error);} 2563let traceback;if(isBrowserChrome()&&ev instanceof CustomEvent&&error===undefined){if(!odoo.debug){return;} 2564traceback=`Uncaught unknown Error\n`+`An unknown error occured. This may be due to a Chrome extension meddling with Odoo.\n`+`(Opening your browser console might give you a hint on the error.)`;} 2565const uncaughtError=new UncaughtPromiseError();uncaughtError.unhandledRejectionEvent=ev;uncaughtError.event=ev;uncaughtError.traceback=traceback;if(error instanceof Error){error.errorEvent=ev;const annotated=env.debug&&env.debug.includes("assets");await completeUncaughtError(uncaughtError,error,annotated);} 2566uncaughtError.cause=error;handleError(uncaughtError);});},};registry.category("services").add("error",errorService,{sequence:1});return __exports;});; 2567 2568/* /web/static/src/core/errors/error_utils.js */ 2569odoo.define('@web/core/errors/error_utils',['@web/core/assets'],function(require){'use strict';let __exports={};const{loadJS}=require("@web/core/assets");function combineErrorNames(uncaughtError,originalError){const originalErrorName=getErrorTechnicalName(originalError);const uncaughtErrorName=getErrorTechnicalName(uncaughtError);if(originalErrorName===Error.name){return uncaughtErrorName;}else{return`${uncaughtErrorName} > ${originalErrorName}`;}} 2570__exports.fullTraceback=fullTraceback;function fullTraceback(error){let traceback=formatTraceback(error);let current=error.cause;while(current){traceback+=`\n\nCaused by: ${ 2571 current instanceof Error ? formatTraceback(current) : current 2572 }`;current=current.cause;} 2573return traceback;} 2574__exports.fullAnnotatedTraceback=fullAnnotatedTraceback;async function fullAnnotatedTraceback(error){if(error.annotatedTraceback){return error.annotatedTraceback;} 2575if(error.errorEvent){error.errorEvent.preventDefault();} 2576let traceback;try{traceback=await annotateTraceback(error);let current=error.cause;while(current){traceback+=`\n\nCaused by: ${ 2577 current instanceof Error ? await annotateTraceback(current) : current 2578 }`;current=current.cause;}}catch(e){console.warn("Failed to annotate traceback for error:",error,"failure reason:",e);traceback=fullTraceback(error);} 2579error.annotatedTraceback=traceback;if(error.errorEvent){throw error;} 2580return traceback;} 2581__exports.completeUncaughtError=completeUncaughtError;async function completeUncaughtError(uncaughtError,originalError,annotated=false){uncaughtError.name=combineErrorNames(uncaughtError,originalError);if(annotated){uncaughtError.traceback=await fullAnnotatedTraceback(originalError);}else{uncaughtError.traceback=fullTraceback(originalError);} 2582if(originalError.message){uncaughtError.message=`${uncaughtError.message} > ${originalError.message}`;} 2583uncaughtError.cause=originalError;} 2584__exports.getErrorTechnicalName=getErrorTechnicalName;function getErrorTechnicalName(error){return error.name!==Error.name?error.
2584name:error.constructor.name;} 2585__exports.formatTraceback=formatTraceback;function formatTraceback(error){const errorName=getErrorTechnicalName(error);let traceback=error.stack;const descriptionLine=`${errorName}: ${error.message}`;if(!traceback){traceback=descriptionLine;}else if(traceback.split("\n")[0].trim()!==descriptionLine){traceback=`${descriptionLine}\n${error.stack}`.replace(/\n/g,"\n ");} 2586return traceback;} 2587__exports.annotateTraceback=annotateTraceback;async function annotateTraceback(error){const traceback=formatTraceback(error);try{await loadJS("/web/static/lib/stacktracejs/stacktrace.js");}catch{return traceback;} 2588if(error.stack){const regex=/ line (\d*) > (Function):(\d*)/gm;const subst=`:$1`;error.stack=error.stack.replace(regex,subst);} 2589let frames;try{frames=await StackTrace.fromError(error);}catch(e){console.warn("The following error could not be annotated:",error,e);return traceback;} 2590const lines=traceback.split("\n");if(lines[lines.length-1].trim()===""){lines.splice(-1);} 2591let lineIndex=0;let frameIndex=0;while(frameIndex<frames.length){const line=lines[lineIndex];if(!line.match(/:\d+:\d+\)?$/)){lineIndex++;continue;} 2592const frame=frames[frameIndex];const info=` (${frame.fileName}:${frame.lineNumber})`;lines[lineIndex]=line+info;lineIndex++;frameIndex++;} 2593return lines.join("\n");} 2594return __exports;});; 2595 2596/* /web/static/src/core/errors/scss_error_dialog.js */ 2597odoo.define('@web/core/errors/scss_error_dialog',['@web/core/browser/browser','@web/core/registry','@web/core/l10n/translation','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{appTranslateFn,translationIsReady}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{getOrigin}=require("@web/core/utils/urls");const scssErrorNotificationService={dependencies:["notification"],start(env,{notification}){const origin=getOrigin();if(browser.location.origin==="null"){return;} 2598const assets=[...document.styleSheets].filter((sheet)=>{return(sheet.href?.includes("/web")&&sheet.href?.includes("/assets/")&&new URL(sheet.href,browser.location.origin).origin===origin);});translationIsReady.then(()=>{for(const asset of assets){let cssRules;try{cssRules=asset.cssRules;}catch{continue;} 2599const lastRule=cssRules?.[cssRules?.length-1];if(lastRule?.selectorText==="css_error_message"){const message=_t("The style compilation failed. This is an administrator or developer error that must be fixed for the entire database before continuing working. See browser console or server logs for details.");notification.add(message,{title:_t("Style error"),sticky:true,type:"danger",});console.log(lastRule.style.content.replaceAll("\\a","\n").replaceAll("\\*","*").replaceAll(`\\"`,`"`));}}});},};registry.category("services").add("scss_error_display",scssErrorNotificationService);return __exports;});; 2600 2601/* /web/static/src/core/expression_editor/expression_editor.js */ 2602odoo.define('@web/core/expression_editor/expression_editor',['@odoo/owl','@web/core/expression_editor/expression_editor_operator_editor','@web/core/l10n/translation','@web/core/model_field_selector/model_field_selector','@web/core/tree_editor/condition_tree','@web/core/tree_editor/expression_from_tree','@web/core/tree_editor/tree_editor','@web/core/tree_editor/tree_editor_operator_editor','@web/core/tree_editor/tree_editor_value_editors','@web/core/tree_editor/tree_from_expression','@web/core/tree_editor/utils'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{getExpressionDisplayedOperators}=require("@web/core/expression_editor/expression_editor_operator_editor");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{ModelFieldSelector}=require("@web/core/model_field_selector/model_field_selector");const{condition}=require("@web/core/tree_editor/condition_tree");const{expressionFromTree}=require("@web/core/tree_editor/expression_from_tree");const{TreeEditor}=require("@web/core/tree_editor/tree_editor");const{getOperatorEditorInfo}=require("@web/core/tree_editor/tree_editor_operator_editor");const{getDefaultValue}=require("@web/core/tree_editor/tree_editor_value_editors");const{treeFromExpression}=require("@web/core/tree_editor/tree_from_expression");const{getDefaultPath}=require("@web/core/tree_editor/utils");const ExpressionEditor=__exports.ExpressionEditor=class ExpressionEditor extends Component{static template="web.ExpressionEditor";static components={TreeEditor};static props={resModel:String,fields:Object,expression:String,update:Function,};
2602setup(){onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));} 2603async onPropsUpdated(props){this.filteredFields=Object.fromEntries(Object.entries(props.fields).filter(([_,fieldDef])=>fieldDef.type!=="properties"));try{this.tree=treeFromExpression(props.expression,{getFieldDef:(name)=>this.getFieldDef(name,props),distributeNot:!this.isDebugMode,generateSmartDates:false,});}catch{this.tree=null;}} 2604getFieldDef(name,props=this.props){if(typeof name==="string"){return props.fields[name]||null;} 2605return null;} 2606getDefaultCondition(){const defaultPath=getDefaultPath(this.filteredFields);const fieldDef=this.filteredFields[defaultPath];const operator=getExpressionDisplayedOperators(fieldDef)[0];const value=getDefaultValue(fieldDef,operator);return condition(fieldDef.name,operator,value);} 2607getDefaultOperator(fieldDef){return getExpressionDisplayedOperators(fieldDef)[0];} 2608getOperatorEditorInfo(fieldDef){const operators=getExpressionDisplayedOperators(fieldDef);return getOperatorEditorInfo(operators,fieldDef);} 2609getPathEditorInfo(resModel,defaultCondition){if(resModel!==this.props.resModel){throw new Error(`Expression editor doesn't support tree as value so resModel has to be props.resModel`);} 2610return{component:ModelFieldSelector,extractProps:({value,update})=>({path:value,update,resModel:this.props.resModel,readonly:false,filter:(fieldDef)=>fieldDef.name in this.filteredFields,showDebugInput:false,followRelations:false,isDebugMode:this.isDebugMode,}),isSupported:(value)=>[0,1].includes(value)||value in this.filteredFields,stringify:(value)=>this.props.fields[value].string,defaultValue:()=>defaultCondition.path,message:_t("Field properties not supported"),};} 2611get isDebugMode(){return!!this.env.debug;} 2612onExpressionChange(expression){this.props.update(expression);} 2613resetExpression(){this.props.update("True");} 2614update(tree){const expression=expressionFromTree(tree,{getFieldDef:(name)=>this.getFieldDef(name),generateSmartDates:false,});this.props.update(expression);}} 2615return __exports;});; 2616 2617/* /web/static/src/core/expression_editor/expression_editor_operator_editor.js */ 2618odoo.define('@web/core/expression_editor/expression_editor_operator_editor',['@web/core/domain_selector/domain_selector_operator_editor'],function(require){'use strict';let __exports={};const{getDomainDisplayedOperators}=require("@web/core/domain_selector/domain_selector_operator_editor");const EXPRESSION_VALID_OPERATORS=["<","<=",">",">=","between","in range","in","not in","=","!=","set","not set",];__exports.getExpressionDisplayedOperators=getExpressionDisplayedOperators;function getExpressionDisplayedOperators(fieldDef){const operators=getDomainDisplayedOperators(fieldDef);return operators.filter((operator)=>EXPRESSION_VALID_OPERATORS.includes(operator));} 2619return __exports;});; 2620 2621/* /web/static/src/core/expression_editor_dialog/expression_editor_dialog.js */ 2622odoo.define('@web/core/expression_editor_dialog/expression_editor_dialog',['@odoo/owl','@web/core/dialog/dialog','@web/core/expression_editor/expression_editor','@web/core/py_js/py','@web/core/utils/hooks','@web/core/l10n/translation','@web/core/user'],function(require){'use strict';let __exports={};const{Component,useRef,useState}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{ExpressionEditor}=require("@web/core/expression_editor/expression_editor");const{evaluateExpr}=require("@web/core/py_js/py");const{useService}=require("@web/core/utils/hooks");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{user}=require("@web/core/user");const ExpressionEditorDialog=__exports.ExpressionEditorDialog=class ExpressionEditorDialog extends Component{static components={Dialog,ExpressionEditor};static template="web.ExpressionEditorDialog";static props={close:Function,resModel:String,fields:Object,expression:String,onConfirm:Function,};setup(){this.notification=useService("notification");this.state=useState({expression:this.props.expression,});this.confirmButtonRef=useRef("confirm");} 2623get expressionEditorProps(){return{resModel:this.props.resModel,fields:this.props.fields,expression:this.state.expression,update:(expression)=>{this.state.expression=expression;},};} 2624makeDefaultRecord(){const record={};for(const[name,{type}
2624]of Object.entries(this.props.fields)){switch(type){case"integer":case"float":case"monetary":record[name]=name==="id"?false:0;break;case"one2many":case"many2many":record[name]=[];break;default:record[name]=false;}} 2625return record;} 2626async onConfirm(){this.confirmButtonRef.el.disabled=true;const record=this.makeDefaultRecord();const evalContext={...user.context,...record};try{evaluateExpr(this.state.expression,evalContext);}catch{if(this.confirmButtonRef.el){this.confirmButtonRef.el.disabled=false;} 2627this.notification.add(_t("Expression is invalid. Please correct it"),{type:"danger",});return;} 2628this.props.onConfirm(this.state.expression);this.props.close();} 2629onDiscard(){this.props.close();}} 2630return __exports;});; 2631 2632/* /web/static/src/core/field_service.js */ 2633odoo.define('@web/core/field_service',['@web/core/domain','@web/core/registry'],function(require){'use strict';let __exports={};const{Domain}=require("@web/core/domain");const{registry}=require("@web/core/registry");function getRelation(fieldDef,followRelationalProperties=false){if(fieldDef.relation){return fieldDef.relation;} 2634if(fieldDef.comodel&&followRelationalProperties){return fieldDef.comodel;} 2635return null;} 2636const fieldService=__exports.fieldService={dependencies:["orm"],async:["loadFieldInfo","loadFields","loadPath","loadPropertyDefinitions","loadPathDescription",],start(env,{orm}){async function loadFields(resModel,options={}){if(typeof resModel!=="string"||!resModel){throw new Error(`Invalid model name: ${resModel}`);} 2637return orm.cache({type:"disk"}).call(resModel,"fields_get",[options.fieldNames,options.attributes]);} 2638async function _loadPropertyDefinitions(resModel,fieldDefs,name,domain=[]){const{definition_record:definitionRecord,definition_record_field:definitionRecordField,}=fieldDefs[name];const definitionRecordModel=fieldDefs[definitionRecord].relation;let result;if(definitionRecordModel==="properties.base.definition"){result=await orm.call("properties.base.definition","get_properties_base_definition",[resModel,name]);}else{domain=Domain.and([[[definitionRecordField,"!=",false]],domain]).toList();result=await orm.webSearchRead(definitionRecordModel,domain,{specification:{display_name:{},[definitionRecordField]:{},},});} 2639const definitions={};for(const record of result.records){for(const definition of record[definitionRecordField]){definitions[definition.name]={is_property:true,searchable:true,record_id:record.id,record_name:record.display_name,...(definition.comodel?{relation:definition.comodel}:{}),...definition,};}} 2640return definitions;} 2641async function loadPropertyDefinitions(resModel,fieldName,domain){const fieldDefs=await loadFields(resModel);return _loadPropertyDefinitions(resModel,fieldDefs,fieldName,domain);} 2642async function _loadPath(resModel,fieldDefs,names,followRelationalProperties=false){if(!fieldDefs){return{isInvalid:"path",names,modelsInfo:[]};} 2643const[name,...remainingNames]=names;const modelsInfo=[{resModel,fieldDefs}];if(resModel==="*"&&remainingNames.length){return{isInvalid:"path",names,modelsInfo};} 2644const fieldDef=fieldDefs[name];if((name!=="*"&&!fieldDef)||(name==="*"&&remainingNames.length)){return{isInvalid:"path",names,modelsInfo};} 2645if(!remainingNames.length){return{names,modelsInfo};} 2646let subResult;const relation=getRelation(fieldDef,followRelationalProperties);if(relation){subResult=await _loadPath(relation,await loadFields(relation),remainingNames);}else if(fieldDef.type==="properties"){subResult=await _loadPath(followRelationalProperties?resModel:"*",await _loadPropertyDefinitions(resModel,fieldDefs,name),remainingNames);} 2647if(subResult){const result={names,modelsInfo:[...modelsInfo,...subResult.modelsInfo],};if(subResult.isInvalid){result.isInvalid="path";} 2648return result;} 2649return{isInvalid:"path",names,modelsInfo};} 2650async function loadPath(resModel,path="*",followRelationalProperties=false){const fieldDefs=await loadFields(resModel);if(typeof path!=="string"||!path){throw new Error(`Invalid path: ${path}`);} 2651return _loadPath(resModel,fieldDefs,path.split("."),followRelationalProperties);} 2652async function loadFieldInfo(resModel,path){if(typeof path!=="str
2652ing"||!path||path==="*"){return{resModel,fieldDef:null};} 2653const{isInvalid,names,modelsInfo}=await loadPath(resModel,path);if(isInvalid){return{resModel,fieldDef:null};} 2654const name=names.at(-1);const modelInfo=modelsInfo.at(-1);return{resModel:modelInfo.resModel,fieldDef:modelInfo.fieldDefs[name]};} 2655function makeString(value){return String(value??"-");} 2656async function loadPathDescription(resModel,path,allowEmpty){if([0,1].includes(path)){return{isInvalid:false,displayNames:[makeString(path)]};} 2657if(allowEmpty&&!path){return{isInvalid:false,displayNames:[]};} 2658if(typeof path!=="string"||!path||path==="*"){return{isInvalid:true,displayNames:[makeString()]};} 2659const{isInvalid,modelsInfo,names}=await loadPath(resModel,path);const result={isInvalid:!!isInvalid,displayNames:[]};if(!isInvalid){const lastName=names.at(-1);const lastFieldDef=modelsInfo.at(-1).fieldDefs[lastName];if(["properties","properties_definition"].includes(lastFieldDef.type)){result.isInvalid=true;}} 2660for(let index=0;index<names.length;index++){const name=names[index];const fieldDef=modelsInfo[index]?.fieldDefs[name];result.displayNames.push(fieldDef?.string||makeString(name));} 2661return result;} 2662return{loadFieldInfo,loadFields,loadPath,loadPathDescription,loadPropertyDefinitions,};},};registry.category("services").add("field",fieldService);return __exports;});; 2663 2664/* /web/static/src/core/file_input/file_input.js */ 2665odoo.define('@web/core/file_input/file_input',['@odoo/owl','@web/core/utils/files'],function(require){'use strict';let __exports={};const{Component,onMounted,status,useRef,useState}=require("@odoo/owl");const{useFileUploader}=require("@web/core/utils/files");const FileInput=__exports.FileInput=class FileInput extends Component{static template="web.FileInput";static defaultProps={acceptedFileExtensions:"*",hidden:false,multiUpload:false,onUpload:()=>{},route:"/web/binary/upload_attachment",beforeOpen:async()=>true,};static props={acceptedFileExtensions:{type:String,optional:true},autoOpen:{type:Boolean,optional:true},hidden:{type:Boolean,optional:true},multiUpload:{type:Boolean,optional:true},onUpload:{type:Function,optional:true},beforeOpen:{type:Function,optional:true},resId:{type:Number,optional:true},resModel:{type:String,optional:true},route:{type:String,optional:true},"*":true,};setup(){this.uploadFiles=useFileUploader();this.fileInputRef=useRef("file-input");this.state=useState({isDisable:false,});onMounted(()=>{if(this.props.autoOpen){this.onTriggerClicked();}});} 2666get httpParams(){const{resId,resModel}=this.props;const params={csrf_token:odoo.csrf_token,ufile:[...this.fileInputRef.el.files],};if(resModel){params.model=resModel;} 2667if(resId!==undefined){params.id=resId;} 2668return params;} 2669async onFileInputChange(){this.state.isDisable=true;const httpParams=this.httpParams;if(this.props.onWillUploadFiles){try{const files=await this.props.onWillUploadFiles(httpParams.ufile);httpParams.ufile=files;}catch(e){this.state.isDisable=false;throw e;}} 2670const parsedFileData=await this.uploadFiles(this.props.route,httpParams);if(status(this)==="destroyed"){return;} 2671if(parsedFileData){this.props.onUpload(parsedFileData,this.fileInputRef.el?this.fileInputRef.el.files:[]);this.fileInputRef.el.value=null;} 2672this.state.isDisable=false;} 2673async onTriggerClicked(){if(await this.props.beforeOpen()){this.fileInputRef.el.click();}}} 2674return __exports;});; 2675 2676/* /web/static/src/core/file_upload/file_upload_progress_bar.js */ 2677odoo.define('@web/core/file_upload/file_upload_progress_bar',['@web/core/l10n/translation','@web/core/utils/hooks','@web/core/confirmation_dialog/confirmation_dialog','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{useService}=require("@web/core/utils/hooks");const{ConfirmationDialog}=require("@web/core/confirmation_dialog/confirmation_dialog");const{Component}=require("@odoo/owl");const FileUploadProgressBar=__exports.FileUploadProgressBar=class FileUploadProgressBar extends Component{static template="web.FileUploadProgressBar";static props={fileUpload:{type:Object},};setup(){this.dialogService=useService("dialog");} 2678onCancel(){if(!this.props.fileUpload.xhr){return;} 2679this.dialogService.add(ConfirmationDialog,{body:_t("Do you really want to cancel the upload of %s?",this.props.fileUpload.title),confirm:()=>{this.props.fileUpload.xhr.abort();},});}} 2680return __exports;});; 2681 2682/* /web/static/src/core/file_upload/file_upload_progress_container.js */ 2683odoo.define('@web/core/file_upload/file_upload_progress_container',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const FileUploadProgressContainer=__exports.FileUploadProgressContainer=class FileUploadProgressContainer extends Component{static template="web.FileUploadProgressContainer";static props={Component:{optional:false},shouldDisplay:{type:Function,optional:true},fileUploads:{type:Object},};} 2684return __exports;});; 2685 2686/* /web/static/src/core/file_upload/file_upload_progress_record.js */ 2687odoo.define('@web/core/file_upload/file_upload_progress_record',['@web/core/l10n/translation','@web/core/file_upload/file_upload_progress_bar','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{FileUploadProgressBar}=require("@web/core/file_upload/file_upload_progress_bar");const{Component}=require("@odoo/owl");const FileUploadProgressRecord=__exports.FileUploadProgressRecord=class FileUploadProgressRecord extends Component{static template="";static components={FileUploadProgressBar,};static props={fileUpload:Object,selector:{type:String,optional:true},};getProgressTexts(){const fileUpload=this.props.fileUpload;const percent=Math.round(fileUpload.progress*100);if(percent===100){return{left:_t("Processing..."),right:"",};}else{const mbLoaded=Math.round(fileUpload.loaded/1000000);const mbTotal=Math.round(fileUpload.total/1000000);
2687return{left:_t("Uploading... (%s%)",percent),right:_t("(%(mbLoaded)s/%(mbTotal)sMB)",{mbLoaded,mbTotal}),};}}} 2688const FileUploadProgressKanbanRecord=__exports.FileUploadProgressKanbanRecord=class FileUploadProgressKanbanRecord extends FileUploadProgressRecord{static template="web.FileUploadProgressKanbanRecord";} 2689const FileUploadProgressDataRow=__exports.FileUploadProgressDataRow=class FileUploadProgressDataRow extends FileUploadProgressRecord{static template="web.FileUploadProgressDataRow";} 2690return __exports;});; 2691 2692/* /web/static/src/core/file_upload/file_upload_service.js */ 2693odoo.define('@web/core/file_upload/file_upload_service',['@web/core/l10n/translation','@web/core/registry','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{EventBus,reactive}=require("@odoo/owl");const fileUploadService=__exports.fileUploadService={dependencies:["notification"],createXhr(){return new window.XMLHttpRequest();},start(env,{notification:notificationService}){const uploads=reactive({});let nextId=1;const bus=new EventBus();const upload=async(route,files,params={})=>{const xhr=this.createXhr();xhr.open("POST",route);const formData=new FormData();formData.append("csrf_token",odoo.csrf_token);for(const file of files){formData.append("ufile",file);} 2694if(params.buildFormData){params.buildFormData(formData);} 2695const upload=reactive({id:nextId++,xhr,data:formData,progress:0,loaded:0,total:0,state:"pending",title:files.length===1?files[0].name:_t("%s Files",files.length),type:files.length===1?files[0].type:undefined,});uploads[upload.id]=upload;xhr.upload.addEventListener("progress",async(ev)=>{upload.progress=ev.loaded/ev.total;upload.loaded=ev.loaded;upload.total=ev.total;upload.state="loading";});xhr.addEventListener("load",()=>{try{handleResponse();}catch(e){onError(e);return;} 2696delete uploads[upload.id];upload.state="loaded";bus.trigger("FILE_UPLOAD_LOADED",{upload});});function handleResponse(){const resp=xhr.responseText??xhr.response;let error;let errorMessage="";if(!(xhr.status>=200&&xhr.status<300)){error=true;} 2697if(resp){let content=resp;if(typeof content==="string"){try{content=JSON.parse(content);}catch{try{content=new DOMParser().parseFromString(content,"text/html");}catch{}}} 2698if(error&&content instanceof Document){errorMessage=content.body.textContent;}else if(content instanceof Object){if(content.error){error=true;if(content.error.data){errorMessage=`${content.error.data.name}: ${content.error.data.message}`;}else{errorMessage=content.error.message||errorMessage;}}}} 2699if(error){throw new Error(errorMessage);} 2700return true;} 2701function onError(error){const defaultErrorMessage=_t("An error occured while uploading.");delete uploads[upload.id];upload.state="error";const displayError=params.displayErrorNotification??true;if(displayError){notificationService.add(error?.message||defaultErrorMessage,{type:"danger",sticky:true,});} 2702bus.trigger("FILE_UPLOAD_ERROR",{upload});} 2703xhr.addEventListener("error",(ev)=>onError(ev.error));xhr.addEventListener("abort",async()=>{delete uploads[upload.id];upload.state="abort";bus.trigger("FILE_UPLOAD_ERROR",{upload});});xhr.send(formData);bus.trigger("FILE_UPLOAD_ADDED",{upload});return upload;};return{bus,upload,uploads};},};registry.category("services").add("file_upload",fileUploadService);return __exports;});; 2704 2705/* /web/static/src/core/file_viewer/file_model.js */ 2706odoo.define('@web/core/file_viewer/file_model',['@web/core/utils/urls'],function(require){'use strict';let __exports={};const{url}=require("@web/core/utils/urls");const FileModelMixin=__exports.FileModelMixin=(T)=>class extends T{access_token;checksum;extension;id;mimetype;name;ownership_token;raw_access_token;type;tmpUrl;url;uploading;get defaultSource(){const route=url(this.urlRoute,this.urlQueryParams);const encodedRoute=encodeURIComponent(route);if(this.isPdf){return`/web/static/lib/pdfjs/web/viewer.html?file=${encodedRoute}#pagemode=none`;} 2707if(this.isUrlYoutube){const urlArr=this.url.split("/");let token=urlArr[urlArr.length-1];if(token.includes("watch")){token=token.split("v=")[1];const amp=token.indexOf("&");if(amp!==-1){token=token.substring(0,amp);}} 2708return`https://www.youtube.com/embed/${token}`;} 2709return route;}
2710get downloadUrl(){return url(this.urlRoute,{...this.urlQueryParams,download:true});} 2711get isImage(){const imageMimetypes=["image/bmp","image/gif","image/jpeg","image/png","image/svg+xml","image/tiff","image/x-icon","image/webp",];return imageMimetypes.includes(this.mimetype);} 2712get isPdf(){return this.mimetype&&this.mimetype.startsWith("application/pdf");} 2713get isText(){const textMimeType=["application/javascript","application/json","text/css","text/html","text/plain",];return textMimeType.includes(this.mimetype);} 2714get isUrl(){return this.type==="url"&&this.url;} 2715get isUrlYoutube(){return!!this.url&&this.url.includes("youtu");} 2716get isVideo(){const videoMimeTypes=["audio/mpeg","video/x-matroska","video/mp4","video/webm"];return videoMimeTypes.includes(this.mimetype);} 2717get isViewable(){return((this.isText||this.isImage||this.isVideo||this.isPdf||this.isUrlYoutube)&&!this.uploading);} 2718get urlQueryParams(){if(this.uploading&&this.tmpUrl){return{};} 2719const params={access_token:this.raw_access_token||this.access_token,filename:this.name,unique:this.checksum,};for(const prop in params){if(!params[prop]){delete params[prop];}} 2720return params;} 2721get urlRoute(){if(this.uploading&&this.tmpUrl){return this.tmpUrl;} 2722return this.isImage?`/web/image/${this.id}`:`/web/content/${this.id}`;}};const FileModel=__exports.FileModel=class FileModel extends FileModelMixin(Object){} 2723return __exports;});; 2724 2725/* /web/static/src/core/file_viewer/file_viewer.js */ 2726odoo.define('@web/core/file_viewer/file_viewer',['@odoo/owl','@web/core/network/download','@web/core/utils/hooks','@web/core/utils/pdfjs'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef,useState}=require("@odoo/owl");const{downloadFile}=require("@web/core/network/download");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{hidePDFJSButtons}=require("@web/core/utils/pdfjs");const FileViewer=__exports.FileViewer=class FileViewer extends Component{static template="web.FileViewer";static components={};static props=["files","startIndex","close?","modal?"];static defaultProps={modal:true,};setup(){useAutofocus();this.imageRef=useRef("image");this.zoomerRef=useRef("zoomer");this.iframeViewerPdfRef=useRef("iframeViewerPdf");this.isDragging=false;this.dragStartX=0;this.dragStartY=0;this.scrollZoomStep=0.1;this.zoomStep=0.5;this.minScale=0.5;this.translate={dx:0,dy:0,x:0,y:0,};this.state=useState({index:this.props.startIndex,file:this.props.files[this.props.startIndex],imageLoaded:false,scale:1,angle:0,isIframeLoaded:false,});this.ui=useService("ui");useEffect((el)=>{if(el){hidePDFJSButtons(this.iframeViewerPdfRef.el,{hideDownload:true,});}},()=>[this.iframeViewerPdfRef.el]);} 2727onImageLoaded(){this.state.imageLoaded=true;} 2728onIframeLoaded(ev){requestAnimationFrame(()=>{this.state.isIframeLoaded=true;});} 2729close(){this.props.close&&this.props.close();} 2730next(){const last=this.props.files.length-1;this.activateFile(this.state.index===last?0:this.state.index+1);} 2731previous(){const last=this.props.files.length-1;this.activateFile(this.state.index===0?last:this.state.index-1);} 2732activateFile(index){this.state.index=index;this.state.file=this.props.files[index];} 2733onKeydown(ev){switch(ev.key){case"ArrowRight":this.next();break;case"ArrowLeft":this.previous();break;case"Escape":this.close();break;case"q":this.close();break;} 2734if(this.state.file.isImage){switch(ev.key){case"r":this.rotate();break;case"+":this.zoomIn();break;case"-":this.zoomOut();break;case"0":this.resetZoom();break;}}} 2735onWheelImage(ev){if(ev.deltaY>0){this.zoomOut({scroll:true});}else{this.zoomIn({scroll:true});}} 2736onMousedownImage(ev){if(this.isDragging){return;} 2737if(ev.button!==0){return;} 2738this.isDragging=true;this.dragStartX=ev.clientX;this.dragStartY=ev.clientY;} 2739onMouseupImage(){if(!this.isDragging){return;} 2740this.isDragging=false;this.translate.x+=this.translate.dx;this.translate.y+=this.translate.dy;this.translate.dx=0;this.translate.dy=0;this.updateZoomerStyle();} 2741onMousemoveView(ev){if(!this.isDragging){return;} 2742this.translate.dx=ev.clientX-this.dragStartX;this.translate.dy=ev.clientY-this.dragStartY;this.updateZoomerStyle();} 2743resetZoom(){this.state.scale=1;this.updateZoomerStyle();} 2744rotate(){this.state.angle+=90;} 2745zoomIn({scroll=false}={}){this.state.scale=this.state.scale+(scroll?this.scrollZoomStep:this.zoomStep);this.updateZoomerStyle();} 2746zoomOut({scroll=false}={}){if(this.state.scale===this.minScale){return;} 2747const unflooredAdaptedScale=this.state.scale-(scroll?this.scrollZoomStep:this.zoomStep);this.state.scale=Math.max(this.minScale,unflooredAdaptedScale);this.updateZoomerStyle();} 2748updateZoomerStyle(){const tx=this.imageRef.el.offsetWidth*this.state.scale>this.zoomerRef.el.offsetWidth?this.translate.x+this.translate.dx:0;const ty=this.imageRef.el.offsetHeight*this.state.scale>this.zoomerRef.el.offsetHeight?this.translate.y+this.translate.dy:0;if(tx===0){this.translate.x=0;} 2749if(ty===0){this.translate.y=0;} 2750this.zoomerRef.el.style="transform: "+`translate(${tx}px, ${ty}px)`;} 2751get imageStyle(){let style="transform: "+`scale3d(${this.state.scale}, ${this.state.scale}, 1) `+`rotate(${this.state.angle}deg);`;if(this.state.angle%180!==0){style+=`max-height: ${window.innerWidth}px; max-width: ${window.innerHeight}px;`;}else{style+="max-height: 100%; max-width: 100%;";} 2752style+=`background: repeating-conic-gradient(#ccc 0deg 90deg, #fff 90deg 180deg) 50% / 20p
2752x 20px;`;return style;} 2753onClickPrint(){const printWindow=window.open();const image=printWindow.document.createElement("img");image.setAttribute("onload","window.print(); setTimeout(window.close, 10)");image.setAttribute("onerror","window.print(); setTimeout(window.close, 10)");image.src=this.state.file.defaultSource;printWindow.document.body.appendChild(image);} 2754onClickDownload(){downloadFile(this.state.file.downloadUrl);}} 2755return __exports;});; 2756 2757/* /web/static/src/core/file_viewer/file_viewer_hook.js */ 2758odoo.define('@web/core/file_viewer/file_viewer_hook',['@odoo/owl','@web/core/registry','@web/core/file_viewer/file_viewer'],function(require){'use strict';let __exports={};const{onWillDestroy}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{FileViewer}=require("@web/core/file_viewer/file_viewer");let id=1;__exports.createFileViewer=createFileViewer;function createFileViewer(){const fileViewerId=`web.file_viewer${id++}`;function open(file,files=[file]){close();if(!file.isViewable){return;} 2759if(files.length>0){const viewableFiles=files.filter((file)=>file.isViewable);const index=viewableFiles.indexOf(file);registry.category("main_components").add(fileViewerId,{Component:FileViewer,props:{files:viewableFiles,startIndex:index,close},});}} 2760function close(){registry.category("main_components").remove(fileViewerId);} 2761return{open,close};} 2762__exports.useFileViewer=useFileViewer;function useFileViewer(){const{open,close}=createFileViewer();onWillDestroy(close);return{open,close};} 2763return __exports;});; 2764 2765/* /web/static/src/core/hotkeys/hotkey_hook.js */ 2766odoo.define('@web/core/hotkeys/hotkey_hook',['@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{useEffect}=require("@odoo/owl");__exports.useHotkey=useHotkey;function useHotkey(hotkey,callback,options={}){const hotkeyService=useService("hotkey");useEffect(()=>hotkeyService.add(hotkey,callback,options),()=>[]);} 2767return __exports;});; 2768 2769/* /web/static/src/core/hotkeys/hotkey_service.js */ 2770odoo.define('@web/core/hotkeys/hotkey_service',['@web/core/browser/feature_detection','@web/core/registry','@web/core/browser/browser','@web/core/utils/ui'],function(require){'use strict';let __exports={};const{isMacOS}=require("@web/core/browser/feature_detection");const{registry}=require("@web/core/registry");const{browser}=require("@web/core/browser/browser");const{getVisibleElements}=require("@web/core/utils/ui");const ALPHANUM_KEYS="abcdefghijklmnopqrstuvwxyz0123456789".split("");const NAV_KEYS=["arrowleft","arrowright","arrowup","arrowdown","pageup","pagedown","home","end","backspace","enter","tab","delete","space",];const MODIFIERS=["alt","control","shift"];const AUTHORIZED_KEYS=[...ALPHANUM_KEYS,...NAV_KEYS,"escape","<",">"];__exports.getActiveHotkey=getActiveHotkey;function getActiveHotkey(ev){if(!ev.key){return"";} 2771if(ev.isComposing){return"";} 2772const hotkey=[];if(isMacOS()?ev.ctrlKey:ev.altKey){hotkey.push("alt");} 2773if(isMacOS()?ev.metaKey:ev.ctrlKey){hotkey.push("control");} 2774if(ev.shiftKey){hotkey.push("shift");} 2775let key=ev.key.toLowerCase();if(key===" "){key="space";} 2776if(ev.code&&ev.code.indexOf("Digit")===0){key=ev.code.slice(-1);} 2777if(!AUTHORIZED_KEYS.includes(key)&&ev.code&&ev.code.indexOf("Key")===0){key=ev.code.slice(-1).toLowerCase();} 2778if(!MODIFIERS.includes(key)){hotkey.push(key);} 2779return hotkey.join("+");} 2780const hotkeyService=__exports.hotkeyService={dependencies:["ui"],overlayModifier:"alt",start(env,{ui}){const registrations=new Map();let nextToken=0;let overlaysVisible=false;addListeners(browser);function addListeners(target){target.addEventListener("keydown",onKeydown);target.addEventListener("keyup",removeHotkeyOverlays);target.addEventListener("blur",removeHotkeyOverlays);target.addEventListener("click",removeHotkeyOverlays);} 2781function onKeydown(event){if(event.code&&event.code.indexOf("Numpad")===0&&/^\d$/.test(event.key)){return;} 2782const hotkey=getActiveHotkey(event);if(!hotkey){return;} 2783const{activeElement,isBlocked}=ui;if(isBlocked){return;} 2784const elementsWithAccessKey=document.querySelectorAll("[accesskey]");for(const el of elementsWithAccessKey){if(el instanceof HTMLElement){el.dataset.hotkey=el.accessKey;el.removeAttribute("accesskey");}} 2785if(!overlaysVisible&&hotkey===hotkeyService.overlayModifier){if(addHotkeyOverlays(activeElement)){event.preventDefault();} 2786return;} 2787const singleKey=hotkey.split("+").pop();if(!AUTHORIZED_KEYS.includes(singleKey)){return;} 2788const targetIsEditable=event.target instanceof HTMLElement&&(/input|textarea/i.test(event.target.tagName)||event.target.isContentEditable)&&!event.target.matches("input[type=checkbox], input[type=radio]");const shouldProtectEditable=targetIsEditable&&!event.target.dataset.allowHotkeys&&singleKey!=="escape";const infos={activeElement,hotkey,isRepeated:event.repeat,target:event.target,shouldProtectEditable,};const dispatched=dispatch(infos);
2788if(dispatched){event.preventDefault();event.stopImmediatePropagation();} 2789if(overlaysVisible){removeHotkeyOverlays();event.preventDefault();}} 2790function dispatch(infos){const{activeElement,hotkey,isRepeated,target,shouldProtectEditable}=infos;const reversedRegistrations=Array.from(registrations.values()).reverse();const domRegistrations=getDomRegistrations(hotkey,activeElement);const allRegistrations=reversedRegistrations.concat(domRegistrations);const candidates=allRegistrations.filter((reg)=>reg.hotkey===hotkey&&(reg.allowRepeat||!isRepeated)&&(reg.bypassEditableProtection||!shouldProtectEditable)&&(reg.global||reg.activeElement===activeElement)&&(!reg.isAvailable||reg.isAvailable(target))&&(!reg.area||(target&®.area()&®.area().contains(target))));let winner=candidates.shift();if(winner&&winner.area){for(const candidate of candidates.filter((c)=>Boolean(c.area))){if(candidate.area()&&winner.area().contains(candidate.area())){winner=candidate;}}} 2791if(winner){winner.callback({area:winner.area&&winner.area(),target,});return true;} 2792return false;} 2793function getDomRegistrations(hotkey,activeElement){const overlayModParts=hotkeyService.overlayModifier.split("+");if(!overlayModParts.every((el)=>hotkey.includes(el))){return[];} 2794const cleanHotkey=hotkey.split("+").filter((key)=>!overlayModParts.includes(key)).join("+");const elems=getVisibleElements(activeElement,`[data-hotkey='${cleanHotkey}' i]`);return elems.map((el)=>({hotkey,activeElement,bypassEditableProtection:true,callback:()=>{if(document.activeElement){document.activeElement.blur();} 2795el.focus();setTimeout(()=>el.click());},}));} 2796function addHotkeyOverlays(activeElement){const hotkeysFromHookToHighlight=[];for(const[,registration]of registrations){const overlayElement=registration.withOverlay?.();if(overlayElement){hotkeysFromHookToHighlight.push({hotkey:registration.hotkey.replace(`${hotkeyService.overlayModifier}+`,""),el:overlayElement,});}} 2797const hotkeysFromDomToHighlight=getVisibleElements(activeElement,"[data-hotkey]:not(:disabled)").map((el)=>({hotkey:el.dataset.hotkey,el}));const items=[...hotkeysFromDomToHighlight,...hotkeysFromHookToHighlight];if(!items.length){return false;} 2798for(const item of items){const hotkey=item.hotkey;const overlay=document.createElement("div");overlay.classList.add("o_web_hotkey_overlay","position-absolute","top-0","bottom-0","start-0","end-0","d-flex","justify-content-center","align-items-center","m-0","bg-black-50","h6");overlay.style.zIndex=1;const overlayKbd=document.createElement("kbd");overlayKbd.className="small";overlayKbd.appendChild(document.createTextNode(hotkey.toUpperCase()));overlay.appendChild(overlayKbd);let overlayParent;if(item.el.tagName.toUpperCase()==="INPUT"){overlayParent=item.el.parentElement;}else{overlayParent=item.el;} 2799if(overlayParent.style.position!=="absolute"){overlayParent.style.position="relative";} 2800overlayParent.appendChild(overlay);} 2801overlaysVisible=true;return true;} 2802function removeHotkeyOverlays(){for(const overlay of document.querySelectorAll(".o_web_hotkey_overlay")){overlay.remove();} 2803overlaysVisible=false;} 2804function registerHotkey(hotkey,callback,options={}){if(!hotkey||hotkey.length===0){throw new Error("You must specify an hotkey when registering a registration.");} 2805if(!callback||typeof callback!=="function"){throw new Error("You must specify a callback function when registering a registration.");} 2806const keys=hotkey.toLowerCase().split("+").filter((k)=>!MODIFIERS.includes(k));if(keys.some((k)=>!AUTHORIZED_KEYS.includes(k))){throw new Error(`You are trying to subscribe for an hotkey ('${hotkey}') 2807 that contains parts not whitelisted: ${keys.join(", ")}`);}else if(keys.length>1){throw new Error(`You are trying to subscribe for an hotkey ('${hotkey}') 2808 that contains more than one single key part: ${keys.join("+")}`);} 2809const token=nextToken++;const registration={hotkey:hotkey.toLowerCase(),callback,activeElement:null,allowRepeat:options&&options.allowRepeat,bypassEditableProtection:options&&options.bypassEditableProtection,global:options&&options.global,area:options&&options.area,isAvailable:options&&options.isAvailable,withOverlay:options&&options.withOverlay,};Promise.resolve().then(()=>{registration.activeElement=ui.activeElement;});registrations.set(token,registration);return token;} 2810function unregisterHotkey(token){registrations.delete(token);} 2811return{add(hotkey,callback,options={}){const token=registerHotkey(hotkey,callback,options);return()=>{unregisterHotkey(token);};},registerIframe(iframe){addListeners(iframe.contentWindow);},};},};registry.category("services").add("hotkey",hotkeyService);return __exports;});; 2812 2813/* /web/static/src/core/install_scoped_app/install_scoped_app.js */ 2814odoo.define('@web/core/install_scoped_app/install_scoped_app',['@web/core/browser/browser','@web/core/registry','@odoo/owl','@web/core/browser/feature_detection','@web/core/utils/hooks','@web/core/dropdown/dropdown'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Component,onMounted,useState}=require("@odoo/owl");const{isDisplayStandalone}=require("@web/core/browser/feature_detection");const{useService}=require("@web/core/utils/hooks");const{Dropdown}=require("@web/core/dropdown/dropdown");const InstallScopedApp=__exports.InstallScopedApp=class InstallScopedApp extends Component{static props={};static template="web.InstallScopedApp";static components={Dropdown};setup(){this.pwa=useService("pwa");this.state=useState({manifest:{},showInstallUI:false});this.isDisplayStandalone=isDisplayStandalone();this.isInstallationPossible=browser.BeforeInstallPromptEvent!==undefined;onMounted(async()=>{this.state.manifest=await this.pwa.getManifest();this.state.showInstallUI=true;});} 2815onChangeName(ev){const value=ev.target.value;if(value!==this.state.manifest.name){const url=new URL(document.location.href);
2815url.searchParams.set("app_name",encodeURIComponent(value));browser.location.replace(url);}} 2816onInstall(){this.state.showInstallUI=false;this.pwa.show({onDone:(res)=>{if(res.outcome==="accepted"){browser.location.replace(this.state.manifest.start_url);}else{this.state.showInstallUI=true;}},});}} 2817registry.category("public_components").add("web.install_scoped_app",InstallScopedApp);return __exports;});; 2818 2819/* /web/static/src/core/ir_ui_view_code_editor/code_editor.js */ 2820odoo.define('@web/core/ir_ui_view_code_editor/code_editor',['@odoo/owl','@web/core/code_editor/code_editor','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{useEffect,onMounted}=require("@odoo/owl");const{CodeEditor}=require("@web/core/code_editor/code_editor");const{escapeRegExp}=require("@web/core/utils/strings");const IrUiViewCodeEditor=__exports.IrUiViewCodeEditor=class IrUiViewCodeEditor extends CodeEditor{static props={...this.props,record:{type:Object},};setup(){super.setup(...arguments);this.markers=[];onMounted(()=>{this.aceEditor.getSession().on("change",()=>{this.clearMarkers();});});useEffect((arch,invalid_locators)=>{if(arch&&invalid_locators){this.highlightInvalidLocators(arch,invalid_locators);return()=>this.clearMarkers();}},()=>[this.props.value,this.props.record?.data.invalid_locators]);} 2821async highlightInvalidLocators(arch,invalid_locators){const resModel=this.env.model?.config.resModel;const resId=this.env.model?.config.resId;if(resModel==="ir.ui.view"&&resId){const{doc}=this.aceEditor.session;for(const spec of invalid_locators){if(spec.broken_hierarchy){continue} 2822const{tag,attrib,sourceline}=spec;const attribRegex=Object.entries(attrib).map(([key,value])=>{const escapedValue=escapeRegExp(value).replace(/"/g,'("|")');return(`(?=[^>]*?\\b${escapeRegExp(key)}\\s*=\\s*`+`(?:"[^"]*${escapedValue}[^"]*"|'[^']*${escapedValue}[^']*'))`);}).join("");const nodeRegex=new RegExp(`<${escapeRegExp(tag)}\\s+${attribRegex}[^>]*>`,"g");for(const match of arch.matchAll(nodeRegex)){const startIndex=match.index;const endIndex=startIndex+match[0].length;const startPos=doc.indexToPosition(startIndex);const endPos=doc.indexToPosition(endIndex);if(startPos.row+1===sourceline){const range=new window.ace.Range(startPos.row,startPos.column,endPos.row,endPos.column);this.markers.push(this.aceEditor.session.addMarker(range,"invalid_locator","text"));}}}}} 2823clearMarkers(){this.markers.forEach((marker)=>this.aceEditor.session.removeMarker(marker));this.markers=[];}} 2824return __exports;});; 2825 2826/* /web/static/src/core/l10n/dates.js */ 2827odoo.define('@web/core/l10n/dates',['@web/core/l10n/localization','@web/core/l10n/translation','@web/core/utils/functions','@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{memoize}=require("@web/core/utils/functions");const{ensureArray}=require("@web/core/utils/arrays");const{DateTime,Settings}=luxon;const MIN_VALID_DATE=__exports.MIN_VALID_DATE=DateTime.fromObject({year:1000});const MAX_VALID_DATE=__exports.MAX_VALID_DATE=DateTime.fromObject({year:9999}).endOf("year");const SERVER_DATE_FORMAT="yyyy-MM-dd";const SERVER_TIME_FORMAT="HH:mm:ss";const SERVER_DATETIME_FORMAT=`${SERVER_DATE_FORMAT} ${SERVER_TIME_FORMAT}`;const nonAlphaRegex=/[^a-z]/gi;const nonDigitRegex=/[^\d]/g;const normalizeFormatTable={a:"ccc",A:"cccc",b:"MMM",B:"MMMM",d:"dd",H:"HH",I:"hh",j:"o",m:"MM",M:"mm",p:"a",S:"ss",W:"WW",w:"c",y:"yy",Y:"yyyy",c:"ccc MMM d HH:mm:ss yyyy",x:"MM/dd/yy",X:"HH:mm:ss",};const smartDateUnits={d:"days",m:"months",w:"weeks",y:"years",H:"hours",M:"minutes",S:"seconds",};const smartWeekdays={monday:1,tuesday:2,wednesday:3,thursday:4,friday:5,saturday:6,sunday:7,};const dateCache=new WeakMap();const dateTimeCache=new WeakMap();const ConversionError=__exports.ConversionError=class ConversionError extends Error{name="ConversionError";} 2828__exports.areDatesEqual=areDatesEqual;function areDatesEqual(d1,d2){if(Array.isArray(d1)||Array.isArray(d2)){d1=ensureArray(d1);d2=ensureArray(d2);return d1.length===d2.length&&d1.every((d1Val,i)=>areDatesEqual(d1Val,d2[i]));} 2829if(d1 instanceof DateTime&&d2 instanceof DateTime&&d1!==d2){return d1.equals(d2);}else{return d1===d2;}} 2830__exports.clampDate=clampDate;
2830function clampDate(desired,minDate,maxDate){if(maxDate<desired){return maxDate;} 2831if(minDate>desired){return minDate;} 2832return desired;} 2833__exports.getLocalYearAndWeek=getLocalYearAndWeek;function getLocalYearAndWeek(date){if(!date.isLuxonDateTime){date=DateTime.fromJSDate(date);} 2834const{weekStart}=localization;const startDate=date.minus({days:(date.weekday+7-weekStart)%7});date=weekStart>1&&weekStart<5?startDate.minus({days:(startDate.weekday+6)%7}):startDate.plus({days:(8-startDate.weekday)%7});date=date.plus({days:6});const jan4=DateTime.local(date.year,1,4);let diffDays,year;if(date<jan4){diffDays=date.diff(jan4.minus({years:1}),"day").days 2835year=date.year-1}else{diffDays=date.diff(jan4,"day").days;year=date.year} 2836return{year:year,week:Math.trunc(diffDays/7)+1,startDate,};} 2837__exports.getStartOfLocalWeek=getStartOfLocalWeek;function getStartOfLocalWeek(date){const{weekStart}=localization;const weekday=date.weekday<weekStart?weekStart-7:weekStart;return date.set({weekday}).startOf("day");} 2838__exports.getEndOfLocalWeek=getEndOfLocalWeek;function getEndOfLocalWeek(date){return getStartOfLocalWeek(date).plus({days:6}).endOf("day");} 2839__exports.isInRange=isInRange;function isInRange(value,range){if(!value||!range){return false;} 2840if(Array.isArray(value)){const actualValues=value.filter(Boolean).sort();if(actualValues.length<2){return isInRange(actualValues[0],range);} 2841return((actualValues[0]<=range[0]&&range[0]<=actualValues[1])||(range[0]<=actualValues[0]&&actualValues[0]<=range[1]));}else{return range[0]<=value&&value<=range[1];}} 2842function isValidDate(date){return date&&date.isValid&&isInRange(date,[MIN_VALID_DATE,MAX_VALID_DATE]);} 2843function parseSmartDateInput(value){const terms=value.split(/\s+/);if(!terms.length){return false;} 2844var now=DateTime.local().startOf("second");if(terms[0]=="today"){terms.shift();now=now.startOf("day");}else if(terms[0]=="now"){terms.shift();}else if(terms.length==1&&/^[=+-]\d+$/.test(terms[0])){terms[0]+="d";} 2845for(let i=0;i<terms.length;i++){const term=terms[i];const operator=term[0];if(term.length<3||!["+","-","="].includes(operator)){return false;} 2846const dayname=term.slice(1);if(Object.hasOwn(smartWeekdays,dayname)||dayname==="week_start"){const{weekStart}=localization;const weekdayNumber=dayname==="week_start"?weekStart:smartWeekdays[dayname];let weekdayOffset=((weekdayNumber-weekStart+7)%7)-((now.weekday-weekStart+7)%7);if(operator=="+"||operator=="-"){if(weekdayOffset>0&&operator=="-"){weekdayOffset-=7;}else if(weekdayOffset<0&&operator=="+"){weekdayOffset+=7;}}else{now=now.startOf("day");} 2847now=now.plus({days:weekdayOffset});continue;} 2848try{const field_name=smartDateUnits[term[term.length-1]];const number=parseInt(term.slice(1,-1),10);if(!field_name||isNaN(number)){return false;} 2849if(operator=="+"){now=now.plus({[field_name]:number});}else if(operator=="-"){now=now.minus({[field_name]:number});}else if(operator=="="){if(field_name=="seconds"||field_name=="minutes"||field_name=="hours"){now=now.startOf(field_name);}else if(field_name=="weeks"){return false;}else{now=now.startOf("day");} 2850now=now.set({[field_name]:number});}}catch{return false;}} 2851return now;} 2852const stripAlphaDupes=memoize(function stripAlphaDupes(str){return str.replace(/[a-z]/gi,(letter,index,str)=>letter===str[index-1]?"":letter);});const strftimeToLuxonFormat=__exports.strftimeToLuxonFormat=memoize(function strftimeToLuxonFormat(format){const output=[];let inToken=false;for(let index=0;index<format.length;++index){let character=format[index];if(character==="%"&&!inToken){inToken=true;continue;} 2853if(/[a-z]/gi.test(character)){if(inToken&&normalizeFormatTable[character]!==undefined){character=normalizeFormatTable[character];}else{character=`'${character}'`;}} 2854output.push(character);inToken=false;} 2855return output.join("");});__exports.today=today;function today(){return DateTime.local().startOf("day");} 2856__exports.formatDate=formatDate;function formatDate(value,options={}){if(!value){return"";} 2857const format=options.format||localization.dateFormat;return value.toFormat(format);} 2858__exports.formatDateTime=formatDateTime;function formatDateTime(value,options={}){if(!value){return"";} 2859const format=options.format||localization.dateTimeFormat;return value.setZone(options.tz||"default").toFormat(format);} 2860__exports.toLocaleDateString=toLocaleDateString;function toLocaleDateString(value){if(!value){return"";} 2861const format={...DateTime.DATE_MED};if(today().year===value.year){delete format.year;}
2862return value.toLocaleString(format);} 2863__exports.toLocaleDateTimeString=toLocaleDateTimeString;function toLocaleDateTimeString(value,options={showDate:true,showTime:true,showSeconds:false}){if(!value){return"";} 2864const format={...DateTime.DATETIME_MED_WITH_SECONDS};if(!options.showSeconds){delete format.second;} 2865if(options.showDate===false){delete format.day;delete format.month;delete format.year;} 2866if(options.showTime===false){delete format.hour;delete format.minute;} 2867if(today().year===value.year){delete format.year;} 2868return value.setZone(options.tz||"default").toLocaleString(format);} 2869__exports.formatDuration=formatDuration;function formatDuration(seconds,showFullDuration){const displayStyle=showFullDuration?"long":"narrow";const numberOfValuesToDisplay=showFullDuration?2:1;const durationKeys=["years","months","days","hours","minutes"];if(seconds<60){seconds=60;} 2870seconds-=seconds%60;let duration=luxon.Duration.fromObject({seconds:seconds}).shiftTo(...durationKeys);duration=duration.shiftTo(...durationKeys.filter((key)=>duration.get(key)));const durationSplit=duration.toHuman({unitDisplay:displayStyle}).split(",");if(!showFullDuration&&duration.loc.locale.includes("en")&&duration.months>0){durationSplit[0]=durationSplit[0].replace("m","M");} 2871return durationSplit.slice(0,numberOfValuesToDisplay).join(",");} 2872__exports.serializeDate=serializeDate;function serializeDate(value){if(!dateCache.has(value)){dateCache.set(value,value.toFormat(SERVER_DATE_FORMAT,{numberingSystem:"latn"}));} 2873return dateCache.get(value);} 2874__exports.serializeDateTime=serializeDateTime;function serializeDateTime(value){if(!dateTimeCache.has(value)){dateTimeCache.set(value,value.setZone("utc").toFormat(SERVER_DATETIME_FORMAT,{numberingSystem:"latn"}));} 2875return dateTimeCache.get(value);} 2876__exports.parseDate=parseDate;function parseDate(value,options={}){const parsed=parseDateTime(value,{...options,format:options.format||localization.dateFormat,});return parsed&&parsed.startOf("day");} 2877__exports.parseDateTime=parseDateTime;function parseDateTime(value,options={}){if(!value){return false;} 2878const fmt=options.format||localization.dateTimeFormat;const parseOpts={setZone:true,zone:options.tz||"default",};const switchToLatin=Settings.defaultNumberingSystem!=="latn"&&/[0-9]/.test(value);if(switchToLatin){parseOpts.numberingSystem="latn";} 2879let result=DateTime.fromFormat(value,fmt,parseOpts);if(!isValidDate(result)){result=parseSmartDateInput(value);} 2880if(!isValidDate(result)){const fmtWoZero=stripAlphaDupes(fmt);result=DateTime.fromFormat(value,fmtWoZero,parseOpts);} 2881if(!isValidDate(result)){const digitList=value.split(nonDigitRegex).filter(Boolean);const fmtList=fmt.split(nonAlphaRegex).filter(Boolean);const valWoSeps=digitList.join("");let carry=0;const fmtWoSeps=fmtList.map((part,i)=>{const digitLength=(digitList[i]||"").length;const actualPart=part.slice(0,digitLength+carry);carry+=digitLength-actualPart.length;return actualPart;}).join("");result=DateTime.fromFormat(valWoSeps,fmtWoSeps,parseOpts);} 2882if(!isValidDate(result)){const valueDigits=value.replace(nonDigitRegex,"");if(valueDigits.length>4){result=DateTime.fromISO(value,parseOpts);if(!isValidDate(result)){result=DateTime.fromSQL(value,parseOpts);}}} 2883if(!isValidDate(result)){throw new ConversionError(_t("'%s' is not a correct date or datetime",value));} 2884if(switchToLatin){result=result.reconfigure({numberingSystem:Settings.defaultNumberingSystem,});} 2885return result.setZone(options.tz||"default");} 2886__exports.deserializeDate=deserializeDate;function deserializeDate(value,options={}){options={numberingSystem:"latn",zone:"default",...options};return DateTime.fromSQL(value,options).reconfigure({numberingSystem:Settings.defaultNumberingSystem,});} 2887__exports.deserializeDateTime=deserializeDateTime;function deserializeDateTime(value,options={}){return DateTime.fromSQL(value,{numberingSystem:"latn",zone:"utc"}).setZone(options?.tz||"default").reconfigure({numberingSystem:Settings.defaultNumberingSystem,});} 2888return __exports;});; 2889 2890/* /web/static/src/core/l10n/localization.js */ 2891odoo.define('@web/core/l10n/localization',[],function(require){'use strict';let __exports={};const localization=__exports.localization=new Proxy({},{get:(target,p)=>
2891{if(p in target||p==="then"){return Reflect.get(target,p);} 2892throw new Error(`could not access localization parameter "${p}": parameters are not ready yet. Maybe add 'localization' to your dependencies?`);},});return __exports;});; 2893 2894/* /web/static/src/core/l10n/localization_service.js */ 2895odoo.define('@web/core/l10n/localization_service',['@web/session','@web/core/l10n/utils','@web/core/user','@web/core/browser/browser','@web/core/registry','@web/core/l10n/dates','@web/core/l10n/localization','@web/core/network/rpc','@web/core/l10n/translation','@web/core/utils/urls','@web/core/utils/indexed_db'],function(require){'use strict';let __exports={};const{session}=require("@web/session");const{jsToPyLocale}=require("@web/core/l10n/utils");const{user}=require("@web/core/user");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{strftimeToLuxonFormat}=require("@web/core/l10n/dates");const{localization}=require("@web/core/l10n/localization");const{rpcBus}=require("@web/core/network/rpc");const{translatedTerms,translatedTermsGlobal,translationLoaded,translationIsReady,}=require("@web/core/l10n/translation");const{objectToUrlEncodedString}=require("@web/core/utils/urls");const{IndexedDB}=require("@web/core/utils/indexed_db");const{Settings}=luxon;const NUMBERING_SYSTEMS=[[/^ar-(sa|sy|001)$/i,"arab"],[/^bn/i,"beng"],[/^bo/i,"tibt"],[/^pa-in/i,"guru"],[/^ta/i,"tamldec"],[/.*/i,"latn"],];const localizationService=__exports.localizationService={start:async()=>{const localizationDB=new IndexedDB("localization",session.registry_hash);const translationURL=session.translationURL||"/web/webclient/translations";const lang=jsToPyLocale(user.lang||document.documentElement.getAttribute("lang"));rpcBus.addEventListener("RPC:RESPONSE",(ev)=>{const{method,model}=ev.detail.data.params||{};if(method==="lang_install"&&model==="base.language.install"){rpcBus.trigger("CLEAR-CACHES");}});const fetchTranslations=async(hash)=>{let queryString=objectToUrlEncodedString({hash,lang});queryString=queryString.length>0?`?${queryString}`:queryString;const response=await browser.fetch(`${translationURL}${queryString}`,{cache:"no-store",});if(!response.ok){throw new Error("Error while fetching translations");} 2896const result=await response.json();if(result.hash!==hash){localizationDB.write(translationURL,JSON.stringify({lang}),result);updateTranslations(result);}};const updateTranslations=(result)=>{const terms={};for(const addon of Object.keys(result.modules)){terms[addon]={};for(const message of result.modules[addon].messages){terms[addon][message.id]=message.string;translatedTermsGlobal[message.id]=message.string;}} 2897Object.assign(translatedTerms,terms);const userLocalization=result.lang_parameters;const dateFormat=strftimeToLuxonFormat(userLocalization.date_format);const timeFormat=strftimeToLuxonFormat(userLocalization.time_format);Object.assign(localization,{dateFormat,timeFormat,dateTimeFormat:`${dateFormat} ${timeFormat}`,decimalPoint:userLocalization.decimal_point,direction:userLocalization.direction,grouping:JSON.parse(userLocalization.grouping),multiLang:result.multi_lang,thousandsSep:userLocalization.thousands_sep,weekStart:userLocalization.week_start,});};const storedTranslations=await localizationDB.read(translationURL,JSON.stringify({lang}));const translationProm=fetchTranslations(storedTranslations?.hash);if(storedTranslations){updateTranslations(storedTranslations);}else{await translationProm;} 2898translatedTerms[translationLoaded]=true;translationIsReady.resolve(true);const locale=user.lang||browser.navigator.language;Settings.defaultLocale=locale;for(const[re,numberingSystem]of NUMBERING_SYSTEMS){if(re.test(locale)){Settings.defaultNumberingSystem=numberingSystem;break;}} 2899localization.code=jsToPyLocale(locale);return localization;},};registry.category("services").add("localization",localizationService);return __exports;});; 2900 2901/* /web/static/src/core/l10n/time.js */ 2902odoo.define('@web/core/l10n/time',['@web/core/l10n/localization'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const{DateTime}=luxon;const NUMERAL_MAPS=["٠١٢٣٤٥٦٧٨٩","Û°Û±Û²Û³Û´ÛµÛ¶Û·Û¸Û¹","०१२३४५६à¥à¥®à¥¯","à¹à¹à¹à¹à¹à¹à¹à¹à¹à¹","é¶ä¸äºä¸åäºå ä¸å «ä¹",];const Time=__exports.Time=class Time{static from(value){if(value===null||value===undefined||value===false){return null;}else if(value instanceof Time){return value;}else if(typeof value==="string"){return parseTime(value,true);}else if(typeof value==="object"){return new Time(value);}else{return null;}} 2903constructor({hour=0,minute=0,second=0}={}){this.hour=hour;this.minute=minute;this.second=second;this._is24HourFormat=is24HourFormat();this._isMeridiemFormat=isMeridiemFormat();} 2904roundMinutes(rounding){this.minute=Math.round(this.minute/rounding)*rounding;} 2905copy(){return new Time(this);} 2906equals(other,checkSeconds=false){return(other&&this.hour===other.hour&&this.minute===other.minute&&(!checkSeconds||this.second===other.second));} 2907toString(showSeconds=false){const hourFormat=this._is24HourFormat?"H":"h";const secondFormat=showSeconds?":ss":"";const meridiemFormat=this._isMeridiemFormat?"a":"";return this.toDateTime().toFormat(`${hourFormat}:mm${secondFormat}${meridiemFormat}`).toLowerCase();} 2908toDateTime(){return DateTime.fromObject(this.toObject());} 2909toObject(){return{hour:this.hour,minute:this.minute,second:this.second,};}} 2910__exports.is24HourFormat=is24HourFormat;function is24HourFormat(format){return/H/.test(format||localization.timeFormat);} 2911__exports.isMeridiemFormat=isMeridiemFormat;function isMeridiemFormat(format){return/a/.test(format||localization.timeFormat);} 2912__exports.parseTime=parseTime;function parseTime(value,parseSeconds){const{isPm,isAm}=meridiemCheck(value);value=normalizeTimeStr(value);if(!value){return null;} 2913let hour=0;let minute=0;let second=0;const parse=(str)=>{if(str.length===0){return 0;}else if(/^[\d]+$/.test(str)){return parseInt(str,10);}else{return NaN;}};const parts=value.split(/[\s:]/g);if(parts.length>3){return null;}else if(parts.length===3){if(!parseSeconds){return null;} 2914hour=parse(parts[0]);minute=parse(parts[1].padEnd(2,"0"));second=parse(parts[2].padEnd(2,"0"));}else if(parts.length===2){hour=parse(parts[0]);minute=parse(parts[1].padEnd(2,"0"));}else if(parts.length===1){const raw=parts[0];
2914const pickSolution=(...solutions)=>{for(const solution of solutions){const h=parse(solution[0]);if(h<=24){hour=h;if(solution[1]){minute=parse(solution[1].padEnd(2,"0"));} 2915break;}}};if(raw.length==1){hour=parse(raw);}else if(raw.length==2){pickSolution([raw],[raw[0],raw[1]]);}else if(raw.length===3){pickSolution([raw.slice(0,2),raw[2]],[raw[0],raw.slice(1)]);}else if(raw.length===4){hour=parse(raw.slice(0,2));minute=parse(raw.slice(2));}else if(raw.length>4&&raw.length<=6){if(!parseSeconds){return null;} 2916hour=parse(raw.slice(0,2));minute=parse(raw.slice(2,4));second=parse(raw.slice(4).padEnd(2,"0"));}else{return null;}} 2917if(isPm&&hour<12){hour+=12;}else if(isAm&&hour===12){hour=0;} 2918if(hour>=0&&hour<=24&&minute>=0&&minute<60&&second>=0&&second<60){if(hour===24){hour=0;} 2919return new Time({hour,minute,second});}else{return null;}} 2920function normalizeTimeStr(timeStr){if(typeof timeStr!=="string"){return false;} 2921timeStr=timeStr.trim().toLowerCase();for(const map of NUMERAL_MAPS){for(let i=0;i<map.length;i++){timeStr=timeStr.replaceAll(map[i],i);}} 2922return timeStr.replace(/^\D+|\D+$/g,"").replace(/\D+/g,":");} 2923function meridiemCheck(timeStr){const amPmMatch=typeof timeStr==="string"?timeStr.toLowerCase().match(/(am|pm)/g):false;return{isPm:amPmMatch&&amPmMatch[0]==="pm",isAm:amPmMatch&&amPmMatch[0]==="am",};} 2924return __exports;});; 2925 2926/* /web/static/src/core/l10n/translation.js */ 2927odoo.define('@web/core/l10n/translation',['@web/core/l10n/utils','@web/core/utils/arrays','@web/core/utils/concurrency','@web/core/utils/html','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{formatList}=require("@web/core/l10n/utils");const{isIterable}=require("@web/core/utils/arrays");const{Deferred}=require("@web/core/utils/concurrency");const{htmlSprintf,isMarkup}=require("@web/core/utils/html");const{mapSubstitutions,sprintf}=require("@web/core/utils/strings");function isNotBlank(value){return typeof value==="string"&&!R_BLANK.test(value);} 2928function translationSprintf(str,substitutions){let hasMarkup=false;function formatSubstitution(value){hasMarkup||=isMarkup(value);if(isIterable(value)&&!(value instanceof String)){return formatList(value);}else{return value;}} 2929const formattedSubstitutions=mapSubstitutions(substitutions,formatSubstitution);if(hasMarkup){return htmlSprintf(str,...formattedSubstitutions);}else{return sprintf(str,...formattedSubstitutions);}} 2930const DEFAULT_MODULE="base";const R_BLANK=/^[\s\u200B]*$/;__exports._t=_t;function _t(source,...substitutions){return appTranslateFn(source,odoo.translationContext,...substitutions);} 2931__exports.appTranslateFn=appTranslateFn;function appTranslateFn(source,moduleName,...substitutions){const string=new TranslatedString(source,substitutions,moduleName);return string.lazy?string:string.valueOf();} 2932__exports.loadLanguages=loadLanguages;async function loadLanguages(orm){if(!loadLanguages.installedLanguages){loadLanguages.installedLanguages=await orm.call("res.lang","get_installed");} 2933return loadLanguages.installedLanguages;} 2934const TranslatedString=__exports.TranslatedString=class TranslatedString extends String{context;lazy=false;substitutions;constructor(value,substitutions,context){super(value);if(!isNotBlank(value)){return new String(value);} 2935this.lazy=!translatedTerms[translationLoaded];this.substitutions=substitutions;this.context=context||DEFAULT_MODULE;} 2936toString(){return this.valueOf();} 2937valueOf(){const source=super.valueOf();if(this.lazy&&!translatedTerms[translationLoaded]){throw new Error(`Cannot translate string: translations have not been loaded`);} 2938const translation=translatedTerms[this.context]?.[source]??translatedTermsGlobal[source]??source;if(this.substitutions.length){return translationSprintf(translation,this.substitutions);}else{return translation;}}} 2939const translationLoaded=__exports.translationLoaded=Symbol("translationLoaded");const translatedTerms=__exports.translatedTerms={[translationLoaded]:false,};const translatedTermsGlobal=__exports.translatedTermsGlobal=Object.create(null);const translationIsReady=__exports.translationIsReady=new Deferred();return __exports;});; 2940 2941/* /web/static/src/core/l10n/utils.js */ 2942odoo.define('@web/core/l10n/utils',['@web/core/l10n/utils/format_list','@web/core/l10n/utils/locales','@web/core/l10n/utils/normalize'],function(require){'use strict';let __exports={};Object.assign(__exports,require("@web/core/l10n/utils/format_list"));Object.assign(__exports,require("@web/core/l10n/utils/locales"));Object.assign(__exports,require("@web/core/l10n/utils/normalize"));return __exports;});; 2943 2944/* /web/static/src/core/l10n/utils/format_list.js */ 2945odoo.define('@web/core/l10n/utils/format_list',['@web/core/user'],function(require){'use strict';let __exports={};const{user}=require("@web/core/user");const LIST_STYLES={standard:{type:"conjunction",style:"long",},"standard-short":{type:"conjunction",style:"short",},or:{type:"disjunction",style:"long",},"or-short":{type:"disjunction",style:"short",},unit:{type:"unit",style:"long",},"unit-short":{type:"unit",style:"short",},"unit-narrow":{type:"unit",style:"narrow",},};__exports.formatList=formatList;function formatList(values,{localeCode,style}={}){const locale=localeCode||user.lang||"en-US";const formatter=new Intl.ListFormat(locale,LIST_STYLES[style||"standard"]);return formatter.format(Array.from(values,String));} 2946return __exports;});; 2947 2948/* /web/static/src/core/l10n/utils/locales.js */ 2949odoo.define('@web/core/l10n/utils/locales',[],function(require){'use strict';let __exports={};__exports.jsToPyLocale=jsToPyLocale;function jsToPyLocale(locale){if(!locale){return"";}
2950try{var{language,script,region}=new Intl.Locale(locale);if(language==="fil"){language="tl";}}catch{return locale;} 2951let xpgLocale=language;if(region){xpgLocale+=`_${region}`;} 2952switch(script){case"Cyrl":xpgLocale+="@Cyrl";break;case"Latn":xpgLocale+="@latin";break;} 2953return xpgLocale;} 2954__exports.pyToJsLocale=pyToJsLocale;function pyToJsLocale(locale){if(!locale){return"";} 2955const regex=/^([a-z]+)(_[A-Z\d]+)?(@.+)?$/;const match=locale.match(regex);if(!match){return locale;} 2956const[,language,territory,modifier]=match;const subtags=[language];switch(modifier){case"@Cyrl":subtags.push("Cyrl");break;case"@latin":subtags.push("Latn");break;} 2957if(territory){subtags.push(territory.slice(1));} 2958return subtags.join("-");} 2959return __exports;});; 2960 2961/* /web/static/src/core/l10n/utils/normalize.js */ 2962odoo.define('@web/core/l10n/utils/normalize',[],function(require){'use strict';let __exports={};__exports.normalize=normalize;function normalize(str){return casefold(unaccent(expandLigatures(str.normalize("NFKC"))));} 2963__exports.normalizedMatch=normalizedMatch;function normalizedMatch(src,substr){if(!substr){return{start:0,end:0,match:""};} 2964const srcAsCodepoints=Array.from(src);const normalizedSrc=srcAsCodepoints.map(normalize);const normalizedSubstr=Array.from(normalize(substr));const flattenSrcLength=normalizedSrc.reduce((acc,x)=>acc+Math.max(x.length,1),0);for(let i=0;i<=flattenSrcLength-normalizedSubstr.length;++i){const substrStack=Array.from(normalizedSubstr).reverse();for(let j=0;i+j<normalizedSrc.length;++j){const current=normalizedSrc[i+j];if(![...current].every((c)=>substrStack.length===0||c===substrStack.pop())){break;} 2965if(substrStack.length===0){const start=srcAsCodepoints.slice(0,i).join("").length;const match=srcAsCodepoints.slice(i,i+j+1).join("");const end=start+match.length;return{start,end,match};}}} 2966return{start:-1,end:-1,match:""};} 2967__exports.normalizedMatches=normalizedMatches;function normalizedMatches(src,substr){const matches=[];let index=0;while(src.length){const{start,end,match}=normalizedMatch(src,substr);if(match){matches.push({start:index+start,end:index+end,match});index+=end;src=src.slice(end);}else{break;}} 2968return matches;} 2969const DECOMPOSITION_BY_LIGATURE=new Map([["Ã","Ae"],["æ","ae"],["Å","Oe"],["Å","oe"],["IJ","IJ"],["ij","ij"],]);function expandLigatures(str){return Array.from(str,(char)=>DECOMPOSITION_BY_LIGATURE.get(char)??char).join("");} 2970const DIACRITIC_LIKES=new Map([["Ã","O"],["ø","o"],["Å","L"],["Å","l"],["Ã","D"],["ð","d"],["Ħ","H"],["ħ","h"],["Ŧ","T"],["ŧ","t"],]);function unaccent(str){return Array.from(str.normalize("NFD").replace(/\p{Nonspacing_Mark}/gu,""),(char)=>DIACRITIC_LIKES.get(char)??char).join("");} 2971function casefold(str){return str.toLowerCase().toUpperCase().toLowerCase();} 2972return __exports;});; 2973 2974/* /web/static/src/core/macro.js */ 2975odoo.define('@web/core/macro',['@web/core/utils/ui','@web/core/utils/concurrency','@odoo/owl'],function(require){'use strict';let __exports={};const{isVisible}=require("@web/core/utils/ui");const{delay}=require("@web/core/utils/concurrency");const{validate}=require("@odoo/owl");const macroSchema={name:{type:String,optional:true},timeout:{type:Number,optional:true},steps:{type:Array,element:{type:Object,shape:{action:{type:[Function,String],optional:true},timeout:{type:Number,optional:true},trigger:{type:[Function,String],optional:true},},validate:(step)=>step.action||step.trigger,},},onComplete:{type:Function,optional:true},onStep:{type:Function,optional:true},onError:{type:Function,optional:true},};class MacroError extends Error{constructor(type,message,options){super(message,options);this.type=type;}} 2976async function performAction(trigger,action){if(!action){return;} 2977try{return await action(trigger);}catch(error){throw new MacroError("Action",error.stack||`ERROR during perform action: ${error.message}`,{cause:error});}} 2978async function waitForTrigger(trigger){if(!trigger){return;} 2979try{await delay(50);return await waitUntil(()=>{if(typeof trigger==="function"){return trigger();}else if(typeof trigger==="string"){const triggerEl=document.querySelector(trigger);return isVisible(triggerEl)&&triggerEl;}});}catch(error){throw new MacroError("Trigger",`ERROR during find trigger:\n${error.message}`,{cause:error,});}} 2980__exports.waitUntil=waitUntil;async function waitUntil(predicate){const result=predicate();if(result){return Promise.resolve(result);} 2981let handle;return new Promise((resolve)=>{const runCheck=()=>{const result=predicate();if(result){resolve(result);} 2982handle=requestAnimationFrame(runCheck);};handle=requestAnimationFrame(runCheck);}).finally(()=>{cancelAnimationFrame(handle);});} 2983const Macro=__exports.Macro=class Macro{currentIndex=0;isComplete=false;constructor(descr){try{validate(descr,macroSchema);}catch(error){throw new Error(`Error in schema for Macro ${JSON.stringify(descr, null, 4)}\n${error.message}`);} 2984Object.assign(this,descr);this.onComplete=this.onComplete||(()=>{});this.onStep=this.onStep||(()=>{});this.onError=this.onError||((error,step,index)=>{console.error(error.message,step,index);});} 2985async start(){await this.advance();} 2986async advance(){if(this.isComplete||this.currentIndex>=this.steps.length){this.stop();return;} 2987try{const step=this.steps[this.currentIndex];const timeoutDelay=step.timeout||this.timeout||10000;const executeStep=async()=>{const trigger=await waitForTrigger(step.trigger);const result=await performAction(trigger,step.action);await this.onStep({step,trigger,index:this.currentIndex});return result;};const launchTimer=async()=>{await delay(timeoutDelay);throw new MacroError("Timeout",`TIMEOUT step failed to complete within ${timeoutDelay} ms.`);};const actionResult=await Promise.race([executeStep(),launchTimer()]);if(actionResult){this.stop();return;}}catch(error){this.stop(error);return;} 2988this.currentIndex++;await this.advance();} 2989stop(error){if(this.isComplete){return;} 2990this.isComplete=true;if(error){const step=this.steps[this.currentIndex];this.onError({error,step,index:this.currentIndex});}else if(this.currentIndex===this.steps.length){this.onComplete();}}} 2991const MacroMutationObserver=__exports.MacroMutationObserver=class MacroMutationObserver{observerOptions={attributes:true,childList:true,subtree:true,characterData:true,};constructor(callback){this.callback=callback;this.observer=new MutationObserver((mutationList,observer)=>{callback(mutationList);mutationList.forEach((mutationRecord)=>
2991Array.from(mutationRecord.addedNodes).forEach((node)=>{let iframes=[];if(String(node.tagName).toLowerCase()==="iframe"){iframes=[node];}else if(node instanceof HTMLElement){iframes=Array.from(node.querySelectorAll("iframe"));} 2992iframes.forEach((iframeEl)=>this.observeIframe(iframeEl,observer,()=>callback()));this.findAllShadowRoots(node).forEach((shadowRoot)=>observer.observe(shadowRoot,this.observerOptions));}));});} 2993disconnect(){this.observer.disconnect();} 2994findAllShadowRoots(node,shadowRoots=[]){if(node.shadowRoot){shadowRoots.push(node.shadowRoot);this.findAllShadowRoots(node.shadowRoot,shadowRoots);} 2995node.childNodes.forEach((child)=>{this.findAllShadowRoots(child,shadowRoots);});return shadowRoots;} 2996observe(target){this.observer.observe(target,this.observerOptions);target.querySelectorAll("iframe").forEach((el)=>this.observeIframe(el,this.observer,()=>this.callback()));this.findAllShadowRoots(target).forEach((shadowRoot)=>{this.observer.observe(shadowRoot,this.observerOptions);});} 2997observeIframe(iframeEl,observer,callback){const observerOptions={attributes:true,childList:true,subtree:true,characterData:true,};const observeIframeContent=()=>{if(iframeEl.contentDocument){iframeEl.contentDocument.addEventListener("load",(event)=>{callback();observer.observe(event.target,observerOptions);});if(!iframeEl.src||iframeEl.contentDocument.readyState==="complete"){callback();observer.observe(iframeEl.contentDocument,observerOptions);}}};observeIframeContent();iframeEl.addEventListener("load",observeIframeContent);}} 2998return __exports;});; 2999 3000/* /web/static/src/core/main_components_container.js */ 3001odoo.define('@web/core/main_components_container',['@odoo/owl','@web/core/registry','@web/core/registry_hook','@web/core/utils/components','@web/core/l10n/localization'],function(require){'use strict';let __exports={};const{Component,xml}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{useRegistry}=require("@web/core/registry_hook");const{ErrorHandler}=require("@web/core/utils/components");const{localization}=require("@web/core/l10n/localization");const mainComponents=registry.category("main_components");mainComponents.addValidation({Component:{validate:(c)=>c.prototype instanceof Component},props:{type:Object,optional:true}});const MainComponentsContainer=__exports.MainComponentsContainer=class MainComponentsContainer extends Component{static components={ErrorHandler};static props={};static template=xml` 3002 <div class="o-main-components-container" t-att-class="{'o_rtl': this.isRTL}"> 3003 <t t-foreach="Components.entries" t-as="C" t-key="C[0]"> 3004 <ErrorHandler onError="error => this.handleComponentError(error, C)"> 3005 <t t-component="C[1].Component" t-props="C[1].props"/> 3006 </ErrorHandler> 3007 </t> 3008 </div> 3009 `;setup(){this.Components=useRegistry(mainComponents);this.isRTL=localization.direction==="rtl";} 3010handleComponentError(error,C){this.Components.entries.splice(this.Components.entries.indexOf(C),1);this.render();Promise.resolve().then(()=>{throw error;});}} 3011return __exports;});; 3012 3013/* /web/static/src/core/model_field_selector/model_field_selector.js */ 3014odoo.define('@web/core/model_field_selector/model_field_selector',['@odoo/owl','@web/core/popover/popover_hook','@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/model_field_selector/model_field_selector_popover'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps,useState}=require("@odoo/owl");const{usePopover}=require("@web/core/popover/popover_hook");const{KeepLast}=require("@web/core/utils/concurrency");const{useService}=require("@web/core/utils/hooks");const{ModelFieldSelectorPopover}=require("@web/core/model_field_selector/model_field_selector_popover");const ModelFieldSelector=__exports.ModelFieldSelector=class ModelFieldSelector extends Component{static template="web._ModelFieldSelector";static components={Popover:ModelFieldSelectorPopover,};static props={resModel:String,path:{optional:true},allowEmpty:{type:Boolean,optional:true},readonly:{type:Boolean,optional:true},readProperty:{type:Boolean,optional:true},showSearchInput:{type:Boolean,optional:true},isDebugMode:{type:Boolean,optional:true},update:{type:Function,optional:true},filter:{type:Function,optional:true},sort:{type:Function,optional:true},followRelations:{type:Boolean,optional:true},showDebugInput:{type:Boolean,optional:true},};static defaultProps={readonly:true,allowEmpty:false,isDebugMode:false,showSearchInput:true,update:()=>{},followRelations:true,};setup(){this.fieldService=useService("field");this.popover=usePopover(this.constructor.components.Popover,{popoverClass:"o_popover_field_selector",onClose:async()=>
3014{if(this.newPath!==null){const fieldInfo=await this.fieldService.loadFieldInfo(this.props.resModel,this.newPath);this.props.update(this.newPath,fieldInfo);}},});this.keepLast=new KeepLast();this.state=useState({isInvalid:false,displayNames:[]});onWillStart(()=>this.updateState(this.props));onWillUpdateProps((nextProps)=>{const modelPathKeys=["resModel","path","allowEmpty"];if(modelPathKeys.some((key)=>this.props[key]!==nextProps[key])){this.updateState(nextProps);}});} 3015openPopover(currentTarget){if(this.props.readonly){return;} 3016this.newPath=null;this.popover.open(currentTarget,{resModel:this.props.resModel,path:this.props.path,readProperty:this.props.readProperty,update:(path,_fieldInfo,debug=false)=>{this.newPath=path;if(!debug){this.updateState({...this.props,path},true);}},showSearchInput:this.props.showSearchInput,isDebugMode:this.props.isDebugMode,filter:this.props.filter,sort:this.props.sort,followRelations:this.props.followRelations,showDebugInput:this.props.showDebugInput,});} 3017async updateState(params,isConcurrent){const{resModel,path,allowEmpty}=params;let prom=this.fieldService.loadPathDescription(resModel,path,allowEmpty);if(isConcurrent){prom=this.keepLast.add(prom);} 3018const state=await prom;Object.assign(this.state,state);} 3019clear(){if(this.popover.isOpen){this.newPath="";this.popover.close();return;} 3020this.props.update("",{resModel:this.props.resModel,fieldDef:null});}} 3021return __exports;});; 3022 3023/* /web/static/src/core/model_field_selector/model_field_selector_popover.js */ 3024odoo.define('@web/core/model_field_selector/model_field_selector_popover',['@odoo/owl','@web/core/l10n/translation','@web/core/utils/arrays','@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/utils/search','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Component,onWillStart,useEffect,useRef,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{sortBy}=require("@web/core/utils/arrays");const{KeepLast}=require("@web/core/utils/concurrency");const{useService}=require("@web/core/utils/hooks");const{fuzzyLookup}=require("@web/core/utils/search");const{debounce}=require("@web/core/utils/timing");class Page{constructor(resModel,fieldDefs,options={}){this.resModel=resModel;this.fieldDefs=fieldDefs;const{previousPage=null,selectedName=null,isDebugMode,readProperty=false,sortFn=(fieldDefs)=>sortBy(Object.keys(fieldDefs),(key)=>fieldDefs[key].string),}=options;this.previousPage=previousPage;this.selectedName=selectedName;this.isDebugMode=isDebugMode;this.readProperty=readProperty;this.sortedFieldNames=sortFn(fieldDefs);this.fieldNames=this.sortedFieldNames;this.query="";this.focusedFieldName=null;this.resetFocusedFieldName();} 3025get path(){const previousPath=this.previousPage?.path||"";const name=this.selectedName;if(this.readProperty&&this.selectedField&&this.selectedField.is_property){if(this.selectedField.relation){return`${previousPath}.get('${name}', env['${this.selectedField.relation}'])`;} 3026return`${previousPath}.get('${name}')`;} 3027if(name){if(previousPath){return`${previousPath}.${name}`;} 3028return name;} 3029return previousPath;} 3030get selectedField(){return this.fieldDefs[this.selectedName];} 3031get title(){const prefix=this.previousPage?.previousPage?"... > ":"";const title=this.previousPage?.selectedField?.string||"";if(prefix.length||title.length){return`${prefix}${title}`;} 3032return _t("Select a field");} 3033focus(direction){if(!this.fieldNames.length){return;} 3034const index=this.fieldNames.indexOf(this.focusedFieldName);if(direction==="previous"){if(index===0){this.focusedFieldName=this.fieldNames[this.fieldNames.length-1];}else{this.focusedFieldName=this.fieldNames[index-1];}}else{if(index===this.fieldNames.length-1){this.focusedFieldName=this.fieldNames[0];}else{this.focusedFieldName=this.fieldNames[index+1];}}} 3035resetFocusedFieldName(){if(this.selectedName&&this.fieldNames.includes(this.selectedName)){this.focusedFieldName=this.selectedName;}else{this.focusedFieldName=this.fieldNames.length?this.fieldNames[0]:null;}} 3036searchFields(query=""){this.query=query;this.fieldNames=this.sortedFieldNames;if(query){this.fieldNames=fuzzyLookup(query,this.fieldNames,(key)=>{const vals=[this.fieldDefs[key].string];if(this.isDebugMode){vals.push(key);} 3037return vals;});} 3038this.resetFocusedFieldName();}} 3039const ModelFieldSelectorPopover=__exports.ModelFieldSelectorPopover=class ModelFieldSelectorPopover extends Component{static template="web.ModelFieldSelectorPopover";static props={close:Function,filter:{type:Function,optional:true},sort:{type:Function,optional:true},followRelations:{type:Boolean,optional:true},showDebugInput:{type:Boolean,optional:true},isDebugMode:{type:Boolean,optional:true},path:{optional:true},readProperty:{type:Boolean,optional:true},resModel:String,showSearchInput:{type:Boolean,optional:true},update:Function,};
3039static defaultProps={filter:(value)=>value.searchable&&value.type!="json"&&value.type!=="separator",isDebugMode:false,followRelations:true,};setup(){this.fieldService=useService("field");this.state=useState({page:null});this.keepLast=new KeepLast();this.debouncedSearchFields=debounce(this.searchFields.bind(this),250);onWillStart(async()=>{this.state.page=await this.loadPages(this.props.resModel,this.props.path);});const rootRef=useRef("root");useEffect(()=>{const focusedElement=rootRef.el.querySelector(".o_model_field_selector_popover_item.active");if(focusedElement){focusedElement.scrollIntoView({block:"center"});}});useEffect(()=>{if(this.props.showSearchInput){const searchInput=rootRef.el.querySelector(".o_model_field_selector_popover_search .o_input");searchInput.focus();}},()=>[this.state.page]);} 3040get fieldNames(){return this.state.page.fieldNames;} 3041get showDebugInput(){return this.props.showDebugInput??this.props.isDebugMode;} 3042canFollowRelationFor(fieldDef){if(fieldDef.type==="properties"){return true;} 3043if(!this.props.followRelations){return false;} 3044return fieldDef.relation;} 3045filter(fieldDefs,path,resModel){const filteredKeys=Object.keys(fieldDefs).filter((k)=>this.props.filter(fieldDefs[k],path,resModel));return Object.fromEntries(filteredKeys.map((k)=>[k,fieldDefs[k]]));} 3046async followRelation(fieldDef){const{modelsInfo}=await this.keepLast.add(this.fieldService.loadPath(fieldDef.is_property?fieldDef.relation:this.state.page.resModel,`${fieldDef.name}.*`));this.state.page.selectedName=fieldDef.name;const{resModel,fieldDefs}=modelsInfo.at(-1);this.openPage(new Page(resModel,this.filter(fieldDefs,this.state.page.path,resModel),{previousPage:this.state.page,isDebugMode:this.props.isDebugMode,readProperty:this.props.readProperty,sortFn:this.props.sort,}));} 3047goToPreviousPage(){this.keepLast.add(Promise.resolve());this.openPage(this.state.page.previousPage);} 3048async loadNewPath(path){const newPage=await this.keepLast.add(this.loadPages(this.props.resModel,path));this.openPage(newPage);} 3049async loadPages(resModel,path){if(typeof path!=="string"||!path.length){const fieldDefs=await this.fieldService.loadFields(resModel);return new Page(resModel,this.filter(fieldDefs,path,resModel),{isDebugMode:this.props.isDebugMode,readProperty:this.props.readProperty,sortFn:this.props.sort,});} 3050const{isInvalid,modelsInfo,names}=await this.fieldService.loadPath(resModel,path);switch(isInvalid){case"model":throw new Error(`Invalid model name: ${resModel}`);case"path":{const{resModel,fieldDefs}=modelsInfo[0];return new Page(resModel,this.filter(fieldDefs,path,resModel),{selectedName:path,isDebugMode:this.props.isDebugMode,readProperty:this.props.readProperty,sortFn:this.props.sort,});} 3051default:{let page=null;for(let index=0;index<names.length;index++){const name=names[index];const{resModel,fieldDefs}=modelsInfo[index];page=new Page(resModel,this.filter(fieldDefs,path,resModel),{previousPage:page,selectedName:name,isDebugMode:this.props.isDebugMode,readProperty:this.props.readProperty,sortFn:this.props.sort,});} 3052return page;}}} 3053openPage(page){this.state.page=page;this.state.page.searchFields();this.props.update(page.path);} 3054searchFields(query){this.state.page.searchFields(query);} 3055selectField(field){if(field.type==="properties"){return this.followRelation(field);} 3056this.keepLast.add(Promise.resolve());this.state.page.selectedName=field.name;this.props.update(this.state.page.path,field);this.props.close(true);} 3057onDebugInputKeydown(ev){switch(ev.key){case"Enter":{ev.preventDefault();ev.stopPropagation();this.loadNewPath(ev.currentTarget.value);break;}}} 3058async onInputKeydown(ev){const{page}=this.state;switch(ev.key){case"ArrowUp":{if(ev.target.selectionStart===0){page.focus("previous");} 3059break;} 3060case"ArrowDown":{if(ev.target.selectionStart===page.query.length){page.focus("next");} 3061break;} 3062case"ArrowLeft":{if(ev.target.selectionStart===0&&page.previousPage){this.goToPreviousPage();} 3063break;} 3064case"ArrowRight":{if(ev.target.selectionStart===page.query.length){const focusedFieldName=this.state.page.focusedFieldName;if(focusedFieldName){const fieldDef=this.state.page.fieldDefs[focusedFieldName];if(this.canFollowRelationFor(fieldDef)){this.followRelation(fieldDef);}}} 3065break;} 3066case"Enter":{const focusedFieldName=this.state.page.focusedFieldName;if(focusedFieldName){const fieldDef=this.state.page.fieldDefs[focusedFieldName];this.selectField(fieldDef);}else{ev.preventDefault();ev.stopPropagation();} 3067break;} 3068case"Escape":{ev.preventDefault();ev.stopPropagation();this.props.close();break;}}}} 3069return __exports;});; 3070 3071/* /web/static/src/core/model_selector/model_selector.js */ 3072odoo.define('@web/core/model_selector/model_selector',['@web/core/autocomplete/autocomplete','@web/core/utils/hooks','@web/core/utils/search','@web/core/l10n/translation','@odoo/owl'],function(require){'use strict';let __exports={};const{AutoComplete}=require("@web/core/autocomplete/autocomplete");const{useService}=require("@web/core/utils/hooks");const{fuzzyLookup}=require("@web/core/utils/search");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{Component,onWillStart}=require("@odoo/owl");const ModelSelector=__exports.ModelSelector=class ModelSelector extends Component{static template="web.ModelSelector";static components={AutoComplete};static props={onModelSelected:Function,id:{type:String,optional:true},value:{type:String,optional:true},placeholder:{type:String,optional:true},models:{type:Array,optional:true},nbVisibleModels:{type:Number,optional:true},autofocus:{type:Boolean,optional:true},};setup(){this.orm=useService("orm");onWillStart(async()=>
3072{if(!this.props.models){this.models=await this._fetchAvailableModels();}else{this.models=await this.orm.call("ir.model","display_name_for",[this.props.models,]);} 3073this.models=this.models.map((record)=>({cssClass:`o_model_selector_${record.model.replaceAll(".", "_")}`,data:{technical:record.model,},label:record.display_name,onSelect:()=>this.props.onModelSelected({label:record.display_name,technical:record.model,}),}));});} 3074get sources(){return[this.optionsSource];} 3075get placeholder(){return this.props.placeholder||_t("Type a model here...");} 3076get optionsSource(){return{placeholder:_t("Loading..."),options:this.loadOptionsSource.bind(this),};} 3077get nbVisibleModels(){return this.props.nbVisibleModels||8;} 3078filterModels(name){if(!name){const visibleModels=this.models.slice(0,this.nbVisibleModels);if(this.models.length-visibleModels.length>0){visibleModels.push({label:_t("Start typing..."),cssClass:"o_m2o_start_typing",});} 3079return visibleModels;} 3080return fuzzyLookup(name,this.models,(model)=>model.data.technical+model.label);} 3081loadOptionsSource(request){const options=this.filterModels(request);if(!options.length){options.push({label:_t("No records"),cssClass:"o_m2o_no_result",});} 3082return options;} 3083async _fetchAvailableModels(){const result=await this.orm.call("ir.model","get_available_models");return result||[];}} 3084return __exports;});; 3085 3086/* /web/static/src/core/name_service.js */ 3087odoo.define('@web/core/name_service',['@web/core/registry','@web/core/utils/arrays','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{unique,zip}=require("@web/core/utils/arrays");const{Deferred}=require("@web/core/utils/concurrency");const ERROR_INACCESSIBLE_OR_MISSING=__exports.ERROR_INACCESSIBLE_OR_MISSING=Symbol("INACCESSIBLE OR MISSING RECORD ID");function isId(val){return Number.isInteger(val)&&val>=1;} 3088const nameService=__exports.nameService={dependencies:["orm"],async:["loadDisplayNames"],start(env,{orm}){let cache={};const batches={};function clearCache(){cache={};} 3089env.bus.addEventListener("ACTION_MANAGER:UPDATE",clearCache);function getMapping(resModel){if(!cache[resModel]){cache[resModel]={};} 3090return cache[resModel];} 3091function addDisplayNames(resModel,displayNames){const mapping=getMapping(resModel);for(const resId in displayNames){mapping[resId]=new Deferred();mapping[resId].resolve(displayNames[resId]);}} 3092async function loadDisplayNames(resModel,resIds){const mapping=getMapping(resModel);const proms=[];const resIdsToFetch=[];for(const resId of unique(resIds)){if(!isId(resId)){throw new Error(`Invalid ID: ${resId}`);} 3093if(!(resId in mapping)){mapping[resId]=new Deferred();resIdsToFetch.push(resId);} 3094proms.push(mapping[resId]);} 3095if(resIdsToFetch.length){if(batches[resModel]){batches[resModel].push(...resIdsToFetch);}else{batches[resModel]=resIdsToFetch;await Promise.resolve();const idsInBatch=unique(batches[resModel]);delete batches[resModel];const specification={display_name:{}};orm.silent.webSearchRead(resModel,[["id","in",idsInBatch]],{specification,context:{active_test:false},}).then(({records})=>{const displayNames=Object.fromEntries(records.map((rec)=>[rec.id,rec.display_name]));for(const resId of idsInBatch){mapping[resId].resolve(resId in displayNames?displayNames[resId]:ERROR_INACCESSIBLE_OR_MISSING);}});}} 3096const names=await Promise.all(proms);return Object.fromEntries(zip(resIds,names));} 3097return{addDisplayNames,clearCache,loadDisplayNames};},};registry.category("services").add("name",nameService);return __exports;});; 3098 3099/* /web/static/src/core/navigation/navigation.js */ 3100odoo.define('@web/core/navigation/navigation',['@odoo/owl','@web/core/utils/hooks','@web/core/utils/objects','@web/core/utils/scrolling','@web/core/utils/timing','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{onWillDestroy,useEffect,useExternalListener,useRef}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{deepMerge}=require("@web/core/utils/objects");const{scrollTo}=require("@web/core/utils/scrolling");const{throttleForAnimation}=require("@web/core/utils/timing");const{browser}=require("@web/core/browser/browser");const ACTIVE_ELEMENT_CLASS=__exports.ACTIVE_ELEMENT_CLASS="focus";const throttledFocus=throttleForAnimation((el)=>el?.focus());class NavigationItem{index=-1;el=undefined;target=undefined;constructor({index,el,options,navigator}){this.index=index;this._options=options;this._navigator=navigator;this.el=el;if(this._options.shouldFocusChildInput){const subInput=el.querySelector(":scope input, :scope button, :scope textarea");this.target=subInput||el;}else{this.target=el;} 3101if(this.el.ariaSelected!==true){this.el.ariaSelected=false;} 3102const onFocus=()=>this.setActive(false);const onMouseMove=()=>this._onMouseMove();
3102this.target.addEventListener("focus",onFocus);this.target.addEventListener("mousemove",onMouseMove);this._removeListeners=()=>{this.target.removeEventListener("focus",onFocus);this.target.removeEventListener("mousemove",onMouseMove);};} 3103select(){this.setActive();this.target.click();} 3104setActive(focus=true){scrollTo(this.target);this._navigator._setActiveItem(this.index);this.target.classList.add(ACTIVE_ELEMENT_CLASS);this.target.ariaSelected=true;if(focus&&!this._options.virtualFocus){throttledFocus.cancel();throttledFocus(this.target);}} 3105setInactive(blur=true){this.target.classList.remove(ACTIVE_ELEMENT_CLASS);this.target.ariaSelected=false;if(blur&&!this._options.virtualFocus){this.target.blur();}} 3106_onMouseMove(){if(this._navigator.activeItem!==this&&this._navigator._isNavigationAvailable(this.target)){this.setActive(false);this._options.onMouseEnter?.(this);}}} 3107const Navigator=__exports.Navigator=class Navigator{activeItem=undefined;activeItemIndex=-1;items=[];_hotkeyRemoves=[];_hotkeyService=undefined;constructor(options,hotkeyService){this._hotkeyService=hotkeyService;this._options=deepMerge({isNavigationAvailable:({target})=>this.contains(target)&&(this.isFocused||this._options.virtualFocus),shouldFocusChildInput:true,shouldFocusFirstItem:false,shouldRegisterHotkeys:true,virtualFocus:false,hotkeys:{home:()=>this.items[0]?.setActive(),end:()=>this.items.at(-1)?.setActive(),tab:{callback:()=>this.next(),bypassEditableProtection:true,},"shift+tab":{callback:()=>
3107this.previous(),bypassEditableProtection:true,},arrowdown:{callback:()=>this.next(),bypassEditableProtection:true,},arrowup:{callback:()=>this.previous(),bypassEditableProtection:true,},enter:{isAvailable:({navigator})=>Boolean(navigator.activeItem),callback:()=>{const item=this.activeItem||this.items[0];item?.select();},bypassEditableProtection:true,},},},options);if(this._options.shouldRegisterHotkeys){this.registerHotkeys();}} 3108get hasActiveItem(){return Boolean(this.activeItem?.el.isConnected);} 3109get isFocused(){return this.items.some((item)=>item.target.contains(document.activeElement));} 3110next(){if(!this.hasActiveItem){this.items[0]?.setActive();}else{this.items[(this.activeItemIndex+1)%this.items.length]?.setActive();}} 3111previous(){const index=this.activeItemIndex-1;if(!this.hasActiveItem||index<0){this.items.at(-1)?.setActive();}else{this.items[index%this.items.length]?.setActive();}} 3112update(){const oldItems=new Map(this.items.map((item)=>[item.el,item]));const oldActiveItem=this.activeItem;const elements=this._options.getItems();this.items=[];let didUpdate=elements.length!==oldItems.size;for(let index=0;index<elements.length;index++){const element=elements[index];let item=oldItems.get(element);if(item){if(item.index!==index){item.index=index;didUpdate=true;} 3113oldItems.delete(element);}else{didUpdate=true;item=new NavigationItem({index,el:element,options:this._options,navigator:this,});} 3114this.items.push(item);} 3115for(const item of oldItems.values()){item._removeListeners();} 3116if(didUpdate){const activeItemIndex=oldActiveItem&&oldActiveItem.el.isConnected?this.items.findIndex((item)=>item.el===oldActiveItem.el):-1;const focusedElementIndex=this.items.findIndex((item)=>item.el===document.activeElement);if(activeItemIndex>-1){this._updateActiveItemIndex(activeItemIndex);}else if(this.activeItemIndex>=0){const closest=Math.min(this.activeItemIndex,elements.length-1);this._updateActiveItemIndex(closest);}else if(focusedElementIndex>=0){this._updateActiveItemIndex(focusedElementIndex);}else{this._updateActiveItemIndex(-1);} 3117this._options.onUpdated?.(this);if(this._options.shouldFocusFirstItem){this.items[0]?.setActive();}}} 3118contains(target){return this.items.some((item)=>item.target.contains(target));} 3119registerHotkeys(){if(this._hotkeyRemoves.length>0){return;} 3120for(const[hotkey,hotkeyInfo]of Object.entries(this._options.hotkeys)){if
3120(!hotkeyInfo){continue;} 3121const callback=typeof hotkeyInfo=="function"?hotkeyInfo:hotkeyInfo.callback;if(!callback){continue;} 3122const isAvailable=hotkeyInfo?.isAvailable??(()=>true);const bypassEditableProtection=hotkeyInfo?.bypassEditableProtection??false;const allowRepeat=hotkeyInfo?.allowRepeat??true;this._hotkeyRemoves.push(this._hotkeyService.add(hotkey,async()=>await callback(this),{global:true,allowRepeat,isAvailable:(target)=>this._isNavigationAvailable(target)&&isAvailable({navigator:this,target}),bypassEditableProtection,}));}} 3123unregisterHotkeys(){for(const removeHotkey of this._hotkeyRemoves){removeHotkey();} 3124this._hotkeyRemoves=[];} 3125_destroy(){for(const item of this.items){item._removeListeners();} 3126this.items=[];this.unregisterHotkeys();} 3127_setActiveItem(index){this.activeItem?.setInactive(false);this.activeItemIndex=index;if(index>=0){this.activeItem=this.items[index];this._options.onItemActivated?.(this.activeItem.el);}else{this.activeItem=null;}} 3128_updateActiveItemIndex(index){if(this.items[index]){const shouldFocus=!this.items.some((item)=>item.target===document.activeElement);this.items[index].setActive(shouldFocus);}else{this.activeItemIndex=-1;this.activeItem=null;}} 3129_isNavigationAvailable(target){return this._options.isNavigationAvailable({navigator:this,target});} 3130_checkFocus(target){if(!(target instanceof HTMLElement)||!this._isNavigationAvailable(target)){this._setActiveItem(-1);}}} 3131__exports.useNavigation=useNavigation;function useNavigation(containerRef,options={}){containerRef=typeof containerRef==="string"?useRef(containerRef):containerRef;const newOptions={...options};if(!newOptions.getItems){newOptions.getItems=()=>containerRef.el?.querySelectorAll(":scope .o-navigable")??[];} 3132const hotkeyService=useService("hotkey");const navigator=new Navigator(newOptions,hotkeyService);const observer=new MutationObserver(()=>navigator.update());useEffect((containerEl)=>{if(containerEl){navigator.update();observer.observe(containerEl,{childList:true,subtree:true,});} 3133return()=>observer.disconnect();},()=>[containerRef.el]);useExternalListener(browser,"focus",({target})=>navigator._checkFocus(target),true);onWillDestroy(()=>navigator._destroy());return navigator;} 3134return __exports;});; 3135 3136/* /web/static/src/core/network/download.js */ 3137odoo.define('@web/core/network/download',['@web/core/l10n/translation','@web/core/network/rpc','@web/core/browser/browser','@web/session'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{makeErrorFromResponse,ConnectionLostError}=require("@web/core/network/rpc");const{browser}=require("@web/core/browser/browser");const{session}=require("@web/session");const HEX_ESCAPE_REPLACE_REGEXP=/%([0-9A-Fa-f]{2})/g;const NON_LATIN1_REGEXP=/[^\x20-\x7e\xa0-\xff]/g;const QESC_REGEXP=/\\([\u0000-\u007f])/g;const PARAM_REGEXP=/;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x09\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g;const EXT_VALUE_REGEXP=/^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/;const DISPOSITION_TYPE_REGEXP=/^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/;function decodefield(str){const match=EXT_VALUE_REGEXP.exec(str);if(!match){throw new TypeError("invalid extended field value");} 3138const charset=match[1].toLowerCase();const encoded=match[2];switch(charset){case"iso-8859-1":return encoded.replace(HEX_ESCAPE_REPLACE_REGEXP,pdecode).replace(NON_LATIN1_REGEXP,"?");case"utf-8":return decodeURIComponent(encoded);default:throw new TypeError("unsupported charset in extended field");}} 3139__exports.parse=parse;function parse(string){if(!string||typeof string!=="string"){throw new TypeError("argument string is required");} 3140let match=DISPOSITION_TYPE_REGEXP.exec(string);if(!match){throw new TypeError("invalid type format");} 3141let index=match[0].length;const type=match[1].toLowerCase();let key;const names=[];const params={};let value;index=PARAM_REGEXP.lastIndex=match[0].substr(-1)===";"?index-1:index;while((match=PARAM_REGEXP.exec(string))){if(match.index!==index){throw new TypeError("invalid parameter format");} 3142index+=match[0].length;key=match[1].toLowerCase();value=match[2];
3142if(names.indexOf(key)!==-1){throw new TypeError("invalid duplicate parameter");} 3143names.push(key);if(key.indexOf("*")+1===key.length){key=key.slice(0,-1);value=decodefield(value);params[key]=value;continue;} 3144if(typeof params[key]==="string"){continue;} 3145if(value[0]==='"'){value=value.substr(1,value.length-2).replace(QESC_REGEXP,"$1");} 3146params[key]=value;} 3147if(index!==-1&&index!==string.length){throw new TypeError("invalid parameter format");} 3148return new ContentDisposition(type,params);} 3149function pdecode(str,hex){return String.fromCharCode(parseInt(hex,16));} 3150function ContentDisposition(type,parameters){this.type=type;this.parameters=parameters;} 3151function _download(data,filename,mimetype){let self=window,defaultMime="application/octet-stream",mimeType=mimetype||defaultMime,payload=data,url=!filename&&!mimetype&&payload,anchor=document.createElement("a"),toString=function(a){return String(a);},myBlob=self.Blob||self.MozBlob||self.WebKitBlob||toString,fileName=filename||"download",blob,reader;myBlob=myBlob.call?myBlob.bind(self):Blob;if(String(this)==="true"){payload=[payload,mimeType];mimeType=payload[0];payload=payload[1];} 3152if(url&&url.length<2048){fileName=url.split("/").pop().split("?")[0];anchor.href=url;const targetOrigin=new URL(url,browser.location.origin).origin;if(targetOrigin&&targetOrigin!==browser.location.origin&&targetOrigin===session.origin){anchor.setAttribute("download","");document.body.appendChild(anchor);anchor.click();document.body.removeChild(anchor);return true;} 3153if(anchor.href.indexOf(url)!==-1){return new Promise((resolve,reject)=>{let xhr=new browser.XMLHttpRequest();xhr.open("GET",url,true);configureBlobDownloadXHR(xhr,{onSuccess:resolve,onFailure:reject,url});xhr.send();});}} 3154if(/^data:[\w+\-]+\/[\w+\-]+[,;]/.test(payload)){if(payload.length>1024*1024*1.999&&myBlob!==toString){payload=dataUrlToBlob(payload);mimeType=payload.type||defaultMime;}else{return navigator.msSaveBlob?navigator.msSaveBlob(dataUrlToBlob(payload),fileName):saver(payload);}} 3155blob=payload instanceof myBlob?payload:new myBlob([payload],{type:mimeType});function dataUrlToBlob(strUrl){let parts=strUrl.split(/[:;,]/),type=parts[1],decoder=parts[2]==="base64"?atob:decodeURIComponent,binData=decoder(parts.pop()),mx=binData.length,i=0,uiArr=new Uint8Array(mx);for(i;i<mx;++i){uiArr[i]=binData.charCodeAt(i);} 3156return new myBlob([uiArr],{type});} 3157function saver(url,winMode){if("download"in anchor){anchor.href=url;anchor.setAttribute("download",fileName);anchor.className="download-js-link";anchor.innerText=_t("downloading...");anchor.style.display="none";anchor.target="_blank";document.body.appendChild(anchor);setTimeout(()=>{anchor.click();document.body.removeChild(anchor);if(winMode===true){setTimeout(()=>{self.URL.revokeObjectURL(anchor.href);},250);}},66);return true;} 3158if(/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(navigator.userAgent)){url=url.replace(/^data:([\w\/\-+]+)/,defaultMime);if(!window.open(url)){if(confirm("Displaying New Document\n\nUse Save As... to download, then click back to return to this page.")){location.href=url;}} 3159return true;} 3160let f=document.createElement("iframe");document.body.appendChild(f);if(!winMode){url=`data:${url.replace(/^data:([\w\/\-+]+)/, defaultMime)}`;} 3161f.src=url;setTimeout(()=>{document.body.removeChild(f);},333);} 3162if(navigator.msSaveBlob){return navigator.msSaveBlob(blob,fileName);} 3163if(self.URL){saver(self.URL.createObjectURL(blob),true);}else{if(typeof blob==="string"||blob.constructor===toString){try{return saver(`data:${mimeType};base64,${self.btoa(blob)}`);}catch{return saver(`data:${mimeType},${encodeURIComponent(blob)}`);}} 3164reader=new FileReader();reader.onload=function(){saver(this.result);};reader.readAsDataURL(blob);} 3165return true;} 3166__exports.downloadFile=downloadFile;function downloadFile(data,filename,mimetype){return downloadFile._download(data,filename,mimetype);} 3167downloadFile._download=_download;__exports.download=download;function download(options){return download._download(options);} 3168download._download=(options)=>{return new Promise((resolve,reject)=>{const xhr=new browser.XMLHttpRequest();let data;if(Object.prototype.hasOwnProperty.call(options,"form")){xhr.open(options.form.method,options.form.action);data=new FormData(options.form);}else{xhr.open("POST",options.url);data=new FormData();
3168Object.entries(options.data).forEach((entry)=>{const[key,value]=entry;data.append(key,value);});} 3169data.append("token","dummy-because-api-expects-one");if(odoo.csrf_token){data.append("csrf_token",odoo.csrf_token);} 3170configureBlobDownloadXHR(xhr,{onSuccess:resolve,onFailure:reject,url:options.url,});xhr.send(data);});};__exports.configureBlobDownloadXHR=configureBlobDownloadXHR;function configureBlobDownloadXHR(xhr,{onSuccess=()=>{},onFailure=()=>{},url}={}){xhr.responseType="blob";xhr.onload=()=>{const mimetype=xhr.response.type;const header=(xhr.getResponseHeader("Content-Disposition")||"").replace(/;$/,"");const filename=header?parse(header).parameters.filename:null;if(xhr.status===200&&(mimetype!=="text/html"||filename)){_download(xhr.response,filename,mimetype);onSuccess(filename);}else if(xhr.status===502){onFailure(new ConnectionLostError(url));}else{const decoder=new FileReader();decoder.onload=()=>{const contents=decoder.result;const doc=new DOMParser().parseFromString(contents,"text/html");const nodes=doc.body.children.length===0?[doc.body]:doc.body.children;let error;try{const node=nodes[1]||nodes[0];error=JSON.parse(node.textContent);}catch{error={message:"Arbitrary Uncaught Python Exception",data:{debug:`${xhr.status}`+`\n`+`${nodes.length > 0 ? nodes[0].textContent : ""} 3171 ${nodes.length > 1 ? nodes[1].textContent : ""}`,},};} 3172error=makeErrorFromResponse(error);onFailure(error);};decoder.readAsText(xhr.response);}};xhr.onerror=()=>{onFailure(new ConnectionLostError(url));};} 3173return __exports;});; 3174 3175/* /web/static/src/core/network/http_service.js */ 3176odoo.define('@web/core/network/http_service',['@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");function checkResponseStatus(response){if(response.status===502){throw new Error("Failed to fetch");} 3177if(response.status===413){throw new Error("Content too large");}} 3178__exports.get=get;async function get(route,readMethod="json"){const response=await browser.fetch(route,{method:"GET"});checkResponseStatus(response);return response[readMethod]();} 3179__exports.post=post;async function post(route,params={},readMethod="json"){let formData=params;if(!(formData instanceof FormData)){formData=new FormData();for(const key in params){const value=params[key];if(Array.isArray(value)&&value.length){for(const val of value){formData.append(key,val);}}else{formData.append(key,value);}}} 3180const response=await browser.fetch(route,{body:formData,method:"POST",});checkResponseStatus(response);return response[readMethod]();} 3181const httpService=__exports.httpService={start(){return{get,post};},};registry.category("services").add("http",httpService);return __exports;});; 3182 3183/* /web/static/src/core/network/rpc.js */ 3184odoo.define('@web/core/network/rpc',['@odoo/owl','@web/core/browser/browser','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{EventBus}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{omit}=require("@web/core/utils/objects");const rpcBus=__exports.rpcBus=new EventBus();const RPC_SETTINGS=new Set(["cache","silent","xhr","headers"]);function validateRPCSettings(settings){if(!Object.keys(settings).every((key)=>RPC_SETTINGS.has(key))){throw new Error(`The settings for rpc should be ${[...RPC_SETTINGS].join(" ")}`);} 3185if("cache"in settings&&"xhr"in settings){throw new Error("Can't use 'cache' and 'xhr' at the same time");}} 3186const RPCError=__exports.RPCError=class RPCError extends Error{constructor(){super(...arguments);this.name="RPC_ERROR";this.type="server";this.code=null;this.data=null;this.exceptionName=null;this.subType=null;}} 3187const ConnectionLostError=__exports.ConnectionLostError=class ConnectionLostError extends Error{constructor(url,...args){const message=url?`Connection to "${url}" couldn't be established or was interrupted`:"Connection couldn't be established or was interrupted";super(message,...args);this.url=url;}} 3188const ConnectionAbortedError=__exports.ConnectionAbortedError=class ConnectionAbortedError extends
3188Error{} 3189const RequestEntityTooLargeError=__exports.RequestEntityTooLargeError=class RequestEntityTooLargeError extends Error{constructor(){super("The request you sent exceeded the maximum size limit configured on the server");}} 3190__exports.makeErrorFromResponse=makeErrorFromResponse;function makeErrorFromResponse(response){const{code,data:errorData,message,type:subType}=response;const error=new RPCError();error.exceptionName=errorData?.name;error.subType=subType;error.data=errorData;error.message=message;error.code=code;return error;} 3191let rpcCache;rpc.setCache=function(cache){rpcCache=cache;};rpcBus.addEventListener("CLEAR-CACHES",(event)=>{rpcCache?.invalidate(event.detail);});let rpcId=0;__exports.rpc=rpc;function rpc(url,params={},settings={}){return rpc._rpc(url,params,settings);} 3192rpc._rpc=function(url,params,settings){validateRPCSettings(settings);if(settings.cache&&rpcCache){return rpcCache.read(params?.method||url,JSON.stringify({url,params}),()=>rpc._rpc(url,params,omit(settings,"cache")),typeof settings.cache==="boolean"?{}:settings.cache);} 3193const XHR=browser.XMLHttpRequest;const data={id:rpcId++,jsonrpc:"2.0",method:"call",params:params,};const request=settings.xhr||new XHR();let rejectFn;const promise=new Promise((resolve,reject)=>{rejectFn=reject;rpcBus.trigger("RPC:REQUEST",{data,url,settings});request.addEventListener("load",()=>{let specialError=null;switch(request.status){case 502:specialError=new ConnectionLostError(url);break;case 413:specialError=new RequestEntityTooLargeError();break;} 3194if(specialError){rpcBus.trigger("RPC:RESPONSE",{data,settings,error:specialError});reject(specialError);return;} 3195let params;try{params=JSON.parse(request.response);}catch{const error=new ConnectionLostError(url);rpcBus.trigger("RPC:RESPONSE",{data,settings,error});return reject(error);} 3196const{error:responseError,result:responseResult}=params;if(!params.error){rpcBus.trigger("RPC:RESPONSE",{data,settings,result:params.result});return resolve(responseResult);} 3197const error=makeErrorFromResponse(responseError);error.model=data.params.model;rpcBus.trigger("RPC:RESPONSE",{data,settings,error});reject(error);});request.addEventListener("error",()=>{const error=new ConnectionLostError(url);rpcBus.trigger("RPC:RESPONSE",{data,settings,error});reject(error);});request.open("POST",url);const headers=settings.headers||{};headers["Content-Type"]="application/json";for(const[header,value]of Object.entries(headers)){request.setRequestHeader(header,value);} 3198request.send(JSON.stringify(data));});promise.abort=function(rejectError=true){if(request.abort){request.abort();} 3199const error=new ConnectionAbortedError("XmlHttpRequestError abort");rpcBus.trigger("RPC:RESPONSE",{data,settings,error});if(rejectError){rejectFn(error);}};return promise;};return __exports;});; 3200 3201/* /web/static/src/core/network/rpc_cache.js */ 3202odoo.define('@web/core/network/rpc_cache',['@web/core/utils/concurrency','@web/core/utils/indexed_db','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{Deferred}=require("@web/core/utils/concurrency");const{IDBQuotaExceededError,IndexedDB}=require("@web/core/utils/indexed_db");const{deepCopy}=require("@web/core/utils/objects");function jsonEqual(v1,v2){return JSON.stringify(v1)===JSON.stringify(v2);} 3203function validateSettings({type,update}){if(!["ram","disk"].includes(type)){throw new Error(`Invalid "type" settings provided to RPCCache: ${type}`);} 3204if(!["always","once"].includes(update)){throw new Error(`Invalid "update" settings provided to RPCCache: ${update}`);}} 3205const CRYPTO_ALGO="AES-GCM";const MAX_STORAGE_SIZE=2*1024*1024*1024;class Crypto{constructor(secret){this._cryptoKey=null;this._ready=window.crypto.subtle.importKey("raw",new Uint8Array(secret.match(/../g).map((h)=>parseInt(h,16))).buffer,CRYPTO_ALGO,false,["encrypt","decrypt"]).then((encryptedKey)=>{this._cryptoKey=encryptedKey;});} 3206async encrypt(value){await this._ready;const iv=window.crypto.getRandomValues(new Uint8Array(12));const ciphertext=await window.crypto.subtle.encrypt({name:CRYPTO_ALGO,iv,length:64,},this._cryptoKey,new TextEncoder().encode(JSON.stringify(value)));return{ciphertext,iv};} 3207async decrypt({ciphertext,iv}){await this._ready;
3207const decrypted=await window.crypto.subtle.decrypt({name:CRYPTO_ALGO,iv,length:64,},this._cryptoKey,ciphertext);return JSON.parse(new TextDecoder().decode(decrypted));}} 3208class RamCache{constructor(){this.ram={};} 3209write(table,key,value){if(!(table in this.ram)){this.ram[table]={};} 3210this.ram[table][key]=value;} 3211read(table,key){return this.ram[table]?.[key];} 3212delete(table,key){delete this.ram[table]?.[key];} 3213invalidate(tables=null){if(tables){tables=typeof tables==="string"?[tables]:tables;for(const table of tables){if(table in this.ram){this.ram[table]={};}}}else{this.ram={};}}} 3214const RPCCache=__exports.RPCCache=class RPCCache{constructor(name,version,secret){this.crypto=new Crypto(secret);this.indexedDB=new IndexedDB(name,version+CRYPTO_ALGO);this.ramCache=new RamCache();this.pendingRequests={};this.checkSize();} 3215async checkSize(){const{usage}=await navigator.storage.estimate();if(usage>MAX_STORAGE_SIZE){console.log(`Deleting indexedDB database as maximum storage size is reached`);return this.indexedDB.deleteDatabase();}} 3216read(table,key,fallback,{callback=()=>{},type="ram",update="once"}={}){validateSettings({type,update});let ramValue=this.ramCache.read(table,key);const requestKey=`${table}/${key}`;const hasPendingRequest=requestKey in this.pendingRequests;if(hasPendingRequest){this.pendingRequests[requestKey].callbacks.push(callback);return ramValue.then((result)=>deepCopy(result));} 3217if(!ramValue||update==="always"){const request={callbacks:[callback],invalidated:false};this.pendingRequests[requestKey]=request;const prom=new Promise((resolve,reject)=>{const fromCache=new Deferred();let fromCacheValue;const onFullfilled=(result)=>{resolve(result);const hasChanged=!!fromCacheValue&&!jsonEqual(fromCacheValue,result);request.callbacks.forEach((cb)=>cb(deepCopy(result),hasChanged));if(request.invalidated){return result;} 3218delete this.pendingRequests[requestKey];this.ramCache.write(table,key,Promise.resolve(result));if(type==="disk"){this.crypto.encrypt(result).then((encryptedResult)=>{this.indexedDB.write(table,key,encryptedResult).catch((e)=>{if(e instanceof IDBQuotaExceededError){this.indexedDB.deleteDatabase();}else{throw e;}});});} 3219return result;};const onRejected=async(error)=>{await fromCache;if(!request.invalidated){delete this.pendingRequests[requestKey];if(!fromCacheValue){this.ramCache.delete(table,key);}} 3220if(fromCacheValue){throw error;} 3221reject(error);};fallback().then(onFullfilled,onRejected);if(ramValue){ramValue.then((value)=>{resolve(value);fromCacheValue=value;fromCache.resolve();});}else if(type==="disk"){this.indexedDB.read(table,key).then(async(result)=>{if(result){let decrypted;try{decrypted=await this.crypto.decrypt(result);}catch{return;} 3222resolve(decrypted);fromCacheValue=decrypted;}}).finally(()=>fromCache.resolve());}else{fromCache.resolve();}});this.ramCache.write(table,key,prom);ramValue=prom;} 3223return ramValue.then((result)=>deepCopy(result));} 3224invalidate(tables){this.indexedDB.invalidate(tables);this.ramCache.invalidate(tables);for(const key in this.pendingRequests){this.pendingRequests[key].invalidated=true;} 3225this.pendingRequests={};}} 3226return __exports;});; 3227 3228/* /web/static/src/core/notebook/notebook.js */ 3229odoo.define('@web/core/notebook/notebook',['@odoo/owl','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{Component,onWillRender,onWillUpdateProps,useEffect,useRef,useState}=require("@odoo/owl");const{KeepLast}=require("@web/core/utils/concurrency");const Notebook=__exports.Notebook=class Notebook extends Component{static template="web.Notebook";static defaultProps={className:"",orientation:"horizontal",onPageUpdate:()=>{},onWillActivatePage:()=>{},};static props={slots:{type:Object,optional:true},pages:{type:Object,optional:true},class:{optional:true},className:{type:String,optional:true},defaultPage:{type:String,optional:true},orientation:{type:String,optional:true},icons:{type:Object,optional:true},onPageUpdate:{type:Function,optional:true},onWillActivatePage:{type:Function,optional:true},};setup(){this.activePane=useRef("activePane");this.pages=this.computePages(this.props);this.invalidPages=new Set();this.state=useState({currentPage:null});this.state.currentPage=this.computeActivePage(this.props.defaultPage,true);this.keepLastPageTransition=new KeepLast();useEffect(()=>{this.props.onPageUpdate(this.state.currentPage);this.activePane.el?.classList.add("show");},()=>[this.state.currentPage]);onWillRender(()=>{this.computeInvalidPages();});onWillUpdateProps((nextProps)=>{const activateDefault=this.props.defaultPage!==nextProps.defaultPage||!this.defaultVisible;this.pages=this.computePages(nextProps);this.state.currentPage=this.computeActivePage(nextProps.defaultPage,activateDefault);});} 3230get navItems(){return this.pages.filter((e)=>
3230e[1].isVisible);} 3231get page(){const page=this.pages.find((e)=>e[0]===this.state.currentPage)[1];return page.Component&&page;} 3232async activatePage(pageIndex){if(!this.disabledPages.includes(pageIndex)&&this.state.currentPage!==pageIndex){const prom=(async()=>this.props.onWillActivatePage(pageIndex))();const canProceed=await this.keepLastPageTransition.add(prom);if(canProceed!==false){this.activePane.el?.classList.remove("show");this.state.currentPage=pageIndex;}}} 3233computePages(props){if(!props.slots&&!props.pages){return[];} 3234if(props.pages){for(const page of props.pages){page.isVisible=true;}} 3235this.disabledPages=[];const pages=[];const pagesWithIndex=[];for(const[k,v]of Object.entries({...props.slots,...props.pages})){const id=v.id||k;if(v.index){pagesWithIndex.push([id,v]);}else{pages.push([id,v]);} 3236if(v.isDisabled){this.disabledPages.push(k);}} 3237for(const page of pagesWithIndex){pages.splice(page[1].index,0,page);} 3238return pages;} 3239computeActivePage(defaultPage,activateDefault){if(!this.pages.length){return null;} 3240const pages=this.pages.filter((e)=>e[1].isVisible).map((e)=>e[0]);if(defaultPage){if(!pages.includes(defaultPage)){this.defaultVisible=false;}else{this.defaultVisible=true;if(activateDefault){return defaultPage;}}} 3241const current=this.state.currentPage;if(!current||(current&&!pages.includes(current))){return pages[0];} 3242return current;} 3243computeInvalidPages(){this.invalidPages=new Set();for(const page of this.navItems){const invalid=page[1].fieldNames?.some((fieldName)=>this.env.model?.root.isFieldInvalid(fieldName));if(invalid){this.invalidPages.add(page[0]);}}}} 3244return __exports;});; 3245 3246/* /web/static/src/core/notifications/notification.js */ 3247odoo.define('@web/core/notifications/notification',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,useRef,onMounted}=require("@odoo/owl");const AUTOCLOSE_DELAY=4000;const Notification=__exports.Notification=class Notification extends Component{static template="web.NotificationWowl";static props={message:{validate:(m)=>typeof m==="string"||(typeof m==="object"&&typeof m.toString==="function"),},type:{type:String,optional:true,validate:(t)=>["warning","danger","success","info"].includes(t),},title:{type:[String,Boolean,{toString:Function}],optional:true},className:{type:String,optional:true},buttons:{type:Array,element:{type:Object,shape:{name:{type:String},icon:{type:String,optional:true},primary:{type:Boolean,optional:true},onClick:Function,},},optional:true,},sticky:{type:Boolean,optional:true},autocloseDelay:{type:Number,optional:true},close:{type:Function},};static defaultProps={buttons:[],className:"",type:"warning",autocloseDelay:AUTOCLOSE_DELAY,};setup(){this.autocloseProgress=useRef("autoclose_progress_bar");onMounted(()=>this.startNotificationTimer());} 3248freeze(){this.startedTimestamp=false;this.autocloseProgress.el.style.width=0;} 3249refresh(){this.startNotificationTimer();} 3250close(){this.props.close();} 3251startNotificationTimer(){if(this.props.sticky){return;} 3252this.startedTimestamp=luxon.DateTime.now().ts;const cb=()=>{if(this.startedTimestamp){const currentProgress=(luxon.DateTime.now().ts-this.startedTimestamp)/this.props.autocloseDelay;if(currentProgress>1){this.close();return;} 3253if(this.autocloseProgress.el){this.autocloseProgress.el.style.width=`${(1 - currentProgress) * 100}%`;} 3254requestAnimationFrame(cb);}};cb();}} 3255return __exports;});; 3256 3257/* /web/static/src/core/notifications/notification_container.js */ 3258odoo.define('@web/core/notifications/notification_container',['@web/core/notifications/notification','@web/core/transition','@odoo/owl'],function(require){'use strict';let __exports={};const{Notification}=require("@web/core/notifications/notification");const{Transition}=require("@web/core/transition");const{Component,xml,useState}=require("@odoo/owl");const NotificationContainer=__exports.NotificationContainer=class NotificationContainer extends Component{static props={notifications:Object,};static template=xml` 3259 <div class="o_notification_manager"> 3260 <t t-foreach="notifications" t-as="notification" t-key="notification"> 3261 <Transition leaveDuration="0" immediate="true" name="'o_notification_fade'" t-slot-scope="transition"> 3262 <Notification t-props="notification_value.props" className="(notification_value.props.className || '') + ' ' + transition.className"/> 3263 </Transition> 3264 </t> 3265 </div>`;static components={Notification,Transition};setup(){this.notifications=useState(this.props.notifications);}} 3266return __exports;});; 3267 3268/* /web/static/src/core/notifications/notification_service.js */ 3269odoo.define('@web/core/notifications/notification_service',['@web/core/registry','@web/core/notifications/notification_container','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{NotificationContainer}=require("@web/core/notifications/notification_container");const{reactive}=require("@odoo/owl");const notificationService=__exports.notificationService={notificationContainer:NotificationContainer,start(){let notifId=0;const notifications=reactive({});registry.category("main_components").add(this.notificationContainer.name,{Component:this.notificationContainer,props:{notifications},},{sequence:100});function add(message,options={}){const id=++notifId;const closeFn=()=>close(id);const props=Object.assign({},options,{message,close:closeFn});delete props.onClose;const notification={id,props,onClose:options.onClose,};notifications[id]=notification;return closeFn;}
3270function close(id){if(notifications[id]){const notification=notifications[id];if(notification.onClose){notification.onClose();} 3271delete notifications[id];}} 3272return{add};},};registry.category("services").add("notification",notificationService);return __exports;});; 3273 3274/* /web/static/src/core/orm_service.js */ 3275odoo.define('@web/core/orm_service',['@web/core/registry','@web/core/network/rpc','@web/core/user','@web/core/domain'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{rpc}=require("@web/core/network/rpc");const{user}=require("@web/core/user");const{Domain}=require("@web/core/domain");const x2ManyCommands=__exports.x2ManyCommands={CREATE:0,create(virtualID,values){delete values.id;return[x2ManyCommands.CREATE,virtualID||false,values];},UPDATE:1,update(id,values){delete values.id;return[x2ManyCommands.UPDATE,id,values];},DELETE:2,delete(id){return[x2ManyCommands.DELETE,id,false];},UNLINK:3,unlink(id){return[x2ManyCommands.UNLINK,id,false];},LINK:4,link(id){return[x2ManyCommands.LINK,id,false];},CLEAR:5,clear(){return[x2ManyCommands.CLEAR,false,false];},SET:6,set(ids){return[x2ManyCommands.SET,false,ids];},};function validateModel(value){if(typeof value!=="string"||value.length===0){throw new Error(`Invalid model name: ${value}`);}} 3276function validatePrimitiveList(name,type,value){if(!Array.isArray(value)||value.some((val)=>typeof val!==type)){throw new Error(`Invalid ${name} list: ${value}`);}} 3277function validateObject(name,obj){if(typeof obj!=="object"||obj===null||Array.isArray(obj)){throw new Error(`${name} should be an object`);}} 3278function validateArray(name,array){if(!Array.isArray(array)){throw new Error(`${name} should be an array`);}} 3279const UPDATE_METHODS=__exports.UPDATE_METHODS=["unlink","create","write","web_save","web_save_multi","action_archive","action_unarchive",];const ORM=__exports.ORM=class ORM{constructor(){this.rpc=rpc;this._silent=false;this._cache=false;} 3280get silent(){return Object.assign(Object.create(this),{_silent:true});} 3281cache(options={}){return Object.assign(Object.create(this),{_cache:options});} 3282call(model,method,args=[],kwargs={}){validateModel(model);const url=`/web/dataset/call_kw/${model}/${method}`;const fullContext=Object.assign({},user.context,kwargs.context||{});const fullKwargs=Object.assign({},kwargs,{context:fullContext});const params={model,method,args,kwargs:fullKwargs,};return this.rpc(url,params,{silent:this._silent,cache:this._cache,});} 3283create(model,records,kwargs={}){validateArray("records",records);for(const record of records){validateObject("record",record);} 3284return this.call(model,"create",[records],kwargs);} 3285read(model,ids,fields,kwargs={}){validatePrimitiveList("ids","number",ids);if(fields){validatePrimitiveList("fields","string",fields);} 3286if(!ids.length){return Promise.resolve([]);} 3287return this.call(model,"read",[ids,fields],kwargs);} 3288formattedReadGroup(model,domain,groupby,aggregates,kwargs={}){validateArray("domain",domain);validatePrimitiveList("groupby","string",groupby);validatePrimitiveList("aggregates","string",aggregates);return this.call(model,"formatted_read_group",[],{domain,groupby,aggregates,...kwargs,}).then((res)=>{for(const group of res){group["__domain"]=Domain.and([domain,group["__extra_domain"]]).toList();} 3289return res;});} 3290formattedReadGroupingSets(model,domain,grouping_sets,aggregates,kwargs={}){validateArray("domain",domain);validateArray("groupby",grouping_sets);validatePrimitiveList("aggregates","string",aggregates);return this.call(model,"formatted_read_grouping_sets",[],{domain,grouping_sets,aggregates,...kwargs,}).then((res)=>{for(const groups of res){for(const group of groups){group["__domain"]=Domain.and([domain,group["__extra_domain"]]).toList();}} 3291return res;});} 3292search(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"search",[domain],kwargs);} 3293searchRead(model,domain,fields,kwargs={}){validateArray("domain",domain);if(fields){validatePrimitiveList("fields","string",fields);} 3294return this.call(model,"search_read",[],{...kwargs,domain,fields});} 3295searchCount(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"search_count",[domain],kwargs);} 3296unlink(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);if(!ids.length){return Promise.resolve(true);} 3297return this.call(model,"unlink",[ids],kwargs);} 3298webReadGroup(model,domain,groupby,aggregates,kwargs={}){validateArray("domain",domain);validatePrimitiveList("aggregates","string",aggregates);return this.call(model,"web_read_group",[],{domain,groupby,aggregates,...kwargs,});} 3299webRead(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);return this.call(model,"web_read",[ids],kwargs);} 3300webResequence(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);
3300return this.call(model,"web_resequence",[ids],{...kwargs,specification:kwargs.specification||{},});} 3301webSearchRead(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"web_search_read",[],{...kwargs,domain});} 3302write(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateObject("data",data);return this.call(model,"write",[ids,data],kwargs);} 3303webSave(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateObject("data",data);return this.call(model,"web_save",[ids,data],kwargs);} 3304async webSaveMulti(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateArray("data",data);data.forEach((d)=>{validateObject("data item",d);});return this.call(model,"web_save_multi",[ids,data],kwargs);}} 3305const ormService=__exports.ormService={async:["call","create","nameGet","read","formattedReadGroup","webReadGroup","search","searchRead","unlink","webResequence","webSearchRead","write",],start(){return new ORM();},};registry.category("services").add("orm",ormService);return __exports;});; 3306 3307/* /web/static/src/core/overlay/overlay_container.js */ 3308odoo.define('@web/core/overlay/overlay_container',['@odoo/owl','@web/core/utils/arrays','@web/core/utils/components'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,useChildSubEnv,useRef,useState}=require("@odoo/owl");const{sortBy}=require("@web/core/utils/arrays");const{ErrorHandler}=require("@web/core/utils/components");const OVERLAY_ITEMS=[];const OVERLAY_SYMBOL=__exports.OVERLAY_SYMBOL=Symbol("Overlay");class OverlayItem extends Component{static template="web.OverlayContainer.Item";static components={};static props={component:{type:Function},props:{type:Object},env:{type:Object,optional:true},};setup(){this.rootRef=useRef("rootRef");OVERLAY_ITEMS.push(this);onWillDestroy(()=>{const index=OVERLAY_ITEMS.indexOf(this);OVERLAY_ITEMS.splice(index,1);});if(this.props.env){this.__owl__.childEnv=this.props.env;} 3309useChildSubEnv({[OVERLAY_SYMBOL]:{contains:(target)=>this.contains(target),},});} 3310get subOverlays(){return OVERLAY_ITEMS.slice(OVERLAY_ITEMS.indexOf(this));} 3311contains(target){return(this.rootRef.el?.contains(target)||this.subOverlays.some((oi)=>oi.rootRef.el?.contains(target)));}} 3312const OverlayContainer=__exports.OverlayContainer=class OverlayContainer extends Component{static template="web.OverlayContainer";static components={ErrorHandler,OverlayItem};static props={overlays:Object};setup(){this.root=useRef("root");this.state=useState({rootEl:null});} 3313get sortedOverlays(){return sortBy(Object.values(this.props.overlays),(overlay)=>overlay.sequence);} 3314isVisible(overlay){return overlay.rootId===this.env?.rootId;} 3315handleError(overlay,error){overlay.remove();Promise.resolve().then(()=>{throw error;});}} 3316return __exports;});; 3317 3318/* /web/static/src/core/overlay/overlay_service.js */ 3319odoo.define('@web/core/overlay/overlay_service',['@odoo/owl','@web/core/registry','@web/core/overlay/overlay_container'],function(require){'use strict';let __exports={};const{markRaw,reactive}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{OverlayContainer}=require("@web/core/overlay/overlay_container");const mainComponents=registry.category("main_components");const services=registry.category("services");const overlayService=__exports.overlayService={start(){let nextId=0;const overlays=reactive({});mainComponents.add("OverlayContainer",{Component:OverlayContainer,props:{overlays},});const remove=async(id,onRemove=()=>{},removeParams)=>{if(id in overlays){await onRemove(removeParams);delete overlays[id];}};const add=(component,props,options={})=>{const id=++nextId;const removeCurrentOverlay=(removeParams)=>remove(id,options.onRemove,removeParams);overlays[id]={id,component,env:options.env&&markRaw(options.env),props,remove:removeCurrentOverlay,sequence:options.sequence??50,rootId:options.rootId,};return removeCurrentOverlay;};return{add,overlays};},};services.add("overlay",overlayService);return __exports;});; 3320 3321/* /web/static/src/core/pager/pager.js */ 3322odoo.define('@web/core/pager/pager',['@web/core/utils/hooks','@web/core/utils/numbers','@odoo/owl'],function(require){'use strict';let __exports={};const{useAutofocus}=require("@web/core/utils/hooks");const{clamp}=require("@web/core/utils/numbers");const{Component,EventBus,useEffect,useExternalListener,useState}=require("@odoo/owl");const PAGER_UPDATED_EVENT=__exports.PAGER_UPDATED_EVENT="PAGER:UPDATED";const pagerBus=__exports.pagerBus=new EventBus();const Pager=__exports.Pager=class Pager extends Component{static template="web.Pager";static defaultProps={isEditable:true,withAccessKey:true,};static props={offset:Number,limit:Number,total:Number,onUpdate:Function,isEditable:{type:Boolean,optional:true},withAccessKey:{type:Boolean,optional:true},updateTotal:{type:Function,optional:true},};setup(){this.state=useState({isEditing:false,isDisabled:false,});this.inputRef=useAutofocus();useExternalListener(document,"mousedown",this.onClickAway,{capture:true});let firstMount=true;useEffect(()=>{if(!firstMount&&this.env.isSmall){pagerBus.trigger(PAGER_UPDATED_EVENT,{value:this.value,total:this.props.total,});} 3323firstMount=false;},()=>[this.props.offset,this.props.limit,this.props.total]);} 3324get minimum(){return this.props.offset+1;} 3325get maximum(){return Math.min(this.props.offset+this.props.limit,this.props.total);} 3326get value(){const parts=[this.minimum];if(this.props.limit>1){parts.push(this.maximum);} 3327return parts.join("-");} 3328get isSinglePage(){return!this.props.updateTotal&&this.minimum===1&&this.maximum===this.props.total;} 3329async navigate(direction){let minimum=this.props.offset+this.props.limit*direction;let total=this.props.total;if(this.props.updateTotal&&minimum<0){total=await this.props.updateTotal();} 3330if(minimum>=total){if(!this.props.updateTotal){minimum=0;}}else if(minimum<0&&this.props.limit===1){minimum=total-1;}else if(minimum<0&&this.props.limit>1){minimum=total-(total%this.props.limit||this.props.limit);} 3331this.update(minimum,this.props.limit,true);} 3332async parse(value){let[minimum,maximum]=value.trim().split(/\s*[-\s,;]\s*/);minimum=parseInt(minimum,10);maximum=maximum?parseInt(maximum,10):minimum;if(this.props.updateTotal){return{minimum:minimum-1,maximum};} 3333return{minimum:clamp(minimum,1,this.props.total)-1,maximum:clamp(maximum,1,this.props.total),};} 3334async setValue(value){const{minimum,maximum}=await this.parse(value);if(!isNaN(minimum)&&!isNaN(maximum)&&minimum<maximum){this.update(minimum,maximum-minimum);}} 3335async update(offset,limit,hasNavigated){this.state.isDisabled=true;try{await this.props.onUpdate({offset,limit},hasNavigated);}finally{this.state.isDisabled=false;this.state.isEditing=false;}} 3336async updateTotal(){if(!this.state.isDisabled){this.state.isDisabled=true;await this.props.updateTotal();this.state.isDisabled=false;}} 3337onClickAway(ev){if(ev.target!==this.inputRef.el){this.state.isEditing=false;}} 3338onInputBlur(){this.state.isEditing=false;} 3339onInputChange(ev){this.setValue(ev.target.value);if(!this.state.isDisabled){ev.preventDefault();}} 3340onInputKeydown(ev){switch(ev.key){case"Enter":ev.preventDefault();ev.stopPropagation();this.setValue(ev.currentTarget.value);break;case"Escape":ev.preventDefault();ev.stopPropagation();this.state.isEditing=false;break;}} 3341onValueClick(){if(this.props.isEditable&&!this.state.isEditing&&!this.state.isDisabled){if(this.inputRef.el){this.inputRef.el.focus();} 3342this.state.isEditing=true;}}} 3343return __exports;});; 3344 3345/* /web/static/src/core/pager/pager_indicator.js */ 3346odoo.define('@web/core/pager/pager_indicator',['@web/core/browser/browser','@web/core/registry','@web/core/transition','@web/core/utils/hooks','@odoo/owl','@web/core/pager/pager'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Transition}=require("@web/core/transition");const{useBus}=require("@web/core/utils/hooks");const{Component,useState}=require("@odoo/owl");const{PAGER_UPDATED_EVENT,pagerBus}=require("@web/core/pager/pager");const PagerIndicator=__exports.PagerIndicator=class PagerIndicator extends Component{static template="web.PagerIndicator";static components={Transition};static props={};setup(){this.state=useState({show:false,value:"-",total:0,});this.startShowTimer=null;useBus(pagerBus,PAGER_UPDATED_EVENT,this.pagerUpdate);} 3347pagerUpdate({detail}){this.state.value=detail.value;this.state.total=detail.total;browser.clearTimeout(this.startShowTimer);this.state.show=true;this.startShowTimer=browser.setTimeout(()=>{this.state.show=false;},1400);}} 3348registry.category("main_components").add("PagerIndicator",{Component:PagerIndicator,});return __exports;});; 3349 3350/* /web/static/src/core/popover/popover.js */ 3351odoo.define('@web/core/popover/popover',['@odoo/owl','@web/core/h
3351otkeys/hotkey_hook','@web/core/overlay/overlay_container','@web/core/position/position_hook','@web/core/position/utils','@web/core/ui/ui_service','@web/core/utils/classname','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillDestroy,useRef}=require("@odoo/owl");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{OVERLAY_SYMBOL}=require("@web/core/overlay/overlay_container");const{usePosition}=require("@web/core/position/position_hook");const{reverseForRTL}=require("@web/core/position/utils");const{useActiveElement}=require("@web/core/ui/ui_service");const{mergeClasses}=require("@web/core/utils/classname");const{useForwardRefToParent}=require("@web/core/utils/hooks");function useEarlyExternalListener(target,eventName,handler,eventParams){target.addEventListener(eventName,handler,eventParams);onWillDestroy(()=>target.removeEventListener(eventName,handler,eventParams));} 3352function useClickAway(popover,callback){function blurHandler(ev){const target=ev.relatedTarget||document.activeElement;if(target?.tagName==="IFRAME"){callback(target);}} 3353function navigationHandler(){callback(document.documentElement);} 3354function pointerDownHandler(ev){callback(ev.composedPath()[0]);} 3355useEarlyExternalListener(window,"pointerdown",pointerDownHandler,{capture:true});useEarlyExternalListener(window,"blur",blurHandler,{capture:true});useEarlyExternalListener(window,"popstate",navigationHandler,{capture:true});for(const iframeEl of document.querySelectorAll("iframe")){try{useEarlyExternalListener(iframeEl.contentWindow,"pointerdown",()=>{const popupEl=popover.popoverRef.el;let checkEl=iframeEl.parentElement;while(checkEl){if(checkEl===popupEl){return;} 3356checkEl=checkEl.parentElement;} 3357callback(iframeEl);},{capture:true,once:true});}catch(e){if(e.name!=="SecurityError")throw e;}}} 3358const POPOVERS=new WeakMap();__exports.getPopoverForTarget=getPopoverForTarget;function getPopoverForTarget(target){return POPOVERS.get(target);} 3359const Popover=__exports.Popover=class Popover extends Component{static template="web.Popover";static defaultProps={animation:true,arrow:true,class:"",closeOnClickAway:()=>true,closeOnEscape:true,componentProps:{},fixedPosition:false,position:"bottom",setActiveElement:false,};static props={component:{type:Function},componentProps:{optional:true,type:Object},target:{validate:(target)=>{const Element=target?.ownerDocument?.defaultView?.Element;return((Boolean(Element)&&(target instanceof Element||target instanceof window.Element))||(typeof target==="object"&&target?.constructor?.name?.endsWith("Element")));},},close:{type:Function},animation:{optional:true,type:Boolean},arrow:{optional:true,type:Boolean},class:{optional:true},role:{optional:true,type:String},fixedPosition:{optional:true,type:Boolean},extendedFlipping:{optional:true,type:Boolean},holdOnHover:{optional:true,type:Boolean},onPositioned:{optional:true,type:Function},position:{optional:true,type:String,validate:(p)=>{const[d,v="middle"]=p.split("-");return(["top","bottom","left","right"].includes(d)&&["start","middle","end","fit"].includes(v));},},closeOnClickAway:{optional:true,type:Function},closeOnEscape:{optional:true,type:Boolean},setActiveElement:{optional:true,type:Boolean},ref:{optional:true,type:Function},slots:{optional:true,type:Object},};static animationTime=200;setup(){if(this.props.setActiveElement){useActiveElement("ref");} 3360useForwardRefToParent("ref");this.popoverRef=useRef("ref");this.position=usePosition("ref",()=>this.props.target,this.positioningOptions);if(!this.props.animation){this.animationDone=true;} 3361const resizeObserver=new ResizeObserver(()=>{if(!this.props.fixedPosition&&this.animationDone){this.position.unlock();}});onMounted(()=>{POPOVERS.set(this.props.target,this.popoverRef.el);resizeObserver.observe(this.popoverRef.el);});onWillDestroy(()=>POPOVERS.delete(this.props.target));if(this.props.target.isConnected){useClickAway(this,this.onClickAway.bind(this));if(this.props.closeOnEscape){useHotkey("escape",()=>this.props.close());} 3362const targetObserver=new MutationObserver(this.onTargetMutate.bind(this));targetObserver.observe(this.props.target.parentElement,{childList:true});onWillDestroy(()=>targetObserver.disconnect());}else{this.props.close();}} 3363get defaultClassObj(){return mergeClasses("o_popover popover mw-100 bs-popover-auto",this.props.class);} 3364get positioningOptions(){return{extendedFlipping:this.props.extendedFlipping,margin:this.props.arrow?8:0,onPositioned:(el,solution)=>{this.onPositioned(solution);this.props.onPositioned?.(el,solution);},position:this.props.position,shrink:true,};} 3365animate(direction){const transform={top:["translateY(-5%)","translateY(0)"],right:["translateX(5%)","translateX(0)"],bottom:["translateY(5%)","translateY(0)"],left:["translateX(-5%)","translateX(0)"],}[direction];return this.popoverRef.el.animate({opacity:[0,1],transform},this.constructor.animationTime);} 3366isInside(target){return(this.props.target?.contains(target)||this.popoverRef?.el?.contains(target)||this.env[OVERLAY_SYMBOL]?.contains(target));} 3367onClickAway(target){if(this.props.closeOnClickAway(target)&&!this.isInside(target)){this.props.close();}} 3368onPositioned({direction,variant,variantOffset}){if(this.props.arrow){this.updateArrow(direction,variant,variantOffset);} 3369if(this.props.animation&&!this.animationDone){this.position.lock();this.animate(direction).finished.then(()=>{this.animationDone=true;if(!this.props.fixedPosition){this.position.unlock();}});} 3370if(this.props.fixedPosition){this.position.lock();}} 3371onTargetMutate(){if(!this.props.target.isConnected){this.props.close();}} 3372updateArrow(direction,variant,variantOffset){const{el}=this.popoverRef;[direction,variant]=reverseForRTL(direction,variant);el.dataset.popperPlacement=direction;const vertical=["top","bottom"].includes(direction);
3372const placementProperty=vertical?"left":"top";const placement={start:"--position-min",middle:"--position-center",fit:"--position-center",end:"--position-max",}[variant];const arrowEl=el.querySelector(":scope > .popover-arrow");Object.assign(arrowEl.style,{top:"",left:"",[placementProperty]:`clamp( 3373 var(--position-min), 3374 calc(var(${placement}) - ${variantOffset}px), 3375 var(--position-max) 3376 )`,});const sizeProperty=vertical?"width":"height";const{[sizeProperty]:arrowSize,[placementProperty]:arrowPosition}=arrowEl.getBoundingClientRect();const{[sizeProperty]:targetSize,[placementProperty]:targetPosition}=this.props.target.getBoundingClientRect();const arrowCenter=arrowPosition+arrowSize/2;const margin=arrowSize/2-1;const hasEnoughSpace=arrowSize<targetSize-2*margin;const isOutsideSafeEdge=arrowCenter<targetPosition+margin||arrowCenter>targetPosition+targetSize-margin;arrowEl.classList.toggle("sucked",hasEnoughSpace&&isOutsideSafeEdge);}} 3377return __exports;});; 3378 3379/* /web/static/src/core/popover/popover_hook.js */ 3380odoo.define('@web/core/popover/popover_hook',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{onWillUnmount,status,useComponent}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");__exports.makePopover=makePopover;function makePopover(addFn,component,options){let removeFn=null;function close(){removeFn?.();} 3381return{open(target,props){close();const newOptions=Object.create(options);newOptions.onClose=()=>{removeFn=null;options.onClose?.();};removeFn=addFn(target,component,props,newOptions);},close,get isOpen(){return Boolean(removeFn);},};} 3382__exports.usePopover=usePopover;function usePopover(component,options={}){let service;if(options.useBottomSheet){service=useService("bottom_sheet");}else{service=useService("popover");} 3383const owner=useComponent();const newOptions=Object.create(options);newOptions.onClose=()=>{if(status(owner)!=="destroyed"){options.onClose?.();}};const popover=makePopover(service.add,component,newOptions);onWillUnmount(popover.close);return popover;} 3384return __exports;});; 3385 3386/* /web/static/src/core/popover/popover_service.js */ 3387odoo.define('@web/core/popover/popover_service',['@odoo/owl','@web/core/popover/popover','@web/core/registry'],function(require){'use strict';let __exports={};const{markRaw}=require("@odoo/owl");const{Popover}=require("@web/core/popover/popover");const{registry}=require("@web/core/registry");const popoverService=__exports.popoverService={dependencies:["overlay"],start(_,{overlay}){const add=(target,component,props={},options={})=>{const closeOnClickAway=typeof options.closeOnClickAway==="function"?options.closeOnClickAway:()=>options.closeOnClickAway??true;const remove=overlay.add(Popover,{target,close:()=>remove(),closeOnClickAway,closeOnEscape:options.closeOnEscape,component,componentProps:markRaw(props),extendedFlipping:options.extendedFlipping,ref:options.ref,class:options.popoverClass,animation:options.animation,arrow:options.arrow,role:options.role,position:options.position,onPositioned:options.onPositioned,fixedPosition:options.fixedPosition,holdOnHover:options.holdOnHover,setActiveElement:options.setActiveElement??true,},{env:options.env,onRemove:options.onClose,rootId:target.getRootNode()?.host?.id,sequence:options.sequence,});return remove;};return{add};},};registry.category("services").add("popover",popoverService);return __exports;});; 3388 3389/* /web/static/src/core/position/position_hook.js */ 3390odoo.define('@web/core/position/position_hook',['@web/core/position/utils','@web/core/utils/objects','@web/core/utils/timing','@odoo/owl'],function(require){'use strict';let __exports={};const{reposition}=require("@web/core/position/utils");const{omit}=require("@web/core/utils/objects");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{EventBus,onWillDestroy,useChildSubEnv,useComponent,useEffect,useRef,}=require("@odoo/owl");const POSITION_BUS=__exports.POSITION_BUS=Symbol("position-bus");__exports.usePosition=usePosition;function usePosition(refName,getTarget,options={}){const ref=useRef(refName);let lock=false;const update=()=>{const targetEl=getTarget();if(!ref.el||!targetEl?.isConnected||lock){return;} 3391const repositionOptions=omit(options,"onPositioned");const solution=reposition(ref.el,targetEl,repositionOptions);options.position=`${solution.direction}-${solution.variant}`;options.onPositioned?.(ref.el,solution);};const component=useComponent();const bus=component.env[POSITION_BUS]||new EventBus();let executingUpdate=false;const batchedUpdate=async()=>
3391{if(!executingUpdate){executingUpdate=true;update();await Promise.resolve();executingUpdate=false;}};bus.addEventListener("update",batchedUpdate);onWillDestroy(()=>bus.removeEventListener("update",batchedUpdate));const isTopmost=!(POSITION_BUS in component.env);if(isTopmost){useChildSubEnv({[POSITION_BUS]:bus});} 3392const throttledUpdate=useThrottleForAnimation(()=>bus.trigger("update"));useEffect(()=>{bus.trigger("update");if(isTopmost){const scrollListener=(e)=>{if(ref.el?.contains(e.target)){return;} 3393throttledUpdate();};const documents=[];const targetDocument=getTarget()?.ownerDocument;if(targetDocument){documents.push(targetDocument);if(targetDocument.defaultView&&targetDocument.defaultView.top!==targetDocument.defaultView){try{documents.push(targetDocument.defaultView.top.document);}catch{}}} 3394for(const document of documents){document.addEventListener("scroll",scrollListener,{capture:true});document.addEventListener("load",throttledUpdate,{capture:true});} 3395window.addEventListener("resize",throttledUpdate);return()=>{for(const document of documents){document.removeEventListener("scroll",scrollListener,{capture:true});document.removeEventListener("load",throttledUpdate,{capture:true});} 3396window.removeEventListener("resize",throttledUpdate);};}});return{lock:()=>{lock=true;},unlock:()=>{lock=false;bus.trigger("update");},};} 3397return __exports;});; 3398 3399/* /web/static/src/core/position/utils.js */ 3400odoo.define('@web/core/position/utils',['@web/core/l10n/localization'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const DEFAULTS={flip:true,margin:0,position:"bottom",};const DIRECTIONS={t:"top",r:"right",b:"bottom",l:"left",c:"center"};const VARIANTS={s:"start",m:"middle",e:"end",f:"fit"};const DIRECTION_FLIP_ORDER={top:"tb",right:"rl",bottom:"bt",left:"lr",center:"c"};const EXTENDED_DIRECTION_FLIP_ORDER={top:"tbrlc",right:"rlbtc",bottom:"btrlc",left:"lrbtc",center:"c",};const VARIANT_FLIP_ORDER={start:"se",middle:"m",end:"es",fit:"f"};function getIFrame(popperEl,targetEl){return[...popperEl.ownerDocument.getElementsByTagName("iframe")].find((iframe)=>iframe.contentDocument?.contains(targetEl));} 3401__exports.reverseForRTL=reverseForRTL;function reverseForRTL(direction,variant="middle"){if(localization.direction==="rtl"){if(["left","right"].includes(direction)){direction=direction==="left"?"right":"left";}else if(["start","end"].includes(variant)){variant=variant==="start"?"end":"start";}} 3402return[direction,variant];} 3403function computePosition(popper,target,{container,extendedFlipping,flip,margin,position,shrink}){const[direction,variant="middle"]=reverseForRTL(...position.split("-"));let directions=[direction.at(0)];if(flip){directions=extendedFlipping?EXTENDED_DIRECTION_FLIP_ORDER[direction]:DIRECTION_FLIP_ORDER[direction];} 3404const variants=VARIANT_FLIP_ORDER[variant];if(!container){container=popper.ownerDocument.documentElement;}else if(typeof container==="function"){container=container();} 3405if(variant==="fit"){const styleProperty=["top","bottom"].includes(direction)?"width":"height";popper.style[styleProperty]=getComputedStyle(target)[styleProperty];} 3406const popperStyle=getComputedStyle(popper);const{marginTop,marginLeft,marginRight,marginBottom}=popperStyle;const popMargins={top:parseFloat(marginTop),left:parseFloat(marginLeft),right:parseFloat(marginRight),bottom:parseFloat(marginBottom),};const shouldAccountForIFrame=popper.ownerDocument!==target.ownerDocument;const iframe=shouldAccountForIFrame?getIFrame(popper,target):null;const popBox=popper.getBoundingClientRect();const targetBox=target.getBoundingClientRect();const contBox=container.getBoundingClientRect();const iframeBox=iframe?.getBoundingClientRect()??{top:0,left:0};const containerIsHTMLNode=container===container.ownerDocument.firstElementChild;const containerIsInIframe=shouldAccountForIFrame&&target.ownerDocument===container.ownerDocument;const directionsData={t:iframeBox.top+targetBox.top-popMargins.bottom-margin-popBox.height,b:iframeBox.top+targetBox.bottom+popMargins.top+margin,r:iframeBox.left+targetBox.right+popMargins.left+margin,l:iframeBox.left+targetBox.left-popMargins.right-margin-
3406popBox.width,c:iframeBox.top+targetBox.top+targetBox.height/2-popBox.height/2,};const variantsData={vf:iframeBox.left+targetBox.left,vs:iframeBox.left+targetBox.left+popMargins.left,vm:iframeBox.left+targetBox.left+targetBox.width/2-popBox.width/2,ve:iframeBox.left+targetBox.right-popMargins.right-popBox.width,hf:iframeBox.top+targetBox.top,hs:iframeBox.top+targetBox.top+popMargins.top,hm:iframeBox.top+targetBox.top+targetBox.height/2-popBox.height/2,he:iframeBox.top+targetBox.bottom-popMargins.bottom-popBox.height,};function getPositioningData(d,v){const[direction,variant]=reverseForRTL(DIRECTIONS[d],VARIANTS[v]);const result={direction,variant};const vertical=["t","b","c"].includes(d);const variantPrefix=vertical?"v":"h";const directionValue=directionsData[d];let variantValue=variantsData[variantPrefix+v];const[leftCompensation,topCompensation]=containerIsInIframe?[iframeBox.left,iframeBox.top]:[0,0];const[directionSize,variantSize]=vertical?[popBox.height,popBox.width]:[popBox.width,popBox.height];let[directionMin,directionMax]=vertical?[contBox.top+topCompensation,contBox.bottom+topCompensation]:[contBox.left+leftCompensation,contBox.right+leftCompensation];let[variantMin,variantMax]=vertical?[contBox.left+leftCompensation,contBox.right+leftCompensation]:[contBox.top+topCompensation,contBox.bottom+topCompensation];if(containerIsHTMLNode){if(vertical){directionMin+=container.scrollTop;directionMax+=container.scrollTop;}else{variantMin+=container.scrollTop;variantMax+=container.scrollTop;}} 3407let directionOverflow=0;if(Math.floor(directionValue)<Math.ceil(directionMin)){directionOverflow=Math.floor(directionValue)-Math.ceil(directionMin);}else if(Math.ceil(directionValue+directionSize)>Math.floor(directionMax)){directionOverflow=Math.ceil(directionValue+directionSize)-Math.floor(directionMax);} 3408let variantOverflow=0;if(Math.floor(variantValue)<Math.ceil(variantMin)){variantOverflow=Math.floor(variantValue)-Math.ceil(variantMin);}else if(Math.ceil(variantValue+variantSize)>Math.floor(variantMax)){variantOverflow=Math.ceil(variantValue+variantSize)-Math.floor(variantMax);} 3409let malus=Math.abs(directionOverflow)+(variantOverflow&&1);variantValue-=variantOverflow;result.variantOffset=-variantOverflow;const positioning=vertical?{top:directionValue,left:variantValue}:{top:variantValue,left:directionValue};result.top=positioning.top-popBox.top;result.left=positioning.left-popBox.left;if(d==="c"){malus=1.001;result.top-=directionOverflow;}else if(shrink&&malus){const minTop=Math.floor(!vertical&&v==="s"?targetBox.top:contBox.top);result.top=Math.max(minTop,result.top);let height;if(vertical){height=Math.abs(targetBox[direction]-(d==="t"?directionMin:directionMax));}else{height={s:variantMax-targetBox.top,m:variantMax-variantMin,e:targetBox.bottom-variantMin,}[v];} 3410result.maxHeight=Math.floor(height);} 3411return{result,malus};} 3412const matches=[];for(const d of directions){for(const v of variants){const match=getPositioningData(d,v);if(!match.malus){return match.result;} 3413matches.push(match);} 3414if(!flip){break;}} 3415return matches.sort((a,b)=>a.malus-b.malus)[0].result;} 3416__exports.reposition=reposition;function reposition(popper,target,options){popper.style.position="fixed";popper.style.top="0px";popper.style.left="0px";const solution=computePosition(popper,target,{...DEFAULTS,...options});const{top,left,maxHeight}=solution;popper.style.top=`${top}px`;popper.style.left=`${left}px`;if(maxHeight){const existingMaxHeight=getComputedStyle(popper).maxHeight;popper.style.maxHeight=existingMaxHeight!=="none"?`min(${existingMaxHeight}, ${maxHeight}px)`:`${maxHeight}px`;popper.style.overflowY="auto";} 3417return solution;} 3418return __exports;});; 3419 3420/* /web/static/src/core/pwa/install_prompt.js */ 3421odoo.define('@web/core/pwa/install_prompt',['@odoo/owl','@web/core/dialog/dialog','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{isIOS}=require("@web/core/browser/feature_detection");const InstallPrompt=__exports.InstallPrompt=class InstallPrompt extends Component{static props={close:true,onClose:{type:Function},};static components={Dialog,};static template="web.InstallPrompt";get isMobileSafari(){return isIOS();} 3422onClose(){this.props.close();this.props.onClose();}} 3423return __exports;});; 3424 3425/* /web/static/src/core/pwa/pwa_service.js */ 3426odoo.define('@web/core/pwa/pwa_service',['@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/network/http_service','@web/core/registry','@web/core/pwa/install_prompt'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isDisplayStandalone,isIOS,isMacOS,isBrowserSafari,}=require("@web/core/browser/feature_detection");const{get}=require("@web/core/network/http_service");const{registry}=require("@web/core/registry");const{InstallPrompt}=require("@web/core/pwa/install_prompt");const serviceRegistry=registry.category("services");let BEFOREINSTALLPROMPT_EVENT;let REGISTER_BEFOREINSTALLPROMPT_EVENT;browser.addEventListener("beforeinstallprompt",(ev)=>{if(REGISTER_BEFOREINSTALLPROMPT_EVENT){return REGISTER_BEFOREINSTALLPROMPT_EVENT(ev);}else{BEFOREINSTALLPROMPT_EVENT=ev;}});const pwaService={dependencies:["dialog"],start(env,{dialog}){let _manifest;let nativePrompt;const state=reactive({canPromptToInstall:false,isAvailable:false,isScopedApp:browser.location.href.includes("/scoped_app"),isSupportedOnBrowser:false,startUrl:"/odoo",decline,getManifest,hasScopeBeenInstalled,show,});function _getInstallationState(scope=state.startUrl){const installationState=browser.localStorage.getItem("pwaService.installationState");return installationState?JSON.parse(installationState)[scope]:"";} 3427function _setInstallationState(value){const ls=JSON.parse(browser.localStorage.getItem("pwaService.installationState")||"{}");ls[state.startUrl]=value;browser.localStorage.setItem("pwaService.installationState",JSON.stringify(ls));} 3428function _removeInstallationState(){const ls=JSON.parse(browser.localStorage.getItem("pwaService.installationState"));delete ls[state.startUrl];browser.localStorage.setItem("pwaService.installationState",JSON.stringify(ls));} 3429if(state.isScopedApp){if(browser.location.pathname==="/scoped_app"){state.startUrl="/"+new URL(browser.location.href).searchParams.get("path");}else{state.startUrl=browser.location.pathname;}} 3430state.isSupportedOnBrowser=browser.BeforeInstallPromptEvent!==undefined||(isBrowserSafari()&&!isDisplayStandalone()&&(isIOS()||(isMacOS()&&browser.navigator.userAgent.match(/Version\/(\d+)/)[1]>=17)));const installationState=_getInstallationState();if(state.isSupportedOnBrowser){if(BEFOREINSTALLPROMPT_EVENT){_handleBeforeInstallPrompt(BE
3430FOREINSTALLPROMPT_EVENT,installationState);BEFOREINSTALLPROMPT_EVENT=null;} 3431REGISTER_BEFOREINSTALLPROMPT_EVENT=(ev)=>{_handleBeforeInstallPrompt(ev,installationState);};if(isBrowserSafari()){state.canPromptToInstall=installationState!=="dismissed";state.isAvailable=true;}} 3432function _handleBeforeInstallPrompt(ev,installationState){nativePrompt=ev;if(installationState==="accepted"){if(!isDisplayStandalone()){_removeInstallationState();}} 3433state.canPromptToInstall=installationState!=="dismissed";state.isAvailable=true;} 3434async function getManifest(){if(!_manifest){const manifest=await get(document.querySelector("link[rel=manifest]")?.getAttribute("href"),"text");_manifest=JSON.parse(manifest);} 3435return _manifest;} 3436function hasScopeBeenInstalled(scope){return _getInstallationState(scope)==="accepted";} 3437async function show({onDone}={}){if(!state.isAvailable){return;} 3438if(nativePrompt){const res=await nativePrompt.prompt();_setInstallationState(res.outcome);state.canPromptToInstall=false;if(onDone){onDone(res);}}else if(isBrowserSafari()){dialog.add(InstallPrompt,{onClose:()=>{if(onDone){onDone({});} 3439this.decline();},});}} 3440function decline(){_setInstallationState("dismissed");state.canPromptToInstall=false;} 3441return state;},};serviceRegistry.add("pwa",pwaService);return __exports;});; 3442 3443/* /web/static/src/core/py_js/py.js */ 3444odoo.define('@web/core/py_js/py',['@web/core/py_js/py_interpreter','@web/core/py_js/py_parser','@web/core/py_js/py_tokenizer','@web/core/py_js/py_utils'],function(require){'use strict';let __exports={};const{evaluate}=require("@web/core/py_js/py_interpreter");const{parse}=require("@web/core/py_js/py_parser");const{tokenize}=require("@web/core/py_js/py_tokenizer");{const{evaluate}=require("@web/core/py_js/py_interpreter");Object.assign(__exports,{evaluate})};{const{parse}=require("@web/core/py_js/py_parser");Object.assign(__exports,{parse})};{const{tokenize}=require("@web/core/py_js/py_tokenizer");Object.assign(__exports,{tokenize})};{const{formatAST}=require("@web/core/py_js/py_utils");Object.assign(__exports,{formatAST})};__exports.parseExpr=parseExpr;function parseExpr(expr){const tokens=tokenize(expr);return parse(tokens);} 3445__exports.evaluateExpr=evaluateExpr;function evaluateExpr(expr,context={}){let ast;try{ast=parseExpr(expr);}catch(error){throw new EvalError(`Can not parse python expression: (${expr})\nError: ${error.message}`);} 3446try{return evaluate(ast,context);}catch(error){throw new EvalError(`Can not evaluate python expression: (${expr})\nError: ${error.message}`);}} 3447__exports.evaluateBooleanExpr=evaluateBooleanExpr;function evaluateBooleanExpr(expr,context={}){if(!expr||expr==='False'||expr==='0'){return false;} 3448if(expr==='True'||expr==='1'){return true;} 3449return evaluateExpr(`bool(${expr})`,context);} 3450return __exports;});; 3451 3452/* /web/static/src/core/py_js/py_builtin.js */ 3453odoo.define('@web/core/py_js/py_builtin',['@web/core/py_js/py_date'],function(require){'use strict';let __exports={};const{PyDate,PyDateTime,PyRelativeDelta,PyTime,PyTimeDelta}=require("@web/core/py_js/py_date");const EvaluationError=__exports.EvaluationError=class EvaluationError extends Error{} 3454__exports.execOnIterable=execOnIterable;function execOnIterable(iterable,func){if(iterable===null){throw new EvaluationError(`value not iterable`);} 3455if(typeof iterable==="object"&&!Array.isArray(iterable)&&!(iterable instanceof Set)){iterable=Object.keys(iterable);} 3456if(typeof iterable?.[Symbol.iterator]!=="function"){throw new EvaluationError(`value not iterable`);} 3457return func(iterable);} 3458const BUILTINS=__exports.BUILTINS={bool(value){switch(typeof value){case"number":return value!==0;case"string":return value!=="";case"boolean":return value;case"object":if(value===null||value===undefined){return false;} 3459if(value.isTrue){return value.isTrue();} 3460if(value instanceof Array){return!!value.length;} 3461if(value instanceof Set){return!!value.size;} 3462return Object.keys(value).length!==0;} 3463return true;},set(iterable){if(arguments.length>2){throw new EvaluationError(`set expected at most 1 argument, got (${arguments.length - 1}`);} 3464return execOnIterable(iterable,(iterable)=>{return new Set(iterable);});},max(...args){return Math.max(...args.slice(0,-1));},min(...args){return Math.min(...args.slice(0,-1));},time:{strftime(format){return PyDateTime.now().strftime(format);},},context_today(){return PyDate.today();},get current_date(){return this.today;},get today(){return PyDate.today().strftime("%Y-%m-%d");},get now(){return PyDateTime.now().strftime("%Y-%m-%d %H:%M:%S");},datetime:{time:PyTime,timedelta:PyTimeDelta,datetime:PyDateTime,date:PyDate,}
3464,relativedelta:PyRelativeDelta,true:true,false:false,};return __exports;});; 3465 3466/* /web/static/src/core/py_js/py_date.js */ 3467odoo.define('@web/core/py_js/py_date',['@web/core/py_js/py_parser'],function(require){'use strict';let __exports={};const{parseArgs}=require("@web/core/py_js/py_parser");const AssertionError=__exports.AssertionError=class AssertionError extends Error{} 3468const ValueError=__exports.ValueError=class ValueError extends Error{} 3469const NotSupportedError=__exports.NotSupportedError=class NotSupportedError extends Error{} 3470function fmt2(n){return String(n).padStart(2,"0");} 3471function fmt4(n){return String(n).padStart(4,"0");} 3472function divmod(a,b,fn){let mod=a%b;if((mod>0&&b<0)||(mod<0&&b>0)){mod+=b;} 3473return fn(Math.floor(a/b),mod);} 3474function assert(bool,message="AssertionError"){if(!bool){throw new AssertionError(message);}} 3475const DAYS_IN_MONTH=[null,31,28,31,30,31,30,31,31,30,31,30,31];const DAYS_BEFORE_MONTH=[null];for(let dbm=0,i=1;i<DAYS_IN_MONTH.length;++i){DAYS_BEFORE_MONTH.push(dbm);dbm+=DAYS_IN_MONTH[i];} 3476function daysInMonth(year,month){if(month===2&&isLeap(year)){return 29;} 3477return DAYS_IN_MONTH[month];} 3478function isLeap(year){return year%4===0&&(year%100!==0||year%400===0);} 3479function daysBeforeYear(year){const y=year-1;return y*365+Math.floor(y/4)-Math.floor(y/100)+Math.floor(y/400);} 3480function daysBeforeMonth(year,month){const postLeapFeb=month>2&&isLeap(year);return DAYS_BEFORE_MONTH[month]+(postLeapFeb?1:0);} 3481function ymd2ord(year,month,day){const dim=daysInMonth(year,month);if(!(1<=day&&day<=dim)){throw new ValueError(`day must be in 1..${dim}`);} 3482return daysBeforeYear(year)+daysBeforeMonth(year,month)+day;} 3483const DI400Y=daysBeforeYear(401);const DI100Y=daysBeforeYear(101);const DI4Y=daysBeforeYear(5);function ord2ymd(n){--n;let n400,n100,n4,n1,n0;divmod(n,DI400Y,function(_n400,n){n400=_n400;divmod(n,DI100Y,function(_n100,n){n100=_n100;divmod(n,DI4Y,function(_n4,n){n4=_n4;divmod(n,365,function(_n1,n){n1=_n1;n0=n;});});});});n=n0;const year=n400*400+1+n100*100+n4*4+n1;if(n1==4||n100==100){assert(n0===0);return{year:year-1,month:12,day:31,};} 3484const leapyear=n1===3&&(n4!==24||n100==3);assert(leapyear==isLeap(year));let month=(n+50)>>5;let preceding=DAYS_BEFORE_MONTH[month]+(month>2&&leapyear?1:0);if(preceding>n){--month;preceding-=DAYS_IN_MONTH[month]+(month===2&&leapyear?1:0);} 3485n-=preceding;return{year:year,month:month,day:n+1,};} 3486function tmxxx(year,month,day,hour,minute,second,microsecond){hour=hour||0;minute=minute||0;second=second||0;microsecond=microsecond||0;if(microsecond<0||microsecond>999999){divmod(microsecond,1000000,function(carry,ms){microsecond=ms;second+=carry;});} 3487if(second<0||second>59){divmod(second,60,function(carry,s){second=s;minute+=carry;});} 3488if(minute<0||minute>59){divmod(minute,60,function(carry,m){minute=m;hour+=carry;});} 3489if(hour<0||hour>23){divmod(hour,24,function(carry,h){hour=h;day+=carry;});} 3490if(month<1||month>12){divmod(month-1,12,function(carry,m){month=m+1;year+=carry;});} 3491const dim=daysInMonth(year,month);if(day<1||day>dim){if(day===0){--month;if(month>0){day=daysInMonth(year,month);}else{--year;month=12;day=31;}}else if(day==dim+1){++month;day=1;if(month>12){month=1;++year;}}else{const r=ord2ymd(ymd2ord(year,month,1)+(day-1));year=r.year;month=r.month;day=r.day;}} 3492return{year:year,month:month,day:day,hour:hour,minute:minute,second:second,microsecond:microsecond,};} 3493const PyDate=__exports.PyDate=class PyDate{static today(){return this.convertDate(new Date());} 3494static convertDate(date){const year=date.getFullYear();const month=date.getMonth()+1;const day=date.getDate();return new PyDate(year,month,day);} 3495constructor(year,month,day){this.year=year;this.month=month;this.day=day;} 3496static create(...args){const{year,month,day}=parseArgs(args,["year","month","day"]);return new PyDate(year,month,day);} 3497add(timedelta){const s=tmxxx(this.year,this.month,this.day+timedelta.days);return new PyDate(s.year,s.month,s.day);} 3498isEqual(other){if(!(other instanceof PyDate)){return false;} 3499return this.year===other.year&&this.month===other.month&&this.day===other.day;} 3500strftime(format){return format.replace(/%([A-Za-z])/g,(m,c)=>{switch(c){case"Y":return fmt4(this.year);case"m":return fmt2(this.month);case"d":return fmt2(this.day);} 3501throw new ValueError(`No known conversion for ${m}`);});} 3502substract(other){if(other instanceof PyTimeDelta){return this.add(other.negate());}
3503if(other instanceof PyDate){return PyTimeDelta.create(this.toordinal()-other.toordinal());} 3504throw new NotSupportedError();} 3505toJSON(){return this.strftime("%Y-%m-%d");} 3506toordinal(){return ymd2ord(this.year,this.month,this.day);}} 3507const PyDateTime=__exports.PyDateTime=class PyDateTime{static now(){return this.convertDate(new Date());} 3508static convertDate(date){const year=date.getUTCFullYear();const month=date.getUTCMonth()+1;const day=date.getUTCDate();const hour=date.getUTCHours();const minute=date.getUTCMinutes();const second=date.getUTCSeconds();return new PyDateTime(year,month,day,hour,minute,second,0);} 3509static create(...args){const namedArgs=parseArgs(args,["year","month","day","hour","minute","second","microsecond",]);const year=namedArgs.year;const month=namedArgs.month;const day=namedArgs.day;const hour=namedArgs.hour||0;const minute=namedArgs.minute||0;const second=namedArgs.second||0;const ms=namedArgs.micro/1000||0;return new PyDateTime(year,month,day,hour,minute,second,ms);} 3510static combine(...args){const{date,time}=parseArgs(args,["date","time"]);return PyDateTime.create(date.year,date.month,date.day,time.hour,time.minute,time.second);} 3511constructor(year,month,day,hour,minute,second,microsecond){this.year=year;this.month=month;this.day=day;this.hour=hour;this.minute=minute;this.second=second;this.microsecond=microsecond;} 3512add(timedelta){const s=tmxxx(this.year,this.month,this.day+timedelta.days,this.hour,this.minute,this.second+timedelta.seconds,this.microsecond+timedelta.microseconds);return new PyDateTime(s.year,s.month,s.day,s.hour,s.minute,s.second,s.microsecond);} 3513isEqual(other){if(!(other instanceof PyDateTime)){return false;} 3514return(this.year===other.year&&this.month===other.month&&this.day===other.day&&this.hour===other.hour&&this.minute===other.minute&&this.second===other.second&&this.microsecond===other.microsecond);} 3515strftime(format){return format.replace(/%([A-Za-z])/g,(m,c)=>{switch(c){case"Y":return fmt4(this.year);case"m":return fmt2(this.month);case"d":return fmt2(this.day);case"H":return fmt2(this.hour);case"M":return fmt2(this.minute);case"S":return fmt2(this.second);} 3516throw new ValueError(`No known conversion for ${m}`);});} 3517substract(timedelta){return this.add(timedelta.negate());} 3518toJSON(){return this.strftime("%Y-%m-%d %H:%M:%S");} 3519to_utc(){const d=new Date(this.year,this.month-1,this.day,this.hour,this.minute,this.second);const timedelta=PyTimeDelta.create({minutes:d.getTimezoneOffset()});return this.add(timedelta);}} 3520const PyTime=__exports.PyTime=class PyTime extends PyDate{static create(...args){const namedArgs=parseArgs(args,["hour","minute","second"]);const hour=namedArgs.hour||0;const minute=namedArgs.minute||0;const second=namedArgs.second||0;return new PyTime(hour,minute,second);} 3521constructor(hour,minute,second){const now=new Date();const year=now.getUTCFullYear();const month=now.getUTCMonth();const day=now.getUTCDate();super(year,month,day);this.hour=hour;this.minute=minute;this.second=second;} 3522strftime(format){return format.replace(/%([A-Za-z])/g,(m,c)=>{switch(c){case"Y":return fmt4(this.year);case"m":return fmt2(this.month+1);case"d":return fmt2(this.day);case"H":return fmt2(this.hour);case"M":return fmt2(this.minute);case"S":return fmt2(this.second);} 3523throw new ValueError(`No known conversion for ${m}`);});} 3524toJSON(){return this.strftime("%H:%M:%S");}} 3525const DAYS_IN_YEAR=[31,59,90,120,151,181,212,243,273,304,334,366];const TIME_PERIODS=["hour","minute","second"];const PERIODS=["year","month","day",...TIME_PERIODS];const RELATIVE_KEYS="years months weeks days hours minutes seconds microseconds leapdays".split(" ");const ABSOLUTE_KEYS="year month day hour minute second microsecond weekday nlyearday yearday".split(" ");const argsSpec=["dt1","dt2"];const PyRelativeDelta=__exports.PyRelativeDelta=class PyRelativeDelta{static create(...args){const params=parseArgs(args,argsSpec);if("dt1"in params){throw new Error("relativedelta(dt1, dt2) is not supported for now");} 3526for(const period of PERIODS){if(period in params){const val=params[period];assert(val>=0,`${period} ${val} is out of range`);}} 3527for(const key of RELATIVE_KEYS){params[key]=params[key]||0;} 3528for(const key of ABSOLUTE_KEYS){params[key]=key in params?params[key]:null;} 3529params.days+=7*params.weeks;let yearDay=0;if(params.nlyearday){yearDay=params.nlyearday;}else if(params.yearday){yearDay=params.yearday;if(yearDay>59){params.leapDays=-1;}} 3530if(yearDay){for(let monthIndex=0;monthIndex<DAYS_IN_YEAR.length;monthIndex++){if(yearDay<=DAYS_IN_YEAR[monthIndex]){params.month=monthIndex+1;if(monthIndex===0){params.day=yearDay;}else{params.day=yearDay-DAYS_IN_YEAR[monthIndex-1];} 3531break;}}} 3532return new PyRelativeDelta(params);} 3533static add(date,delta){if(!(date instanceof PyDate||date instanceof PyDateTime)){throw new NotSupportedError();} 3534const s=tmxxx((delta.year||date.year)+delta.years,(delta.month||date.month)+delta.months,delta.day||date.day,delta.hour||date.hour||0,delta.minute||date.minute||0,delta.second||date.seconds||0,delta.microseconds||date.microseconds||0);const newDateTime=new PyDateTime(s.year,s.month,s.day,s.hour,s.minute,s.second,s.microsecond);let leapDays=0;if(delta.leapDays&&newDateTime.month>2&&isLeap(newDateTime.year)){leapDays=delta.leapDays;}
3535const temp=newDateTime.add(PyTimeDelta.create({days:delta.days+leapDays,hours:delta.hours,minutes:delta.minutes,seconds:delta.seconds,microseconds:delta.microseconds,}));const hasTime=Boolean(temp.hour||temp.minute||temp.second||temp.microsecond);const returnDate=!hasTime&&date instanceof PyDate?new PyDate(temp.year,temp.month,temp.day):temp;if(delta.weekday!==null){const wantedDow=delta.weekday+1;const _date=new Date(returnDate.year,returnDate.month-1,returnDate.day);const days=(7-_date.getDay()+wantedDow)%7;return returnDate.add(new PyTimeDelta(days,0,0));} 3536return returnDate;} 3537static substract(date,delta){return PyRelativeDelta.add(date,delta.negate());} 3538constructor(params={},sign=+1){this.years=sign*params.years;this.months=sign*params.months;this.days=sign*params.days;this.hours=sign*params.hours;this.minutes=sign*params.minutes;this.seconds=sign*params.seconds;this.microseconds=sign*params.microseconds;this.leapDays=params.leapDays;this.year=params.year;this.month=params.month;this.day=params.day;this.hour=params.hour;this.minute=params.minute;this.second=params.second;this.microsecond=params.microsecond;this.weekday=params.weekday;} 3539negate(){return new PyRelativeDelta(this,-1);} 3540isEqual(other){throw new NotSupportedError();}} 3541const TIME_DELTA_KEYS="weeks days hours minutes seconds milliseconds microseconds".split(" ");function modf(x){const mod=x%1;return[mod<0?mod+1:mod,Math.floor(x)];} 3542const PyTimeDelta=__exports.PyTimeDelta=class PyTimeDelta{static create(...args){const namedArgs=parseArgs(args,["days","seconds","microseconds"]);for(const key of TIME_DELTA_KEYS){namedArgs[key]=namedArgs[key]||0;} 3543let d=0;let s=0;let us=0;const days=namedArgs.days+namedArgs.weeks*7;let seconds=namedArgs.seconds+60*namedArgs.minutes+3600*namedArgs.hours;let microseconds=namedArgs.microseconds+1000*namedArgs.milliseconds;const[dFrac,dInt]=modf(days);d=dInt;let daysecondsfrac=0;if(dFrac){const[dsFrac,dsInt]=modf(dFrac*24*3600);s=dsInt;daysecondsfrac=dsFrac;} 3544const[sFrac,sInt]=modf(seconds);seconds=sInt;const secondsfrac=sFrac+daysecondsfrac;divmod(seconds,24*3600,(days,seconds)=>{d+=days;s+=seconds;});microseconds+=secondsfrac*1e6;divmod(microseconds,1000000,(seconds,microseconds)=>{divmod(seconds,24*3600,(days,seconds)=>{d+=days;s+=seconds;us+=Math.round(microseconds);});});return new PyTimeDelta(d,s,us);} 3545constructor(days,seconds,microseconds){this.days=days;this.seconds=seconds;this.microseconds=microseconds;}
3546add(other){return PyTimeDelta.create({days:this.days+other.days,seconds:this.seconds+other.seconds,microseconds:this.microseconds+other.microseconds,});} 3547divide(n){const us=(this.days*24*3600+this.seconds)*1e6+this.microseconds;return PyTimeDelta.create({microseconds:Math.floor(us/n)});} 3548isEqual(other){if(!(other instanceof PyTimeDelta)){return false;} 3549return(this.days===other.days&&this.seconds===other.seconds&&this.microseconds===other.microseconds);} 3550isTrue(){return this.days!==0||this.seconds!==0||this.microseconds!==0;} 3551multiply(n){return PyTimeDelta.create({days:n*this.days,seconds:n*this.seconds,microseconds:n*this.microseconds,});} 3552negate(){return PyTimeDelta.create({days:-this.days,seconds:-this.seconds,microseconds:-this.microseconds,});} 3553substract(other){return PyTimeDelta.create({days:this.days-other.days,seconds:this.seconds-other.seconds,microseconds:this.microseconds-other.microseconds,});} 3554total_seconds(){return this.days*86400+this.seconds+this.microseconds/1000000;}} 3555return __exports;});; 3556 3557/* /web/static/src/core/py_js/py_interpreter.js */ 3558odoo.define('@web/core/py_js/py_interpreter',['@web/core/py_js/py_builtin','@web/core/py_js/py_date','@web/core/py_js/py_utils','@web/core/py_js/py_parser'],function(require){'use strict';let __exports={};const{BUILTINS,EvaluationError,execOnIterable}=require("@web/core/py_js/py_builtin");const{NotSupportedError,PyDate,PyDateTime,PyRelativeDelta,PyTime,PyTimeDelta,}=require("@web/core/py_js/py_date");const{PY_DICT,toPyDict}=require("@web/core/py_js/py_utils");const{parseArgs}=require("@web/core/py_js/py_parser");const isTrue=BUILTINS.bool;function applyUnaryOp(ast,context){const value=evaluate(ast.right,context);switch(ast.op){case"-":if(value instanceof Object&&value.negate){return value.negate();} 3559return-value;case"+":return value;case"not":return!isTrue(value);} 3560throw new EvaluationError(`Unknown unary operator: ${ast.op}`);} 3561function pytypeIndex(val){switch(typeof val){case"object":return val===null?1:Array.isArray(val)?5:3;case"number":return 2;case"string":return 4;} 3562throw new EvaluationError(`Unknown type: ${typeof val}`);} 3563function isConstructor(obj){return!!obj.prototype&&!!obj.prototype.constructor.name;} 3564function isLess(left,right){if(typeof left==="number"&&typeof right==="number"){return left<right;} 3565if(typeof left==="boolean"){left=left?1:0;} 3566if(typeof right==="boolean"){right=right?1:0;} 3567const leftIndex=pytypeIndex(left);const rightIndex=pytypeIndex(right);if(leftIndex===rightIndex){return left<right;} 3568return leftIndex<rightIndex;} 3569function isEqual(left,right){if(typeof left!==typeof right){if(typeof left==="boolean"&&typeof right==="number"){return right===(left?1:0);} 3570if(typeof left==="number"&&typeof right==="boolean"){return left===(right?1:0);} 3571return false;} 3572if(left instanceof Object&&left.isEqual){return left.isEqual(right);} 3573return left===right;} 3574function isIn(left,right){if(Array.isArray(right)){return right.includes(left);} 3575if(typeof right==="string"&&typeof left==="string"){return right.includes(left);} 3576if(typeof right==="object"){return left in right;} 3577return false;} 3578function applyBinaryOp(ast,context){const left=evaluate(ast.left,context);const right=evaluate(ast.right,context);switch(ast.op){case"+":{const relativeDeltaOnLeft=left instanceof PyRelativeDelta;const relativeDeltaOnRight=right instanceof PyRelativeDelta;if(relativeDeltaOnLeft||relativeDeltaOnRight){const date=relativeDeltaOnLeft?right:left;const delta=relativeDeltaOnLeft?left:right;return PyRelativeDelta.add(date,delta);} 3579const timeDeltaOnLeft=left instanceof PyTimeDelta;const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnLeft&&timeDeltaOnRight){return left.add(right);} 3580if(timeDeltaOnLeft){if(right instanceof PyDate||right instanceof PyDateTime){return right.add(left);}else{throw new NotSupportedError();}} 3581if(timeDeltaOnRight){if(left instanceof PyDate||left instanceof PyDateTime){return left.add(right);}else{throw new NotSupportedError();}} 3582if(left instanceof Array&&right instanceof Array){return[...left,...right];} 3583return left+right;} 3584case"-":{const isRightDelta=right instanceof PyRelativeDelta;if(isRightDelta){return PyRelativeDelta.substract(left,right);} 3585const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnRight){if(left instanceof PyTimeDelta){return left.substract(right);}else if(left instanceof PyDate||left instanceof PyDateTime){return left.substract(right);}else{throw new NotSupportedError();}} 3586if(left instanceof PyDate){return left.substract(right);} 3587return left-right;} 3588case"*":{const timeDeltaOnLeft=left instanceof PyTimeDelta;const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnLeft||timeDeltaOnRight){const number=timeDeltaOnLeft?right:left;const delta=timeDeltaOnLeft?left:right;return delta.multiply(number);} 3589return left*right;} 3590case"/":return left/right;case"%":return left%right;
3590case"//":if(left instanceof PyTimeDelta){return left.divide(right);} 3591return Math.floor(left/right);case"**":return left**right;case"==":return isEqual(left,right);case"<>":case"!=":return!isEqual(left,right);case"<":return isLess(left,right);case">":return isLess(right,left);case">=":return isEqual(left,right)||isLess(right,left);case"<=":return isEqual(left,right)||isLess(left,right);case"in":return isIn(left,right);case"not in":return!isIn(left,right);} 3592throw new EvaluationError(`Unknown binary operator: ${ast.op}`);} 3593const DICT={get(...args){const{key,defValue}=parseArgs(args,["key","defValue"]);if(key in this){return this[key];}else if(defValue){return defValue;} 3594return null;},};const STRING={lower(){return this.toLowerCase();},upper(){return this.toUpperCase();},};function applyFunc(key,func,set,...args){if(args.length===1){return new Set(set);} 3595if(args.length>2){throw new EvaluationError(`${key}: py_js supports at most 1 argument, got (${args.length - 1})`);} 3596return execOnIterable(args[0],func);} 3597const SET={intersection(...args){return applyFunc("intersection",(iterable)=>{const intersection=new Set();for(const i of iterable){if(this.has(i)){intersection.add(i);}} 3598return intersection;},this,...args);},difference(...args){return applyFunc("difference",(iterable)=>{iterable=new Set(iterable);const difference=new Set();for(const e of this){if(!iterable.has(e)){difference.add(e);}} 3599return difference;},this,...args);},union(...args){return applyFunc("union",(iterable)=>new Set([...this,...iterable]),this,...args);},};function methods(_class){return Object.getOwnPropertyNames(_class.prototype).map((prop)=>_class.prototype[prop]);} 3600const allowedFns=new Set([BUILTINS.time.strftime,BUILTINS.set,BUILTINS.bool,BUILTINS.min,BUILTINS.max,BUILTINS.context_today,BUILTINS.datetime.datetime.now,BUILTINS.datetime.datetime.combine,BUILTINS.datetime.date.today,...methods(BUILTINS.relativedelta),...Object.values(BUILTINS.datetime).flatMap((obj)=>methods(obj)),...Object.values(SET),...Object.values(DICT),...Object.values(STRING),]);const unboundFn=Symbol("unbound function");__exports.evaluate=evaluate;function evaluate(ast,context={}){const dicts=new Set();let pyContext;const evalContext=Object.create(context);if(!evalContext.context){Object.defineProperty(evalContext,"context",{get(){if
3600(!pyContext){pyContext=toPyDict(context);} 3601return pyContext;},});} 3602function _innerEvaluate(ast){switch(ast.type){case 0:case 1:return ast.value;case 5:if(ast.value in evalContext){return evalContext[ast.value];}else if(ast.value in BUILTINS){return BUILTINS[ast.value];}else{throw new EvaluationError(`Name '${ast.value}' is not defined`);} 3603case 3:return null;case 2:return ast.value;case 6:return applyUnaryOp(ast,evalContext);case 7:return applyBinaryOp(ast,evalContext);case 14:{const left=_evaluate(ast.left);if(ast.op==="and"){return isTrue(left)?_evaluate(ast.right):left;}else{return isTrue(left)?left:_evaluate(ast.right);}} 3604case 4:case 10:return ast.value.map(_evaluate);case 11:{const dict={};for(const key in ast.value){dict[key]=_evaluate(ast.value[key]);} 3605dicts.add(dict);return dict;} 3606case 8:{const fnValue=_evaluate(ast.fn);const args=ast.args.map(_evaluate);const kwargs={};for(const kwarg in ast.kwargs){kwargs[kwarg]=_evaluate(ast.kwargs[kwarg]);} 3607if(fnValue===PyDate||fnValue===PyDateTime||fnValue===PyTime||fnValue===PyRelativeDelta||fnValue===PyTimeDelta){return fnValue.create(...args,kwargs);} 3608return fnValue(...args,kwargs);} 3609case 12:{const dict=_evaluate(ast.target);const key=_evaluate(ast.key);return dict[key];} 3610case 13:{if(isTrue(_evaluate(ast.condition))){return _evaluate(ast.ifTrue);}else{return _evaluate(ast.ifFalse);}} 3611case 15:{let left=_evaluate(ast.obj);let result;if(dicts.has(left)||Object.isPrototypeOf.call(PY_DICT,left)){result=DICT[ast.key];}else if(typeof left==="string"){result=STRING[ast.key];}else if(left instanceof Set){result=SET[ast.key];}else if(ast.key=="get"&&typeof left==="object"){result=DICT[ast.key];left=toPyDict(left);}else{result=left[ast.key];} 3612if(typeof result==="function"){if(!isConstructor(result)){const bound=result.bind(left);bound[unboundFn]=result;return bound;}} 3613return result;}} 3614throw new EvaluationError(`AST of type ${ast.type} cannot be evaluated`);} 3615function _evaluate(ast){const val=_innerEvaluate(ast);if(typeof val==="function"&&!allowedFns.has(val)&&!allowedFns.has(val[unboundFn])){throw new Error("Invalid Function Call");} 3616return val;} 3617return _evaluate(ast);} 3618return __exports;});; 3619 3620/* /web/static/src/core/py_js/py_parser.js */ 3621odoo.define('@web/core/py_js/py_parser',['@web/core/py_js/py_tokenizer'],function(require){'use strict';let __exports={};const{binaryOperators,comparators}=require("@web/core/py_js/py_tokenizer");const ParserError=__exports.ParserError=class ParserError extends Error{} 3622const chainedOperators=new Set(comparators);const infixOperators=new Set(binaryOperators.concat(comparators));__exports.bp=bp;function bp(symbol){switch(symbol){case"=":return 10;case"if":return 20;case"in":case"not in":case"is":case"is not":case"<":case"<=":case">":case">=":case"<>":case"==":case"!=":return 60;case"or":return 30;case"and":return 40;case"not":return 50;case"|":return 70;case"^":return 80;case"&":return 90;case"<<":case">>":return 100;case"+":case"-":return 110;case"*":case"/":case"//":case"%":return 120;case"**":return 140;case".":case"(":case"[":return 150;} 3623return 0;} 3624function bindingPower(token){return token.type===2?bp(token.value):0;} 3625function isSymbol(token,value){return token.type===2&&token.value===value;} 3626function parsePrefix(current,tokens){switch(current.type){case 0:return{type:0,value:current.value};case 1:return{type:1,value:current.value};case 4:if(current.value==="None"){return{type:3};}else{return{type:2,value:current.value==="True"};} 3627case 3:return{type:5,value:current.value};case 2:switch(current.value){case"-":case"+":case"~":return{type:6,op:current.value,right:_parse(tokens,130),};case"not":return{type:6,op:current.value,right:_parse(tokens,50),};case"(":{const content=[];let isTuple=false;while(tokens[0]&&!isSymbol(tokens[0],")")){content.push(_parse(tokens,0));if(tokens[0]){if(tokens[0]&&isSymbol(tokens[0],",")){isTuple=true;tokens.shift();}else if(!isSymbol(tokens[0],")")){throw new ParserError("parsing error");}}else{throw new ParserError("parsing error");}} 3628if(!tokens[0]||!isSymbol(tokens[0],")")){throw new ParserError("parsing error");} 3629tokens.shift();isTuple=isTuple||content.length===0;return isTuple?{type:10,value:content}:content[0];} 3630case"[":{const value=[];while(tokens[0]&&!isSymbol(tokens[0],"]")){value.push(_parse(tokens,0));if(tokens[0]){if(isSymbol(tokens[0],",")){tokens.shift();}else if(!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");}}} 3631if(!tokens[0]||!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");} 3632tokens.shift();return{type:4,value};} 3633case"{":{const dict={};while(tokens[0]&&!isSymbol(tokens[0],"}")){const key=_parse(tokens,0);if((key.type!==1&&key.type!==0)||!tokens[0]||!isSymbol(tokens[0],":")){throw new ParserError("parsing error");} 3634tokens.shift();const value=_parse(tokens,0);dict[key.value]=value;if(isSymbol(tokens[0],",")){tokens.shift();}} 3635if(!tokens.shift()){throw new ParserError("parsing error");} 3636return{type:11,value:dict};}}} 3637throw new ParserError("Token cannot be parsed");} 3638function parseInfix(left,current,tokens){switch(current.type){case 2:if(infixOperators.has(current.value)){let right=_parse(tokens,bindingPower(current));if(current.value==="and"||current.value==="or"){return{type:14,op:current.value,left,right,};}else if(current.value==="."){if(right.type===5){return{type:15,obj:left,key:right.value,};}else{throw new ParserError("invalid obj lookup");}} 3639let op={type:7,op:current.value,left,right,};
3639while(chainedOperators.has(current.value)&&tokens[0]&&tokens[0].type===2&&chainedOperators.has(tokens[0].value)){const nextToken=tokens.shift();op={type:14,op:"and",left:op,right:{type:7,op:nextToken.value,left:right,right:_parse(tokens,bindingPower(nextToken)),},};right=op.right.right;} 3640return op;} 3641switch(current.value){case"(":{const args=[];const kwargs={};while(tokens[0]&&!isSymbol(tokens[0],")")){const arg=_parse(tokens,0);if(arg.type===9){kwargs[arg.name.value]=arg.value;}else{args.push(arg);} 3642if(tokens[0]&&isSymbol(tokens[0],",")){tokens.shift();}} 3643if(!tokens[0]||!isSymbol(tokens[0],")")){throw new ParserError("parsing error");} 3644tokens.shift();return{type:8,fn:left,args,kwargs};} 3645case"=":if(left.type===5){return{type:9,name:left,value:_parse(tokens,10),};} 3646break;case"[":{const key=_parse(tokens);if(!tokens[0]||!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");} 3647tokens.shift();return{type:12,target:left,key:key,};} 3648case"if":{const condition=_parse(tokens);if(!tokens[0]||!isSymbol(tokens[0],"else")){throw new ParserError("parsing error");} 3649tokens.shift();const ifFalse=_parse(tokens);return{type:13,condition,ifTrue:left,ifFalse,};}}} 3650throw new ParserError("Token cannot be parsed");} 3651function _parse(tokens,bp=0){const token=tokens.shift();let expr=parsePrefix(token,tokens);while(tokens[0]&&bindingPower(tokens[0])>bp){expr=parseInfix(expr,tokens.shift(),tokens);} 3652return expr;} 3653__exports.parse=parse;function parse(tokens){if(tokens.length){const ast=_parse(tokens,0);if(tokens.length){throw new ParserError("Token(s) unused");} 3654return ast;} 3655throw new ParserError("Missing token");} 3656__exports.parseArgs=parseArgs;function parseArgs(args,spec){const last=args[args.length-1];const unnamedArgs=typeof last==="object"?args.slice(0,-1):args;const kwargs=typeof last==="object"?last:{};for(const[index,val]of unnamedArgs.entries()){kwargs[spec[index]]=val;} 3657return kwargs;} 3658return __exports;});; 3659 3660/* /web/static/src/core/py_js/py_tokenizer.js */ 3661odoo.define('@web/core/py_js/py_tokenizer',[],function(require){'use strict';let __exports={};const TokenizerError=__exports.TokenizerError=class TokenizerError extends Error{} 3662const directMap={"\\":"\\",'"':'"',"'":"'",a:"\x07",b:"\x08",f:"\x0c",n:"\n",r:"\r",t:"\t",v:"\v",};function decodeStringLiteral(str,unicode){const out=[];let code;for(var i=0;i<str.length;++i){if(str[i]!=="\\"){out.push(str[i]);continue;} 3663var escape=str[i+1];if(escape in directMap){out.push(directMap[escape]);++i;continue;} 3664switch(escape){case"\n":++i;continue;case"N":if(!unicode){break;} 3665throw new TokenizerError("SyntaxError: \\N{} escape not implemented");case"u":if(!unicode){break;} 3666var uni=str.slice(i+2,i+6);if(!/[0-9a-f]{4}/i.test(uni)){throw new TokenizerError(["SyntaxError: (unicode error) 'unicodeescape' codec"," can't decode bytes in position ",i,"-",i+4,": truncated \\uXXXX escape",].join(""));} 3667code=parseInt(uni,16);out.push(String.fromCharCode(code));i+=5;continue;case"U":if(!unicode){break;} 3668throw new TokenizerError("SyntaxError: \\U escape not implemented");case"x":var hex=str.slice(i+2,i+4);if(!/[0-9a-f]{2}/i.test(hex)){if(!unicode){throw new TokenizerError("ValueError: invalid \\x escape");} 3669throw new TokenizerError(["SyntaxError: (unicode error) 'unicodeescape'"," codec can't decode bytes in position ",i,"-",i+2,": truncated \\xXX escape",].join(""));} 3670code=parseInt(hex,16);out.push(String.fromCharCode(code));i+=3;continue;default:if(!/[0-8]/.test(escape)){break;} 3671var r=/[0-8]{1,3}/g;r.lastIndex=i+1;var m=r.exec(str);var oct=m[0];code=parseInt(oct,8);out.push(String.fromCharCode(code));i+=oct.length;continue;} 3672out.push("\\");} 3673return out.join("");} 3674const constants=new Set(["None","False","True"]);const comparators=__exports.comparators=["in","not","not in","is","is not","<","<=",">",">=","<>","!=","==",];const binaryOperators=__exports.binaryOperators=["or","and","|","^","&","<<",">>","+","-","*","/","//","%","~","**",".",];const unaryOperators=__exports.unaryOperators=["-"];const symbols=new Set([...["(",")","[","]","{","}",":",","],...["if","else","lambda","="],...comparators,...binaryOperators,...unaryOperators,]);function group(...args){return"("+args.join("|")+")";} 3675const Name="[a-zA-Z_]\\w*";const Whitespace="[ \\f\\t]*";const DecNumber="\\d+(L|l)?";const IntNumber=DecNumber;const Exponent="[eE][+-]?\\d+";const PointFloat=group(`\\d+\\.\\d*(${Exponent})?`,`\\.\\d+(${Exponent})?`);const FloatNumber=group(PointFloat,`\\d+${Exponent}`);const Number=group(FloatNumber,IntNumber);const Operator=group("\\*\\*=?",">>=?","<<=?","<>","!=","//=?","[+\\-*/%&|^=<>]=?","~");const Bracket="[\\[\\]\\(\\)\\{\\}]";const Special="[:;.,`@]";const Funny=group(Operator,Bracket,Special);const ContStr=group("([uU])?'([^\n'\\\\]*(?:\\\\.[^\n'\\\\]*)*)'",'([uU])?"([^\n"\\\\]*(?:\\\\.[^\n"\\\\]*)*)"');const PseudoToken=Whitespace+group(Number,Funny,ContStr,Name);const NumberPattern=new RegExp("^"+Number+"$");const StringPattern=new RegExp("^"+ContStr+"$");const NamePattern=new RegExp("^"+Name+"$");const strip=new RegExp("^"+Whitespace);__exports.tokenize=tokenize;function tokenize(str){const tokens=[];const max=str.length;let start=0;let end=0;const pseudoprog=new RegExp(PseudoToken,"g");while(pseudoprog.lastIndex<max){const pseudomatch=pseudoprog.exec(str);
3675if(!pseudomatch){if(/^\s+$/.test(str.slice(end))){break;} 3676throw new TokenizerError("Failed to tokenize <<"+ 3677str+">> at index "+ 3678(end||0)+"; parsed so far: "+ 3679tokens);} 3680if(pseudomatch.index>end){if(str.slice(end,pseudomatch.index).trim()){throw new TokenizerError("Invalid expression");}} 3681start=pseudomatch.index;end=pseudoprog.lastIndex;let token=str.slice(start,end).replace(strip,"");if(NumberPattern.test(token)){tokens.push({type:0,value:parseFloat(token),});}else if(StringPattern.test(token)){var m=StringPattern.exec(token);tokens.push({type:1,value:decodeStringLiteral(m[3]!==undefined?m[3]:m[5],!!(m[2]||m[4])),});}else if(symbols.has(token)){if(token==="in"&&tokens.length>0&&tokens[tokens.length-1].value==="not"){token="not in";tokens.pop();}else if(token==="not"&&tokens.length>0&&tokens[tokens.length-1].value==="is"){token="is not";tokens.pop();} 3682tokens.push({type:2,value:token,});}else if(constants.has(token)){tokens.push({type:4,value:token,});}else if(NamePattern.test(token)){tokens.push({type:3,value:token,});}else{throw new TokenizerError("Invalid expression");}} 3683return tokens;} 3684return __exports;});; 3685 3686/* /web/static/src/core/py_js/py_utils.js */ 3687odoo.define('@web/core/py_js/py_utils',['@web/core/py_js/py_parser','@web/core/py_js/py_date'],function(require){'use strict';let __exports={};const{bp}=require("@web/core/py_js/py_parser");const{PyDate,PyDateTime}=require("@web/core/py_js/py_date");__exports.toPyValue=toPyValue;function toPyValue(value){switch(typeof value){case"string":return{type:1,value};case"number":return{type:0,value};case"boolean":return{type:2,value};case"object":if(Array.isArray(value)){return{type:4,value:value.map(toPyValue)};}else if(value===null){return{type:3};}else if(value instanceof Date){return{type:1,value:PyDateTime.convertDate(value)};}else if(value instanceof PyDate||value instanceof PyDateTime){return{type:1,value};}else{const content={};for(const key in value){content[key]=toPyValue(value[key]);} 3688return{type:11,value:content};} 3689default:throw new Error("Invalid type");}} 3690__exports.formatAST=formatAST;function formatAST(ast,lbp=0){switch(ast.type){case 3:return"None";case 1:return JSON.stringify(ast.value);case 0:return String(ast.value);case 2:return ast.value?"True":"False";case 4:return`[${ast.value.map(formatAST).join(", ")}]`;case 6:if(ast.op==="not"){return`not `+formatAST(ast.right,50);} 3691return ast.op+formatAST(ast.right,130);case 7:{const abp=bp(ast.op);const str=`${formatAST(ast.left, abp)} ${ast.op} ${formatAST(ast.right, abp)}`;return abp<lbp?`(${str})`:str;} 3692case 11:{const pairs=[];for(const k in ast.value){pairs.push(`"${k}": ${formatAST(ast.value[k])}`);} 3693return`{`+pairs.join(", ")+`}`;} 3694case 10:return`(${ast.value.map(formatAST).join(", ")})`;case 5:return ast.value;case 12:{return`${formatAST(ast.target)}[${formatAST(ast.key)}]`;} 3695case 13:{const{ifTrue,condition,ifFalse}=ast;return`${formatAST(ifTrue)} if ${formatAST(condition)} else ${formatAST(ifFalse)}`;} 3696case 14:{const abp=bp(ast.op);const str=`${formatAST(ast.left, abp)} ${ast.op} ${formatAST(ast.right, abp)}`;return abp<lbp?`(${str})`:str;} 3697case 15:return`${formatAST(ast.obj, 150)}.${ast.key}`;case 8:{const args=ast.args.map(formatAST);const kwargs=[];for(const kwarg in ast.kwargs){kwargs.push(`${kwarg} = ${formatAST(ast.kwargs[kwarg])}`);} 3698const argStr=args.concat(kwargs).join(", ");return`${formatAST(ast.fn)}(${argStr})`;}} 3699throw new Error("invalid expression: "+ast);} 3700const PY_DICT=__exports.PY_DICT=Object.create(null);__exports.toPyDict=toPyDict;function toPyDict(obj){return new Proxy(obj,{getPrototypeOf(){return PY_DICT;},});} 3701return __exports;});; 3702 3703/* /web/static/src/core/record_selectors/multi_record_selector.js */ 3704odoo.define('@web/core/record_selectors/multi_record_selector',['@odoo/owl','@web/core/l10n/translation','@web/core/tags_list/tags_list','@web/core/tree_editor/utils','@web/core/utils/hooks','@web/core/utils/urls','@web/core/record_selectors/record_autocomplete','@web/core/record_selectors/tag_navigation_hook'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{TagsList}=require("@web/core/tags_list/tags_list");const{isId}=require("@web/core/tree_editor/utils");const{useService}=require("@web/core/utils/hooks");const{imageUrl}=require("@web/core/utils/urls");const{RecordAutocomplete}=require("@web/core/record_selectors/record_autocomplete");const{useTagNavigation}=require("@web/core/record_selectors/tag_navigation_hook");const MultiRecordSelector=__exports.MultiRecordSelector=class MultiRecordSelector extends Component{static props={resIds:{type:Array,element:Number},resModel:String,update:Function,domain:{type:Array,optional:true},context:{type:Object,optional:true},fieldString:{type:String,optional:true},placeholder:{type:String,optional:true},};static components={RecordAutocomplete,TagsList};static template="web.MultiRecordSelector";setup(){this.nameService=useService("name");useTagNavigation("multiRecordSelector",{delete:(index)=>this.deleteTag(index),});onWillStart(()=>this.computeDerivedParams());onWillUpdateProps((nextProps)=>this.computeDerivedParams(nextProps));} 3705get isAvatarModel(){return["res.partner","res.users","hr.employee","hr.employee.public"].includes(this.props.resModel);} 3706async computeDerivedParams(props=this.props){const displayNames=await this.getDisplayNames(props);this.tags=this.getTags(props,displayNames);} 3707async getDisplayNames(props){const ids=this.getIds(props);return this.nameService.loadDisplayNames(props.resModel,ids);} 3708get placeholder(){return this.getTags(this.props,{}).length?"":this.props.placeholder;} 3709getIds(props=this.props){return props.resIds;} 3710getTags(props,displayNames){return props.resIds.map((id,index)=>
3710{const text=typeof displayNames[id]==="string"?displayNames[id]:_t("Inaccessible/missing record ID: %s",id);return{text,onDelete:()=>{this.deleteTag(index);},img:this.isAvatarModel&&isId(id)&&imageUrl(this.props.resModel,id,"avatar_128"),};});} 3711deleteTag(index){this.props.update([...this.props.resIds.slice(0,index),...this.props.resIds.slice(index+1),]);} 3712update(resIds){this.props.update([...this.props.resIds,...resIds]);}} 3713return __exports;});; 3714 3715/* /web/static/src/core/record_selectors/record_autocomplete.js */ 3716odoo.define('@web/core/record_selectors/record_autocomplete',['@odoo/owl','@web/core/autocomplete/autocomplete','@web/core/l10n/translation','@web/core/domain','@web/core/registry','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{AutoComplete}=require("@web/core/autocomplete/autocomplete");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{Domain}=require("@web/core/domain");const{registry}=require("@web/core/registry");const{useOwnedDialogs,useService}=require("@web/core/utils/hooks");const SEARCH_LIMIT=7;const SEARCH_MORE_LIMIT=320;const RecordAutocomplete=__exports.RecordAutocomplete=class RecordAutocomplete extends Component{static props={resModel:String,update:Function,multiSelect:Boolean,getIds:Function,value:String,domain:{type:Array,optional:true},context:{type:Object,optional:true},className:{type:String,optional:true},fieldString:{type:String,optional:true},placeholder:{type:String,optional:true},slots:{optional:true},};static components={AutoComplete};static template="web.RecordAutocomplete";setup(){this.orm=useService("orm");this.nameService=useService("name");this.addDialog=useOwnedDialogs();this.sources=[{placeholder:_t("Loading..."),options:this.loadOptionsSource.bind(this),optionSlot:this.props.slots?.autoCompleteItem?"option":undefined,},];} 3717addNames(options){const displayNames=Object.fromEntries(options);this.nameService.addDisplayNames(this.props.resModel,displayNames);} 3718getIds(){return this.props.getIds();} 3719async loadOptionsSource(name){if(this.lastProm){this.lastProm.abort(false);} 3720this.lastProm=this.search(name,SEARCH_LIMIT+1);const nameGets=(await this.lastProm).map(([id,label])=>[id,label?label.split("\n")[0]:_t("Unnamed"),]);this.addNames(nameGets);const options=nameGets.map(([id,label])=>({data:{record:{id,display_name:label},},label,onSelect:()=>this.props.update([id]),}));if(SEARCH_LIMIT<nameGets.length){options.push({cssClass:"o_m2o_dropdown_option",label:_t("Search More..."),onSelect:this.onSearchMore.bind(this,name),});} 3721if(options.length===0){options.push({label:_t("(no result)")});} 3722return options;} 3723async onSearchMore(name){const{fieldString,multiSelect,resModel}=this.props;let operator;const ids=[];if(name){const nameGets=await this.search(name,SEARCH_MORE_LIMIT);this.addNames(nameGets);operator="in";ids.push(...nameGets.map((nameGet)=>nameGet[0]));}else{operator="not in";ids.push(...this.getIds());} 3724const dynamicFilters=ids.length?[{description:_t("Quick search: %s",name),domain:[["id",operator,ids]],},]:undefined;const SelectCreateDialog=registry.category("dialogs").get("select_create");let title=_t("Search");if(fieldString&&fieldString.trim()){title=_t("Search: %s",fieldString);} 3725this.addDialog(SelectCreateDialog,{title,dynamicFilters,domain:this.getDomain(),resModel,noCreate:true,multiSelect,context:this.props.context||{},onSelected:(resId)=>{const resIds=Array.isArray(resId)?resId:[resId];this.props.update([...resIds]);},});} 3726getDomain(){const domainIds=Domain.not([["id","in",this.getIds()]]);if(this.props.domain){return Domain.and([this.props.domain,domainIds]).toList();} 3727return domainIds.toList();} 3728search(name,limit){const domain=this.getDomain();return this.orm.call(this.props.resModel,"name_search",[],{name,domain:domain,limit,context:this.props.context||{},});} 3729onChange({inputValue}){if(!inputValue.length){this.props.update([]);}}} 3730return __exports;});; 3731 3732/* /web/static/src/core/record_selectors/record_selector.js */ 3733odoo.define('@web/core/record_selectors/record_selector',['@odoo/owl','@web/core/l10n/translation','@web/core/tree_editor/utils','@web/core/utils/hooks','@web/core/record_selectors/record_autocomplete'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{isId}=require("@web/core/tree_editor/utils");const{useService}=require("@web/core/utils/hooks");const{RecordAutocomplete}=require("@web/core/record_selectors/record_autocomplete");const RecordSelector=__exports.RecordSelector=class RecordSelector extends Component{static props={resId:[Number,{value:false}],resModel:String,update:Function,domain:{type:Array,optional:true},context:{type:Object,optional:true},fieldString:{type:String,optional:true},placeholder:{type:String,optional:true},};static components={RecordAutocomplete};static template="web.RecordSelector";setup(){this.nameService=useService("name");onWillStart(()=>this.computeDerivedParams());onWillUpdateProps((nextProps)=>this.computeDerivedParams(nextProps));} 3734get isAvatarModel(){return["res.partner","res.users","hr.employee","hr.employee.public"].includes(this.props.resModel);} 3735get hasAvatarImg(){return this.isAvatarModel&&isId(this.props.resId);} 3736async computeDerivedParams(props=this.props){const displayNames=await this.getDisplayNames(props);this.displayName=this.getDisplayName(props,displayNames);} 3737async getDisplayNames(props){const ids=this.getIds(props);return this.nameService.loadDisplayNames(props.resModel,ids);} 3738getDisplayName(props=this.props,displayNames){const{resId}=props;if(resId===false){return"";}
3739return typeof displayNames[resId]==="string"?displayNames[resId]:_t("Inaccessible/missing record ID: %s",resId);} 3740getIds(props=this.props){if(props.resId){return[props.resId];} 3741return[];} 3742update(resIds){this.props.update(resIds[0]||false);this.render(true);}} 3743return __exports;});; 3744 3745/* /web/static/src/core/record_selectors/tag_navigation_hook.js */ 3746odoo.define('@web/core/record_selectors/tag_navigation_hook',['@odoo/owl','@web/core/navigation/navigation'],function(require){'use strict';let __exports={};const{useRef}=require("@odoo/owl");const{useNavigation}=require("@web/core/navigation/navigation");__exports.useTagNavigation=useTagNavigation;function useTagNavigation(refName,options={}){const tagsContainerRef=useRef(refName);const isEnabled=options.isEnabled??(()=>true);const canRemoveTag=(target)=>options.delete&&(target.tagName.toLowerCase()!=="input"||!target.value);const onBackspaceKeydown=(navigator)=>{const el=navigator.activeItem.el;if(el.classList.contains("o-autocomplete--input")){if(!el.value&&navigator.items.length>1){options.delete(navigator.items.length-2);}}else{options.delete(navigator.activeItemIndex);} 3747navigator.items.at(-1).setActive();};const canNavigateFromInput=(navigator,navNext)=>{const el=navigator.activeItem.el;if(el.classList.contains("o-autocomplete--input")){const menu=tagsContainerRef.el.querySelector(".o-autocomplete--dropdown-menu");const index=navNext?el.value.length:0;if(el.selectionStart!==index||menu){return false;}} 3748return true;};useNavigation(tagsContainerRef,{getItems:()=>tagsContainerRef.el?.querySelectorAll(":scope .o_tag, :scope .o-autocomplete--input")??[],isNavigationAvailable:({navigator,target})=>isEnabled()&&navigator.isFocused&&navigator.contains(target),hotkeys:{tab:null,"shift+tab":null,home:null,end:null,enter:null,arrowup:null,arrowdown:null,backspace:{bypassEditableProtection:true,isAvailable:({target})=>canRemoveTag(target),callback:(navigator)=>onBackspaceKeydown(navigator),},arrowleft:{bypassEditableProtection:true,isAvailable:({navigator})=>canNavigateFromInput(navigator,false),callback:(navigator)=>navigator.previous(),},arrowright:{bypassEditableProtection:true,isAvailable:({navigator})=>canNavigateFromInput(navigator,true),callback:(navigator)=>navigator.next(),},},});} 3749return __exports;});; 3750 3751/* /web/static/src/core/registry.js */ 3752odoo.define('@web/core/registry',['@odoo/owl'],function(require){'use strict';let __exports={};const{EventBus,validate}=require("@odoo/owl");const KeyNotFoundError=__exports.KeyNotFoundError=class KeyNotFoundError extends Error{} 3753const DuplicatedKeyError=__exports.DuplicatedKeyError=class DuplicatedKeyError extends Error{} 3754const validateSchema=(name,key,value,schema)=>
3754{if(!odoo.debug){return;} 3755try{validate(value,schema);}catch(error){throw new Error(`Validation error for key "${key}" in registry "${name}": ${error}`);}};const Registry=__exports.Registry=class Registry extends EventBus{constructor(name){super();this.content={};this.subRegistries={};this.elements=null;this.entries=null;this.name=name;this.validationSchema=null;this.addEventListener("UPDATE",()=>{this.elements=null;this.entries=null;});} 3756add(key,value,{force,sequence}={}){if(this.validationSchema){validateSchema(this.name,key,value,this.validationSchema);} 3757if(!force&&key in this.content){throw new DuplicatedKeyError(`Cannot add key "${key}" in the "${this.name}" registry: it already exists`);} 3758let previousSequence;if(force){const elem=this.content[key];previousSequence=elem&&elem[0];} 3759sequence=sequence===undefined?previousSequence||50:sequence;this.content[key]=[sequence,value];const payload={operation:"add",key,value};this.trigger("UPDATE",payload);return this;} 3760get(key,defaultValue){if(arguments.length<2&&!(key in this.content)){throw new KeyNotFoundError(`Cannot find key "${key}" in the "${this.name}" registry`);} 3761const info=this.content[key];return info?info[1]:defaultValue;} 3762contains(key){return key in this.content;} 3763getAll(){if(!this.elements){const content=Object.values(this.content).sort((el1,el2)=>el1[0]-el2[0]);this.elements=content.map((elem)=>elem[1]);} 3764return this.elements.slice();} 3765getEntries(){if(!this.entries){const entries=Object.entries(this.content).sort((el1,el2)=>el1[1][0]-el2[1][0]);this.entries=entries.map(([str,elem])=>[str,elem[1]]);} 3766return this.entries.slice();} 3767remove(key){const value=this.content[key];delete this.content[key];const payload={operation:"delete",key,value};this.trigger("UPDATE",payload);} 3768category(subcategory){if(!(subcategory in this.subRegistries)){this.subRegistries[subcategory]=new Registry(subcategory);} 3769return this.subRegistries[subcategory];} 3770addValidation(schema){if(this.validationSchema){throw new Error("Validation schema already set on this registry");} 3771this.validationSchema=schema;for(const[key,value]of this.getEntries()){validateSchema(this.name,key,value,schema);}}} 3772const registry=__exports.registry=new Registry();return __exports;});; 3773 3774/* /web/static/src/core/registry_hook.js */ 3775odoo.define('@web/core/registry_hook',['@odoo/owl'],function(require){'use strict';let __exports={};const{useState,onWillStart,onWillDestroy}=require("@odoo/owl");__exports.useRegistry=useRegistry;function useRegistry(registry){const state=useState({entries:registry.getEntries()});const listener=({detail})=>{const index=state.entries.findIndex(([k])=>k===detail.key);if(detail.operation==="add"&&index===-1){const newEntries=registry.getEntries();const newEntry=newEntries.find(([k])=>k===detail.key);const newIndex=newEntries.indexOf(newEntry);if(newIndex===newEntries.length-1){state.entries.push(newEntry);}else{state.entries.splice(newIndex,0,newEntry);}}else if(detail.operation==="delete"&&index>=0){state.entries.splice(index,1);}};onWillStart(()=>registry.addEventListener("UPDATE",listener));onWillDestroy(()=>registry.removeEventListener("UPDATE",listener));return state;} 3776return __exports;});; 3777 3778/* /web/static/src/core/resizable_panel/resizable_panel.js */ 3779odoo.define('@web/core/resizable_panel/resizable_panel',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillUpdateProps,onWillUnmount,useEffect,useExternalListener,useRef,useComponent,}=require("@odoo/owl");function useResizable({containerRef,handleRef,initialWidth=400,getMinWidth=()=>400,onResize=()=>{},getResizeSide=()=>"end",}){containerRef=typeof containerRef=="string"?useRef(containerRef):containerRef;handleRef=typeof handleRef=="string"?useRef(handleRef):handleRef;const props=useComponent().props;let minWidth=getMinWidth(props);let resizeSide=getResizeSide(props);let isChangingSize=false;useExternalListener(document,"mouseup",()=>onMouseUp());useExternalListener(document,"mousemove",(ev)=>onMouseMove(ev));useExternalListener(window,"resize",()=>{const limit=getLimitWidth();if(getContainerRect().width>=limit){resize(computeFinalWidth(limit));}});let docDirection;useEffect((container)=>{if(container){docDirection=getComputedStyle(container).direction;}},()=>[containerRef.el]);onMounted(()=>
3779{if(handleRef.el){resize(initialWidth);handleRef.el.addEventListener("mousedown",onMouseDown);}});onWillUpdateProps((nextProps)=>{minWidth=getMinWidth(nextProps);resizeSide=getResizeSide(nextProps);});onWillUnmount(()=>{if(handleRef.el){handleRef.el.removeEventListener("mousedown",onMouseDown);}});function onMouseDown(){isChangingSize=true;document.body.classList.add("pe-none","user-select-none");} 3780function onMouseUp(){isChangingSize=false;document.body.classList.remove("pe-none","user-select-none");} 3781function onMouseMove(ev){if(!isChangingSize||!containerRef.el){return;} 3782const direction=(docDirection==="ltr"&&resizeSide==="end")||(docDirection==="rtl"&&resizeSide==="start")?1:-1;const fixedSide=direction===1?"left":"right";const containerRect=getContainerRect();const newWidth=(ev.clientX-containerRect[fixedSide])*direction;resize(computeFinalWidth(newWidth));} 3783function computeFinalWidth(targetContainerWidth){const handlerSpacing=handleRef.el?handleRef.el.offsetWidth/2:10;const w=Math.max(minWidth,targetContainerWidth+handlerSpacing);const limit=getLimitWidth();return Math.min(w,limit-handlerSpacing);} 3784function getContainerRect(){const container=containerRef.el;const offsetParent=container.offsetParent;let containerRect={};if(!offsetParent){containerRect=container.getBoundingClientRect();}else{containerRect.left=container.offsetLeft;containerRect.right=container.offsetLeft+container.offsetWidth;containerRect.width=container.offsetWidth;} 3785return containerRect;} 3786function getLimitWidth(){const offsetParent=containerRef.el.offsetParent;return offsetParent?offsetParent.offsetWidth:window.innerWidth;} 3787function resize(width){containerRef.el.style.setProperty("width",`${width}px`);onResize(width);}} 3788const ResizablePanel=__exports.ResizablePanel=class ResizablePanel extends Component{static template="web_studio.ResizablePanel";static components={};static props={onResize:{type:Function,optional:true},initialWidth:{type:Number,optional:true},minWidth:{type:Number,optional:true},class:{type:String,optional:true},slots:{type:Object},handleSide:{validate:(val)=>["start","end"].includes(val),optional:true,},};static defaultProps={onResize:()=>{},width:400,minWidth:400,class:"",handleSide:"end",};setup(){useResizable({containerRef:"containerRef",handleRef:"handleRef",onResize:this.props.onResize,initialWidth:this.props.initialWidth,getMinWidth:(props)=>props.minWidth,getResizeSide:(props)=>props.handleSide,});} 3789get class(){const classes=this.props.class.split(" ");if(!classes.some((cls)=>cls.startsWith("position-"))){classes.push("position-relative");} 3790return classes.join(" ");}} 3791return __exports;});; 3792 3793/* /web/static/src/core/select_menu/select_menu.js */ 3794odoo.define('@web/core/select_menu/select_menu',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/dropdown/dropdown_hooks','@web/core/tags_list/tags_list','@web/core/utils/classname','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/search','@web/core/utils/timing','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component,onWillUpdateProps,useEffect,useRef,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{TagsList}=require("@web/core/tags_list/tags_list");const{mergeClasses}=require("@web/core/utils/classname");const{useChildRef}=require("@web/core/utils/hooks");const{scrollTo}=require("@web/core/utils/scrolling");const{fuzzyLookup}=require("@web/core/utils/search");const{useDebounced}=require("@web/core/utils/timing");const{hasTouch}=require("@web/core/browser/feature_detection");let selectMenuId=0;const DEBOUNCED_DELAY=__exports.DEBOUNCED_DELAY=250;const SelectMenu=__exports.SelectMenu=class SelectMenu extends Component{static template="web.SelectMenu";static choiceItemTemplate="web.SelectMenu.ChoiceItem";static components={Dropdown,DropdownItem,TagsList};static defaultProps={value:undefined,id:"",name:"",class:"",menuClass:"",togglerClass:"",multiSelect:false,onSelect:()=>{},onNavigated:()=>{},onOpened:()=>{},onClosed:()=>{},required:false,searchable:true,autoSort:true,searchPlaceholder:"",choices:[],groups:[],sections:[],disabled:false,};static props={choices:{optional:true,type:Array,element:{type:Object,shape:{value:true,label:{type:String},"*":true,},},},groups:{type:Array,optional:true,element:{type:Object,shape:{label:{type:String,optional:true},choices:{type:Array,element:{type:Object,shape:{value:true,label:{type:String},"*":true,},},},section:{type:String,optional:true,},},},},sections:{type:Array,optional:true,element:{label:{type:String},name:{type:String},},},id:{type:String,optional:true},name:{type:String,optional:true},class:{type:String,optional:true},menuClass:{type:String,optional:true},togglerClass:{type:String,optional:true},required:{type:Boolean,optional:true},searchable:{type:Boolean,optional:true},autoSort:{type:Boolean,optional:true},placeholder:{type:String,optional:true},searchPlaceholder:{type:String,optional:true},searchClass:{type:String,optional:true},value:{optional:true},multiSelect:{type:Boolean,optional:true},onInput:{type:Function,optional:true},onSelect:{type:Function,optional:true},onNavigated:{type:Function,optional:true},onOpened:{type:Function,optional:true},onClosed:{type:Function,optional:true},slots:{type:Object,optional:true},disabled:{type:Boolean,optional:true},menuRef:{type:Function,optional:true},};static SCROLL_SETTINGS={defaultCount:500,increaseAmount:300,distanceBeforeReload:500,};setup(){this.selectMenuId=selectMenuId++;this.state=useState({choices:[],displayedOptions:[],searchValue:null,isFocused:false,});this.inputRef=useRef("inputRef");this.menuRef=useChildRef();this.props.menuRef?.(this.menuRef);this.debouncedOnInput=useDebounced((searchString)=>
3794{if(!this.dropdownState.isOpen){this.dropdownState.open();} 3795this.onInput(searchString);},DEBOUNCED_DELAY);this.dropdownState=useDropdownState();this.selectedChoice=this.getSelectedChoice(this.props);onWillUpdateProps((nextProps)=>{const choicesChanged=this.state.choices!==nextProps.choices;if(choicesChanged){this.state.choices=nextProps.choices;} 3796if(choicesChanged||this.props.value!==nextProps.value){this.selectedChoice=this.getSelectedChoice(nextProps);}});useEffect(()=>{if(this.dropdownState.isOpen){const groups=[{choices:this.props.choices},...this.props.groups];this.filterOptions(this.state.searchValue,groups);}},()=>[this.props.choices,this.props.groups]);this.navigationOptions={shouldFocusFirstItem:!hasTouch(),virtualFocus:this.props.searchable,hotkeys:{enter:{isAvailable:({navigator})=>navigator.items.length>0,callback:(navigator)=>{if(navigator.activeItem){return navigator.activeItem.select();} 3797if(document.activeElement.value){navigator.items[0].select();}},},},onItemActivated:(element)=>{const index=parseInt(element.dataset.choiceIndex);if(index>=0&&this.state.displayedOptions[index]){this.props.onNavigated(this.state.displayedOptions[index]);}else{this.props.onNavigated();}},};} 3798get displayValue(){return this.state.searchValue===null?this.selectedChoice?.label||"":this.state.searchValue;} 3799get displayInputInToggler(){return!this.props.slots||!this.props.slots.default;} 3800get displayInputInDropdown(){return(this.isBottomSheet||!this.displayInputInToggler)&&this.props.searchable;} 3801get isBottomSheet(){return this.env.isSmall&&hasTouch();} 3802get canDeselect(){return!this.props.required&&this.selectedChoice!==undefined;} 3803get multiSelectChoices(){return this.selectedChoice.map((c)=>({id:c.value,text:c.label,onDelete:()=>{const values=[...this.props.value];values.splice(values.indexOf(c.value),1);this.props.onSelect(values);},}));} 3804get menuClass(){return mergeClasses({"my-0":this.displayInputInToggler,o_select_menu_menu:true,o_select_menu_multi_select:this.props.multiSelect,},this.props.menuClass);} 3805get placeholderValue(){if(this.state.isFocused&&this.props.searchPlaceholder){return this.props.searchPlaceholder;} 3806return this.props.placeholder;} 3807async onBeforeOpen(){this.onInput("");} 3808onInputFocus(ev){if(!this.props.searchable){return ev.target.blur();} 3809if(ev.target.classList.contains("o_select_menu_input")){this.state.isFocused=true;ev.target.select();}} 3810onInputBlur(ev){this.state.isFocused=false;if(ev.target.value===""&&!this.props.multiSelect){if(this.canDeselect){this.onInputClear();}else{this.state.searchValue=null;}}} 3811onInputClick(ev){if(!ev.target.classList.contains("o_select_menu_toggler")){ev.stopPropagation();}} 3812onSearchInput(ev){this.state.searchValue=ev.target.value;this.debouncedOnInput(this.state.searchValue);} 3813onInputClear(){this.props.onSelect(null);this.dropdownState.close();} 3814onStateChanged(open){if(open){if(this.isBottomSheet){document.activeElement.blur();} 3815if(this.displayInputInDropdown&&!this.isBottomSheet){this.inputRef.el.focus();} 3816this.menuRef.el?.addEventListener("scroll",(ev)=>this.onScroll(ev));const selectedElement=this.menuRef.el?.querySelectorAll(".selected")[0];if(selectedElement){scrollTo(selectedElement);} 3817this.props.onOpened();}else{this.state.searchValue=null;this.props.onClosed();}} 3818isOptionSelected(choice){if(this.props.multiSelect){return this.props.value.includes(choice.value);} 3819return this.props.value===choice.value;} 3820getItemClass(choice){if(this.isOptionSelected(choice)){return"o_select_menu_item fw-bolder selected";}else{return"o_select_menu_item";}} 3821async onInput(searchString){this.filterOptions(searchString);if(this.props.onInput){await this.props.onInput(searchString);}} 3822getSelectedChoice(props){const choices=[...props.choices,...props.groups.flatMap((g)=>g.choices||[])];if(!this.props.multiSelect){return choices.find((c)=>c.value===props.value);} 3823const valueSet=new Set(props.value);return[...(this.selectedChoice||[]),...choices].filter((c,index,self)=>valueSet.has(c.value)&&self.findIndex((t)=>t.value===c.value)===index);} 3824onItemSelected(value){if(this.props.multiSelect){const values=[...this.props.value];const valueIndex=values.indexOf(value);if(valueIndex!==-1){values.splice(valueIndex,1);this.props.onSelect(values);}else{this.props.onSelect([...this.props.value,value]);}}else if(!this.selectedChoice||this.selectedChoice.value!==value){this.props.onSelect(value);if(this.inputRef.el){this.inputRef.el.value=this.state.choices.find((c)=>c.value===value).label;}} 3825this.state.searchValue=null;} 3826filterOptions(searchString="",groups){const groupsList=groups||[{choices:this.props.choices,section:""},...this.props.groups,];const _choices=[];const _sections=new Set();groupsList.sort((a,b)=>(a.section||"").localeCompare(b.section||""));for(const group of groupsList){let filteredOptions=group.choices||[];if(searchString){filteredOptions=fuzzyLookup(searchString.trim(),filteredOptions,(choice)=>choice.label);}else{if(this.props.autoSort){filteredOptions.sort((optionA,optionB)=>optionA.label.localeCompare(optionB.label));}} 3827if(filteredOptions.length===0){continue;} 3828if(group.section){const section=this.props.sections.find((e)=>e.name===group.section);if(!_sections.has(section)){_sections.add(section);_choices.push({...section,isGroup:true});}} 3829if(group.label){_choices.push({...group,isGroup:true});} 3830_choices.push(...filteredOptions);} 3831this.state.choices=_choices;this.sliceDisplayedOptions();} 3832onScroll(event){const el=event.target;const hasReachMax=this.state.displayedOptions.length>=this.state.choices.length;const remainingDistance=el.scrollHeight-el.scrollTop;const distanceToReload=el.clientHeight+this.constructor.SCROLL_SETTINGS.distanceBeforeReload;if(!hasReachMax&&remainingDistance<distanceToReload){const displayCount=this.state.displayedOptions.length+ 3833this.constructor.SCROLL_SETTINGS.increaseAmount;this.state.displayedOptions=this.state.choices.slice(0,displayCount);}} 3834sliceDisplayedOptions(){const selectedIndex=this.getSelectedOptionIndex();const defaultCount=this.constructor.SCROLL_SETTINGS.defaultCount;if(selectedIndex===-1){this.state.displayedOptions=this.state.choices.slice(0,defaultCount);}else{const endIndex=Math.max(selectedIndex+this.constructor.SCROLL_SETTINGS.increaseAmount,defaultCount);this.state.displayedOptions=this.state.choices.slice(0,endIndex);}} 3835getSelectedOptionIndex(){let selectedIndex=-1;for(let i=0;i<this.state.choices.length;i++){if(this.isOptionSelected(this.state.choices[i])){selectedIndex=i;}} 3836return selectedIndex;}} 3837return __exports;});; 3838 3839/* /web/static/src/core/signature/name_and_signature.js */ 3840odoo.define('@web/core/signature/name_and_signature',['@web/core/assets','@web/core/browser/feature_detection','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/network/rpc','@web/core/utils/hooks','@web/core/utils/render','@web/core/utils/urls','@odoo/owl'],function(require){'use strict';let __exports={};const{loadJS}=require("@web/core/assets");const{isMobileOS}=require("@web/core/browser/feature_detection");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{rpc}=require("@web/core/network/rpc");const{useAutofocus}=require("@web/core/utils/hooks");const{renderToString}=require("@web/core/utils/render");const{getDataURLFromFile}=require("@web/core/utils/urls");const{Component,useState,onWillStart,useRef,useEffect}=require("@odoo/owl");let htmlId=0;const NameAndSignature=__exports.NameAndSignature=class NameAndSignature extends Component{static template="web.NameAndSignature";static components={Dropdown,DropdownItem};static props={signature:{type:Object},defaultFont:{type:String,optional:true},displaySignatureRatio:{type:Number,optional:true},fontColor:{type:String,optional:true},signatureType:{type:String,optional:true},noInputName:{type:Boolean,optional:true},mode:{type:String,optional:true},onSignatureChange:{type:Function,optional:true},};static defaultProps={defaultFont:"",displaySignatureRatio:3.0,fontColor:"DarkBlue",signatureType:"signature",noInputName:false,onSignatureChange:()=>{},};setup(){this.htmlId=htmlId++;this.defaultName=this.props.signature.name||"";this.currentFont=0;this.drawTimeout=null;this.state=useState({signMode:this.props.mode||(this.props.noInputName&&!this.defaultName?"draw":"auto"),showSignatureArea:!!(this.props.noInputName||this.defaultName),show
3840FontList:false,});this.signNameInputRef=useRef("signNameInput");this.signInputLoad=useRef("signInputLoad");useAutofocus({refName:"signNameInput"});useEffect((el)=>{if(el){el.click();}},()=>[this.signInputLoad.el]);onWillStart(async()=>{this.fonts=await rpc(`/web/sign/get_fonts/${this.props.defaultFont}`);});onWillStart(async()=>{await loadJS("/web/static/lib/signature_pad/signature_pad.umd.js");});this.signatureRef=useRef("signature");useEffect((el)=>{if(el){this.signaturePad=new SignaturePad(el,{penColor:this.props.fontColor,backgroundColor:"rgba(255,255,255,0)",minWidth:2,maxWidth:2,});this.signaturePad.addEventListener("endStroke",()=>{this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);});this.resetSignature();this.props.signature.getSignatureImage=()=>this.signaturePad.toDataURL();this.props.signature.resetSignature=()=>this.resetSignature();if(this.state.signMode==="auto"){this.drawCurrentName();} 3841if(this.props.signature.signatureImage){this.clear();this.fromDataURL(this.props.signature.signatureImage);}}},()=>[this.signatureRef.el]);} 3842async drawCurrentName(){const font=this.fonts[this.currentFont];const text=this.getCleanedName();if(text.trim()===""){this.clear();return;} 3843const canvas=this.signatureRef.el;const img=this.getSVGText(font,text,canvas.width,canvas.height);await this.printImage(img);} 3844focusName(){if(!isMobileOS()&&this.signNameInputRef.el){this.signNameInputRef.el.focus();}} 3845clear(){this.signaturePad.clear();this.props.signature.isSignatureEmpty=this.isSignatureEmpty;} 3846async fromDataURL(){await this.signaturePad.fromDataURL(...arguments);this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);} 3847getCleanedName(){const text=this.props.signature.name.replace(/Â /g," ");if(this.props.signatureType==="initial"&&text){return(text.split(" ").map(function(w){return w[0];}).join(".")+".");} 3848return text;} 3849getSVGText(font,text,width,height){const svg=renderToString("web.sign_svg_text",{width:width,height:height,font:font,text:text,type:this.props.signatureType,color:this.props.fontColor,});return"data:image/svg+xml,"+encodeURI(svg);} 3850getSVGTextFont(font){const height=100;const width=parseInt(height*this.props.displaySignatureRatio);return this.getSVGText(font,this.getCleanedName(),width,height);} 3851uploadFile(){this.signInputLoad.el?.click();} 3852async onChangeSignLoadInput(ev){var file=ev.target.files[0];if(file===undefined){return false;} 3853if(file.type.substr(0,5)!=="image"){this.clear();this.state.loadIsInvalid=true;return false;} 3854this.state.loadIsInvalid=false;const result=await getDataURLFromFile(file);await this.printImage(result);} 3855onClickSignAutoSelectStyle(){this.state.showFontList=true;} 3856onClickSignDrawClear(){this.clear();this.props.onSignatureChange(this.state.signMode);} 3857onClickSignLoad(){this.setMode("load");} 3858onClickSignAuto(){this.setMode("auto");} 3859onInputSignName(ev){this.props.signature.name=ev.target.value;if(!this.state.showSignatureArea&&this.getCleanedName()){this.state.showSignatureArea=true;return;} 3860if(this.state.signMode==="auto"){this.drawCurrentName();}} 3861onSelectFont(index){this.currentFont=index;this.drawCurrentName();} 3862async printImage(imgSrc){this.clear();const c=this.signaturePad.canvas;const img=new Image();img.onload=()=>{const ctx=c.getContext("2d");var ratio=((img.width/img.height)>(c.width/c.height))?c.width/img.width:c.height/img.height;ctx.drawImage(img,(c.width/2)-(img.width*ratio/2),(c.height/2)-(img.height*ratio/2),img.width*ratio,img.height*ratio);this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);};img.src=imgSrc;this.signaturePad._isEmpty=false;} 3863resetSignature(){this.resizeSignature();this.clear();this.setMode(this.state.signMode,true);this.focusName();} 3864resizeSignature(){const width=this.signatureRef.el.clientWidth;const height=parseInt(width/this.props.displaySignatureRatio);Object.assign(this.signatureRef.el,{width,height});} 3865setMode(mode,reset){if(reset!==true&&mode===this.signMode){return;} 3866this.state.signMode=mode;this.signaturePad[this.state.signMode==="draw"?"on":"off"]();this.clear();if(this.state.signMode==="auto"){this.drawCurrentName();} 3867this.props.onSignatureChange(this.state.signMode);} 3868get isSignatureEmpty(){return this.signaturePad.isEmpty();} 3869get loadIsInvalid(){return this.state.signMode==="load"&&this.state.loadIsInvalid;}} 3870return __exports;});; 3871 3872/* /web/static/src/core/signature/signature_dialog.js */ 3873odoo.define('@web/core/signature/signature_dialog',['@web/core/dialog/dialog','@web/core/signature/name_and_signature','@odoo/owl'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{NameAndSignature}=require("@web/core/signature/name_and_signature");const{Component,useState}=require("@odoo/owl");const SignatureDialog=__exports.SignatureDialog=class SignatureDialog extends Component{static template="web.SignatureDialog";static components={Dialog,NameAndSignature};static props={defaultName:{type:String,optional:true},nameAndSignatureProps:Object,uploadSignature:Function,close:Function,};
3873static defaultProps={defaultName:"",};setup(){this.signature=useState({name:this.props.defaultName,isSignatureEmpty:true,});} 3874onClickConfirm(){this.props.uploadSignature({name:this.signature.name,signatureImage:this.signature.getSignatureImage(),});this.props.close();} 3875get nameAndSignatureProps(){return{...this.props.nameAndSignatureProps,signature:this.signature,};}} 3876return __exports;});; 3877 3878/* /web/static/src/core/tags_list/tags_list.js */ 3879odoo.define('@web/core/tags_list/tags_list',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const TagsList=__exports.TagsList=class TagsList extends Component{static template="web.TagsList";static defaultProps={displayText:true,};static props={displayText:{type:Boolean,optional:true},visibleItemsLimit:{type:Number,optional:true},tags:{type:Array,element:Object},};get visibleTagsCount(){return this.props.visibleItemsLimit-1;} 3880get visibleTags(){if(this.props.visibleItemsLimit&&this.props.tags.length>this.props.visibleItemsLimit){return this.props.tags.slice(0,this.visibleTagsCount);} 3881return this.props.tags;} 3882get otherTags(){if(this.props.visibleItemsLimit&&this.props.tags.length>this.props.visibleItemsLimit){return this.props.tags.slice(this.visibleTagsCount);} 3883return[];} 3884get tooltipInfo(){return JSON.stringify({tags:this.otherTags.map((tag)=>({text:tag.text,id:tag.id,})),});}} 3885return __exports;});; 3886 3887/* /web/static/src/core/template_inheritance.js */ 3888odoo.define('@web/core/template_inheritance',[],function(require){'use strict';let __exports={};const RSTRIP_REGEXP=/(?=\n[ \t]*$)/;let translationContext=null;const TCTX="t-translation-context";function getTranslationContext(node){if(node.hasAttribute(TCTX)){return node.getAttribute(TCTX);} 3889return getTranslationContext(node.parentElement);} 3890const contextByTextNode=new Map();function setTranslationContext(node){switch(node.nodeType){case Node.TEXT_NODE:if(node.nodeValue.trim()!=""){contextByTextNode.set(node,translationContext);} 3891break;case Node.ELEMENT_NODE:node.setAttribute(TCTX,translationContext);break;}} 3892__exports.applyContextToTextNode=applyContextToTextNode;function applyContextToTextNode(){for(const[textNode,context]of contextByTextNode){const wrapper=document.createElement("t");wrapper.setAttribute(TCTX,context);textNode.before(wrapper);wrapper.appendChild(textNode);} 3893contextByTextNode.clear();} 3894__exports.deepClone=deepClone;function deepClone(node){const clone=node.cloneNode();if(node.nodeType===Node.TEXT_NODE){if(contextByTextNode.has(node)){contextByTextNode.set(clone,contextByTextNode.get(node));}} 3895if(node.childNodes?.length){for(const childNode of[...node.childNodes]){clone.append(deepClone(childNode));}} 3896return clone;} 3897function addBefore(target,operation){const nodes=getNodes(target,operation);if(nodes.length===0){return;} 3898const{previousSibling}=target;target.before(...nodes);if(previousSibling?.nodeType===Node.TEXT_NODE){const[text1,text2]=previousSibling.data.split(RSTRIP_REGEXP);previousSibling.data=text1.trimEnd();if(text2&&nodes.some((n)=>n.nodeType!==Node.TEXT_NODE)){const textNode=document.createTextNode(text2);target.before(textNode);if(textNode.previousSibling.nodeType===Node.TEXT_NODE){textNode.previousSibling.data=textNode.previousSibling.data.trimEnd();}}}} 3899function getRoot(element){while(element.parentElement){element=element.parentElement;} 3900return element;} 3901const HASCLASS_REGEXP=/hasclass\(([^)]*)\)/g;const CLASS_CONTAINS_REGEX=/contains\(@class.*\)/g;function getXpath(operation){const xpath=operation.getAttribute("expr");if(odoo.debug){if(CLASS_CONTAINS_REGEX.test(xpath)){const parent=operation.closest("t[t-inherit]");const templateName=parent.getAttribute("t-name")||parent.getAttribute("t-inherit");console.warn(`Error-prone use of @class in template "${templateName}" (or one of its inheritors).`+" Use the hasclass(*classes) function to filter elements by their classes");}} 3902return xpath.replaceAll(HASCLASS_REGEXP,(_,capturedGroup)=>capturedGroup.split(",").map((c)=>`contains(concat(' ', @class, ' '), ' ${c.trim().slice(1, -1)} ')`).join(" and "));} 3903function getNode(element,operation){const root=getRoot(element);const doc=new Document();doc.appendChild(root);if(operation.tagName==="xpath"){const xpath=getXpath(operation);const result=doc.evaluate(xpath,root,null,XPathResult.FIRST_ORDERED_NODE_TYPE);return result.singleNodeValue;} 3904const attributes=[...operation.attributes].filter((attr)=>!attr.name.startsWith(TCTX));
3904for(const elem of root.querySelectorAll(operation.tagName)){if(attributes.every(({name,value})=>name==="position"||elem.getAttribute(name)===value)){return elem;}} 3905return null;} 3906function getElement(element,operation){const node=getNode(element,operation);if(!node){throw new Error(`Element '${operation.outerHTML}' cannot be located in element tree`);} 3907if(!(node instanceof Element)){throw new Error(`Found node ${node} instead of an element`);} 3908return node;} 3909function getNodes(element,operation){const nodes=[];for(const childNode of operation.childNodes){if(childNode.tagName==="xpath"&&childNode.getAttribute?.("position")==="move"){const node=getElement(element,childNode);node.setAttribute(TCTX,getTranslationContext(node));removeNode(node);nodes.push(node);}else{setTranslationContext(childNode);nodes.push(childNode);}} 3910return nodes;} 3911function splitAndTrim(str,separator){return str.split(separator).map((s)=>s.trim());} 3912function modifyAttributes(target,operation){for(const child of operation.children){if(child.tagName!=="attribute"){continue;} 3913const attributeName=child.getAttribute("name");const firstNode=child.childNodes[0];let value=firstNode?.nodeType===Node.TEXT_NODE?firstNode.data:"";const add=child.getAttribute("add")||"";const remove=child.getAttribute("remove")||"";if(add||remove){if(firstNode?.nodeType===Node.TEXT_NODE){throw new Error(`Useless element content ${firstNode.outerHTML}`);} 3914const separator=child.getAttribute("separator")||",";const toRemove=new Set(splitAndTrim(remove,separator));const values=splitAndTrim(target.getAttribute(attributeName)||"",separator).filter((s)=>!toRemove.has(s));values.push(...splitAndTrim(add,separator).filter((s)=>s));value=values.join(separator);} 3915if(value){target.setAttribute(attributeName,value);if(!(add||remove)){target.setAttribute(`t-translation-context-${attributeName}`,translationContext);}}else{target.removeAttribute(attributeName);}}} 3916function removeNode(node){const{nextSibling,previousSibling}=node;node.remove();if(nextSibling?.nodeType===Node.TEXT_NODE&&previousSibling?.nodeType===Node.TEXT_NODE&&previousSibling.parentElement.firstChild===previousSibling){previousSibling.data=previousSibling.data.trimEnd();}} 3917function replace(root,target,operation){const mode=operation.getAttribute("mode")||"outer";switch(mode){case"outer":{const result=operation.ownerDocument.evaluate(".//*[text()='$0']",operation,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);target.setAttribute(TCTX,getTranslationContext(target));for(let i=0;i<result.snapshotLength;i++){const loc=result.snapshotItem(i);loc.firstChild.replaceWith(deepClone(target));} 3918if(target.parentElement){const nodes=getNodes(target,operation);target.replaceWith(...nodes);}else{let operationContent=null;let comment=null;for(const child of operation.childNodes){if(child.nodeType===Node.ELEMENT_NODE){setTranslationContext(child);operationContent=child;break;} 3919if(child.nodeType===Node.COMMENT_NODE){comment=child;}} 3920root=deepClone(operationContent);if(target.hasAttribute("t-name")){root.setAttribute("t-name",target.getAttribute("t-name"));} 3921if(comment){root.prepend(comment);}} 3922break;} 3923case"inner":while(target.firstChild){target.removeChild(target.lastChild);} 3924for(const node of[...operation.childNodes]){setTranslationContext(node);target.append(node);} 3925break;default:throw new Error(`Invalid mode attribute: '${mode}'`);} 3926return root;} 3927__exports.applyInheritance=applyInheritance;function applyInheritance(root,operations,url=""){translationContext=url.split("/")[1]??"";for(const operation of operations.children){const target=getElement(root,operation);const position=operation.getAttribute("position")||"inside";if(odoo.debug&&url){const attributes=[...operation.attributes].map(({name,value})=>`${name}=${JSON.stringify(name === "position" ? position : value)}`);const comment=document.createComment(` From file: ${url} ; ${attributes.join(" ; ")} `);if(position==="attributes"){target.before(comment);}else{operation.prepend(comment);}} 3928switch(position){case"replace":{root=replace(root,target,operation);break;} 3929case"attributes":{modifyAttributes(target,operation);break;} 3930case"inside":{const sentinel=document.createElement("sentinel");target.append(sentinel);addBefore(sentinel,operation);removeNode(sentinel);break;} 3931case"after":{const sentinel=document.createElement("sentinel");target.after(sentinel);addBefore(sentinel,operation);removeNode(sentinel);break;} 3932case"before":{addBefore(target,operation);break;} 3933default:throw new Error(`Invalid position attribute: '${position}'`);}} 3934translationContext=null;return root;} 3935return __exports;});; 3936 3937/* /web/static/src/core/templates.js */ 3938odoo.define('@web/core/templates',['@web/core/template_inheritance'],function(require){'use strict';let __exports={};const{applyContextToTextNode,applyInheritance,deepClone,}=require("@web/core/template_inheritance");function getClone(template){const c=deepClone(template);new Document().append(c);return c;} 3939function getKey(args){return JSON.stringify([...args]);} 3940function getParsedTemplate(templateString){const doc=parser.parseFromString(templateString,"text/xml");for(const processor of templateProcessors){processor(doc);} 3941return doc.firstChild;} 3942function _getTemplate(name,blockId=null){if(!(name in parsedTemplates)){if(!(name in templates)){return null;} 3943const templateString=templates[name];parsedTemplates[name]=getParsedTemplate(templateString);const inheritFrom=parsedTemplates[name].getAttribute("t-inherit");if(!inheritFrom){const addon=info[name].url.split("/")[1];
3943parsedTemplates[name].setAttribute("t-translation-context",addon);}} 3944let processedTemplate=parsedTemplates[name];const inheritFrom=processedTemplate.getAttribute("t-inherit");if(inheritFrom){const parentTemplate=_getTemplate(inheritFrom,blockId||info[name].blockId);if(!parentTemplate){throw new Error(`Constructing template ${name}: template parent ${inheritFrom} not found`);} 3945const element=getClone(processedTemplate);processedTemplate=applyInheritance(getClone(parentTemplate),element,info[name].url);if(processedTemplate.tagName!==element.tagName){const temp=processedTemplate;processedTemplate=new Document().createElement(element.tagName);processedTemplate.append(...temp.childNodes);} 3946for(const{name,value}of element.attributes){if(!["t-inherit","t-inherit-mode"].includes(name)){processedTemplate.setAttribute(name,value);}}} 3947let cloned=false;for(const otherBlockId in templateExtensions[name]||{}){if(blockId&&otherBlockId>blockId){break;} 3948if(!(name in parsedTemplateExtensions)){parsedTemplateExtensions[name]={};} 3949if(!(otherBlockId in parsedTemplateExtensions[name])){parsedTemplateExtensions[name][otherBlockId]=[];for(const{templateString,url}of templateExtensions[name][otherBlockId]){parsedTemplateExtensions[name][otherBlockId].push({template:getParsedTemplate(templateString),url,});}} 3950for(const{template,url}of parsedTemplateExtensions[name][otherBlockId]){if(!urlFilters.every((filter)=>filter(url))){continue;} 3951if(!inheritFrom&&!cloned){cloned=true;processedTemplate=getClone(processedTemplate);} 3952processedTemplate=applyInheritance(processedTemplate,getClone(template),url);}} 3953return processedTemplate;} 3954const info=Object.create(null);const parsedTemplateExtensions=Object.create(null);const parsedTemplates=Object.create(null);const parser=new DOMParser();const processedTemplates=new Map();const registered=new Set();const templateExtensions=Object.create(null);const templateProcessors=[];const templates=Object.create(null);let blockType=null;let blockId=0;let urlFilters=[];__exports.checkPrimaryTemplateParents=checkPrimaryTemplateParents;function checkPrimaryTemplateParents(namesToCheck){const missing=new Set(namesToCheck.filter((name)=>!(name in templates)));if(missing.size){console.error(`Missing (primary) parent templates: ${[...missing].join(", ")}`);}} 3955__exports.clearProcessedTemplates=clearProcessedTemplates;function clearProcessedTemplates(){processedTemplates.clear();} 3956__exports.getTemplate=getTemplate;function getTemplate(name){if(!processedTemplates.has(name)){processedTemplates.set(name,_getTemplate(name));applyContextToTextNode();} 3957return processedTemplates.get(name);} 3958__exports.registerTemplate=registerTemplate;function registerTemplate(name,url,templateString){const key=getKey(arguments);if(registered.has(key)){return;} 3959registered.add(key);if(blockType!=="templates"){blockType="templates";blockId++;} 3960if(name in templates&&(info[name].url!==url||templates[name]!==templateString)){throw new Error(`Template ${name} already exists`);} 3961templates[name]=templateString;info[name]={blockId,url};return function unregisterTemplate(){delete templates[name];delete info[name];delete parsedTemplates[name];delete parsedTemplateExtensions[name];processedTemplates.delete(name);registered.delete(key);};} 3962__exports.registerTemplateExtension=registerTemplateExtension;function registerTemplateExtension(inheritFrom,url,templateString){const key=getKey(arguments);if(registered.has(key)){return;} 3963registered.add(key);if(blockType!=="extensions"){blockType="extensions";blockId++;} 3964if(!templateExtensions[inheritFrom]){templateExtensions[inheritFrom]=[];} 3965if(!templateExtensions[inheritFrom][blockId]){templateExtensions[inheritFrom][blockId]=[];} 3966templateExtensions[inheritFrom][blockId].push({templateString,url,});return function unregisterTemplateExtension(){const index=templateExtensions[inheritFrom]?.[blockId]?.findIndex((ext)=>ext.templateString===templateString&&ext.url===url);if(Number.isInteger(index)&&index>-1){templateExtensions[inheritFrom][blockId].splice(index,1);} 3967registered.delete(key);};} 3968__exports.registerTemplateProcessor=registerTemplateProcessor;function registerTemplateProcessor(processor){templateProcessors.push(processor);} 3969__exports.setUrlFilters=setUrlFilters;function setUrlFilters(filters){const prev=urlFilters;urlFilters=filters;return function restoreUrlFilters(){urlFilters=prev;};} 3970return __exports;});; 3971 3972/* /web/static/src/core/time_picker/time_picker.js */ 3973odoo.define('@web/core/time_picker/time_picker',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/dropdown/dropdown_item','@web/core/h
3973otkeys/hotkey_service','@web/core/l10n/time','@web/core/utils/classname','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onWillUpdateProps,useRef,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{Time,parseTime}=require("@web/core/l10n/time");const{mergeClasses}=require("@web/core/utils/classname");const{useChildRef}=require("@web/core/utils/hooks");const HOURS=[...Array(24)].map((_,i)=>i);const MINUTES=[...Array(60)].map((_,i)=>i);const TimePicker=__exports.TimePicker=class TimePicker extends Component{static template="web.TimePicker";static components={Dropdown,DropdownItem,};static props={cssClass:{type:[String,Array,Object],optional:true},inputCssClass:{type:[String,Array,Object],optional:true},value:{type:[String,Time,{value:false},{value:null}],optional:true},onChange:{type:Function,optional:true},onInvalid:{type:Function,optional:true},showSeconds:{type:Boolean,optional:true},minutesRounding:{type:Number,optional:true},placeholder:{type:String,optional:true},};static defaultProps={cssClass:{},inputCssClass:{},value:"00:00",onChange:()=>{},onInvalid:()=>{},showSeconds:false,minutesRounding:5,};setup(){this.inputRef=useRef("inputRef");this.menuRef=useChildRef();this.dropdownState=useDropdownState();this.state=useState({value:null,inputValue:"",isValid:true,});this.suggestions=[];this.isNavigating=false;this.navigationOptions=this.getNavigationOptions();this.onPropsUpdated(this.props);onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));} 3974get cssClass(){return mergeClasses(this.props.cssClass,{o_time_picker_seconds:this.props.showSeconds,});} 3975get inputCssClass(){return mergeClasses(this.props.inputCssClass,{o_invalid:!this.state.isValid,});} 3976getNavigationOptions(){const handleArrow=(navigator)=>{const value=this.suggestions[navigator.activeItemIndex];if(value){this.state.inputValue=value.toString(this.props.showSeconds);}};return{virtualFocus:true,onUpdated:(navigator)=>(this.navigator=navigator),hotkeys:{enter:{bypassEditableProtection:true,callback:(navigator)=>{if(!this.isNavigating){const value=parseTime(this.inputRef.el.value,this.props.showSeconds);if(value){this.setValue(value);this.close();}}else if(navigator.activeItem){navigator.activeItem.select();}},},tab:{bypassEditableProtection:true,callback:(navigator)=>{if(navigator.activeItemIndex>=0){this.setValue(this.suggestions[navigator.activeItemIndex]);this.close();}},},arrowdown:{callback:(navigator)=>{navigator.next();handleArrow(navigator);},},arrowup:{callback:(navigator)=>{navigator.previous();handleArrow(navigator);},},},};} 3977onPropsUpdated(props){if(this.suggestions.length===0){this.suggestions=this.getSuggestions(props);} 3978this.updateStateValue(Time.from(props.value));} 3979getSuggestions(props){const suggestions=[];const rounding=props.minutesRounding<=5?15:props.minutesRounding;const minutes=MINUTES.filter((m)=>!(m%rounding));for(const hour of HOURS){for(const minute of minutes){suggestions.push(new Time({hour,minute}));}} 3980return suggestions;} 3981setValue(newValue,cleanValue=true){if(newValue&&cleanValue){if(this.props.minutesRounding>1){newValue.roundMinutes(this.props.minutesRounding);} 3982if(!this.props.showSeconds&&this.state.value){newValue.second=this.state.value.second;}} 3983const lastValue=this.lastValue;this.updateStateValue(newValue);if(newValue&&!newValue.equals(lastValue,this.props.showSeconds)){this.props.onChange(newValue.copy());}} 3984updateStateValue(newValue){if(newValue===this.lastValue||newValue?.equals(this.lastValue,this.props.showSeconds)){return;} 3985this.lastValue=newValue?.copy()??newValue;this.state.value=newValue;this.state.inputValue=newValue?newValue.toString(this.props.showSeconds):"";this.state.isValid=true;} 3986onItemSelected(value){this.setValue(value);this.close();} 3987onInput(event){this.ensureOpen();const value=parseTime(this.inputRef.el.value,this.props.showSeconds);this.state.isValid=value!==null;if(!this.navigator){return;} 3988let index=-1;if(this.state.isValid){index=this.suggestions.findIndex((s)=>s.equals(value));} 3989if(index===-1){this.navigator.activeItem?.setInactive();}else{this.navigator.items[index]?.setActive();}} 3990onChange(){const value=parseTime(this.inputRef.el.value,this.props.showSeconds);this.state.isValid=value!==null;if(this.state.isValid){this.setValue(value);this.close();}else{this.props.onInvalid();}} 3991onKeydown(event){this.isNavigating=["arrowup","arrowdown"].includes(getActiveHotkey(event));} 3992ensureOpen(){if(!this.dropdownState.isOpen){this.isNavigating=false;
3992this.dropdownState.open();this.inputRef.el.select();}} 3993close(){this.dropdownState.close();} 3994getPlaceholder(){if(typeof this.props.placeholder==="string"){return this.props.placeholder;} 3995const seconds=this.props.showSeconds?":ss":"";return`hh:mm${seconds}`;} 3996onDropdownOpened(){if(this.navigator){const index=this.state.value?this.suggestions.findIndex((s)=>s.equals(this.state.value,this.props.showSeconds)):0;this.navigator.items[index]?.setActive();}}} 3997return __exports;});; 3998 3999/* /web/static/src/core/tooltip/tooltip.js */ 4000odoo.define('@web/core/tooltip/tooltip',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const Tooltip=__exports.Tooltip=class Tooltip extends Component{static template="web.Tooltip";static props={close:Function,tooltip:{type:String,optional:true},template:{type:String,optional:true},info:{optional:true},};} 4001return __exports;});; 4002 4003/* /web/static/src/core/tooltip/tooltip_hook.js */ 4004odoo.define('@web/core/tooltip/tooltip_hook',['@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{useEffect,useRef}=require("@odoo/owl");__exports.useTooltip=useTooltip;function useTooltip(refName,params){const tooltip=useService("tooltip");const ref=useRef(refName);useEffect((el)=>tooltip.add(el,params),()=>[ref.el]);} 4005return __exports;});; 4006 4007/* /web/static/src/core/tooltip/tooltip_service.js */ 4008odoo.define('@web/core/tooltip/tooltip_service',['@web/core/browser/browser','@web/core/registry','@web/core/tooltip/tooltip','@web/core/browser/feature_detection','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Tooltip}=require("@web/core/tooltip/tooltip");const{hasTouch}=require("@web/core/browser/feature_detection");const{whenReady}=require("@odoo/owl");const OPEN_DELAY=__exports.OPEN_DELAY=400;const CLOSE_DELAY=__exports.CLOSE_DELAY=200;const SHOW_AFTER_DELAY=__exports.SHOW_AFTER_DELAY=250;const tooltipService=__exports.tooltipService={dependencies:["popover"],start(env,{popover}){let openTooltipTimeout;let closeTooltip;let showTimer;let target=null;const elementsWithTooltips=new WeakMap();function isHelpNode(el){return(el.textContent==="?"&&(el.hasAttribute("data-tooltip")||el.hasAttribute("data-tooltip-template")));} 4009function cleanup(){target=null;browser.clearTimeout(openTooltipTimeout);openTooltipTimeout=null;if(closeTooltip){closeTooltip();closeTooltip=null;}} 4010function shouldCleanup(){if(!target){return false;} 4011if(!document.body.contains(target)){return true;} 4012return false;} 4013function openTooltip(el,{tooltip="",template,info,position,delay=OPEN_DELAY}){cleanup();if(!tooltip&&!template){return;} 4014target=el;target.title="";const timeoutDelay=isHelpNode(el)?0:delay;openTooltipTimeout=browser.setTimeout(()=>{if(target.isConnected){closeTooltip=popover.add(target,Tooltip,{tooltip,template,info},{position});}},timeoutDelay);} 4015function openElementsTooltip(el){if(el.nodeType===Node.TEXT_NODE){return;} 4016const element=el.closest("[data-tooltip], [data-tooltip-template]");if(element&&element===target){return;} 4017if(elementsWithTooltips.has(el)){openTooltip(el,elementsWithTooltips.get(el));}else if(element){const dataset=element.dataset;const params={tooltip:dataset.tooltip,template:dataset.tooltipTemplate,position:dataset.tooltipPosition,};if(dataset.tooltipInfo){params.info=JSON.parse(dataset.tooltipInfo);} 4018if(dataset.tooltipDelay){params.delay=parseInt(dataset.tooltipDelay,10);} 4019openTooltip(element,params);}} 4020function onMouseenter(ev){openElementsTooltip(ev.target);} 4021function onClick(ev){if(isHelpNode(ev.target)){ev.preventDefault();} 4022cleanupTooltip(ev);} 4023function cleanupTooltip(ev){if(target==ev.target){cleanup();}} 4024function onTouchStart(ev){cleanup();const timeoutDelay=isHelpNode(ev.target)?0:SHOW_AFTER_DELAY;showTimer=browser.setTimeout(()=>{openElementsTooltip(ev.target);},timeoutDelay);} 4025whenReady(()=>{browser.setInterval(()=>{if(shouldCleanup()){cleanup();}},CLOSE_DELAY);if(hasTouch()){document.body.addEventListener("touchstart",onTouchStart);document.body.addEventListener("touchend",(ev)=>{if(isHelpNode(ev.target)){ev.preventDefault();return;} 4026if(ev.target.closest("[data-tooltip], [data-tooltip-template]")){if(!ev.target.dataset.tooltipTouchTapToShow){browser.clearTimeout(showTimer);browser.clearTimeout(openTooltipTimeout);}}});document.body.addEventListener("touchcancel",(ev)=>{if(isHelpNode(ev.target)){ev.preventDefault();return;} 4027if(ev.target.closest("[data-tooltip], [data-tooltip-template]")){if(!ev.target.dataset.tooltipTouchTapToShow){browser.clearTimeout(showTimer);browser.clearTimeout(openTooltipTimeout);}}});} 4028document.body.addEventListener("mouseenter",onMouseenter,{capture:true});document.body.addEventListener("mouseleave",cleanupTooltip,{capture:true});document.body.addEventListener("click",onClick,{capture:true});});return{add(el,params){elementsWithTooltips.set(el,params);return()=>{elementsWithTooltips.delete(el);if(target===el){cleanup();}};},};},};registry.category("services").add("tooltip",tooltipService);return __exports;});; 4029 4030/* /web/static/src/core/transition.js */ 4031odoo.define('@web/core/transition',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Component,onWillUpdateProps,status,useComponent,useEffect,useState,xml,}=require("@odoo/owl");const config=__exports.config={disabled:false,};__exports.useTransition=useTransition;function useTransition({name,initialVisibility=true,immediate=false,leaveDuration=500,onLeave=()=>{},}){const component=useComponent();const state=useState({shouldMount:initialVisibility,stage:initialVisibility?"enter":"leave",});if(config.disabled){return{get shouldMount(){return state.shouldMount;},set shouldMount(val){state.shouldMount=val;},get className(){return`${name} ${name}-enter-active`;},get stage(){return"enter-active";},};} 4032let onNextPatch=null;useEffect(()=>{if(onNextPatch){onNextPatch();onNextPatch=null;}});let prevState,timer;const transition={get shouldMount(){return state.shouldMount;},set shouldMount(newState){if(newState===prevState){return;} 4033browser.clearTimeout(timer);prevState=newState;if(newState){if(status(component)==="mounted"||immediate){state.stage="enter";component.render();onNextPatch=()=>{state.stage="enter-active";};}else{state.stage="enter-active";} 4034state.shouldMount=true;}else{state.stage="leave";timer=browser.setTimeout(()=>{state.shouldMount=false;onLeave();},leaveDuration);}},get className(){return`${name} ${name}-${state.stage}`;},get stage(){return state.stage;},};transition.shouldMount=initialVisibility;return transition;} 4035const Transition=__exports.Transition=class Transition extends Component{static template=xml`<t t-slot="default" t-if="transition.shouldMount" className="transition.className"/>`;static props={name:String,visible:{type:Boolean,optional:true},immediate:{type:Boolean,optional:true},leaveDuration:{type:Number,optional:true},onLeave:{type:Function,optional:true},slots:Object,};setup(){const{immediate,visible,leaveDuration,name,onLeave}=this.props;this.transition=useTransition({initialVisibility:visible,immediate,leaveDuration,name,onLeave,});onWillUpdateProps(({visible=true})=>{this.transition.shouldMount=visible;});}} 4036return __exports;});; 4037 4038/* /web/static/src/core/tree_editor/ast_utils.js */ 4039odoo.define('@web/core/tree_editor/ast_utils',['@web/core/tree_editor/operators'],function(require){'use strict';let __exports={};const{COMPARATORS,TERM_OPERATORS_NEGATION_EXTENDED}=require("@web/core/tree_editor/operators");__exports.isBool=isBool;function isBool(ast){return ast.type===8&&ast.fn.type===5&&ast.fn.value==="bool"&&ast.args.length===1;} 4040__exports.isNot=isNot;function isNot(ast){return ast.type===6&&ast.op==="not";} 4041__exports.not=not;function not(ast){if(isNot(ast)){return ast.right;} 4042if(ast.type===2){return{...ast,value:!ast.value};} 4043if(ast.type===7&&COMPARATORS.includes(ast.op)){return{...ast,op:TERM_OPERATORS_NEGATION_EXTENDED[ast.op]};}
4044return{type:6,op:"not",right:isBool(ast)?ast.args[0]:ast};} 4045__exports.isValidPath=isValidPath;function isValidPath(ast,options){const getFieldDef=options.getFieldDef||(()=>null);if(ast.type===5){return getFieldDef(ast.value)!==null;} 4046return false;} 4047return __exports;});; 4048 4049/* /web/static/src/core/tree_editor/condition_tree.js */ 4050odoo.define('@web/core/tree_editor/condition_tree',['@web/core/domain','@web/core/py_js/py','@web/core/py_js/py_utils'],function(require){'use strict';let __exports={};const{Domain}=require("@web/core/domain");const{formatAST,parseExpr}=require("@web/core/py_js/py");const{toPyValue}=require("@web/core/py_js/py_utils");const Expression=__exports.Expression=class Expression{constructor(ast){if(typeof ast==="string"){ast=parseExpr(ast);} 4051this._ast=ast;this._expr=formatAST(ast);} 4052toAST(){return this._ast;} 4053toString(){return this._expr;}} 4054__exports.expression=expression;function expression(expr){return new Expression(expr);} 4055__exports.connector=connector;function connector(value,children=[],negate=false){return{type:"connector",value,children,negate};} 4056__exports.complexCondition=complexCondition;function complexCondition(value){parseExpr(value);return{type:"complex_condition",value};} 4057__exports.condition=condition;function condition(path,operator,value,negate=false,isProperty=false){return{type:"condition",path,operator,value,negate,isProperty};} 4058const TRUE_TREE=__exports.TRUE_TREE=condition(1,"=",1);const FALSE_TREE=__exports.FALSE_TREE=condition(0,"=",1);function cloneValue(value){if(value instanceof Expression){return new Expression(value.toAST());} 4059if(Array.isArray(value)){return value.map(cloneValue);} 4060return value;} 4061__exports.cloneTree=cloneTree;function cloneTree(tree){const clone={};for(const key in tree){clone[key]=cloneValue(tree[key]);} 4062return clone;} 4063const areEqualValues=(value,otherValue)=>formatValue(value)===formatValue(otherValue);const areEqualArraysOfTrees=(array,otherArray)=>{if(array.length!==otherArray.length){return false;} 4064for(let i=0;i<array.length;i++){const elem=array[i];const otherElem=otherArray[i];if(!areEqualTrees(elem,otherElem)){return false;}} 4065return true;};const areEqualTrees=__exports.areEqualTrees=(tree,otherTree)=>{if(tree.type!==otherTree.type){return false;} 4066if(tree.negate!==otherTree.negate){return false;} 4067if(tree.type==="condition"){if(!areEqualValues(tree.path,otherTree.path)){return false;} 4068if(!areEqualValues(tree.operator,otherTree.operator)){return false;} 4069if(isTree(tree.value)){if(isTree(otherTree.value)){return areEqualTrees(tree.value,otherTree.value);} 4070return false;}else if(isTree(otherTree.value)){return false;} 4071if(!areEqualValues(tree.value,otherTree.value)){return false;} 4072return true;} 4073if(!areEqualValues(tree.value,otherTree.value)){return false;} 4074if(tree.type==="complex_condition"){return true;} 4075return areEqualArraysOfTrees(tree.children,otherTree.children);};__exports.toValue=toValue;function toValue(ast,isWithinArray=false){if([4,10].includes(ast.type)&&!isWithinArray){return ast.value.map((v)=>toValue(v,true));}else if([0,1,2].includes(ast.type)){return ast.value;}else if(ast.type===6&&ast.op==="-"&&ast.right.type===0){return-ast.right.value;}else if(ast.type===5&&["false","true"].includes(ast.value)){return JSON.parse(ast.value);}else{return new Expression(ast);}} 4076__exports.astFromValue=astFromValue;function astFromValue(value){if(value instanceof Expression){return value.toAST();} 4077if(Array.isArray(value)){return{type:4,value:value.map(astFromValue)};} 4078return toPyValue(value);} 4079__exports.formatValue=formatValue;function formatValue(value){return formatAST(astFromValue(value));} 4080__exports.normalizeValue=normalizeValue;function normalizeValue(value){return toValue(astFromValue(value));} 4081__exports.isTree=isTree;function isTree(value){return(typeof value==="object"&&!(value instanceof Domain)&&!(value instanceof Expression)&&!Array.isArray(value)&&value!==null);} 4082__exports.addChild=addChild;function addChild(parent,child){if(child.type==="connector"&&!child.negate&&child.value===parent.value){parent.children.push(...child.children);}else{parent.children.push(child);}} 4083__exports.applyTransformations=applyTransformations;function applyTransformations(transformations,transformed,...fixedParams){for(let i=transformations.length-1;i>=0;i--){const fn=transformations[i];transformed=fn(transformed,...fixedParams);} 4084return transformed;} 4085function normalizeConnector(connector){const newTree={...connector,children:[]};for(const child of connector.children){addChild(newTree,child);} 4086if(newTree.children.length===1){const child=newTree.children[0];if(newTree.negate){const newChild={...child,negate:!child.negate};if(newChild.type==="condition"){return newChild;} 4087return newChild;} 4088return child;} 4089return newTree;} 4090function makeOptions(path,options){return{...options,getFieldDef:(p)=>{if(typeof path==="string"&&typeof p==="string"){return options.getFieldDef?.(`${path}.${p}`)||null;} 4091return null;},};} 4092__exports.operate=operate;function operate(transformation,tree,options={},treeType="condition",traverseSubTrees=true){if(tree.type==="connector"){const newTree={...tree,children:tree.children.map((c)=>operate(transformation,c,options,treeType,traverseSubTrees)),};if(treeType==="connector"){return normalizeConnector(transformation(newTree,options)||newTree);} 4093return normalizeConnector(newTree);} 4094const clone=cloneTree(tree);if(traverseSubTrees&&tree.type==="condition"&&isTree(tree.value)){clone.value=operate(transformation,tree.value,makeOptions(tree.path,options),treeType,traverseSubTrees);} 4095if(treeType===tree.type){return transformation(clone,options)||clone;} 4096return clone;} 4097__exports.rewriteNConsecutiveChildren=rewriteNConsecutiveChildren;function rewriteNConsecutiveChildren(transformation,N=2){return(c,options)=>{const children=[];const currentChildren=c.children;for(let i=0;i<currentChildren.length;i++){const NconsecutiveChildren=currentChildren.slice(i,i+N);let replacement=null;if(NconsecutiveChildren.length===N){replacement=transformation(connector(c.value,NconsecutiveChildren),options);} 4098if(replacement){children.push(replacement);i+=N-1;}else{children.push(NconsecutiveChildren[0]);}} 4099return{...c,children};};} 4100return __exports;});; 4101 4102/* /web/static/src/core/tree_editor/construct_domain_from_tree.js */ 4103odoo.define('@web/core/tree_editor/construct_domain_from_tree',['@web/core/py_js/py','@web/core/tree_editor/ast_utils','@web/core/tree_editor/condition_tree'],function(require){'use strict';let __exports={};const{formatAST,parseExpr}=require("@web/core/py_js/py");const{isBool,isNot}=require("@web/core/tree_editor/ast_utils");const{astFromValue,condition,Expression,FALSE_TREE,isTree,TRUE_TREE,}=require("@web/core/tree_editor/condition_tree");function bool(ast){if(isBool(ast)||isNot(ast)||ast.type===2){return ast;} 4104return{type:8,fn:{type:5,value:"bool"},args:[ast],kwargs:{}};} 4105function getASTs(tree,isSubTree=false){const ASTs=[];if(tree.type==="condition"){if(tree.negate){ASTs.push(toAST("!"));} 4106ASTs.push({type:10,value:[tree.path,tree.operator,tree.value].map(toAST),});return ASTs;} 4107if(tree.type==="complex_condition"){const ast=parseExpr(tree.value);return getASTs(condition(new Expression(bool(ast)),"=",1));} 4108const length=tree.children.length;if(length===0){if(tree.value==="|"){return tree.negate?getASTs(TRUE_TREE):getASTs(FALSE_TREE);}else{return tree.negate?getASTs(FALSE_TREE):isSubTree?getASTs(TRUE_TREE):[];}} 4109if(tree.negate){ASTs.push(toAST("!"));} 4110for(let i=0;i<length-1;i++){ASTs.push(toAST(tree.value));} 4111for(const child of tree.children){ASTs.push(...getASTs(child,true));} 4112return ASTs;} 4113function toAST(value){if(isTree(value)){return{type:4,value:getASTs(value)};} 4114return astFromValue(value);} 4115__exports.constructDomainFromTree=constructDomainFromTree;function constructDomainFromTree(tree){return formatAST(toAST(tree));} 4116return __exports;});; 4117 4118/* /web/static/src/core/tree_editor/construct_expression_from_tree.js */ 4119odoo.define('@web/core/tree_editor/construct_expression_from_tree',['@web/core/py_js/py','@web/core/tree_editor/ast_utils','@web/core/tree_editor/condition_tree','@web/core/tree_editor/operators'],function(require){'use strict';let __exports={};const{formatAST}=require("@web/core/py_js/py");const{isValidPath,not}=require("@web/core/tree_editor/ast_utils");const{Expression,astFromValue,isTree}=require("@web/core/tree_editor/condition_tree");const{COMPARATORS,TERM_OPERATORS_NEGATION}=require("@web/core/tree_editor/operators");function getNormalizedCondition(condition){let{operator,negate}=condition;if(negate&&typeof operator==="string"&&TERM_OPERATORS_NEGATION[operator]){operator=TERM_OPERATORS_NEGATION[operator];negate=false;} 4120return{...condition,operator,negate};} 4121function isX2Many(ast,options){if(isValidPath(ast,options)){const fieldDef=options.getFieldDef(ast.value);return["many2many","one2many"].includes(fieldDef.type);} 4122return false;} 4123function _constructExpressionFromTree(tree,options,isRoot=false){if(tree.type==="connector"&&tree.value==="|"&&tree.children.length===2){const isSimpleAnd=(tree)=>tree.type==="connector"&&tree.value==="&"&&tree.children.length===2;if(tree.children.every((c)=>isSimpleAnd(c))){const[c1,c2]=tree.children;for(let i=0;i<2;i++){const c1Child=c1.children[i];const str1=_constructExpressionFromTree({...c1Child},options);for(let j=0;j<2;j++){const c2Child=c2.children[j];const str2=_constructExpressionFromTree(c2Child,options);if(str1===`not ${str2}`||`not ${str1}`===str2){const others=[c1.children[1-i],c2.children[1-j]];const str=_constructExpressionFromTree(c1Child,options);const strs=others.map((c)=>_constructExpressionFromTree(c,options));return`${strs[0]} if ${str} else ${strs[1]}`;}}}}} 4124if(tree.type==="connector"){const connector=tree.value==="&"?"and":"or";const subExpressions=tree.children.map((c)=>_constructExpressionFromTree(c,options));if(!subExpressions.length){return connector==="and"?"1":"0";} 4125let expression=subExpressions.join(` ${connector} `);if(!isRoot||tree.negate){expression=`( ${expression} )`;}
4126if(tree.negate){expression=`not ${expression}`;} 4127return expression;} 4128if(tree.type==="complex_condition"){return tree.value;} 4129tree=getNormalizedCondition(tree);const{path,operator,value}=tree;if(path instanceof Expression&&operator==="="&&value===1){return path.toString();} 4130const op=operator==="="?"==":operator;if(typeof op!=="string"||!COMPARATORS.includes(op)){throw new Error("Invalid operator");} 4131if([0,1].includes(path)){if(operator!=="="||value!==1){return new Error("Invalid condition");} 4132return formatAST({type:2,value:Boolean(path)});} 4133const pathAST=astFromValue(path);if(typeof path=="string"&&isValidPath({type:5,value:path},options)){pathAST.type=5;} 4134if(value===false&&["=","!="].includes(operator)){return formatAST(operator==="="?not(pathAST):pathAST);} 4135if(isTree(value)){throw new Error("Invalid value");} 4136let valueAST=astFromValue(value);if(["in","not in"].includes(operator)&&!(value instanceof Expression)&&![4,10].includes(valueAST.type)){valueAST={type:4,value:[valueAST]};} 4137if(pathAST.type===5&&isX2Many(pathAST,options)&&["in","not in"].includes(operator)){const ast={type:8,fn:{type:15,obj:{args:[pathAST],type:8,fn:{type:5,value:"set",},},key:"intersection",},args:[valueAST],};return formatAST(operator==="not in"?not(ast):ast);} 4138return formatAST({type:7,op,left:pathAST,right:valueAST,});} 4139__exports.constructExpressionFromTree=constructExpressionFromTree;function constructExpressionFromTree(tree,options={}){return _constructExpressionFromTree(tree,options,true);} 4140return __exports;});; 4141 4142/* /web/static/src/core/tree_editor/construct_tree_from_domain.js */ 4143odoo.define('@web/core/tree_editor/construct_tree_from_domain',['@web/core/domain','@web/core/py_js/py','@web/core/tree_editor/condition_tree'],function(require){'use strict';let __exports={};const{Domain}=require("@web/core/domain");const{formatAST}=require("@web/core/py_js/py");const{addChild,connector,toValue}=require("@web/core/tree_editor/condition_tree");function _constructTree(ASTs,distributeNot=false,negate=false){const[firstAST,...tailASTs]=ASTs;if(firstAST.type===1&&firstAST.value==="!"){return _constructTree(tailASTs,distributeNot,!negate);} 4144const tree={type:firstAST.type===1?"connector":"condition"};if(tree.type==="connector"){tree.value=firstAST.value;if(distributeNot&&negate){tree.value=tree.value==="&"?"|":"&";tree.negate=false;}else{tree.negate=negate;} 4145tree.children=[];}else{const[pathAST,operatorAST,valueAST]=firstAST.value;tree.path=toValue(pathAST);tree.negate=negate;tree.operator=toValue(operatorAST);tree.value=toValue(valueAST);tree.isProperty=false;if(["any","not any"].includes(tree.operator)){try{tree.value=constructTreeFromDomain(formatAST(valueAST),distributeNot);}catch{tree.value=Array.isArray(tree.value)?tree.value:[tree.value];}}} 4146let remaimingASTs=tailASTs;if(tree.type==="connector"){for(let i=0;i<2;i++){const{tree:child,remaimingASTs:otherASTs}=_constructTree(remaimingASTs,distributeNot,distributeNot&&negate);remaimingASTs=otherASTs;addChild(tree,child);}} 4147return{tree,remaimingASTs};} 4148__exports.constructTreeFromDomain=constructTreeFromDomain;function constructTreeFromDomain(domain,distributeNot=false){domain=new Domain(domain);const domainAST=domain.ast;const initialASTs=domainAST.value;if(!initialASTs.length){return connector("&");} 4149const{tree}=_constructTree(initialASTs,distributeNot);return tree;} 4150return __exports;});; 4151 4152/* /web/static/src/core/tree_editor/construct_tree_from_expression.js */ 4153odoo.define('@web/core/tree_editor/construct_tree_from_expression',['@web/core/py_js/py','@web/core/tree_editor/ast_utils','@web/core/tree_editor/condition_tree','@web/core/tree_editor/operators'],function(require){'use strict';let __exports={};const{formatAST,parseExpr}=require("@web/core/py_js/py");const{isNot,isValidPath,not}=require("@web/core/tree_editor/ast_utils");const{addChild,complexCondition,condition,connector,toValue}=require("@web/core/tree_editor/condition_tree");const{COMPARATORS}=require("@web/core/tree_editor/operators");const EXCHANGE={"<":">","<=":">=",">":"<",">=":"<=","=":"=","!=":"!=",};function or(left,right){return{type:14,op:"or",left,right};} 4154function and(left,right){return{type:14,op:"and",left,right};} 4155function isSet(ast){return ast.type===8&&ast.fn.type===5&&ast.fn.value==="set"&&ast.args.length<=1;} 4156function isValidPath2(ast,options){if(!ast){return null;} 4157if([4,10].includes(ast.type)&&ast.value.length===1){return isValidPath(ast.value[0],options);} 4158return isValidPath(ast,options);} 4159function _getConditionFromComparator(ast,options){if(["is","is not"].includes(ast.op)){return null;} 4160let operator=ast.op;if(operator==="=="){operator="=";} 4161let left=ast.left;let right=ast.right;if(isValidPath(left,options)==isValidPath(right,options)){return null;} 4162if(!isValidPath(left,options)){if(operator in EXCHANGE){const temp=left;
4162left=right;right=temp;operator=EXCHANGE[operator];}else{return null;}} 4163return condition(left.value,operator,toValue(right));} 4164function _getConditionFromIntersection(ast,options,negate=false){let left=ast.fn.obj.args[0];let right=ast.args[0];if(!left){return condition(negate?1:0,"=",1);} 4165if(isValidPath2(left,options)==isValidPath2(right,options)){return null;} 4166if(!isValidPath2(left,options)){const temp=left;left=right;right=temp;} 4167if([4,10].includes(left.type)&&left.value.length===1){left=left.value[0];} 4168if(!right){return condition(left.value,negate?"=":"!=",false);} 4169if(isSet(right)){if(!right.args[0]){right={type:4,value:[]};} 4170if([4,10].includes(right.args[0].type)){right=right.args[0];}} 4171if(![4,10].includes(right.type)){return null;} 4172return condition(left.value,negate?"not in":"in",toValue(right));} 4173function _leafFromAST(ast,options,negate=false){if(isNot(ast)){return _treeFromAST(ast.right,options,!negate);} 4174if(ast.type===5&&isValidPath(ast,options)){return condition(ast.value,negate?"=":"!=",false);} 4175const astValue=toValue(ast);if(["boolean","number","string"].includes(typeof astValue)){return condition(astValue?1:0,"=",1);} 4176if(ast.type===8&&ast.fn.type===15&&isSet(ast.fn.obj)&&ast.fn.key==="intersection"){const tree=_getConditionFromIntersection(ast,options,negate);if(tree){return tree;}} 4177if(ast.type===7&&COMPARATORS.includes(ast.op)){if(negate){return _leafFromAST(not(ast),options);} 4178const tree=_getConditionFromComparator(ast,options);if(tree){return tree;}} 4179return complexCondition(formatAST(negate?not(ast):ast));} 4180function _treeFromAST(ast,options,negate=false){if(isNot(ast)){return _treeFromAST(ast.right,options,!negate);} 4181if(ast.type===14){const tree=connector(ast.op==="and"?"&":"|");if(options.distributeNot&&negate){tree.value=tree.value==="&"?"|":"&";}else{tree.negate=negate;} 4182const subASTs=[ast.left,ast.right];for(const subAST of subASTs){const child=_treeFromAST(subAST,options,options.distributeNot&&negate);addChild(tree,child);} 4183return tree;} 4184if(ast.type===13){const newAST=or(and(ast.condition,ast.ifTrue),and(not(ast.condition),ast.ifFalse));return _treeFromAST(newAST,options,negate);} 4185return _leafFromAST(ast,options,negate);} 4186__exports.constructTreeFromExpression=constructTreeFromExpression;function constructTreeFromExpression(expression,options={}){const ast=parseExpr(expression);return _treeFromAST(ast,options);} 4187return __exports;});; 4188 4189/* /web/static/src/core/tree_editor/domain_contains_expressions.js */ 4190odoo.define('@web/core/tree_editor/domain_contains_expressions',['@web/core/tree_editor/condition_tree','@web/core/tree_editor/construct_tree_from_domain'],function(require){'use strict';let __exports={};const{Expression,isTree}=require("@web/core/tree_editor/condition_tree");const{constructTreeFromDomain}=require("@web/core/tree_editor/construct_tree_from_domain");function treeContainsExpressions(tree){if(tree.type==="condition"){const{path,operator,value}=tree;if(isTree(value)&&treeContainsExpressions(value)){return true;} 4191return[path,operator,value].some((v)=>v instanceof Expression||(Array.isArray(v)&&v.some((w)=>w instanceof Expression)));} 4192for(const child of tree.children){if(treeContainsExpressions(child)){return true;}} 4193return false;} 4194__exports.domainContainsExpressions=domainContainsExpressions;function domainContainsExpressions(domain){let tree;try{tree=constructTreeFromDomain(domain);}catch{return null;} 4195return treeContainsExpressions(tree);} 4196return __exports;});; 4197 4198/* /web/static/src/core/tree_editor/domain_from_tree.js */ 4199odoo.define('@web/core/tree_editor/domain_from_tree',['@web/core/tree_editor/construct_domain_from_tree','@web/core/tree_editor/virtual_operators'],function(require){'use strict';let __exports={};const{constructDomainFromTree}=require("@web/core/tree_editor/construct_domain_from_tree");const{eliminateVirtualOperators}=require("@web/core/tree_editor/virtual_operators");__exports.domainFromTree=domainFromTree;function domainFromTree(tree){const simplifiedTree=eliminateVirtualOperators(tree);return constructDomainFromTree(simplifiedTree);} 4200return __exports;});; 4201 4202/* /web/static/src/core/tree_editor/expression_from_tree.js */ 4203odoo.define('@web/core/tree_editor/expression_from_tree',['@web/core/tree_editor/construct_expression_from_tree','@web/core/tree_editor/virtual_operators'],function(require){'use strict';let __exports={};const{constructExpressionFromTree}=require("@web/core/tree_editor/construct_expression_from_tree");const{eliminateVirtualOperators}=require("@web/core/tree_editor/virtual_operators");__exports.expressionFromTree=expressionFromTree;function expressionFromTree(tree,options={}){const simplifiedTree=eliminateVirtualOperators(tree,options);return constructExpressionFromTree(simplifiedTree,options);} 4204return __exports;});; 4205 4206/* /web/static/src/core/tree_editor/operators.js */ 4207odoo.define('@web/core/tree_editor/operators',[],function(require){'use strict';let __exports={};const TERM_OPERATORS_NEGATION=__exports.TERM_OPERATORS_NEGATION={"<":">=",">":"<=","<=":">",">=":"<","=":"!=","!=":"=",in:"not in",like:"not like",ilike:"not ilike","not in":"in","not like":"like","not ilike":"ilike",};const TERM_OPERATORS_NEGATION_EXTENDED=__exports.TERM_OPERATORS_NEGATION_EXTENDED={...TERM_OPERATORS_NEGATION,is:"is not","is not":"is","==":"!=","!=":"==",};const COMPARATORS=__exports.COMPARATORS=["<","<=",">",">=","in","not in","==","is","!=","is not"];return __exports;});; 4208 4209/* /web/static/src/core/tree_editor/tree_editor.js */ 4210odoo.define('@web/core/tree_editor/tree_editor',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/tree_editor/condition_tree','@web/core/tree_editor/tree_editor_value_editors','@web/core/tree_editor/utils','@web/core/tree_editor/virtual_operators','@web/core/utils/hooks','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{cloneTree,connector,isTree,TRUE_TREE}=require("@web/core/tree_editor/condition_tree");const{getDefaultValue,getValueEditorInfo,}=require("@web/core/tree_editor/tree_editor_value_editors");const{getResModel}=require("@web/core/tree_editor/utils");const{areEquivalentTrees}=require("@web/core/tree_editor/virtual_operators");const{useService}=require("@web/core/utils/hooks");const{shallowEqual}=require("@web/core/utils/objects");const TreeEditor=__exports.TreeEditor=class TreeEditor extends Component{static template="web.TreeEditor";static components={Dropdown,DropdownItem,TreeEditor,};static props={tree:Object,resModel:String,update:Function,getDefaultCondition:Function,getPathEditorInfo:Function,getOperatorEditorInfo:Function,getDefaultOperator:Function,readonly:{type:Boolean,optional:true},slots:{type:Object,optional:true},isDebugMode:{type:Boolean,optional:true},defaultConnector:{type:[{value:"&"},{value:"|"}],optional:true},isSubTree:{type:Boolean,optional:true},};static defaultProps={defaultConnector:"&",readonly:false,isSubTree:false,};setup(){this.isTree=isTree;this.fieldService=useService("field");this.treeProcessor=useService("tree_processor");onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));} 4211async onPropsUpdated(props){if(this.tree){this.previousTree=this.tree;} 4212this.tree=cloneTree(props.tree);if(shallowEqual(this.tree,TRUE_TREE)){this.tree=connector(props.defaultConnector);}else if(this.tree.type!=="connector"){this.tree=connector(props.defaultConnector,[this.tree]);} 4213if(this.previousTree&&areEquivalentTrees(this.tree,this.previousTree)){this.tree=this.previousTree;this.previousTree=null;} 4214await this.prepareInfo(props);} 4215async prepareInfo(props){const[fieldDefs,getFieldDef]=await Promise.all([this.fieldService.loadFields(props.resModel),this.treeProcessor.makeGetFieldDef(props.resModel,this.tree),]);this.getFieldDef=getFieldDef;this.defaultCondition=props.getDefaultCondition(fieldDefs);if(props.readonly){this.getConditionDescription=await this.treeProcessor.makeGetConditionDescription(props.resModel,this.tree);}} 4216get className(){return`${this.props.readonly ? "o_read_mode" : "o_edit_mode"}`;} 4217get isDebugMode(){return this.props.isDebugMode!==undefined?this.props.isDebugMode:!!this.env.debug;} 4218notifyChanges(){this.props.update(this.tree);} 4219_updateConnector(node){node.value=node.value==="&"?"|":"&";node.negate=false;} 4220updateConnector(node){this.updateNode(node,()=>this._updateConnector(node));} 4221_updateComplexCondition(node,value){node.value=value;} 4222updateComplexCondition(node,value){this.updateNode(node,()=>this._updateComplexCondition(node,value));} 4223makeCondition(parent,condition){condition||=parent.children.findLast((c)=>c.type==="condition");return cloneTree(condition||this.defaultCondition);}
4224_addNewCondition(parent,node){if(node){const index=parent.children.indexOf(node);parent.children.splice(index+1,0,this.makeCondition(parent,node));}else{parent.children.push(this.makeCondition(parent));}} 4225addNewCondition(parent,node){this.updateNode(parent,()=>this._addNewCondition(parent,node));} 4226_addNewConnector(parent,node){const index=parent.children.indexOf(node);const nextConnector=parent.value==="&"?"|":"&";parent.children.splice(index+1,0,connector(nextConnector,[this.makeCondition(parent,node)]));} 4227addNewConnector(parent,node){this.updateNode(parent,()=>this._addNewConnector(parent,node));} 4228_delete(ancestors,node){if(ancestors.length===0){return;} 4229const parent=ancestors.at(-1);const index=parent.children.indexOf(node);parent.children.splice(index,1);ancestors=ancestors.slice(0,ancestors.length-1);if(parent.children.length===0){this._delete(ancestors,parent);}} 4230delete(ancestors,node){const upperNode=ancestors[0]||node;this.updateNode(upperNode,()=>this._delete(ancestors,node));} 4231getResModel(node){const fieldDef=this.getFieldDef(node.path);const resModel=getResModel(fieldDef);return resModel;} 4232getPathEditorInfo(){return this.props.getPathEditorInfo(this.props.resModel,this.defaultCondition);} 4233getOperatorEditorInfo(node){const fieldDef=this.getFieldDef(node.path);return this.props.getOperatorEditorInfo(fieldDef);} 4234getValueEditorInfo(node){const fieldDef=this.getFieldDef(node.path);return getValueEditorInfo(fieldDef,node.operator);} 4235async _updatePath(node,path){const{fieldDef}=await this.fieldService.loadFieldInfo(this.props.resModel,path);node.path=path;node.negate=false;node.operator=this.props.getDefaultOperator(fieldDef);node.value=getDefaultValue(fieldDef,node.operator);node.isProperty=fieldDef?.is_property;} 4236async updatePath(node,path){this.updateNode(node,()=>this._updatePath(node,path));} 4237_updateLeafOperator(node,operator,negate){const fieldDef=this.getFieldDef(node.path);node.negate=negate;node.operator=operator;node.value=getDefaultValue(fieldDef,operator,node.value);} 4238updateLeafOperator(node,operator,negate){this.updateNode(node,()=>this._updateLeafOperator(node,operator,negate));} 4239_updateLeafValue(node,value){node.value=value;} 4240updateLeafValue(node,value){this.updateNode(node,()=>this._updateLeafValue(node,value));} 4241async updateNode(node,operation){const previousNode=cloneTree(node);await operation();if(areEquivalentTrees(node,previousNode)){await this.prepareInfo(this.props);this.render();} 4242this.notifyChanges();} 4243highlightNode(target){const nodeEl=target.closest(".o_tree_editor_node");nodeEl.classList.toggle("o_hovered_button");}} 4244return __exports;});; 4245 4246/* /web/static/src/core/tree_editor/tree_editor_autocomplete.js */ 4247odoo.define('@web/core/tree_editor/tree_editor_autocomplete',['@web/core/l10n/translation','@web/core/py_js/py_utils','@web/core/record_selectors/multi_record_selector','@web/core/record_selectors/record_selector','@web/core/tree_editor/condition_tree','@web/core/tree_editor/utils','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{formatAST,toPyValue}=require("@web/core/py_js/py_utils");const{MultiRecordSelector}=require("@web/core/record_selectors/multi_record_selector");const{RecordSelector}=require("@web/core/record_selectors/record_selector");const{Expression}=require("@web/core/tree_editor/condition_tree");const{isId}=require("@web/core/tree_editor/utils");const{imageUrl}=require("@web/core/utils/urls");const getFormat=__exports.getFormat=(val,displayNames)=>{let text;let colorIndex;if(isId(val)){text=typeof displayNames[val]==="string"?displayNames[val]:_t("Inaccessible/missing record ID: %s",val);colorIndex=typeof displayNames[val]==="string"?0:2;}else{text=val instanceof Expression?String(val):_t("Invalid record ID: %s",formatAST(toPyValue(val)));colorIndex=val instanceof Expression?2:1;} 4248return{text,colorIndex};};const DomainSelectorAutocomplete=__exports.DomainSelectorAutocomplete=class DomainSelectorAutocomplete extends MultiRecordSelector{static props={...MultiRecordSelector.props,resIds:true,};getIds(props=this.props){return props.resIds.filter((val)=>isId(val));} 4249getTags(props,displayNames){return props.resIds.map((val,index)=>{const{text,colorIndex}=getFormat(val,displayNames);return{text,colorIndex,onDelete:()=>{this.props.update([...this.props.resIds.slice(0,index),...this.props.resIds.slice(index+1),]);},img:this.isAvatarModel&&isId(val)&&imageUrl(this.props.resModel,val,"avatar_128"),};});}} 4250const DomainSelectorSingleAutocomplete=__exports.DomainSelectorSingleAutocomplete=class DomainSelectorSingleAutocomplete extends RecordSelector{static props={...RecordSelector.props,resId:true,};getDisplayName(props=this.props,displayNames){const{resId}=props;if(resId===false){return"";} 4251const{text}=getFormat(resId,displayNames);return text;} 4252getIds(props=this.props){if(isId(props.resId)){return[props.resId];} 4253return[];}} 4254return __exports;});; 4255 4256/* /web/static/src/core/tree_editor/tree_editor_components.js */ 4257odoo.define('@web/core/tree_editor/tree_editor_components',['@odoo/owl','@web/core/tags_list/tags_list','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{TagsList}=require("@web/core/tags_list/tags_list");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const Input=__exports.Input=class Input extends Component{static props=["value","update","placeholder?","startEmpty?"];static template="web.TreeEditor.Input";} 4258const Select=__exports.Select=class Select extends Component{static props=["value","update","o
4258ptions","placeholder?","addBlankOption?"];static template="web.TreeEditor.Select";deserialize(value){return JSON.parse(value);} 4259serialize(value){return JSON.stringify(value);}} 4260const Range=__exports.Range=class Range extends Component{static props=["value","update","editorInfo"];static template="web.TreeEditor.Range";update(index,newValue){const result=[...this.props.value];result[index]=newValue;return this.props.update(result);}} 4261const InRange=__exports.InRange=class InRange extends Component{static props=["value","update","valueTypeEditorInfo","betweenEditorInfo"];static template="web.TreeEditor.InRange";static options=[["today",_t("Today")],["last 7 days",_t("Last 7 days")],["last 30 days",_t("Last 30 days")],["month to date",_t("Month to date")],["last month",_t("Last month")],["year to date",_t("Year to date")],["last 12 months",_t("Last 12 months")],["custom range",_t("Custom range")],];updateValueType(newValueType){const[fieldType,currentValueType]=this.props.value;if(currentValueType!==newValueType){const values=newValueType==="custom range"?this.props.betweenEditorInfo.defaultValue():[false,false];return this.props.update([fieldType,newValueType,...values]);}} 4262updateValues(values){const[fieldType,currentValueType]=this.props.value;return this.props.update([fieldType,currentValueType,...values]);}} 4263const List=__exports.List=class List extends Component{static components={TagsList};static props=["value","update","editorInfo"];static template="web.TreeEditor.List";get tags(){const{isSupported,stringify}=this.props.editorInfo;return this.props.value.map((val,index)=>({text:stringify(val),colorIndex:isSupported(val)?0:2,onDelete:()=>{this.props.update([...this.props.value.slice(0,index),...this.props.value.slice(index+1),]);},}));}
4264update(newValue){return this.props.update([...this.props.value,newValue]);}} 4265return __exports;});; 4266 4267/* /web/static/src/core/tree_editor/tree_editor_operator_editor.js */ 4268odoo.define('@web/core/tree_editor/tree_editor_operator_editor',['@web/core/l10n/translation','@web/core/py_js/py','@web/core/tree_editor/condition_tree','@web/core/tree_editor/tree_editor_components'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{parseExpr}=require("@web/core/py_js/py");const{formatValue,toValue}=require("@web/core/tree_editor/condition_tree");const{Select}=require("@web/core/tree_editor/tree_editor_components");const OPERATOR_DESCRIPTIONS={"=":(fieldDefType)=>{switch(fieldDefType){case"many2one":case"many2many":case"one2many":return _t("=");default:return _t("is equal to");}},"!=":(fieldDefType)=>{switch(fieldDefType){case"many2one":case"many2many":case"one2many":return _t("!=");default:return _t("is not equal to");}},"<=":_t("lower or equal to"),"<":(fieldDefType)=>{switch(fieldDefType){case"date":case"datetime":return _t("before");default:return _t("lower than");}},">":(fieldDefType)=>{switch(fieldDefType){case"date":case"datetime":return _t("after");default:return _t("greater than");}},">=":_t("greater or equal to"),"=?":"=?","=like":_t("=like"),"=ilike":_t("=ilike"),like:_t("like"),"not like":_t("not like"),ilike:_t("contains"),"not ilike":_t("does not contain"),in:(fieldDefType)=>{switch(fieldDefType){case"many2one":case"many2many":case"one2many":return _t("is equal to");default:return _t("is in");}},"not in":(fieldDefType)=>{switch(fieldDefType){case"many2one":case"many2many":case"one2many":return _t("is not equal to");default:return _t("is not in");}},child_of:_t("child of"),parent_of:_t("parent of"),any:(fieldDefType)=>{switch(fieldDefType){case"many2one":return _t("matches");default:return _t("match");}},"not any":(fieldDefType)=>{switch(fieldDefType){case"many2one":return _t("matches none of");default:return _t("match none of");}},set:_t("is set"),"not set":_t("is not set"),"starts with":_t("starts with"),between:_t("between"),"in range":_t("is in"),};function toKey(operator,negate=false){if(!negate&&typeof operator==="string"&&operator in OPERATOR_DESCRIPTIONS){return operator;} 4269return JSON.stringify([formatValue(operator),negate]);} 4270function toOperator(key){if(!key.includes("[")){return[key,false];} 4271const[expr,negate]=JSON.parse(key);return[toValue(parseExpr(expr)),negate];} 4272function getOperatorDescription(operator,fieldDefType){const description=OPERATOR_DESCRIPTIONS[operator];if(typeof description==="function"&&description.constructor?.name!=="LazyTranslatedString"){return description(fieldDefType);} 4273return description;} 4274__exports.getOperatorLabel=getOperatorLabel;function getOperatorLabel(operator,fieldDefType,negate=false,getDescr=(operator,fieldDefType)=>null){let label;if(typeof operator==="string"&&operator in OPERATOR_DESCRIPTIONS){label=getDescr(operator,fieldDefType)||getOperatorDescription(operator,fieldDefType);}else{label=formatValue(operator);} 4275if(negate){return _t(`not %(operator_label)s`,{operator_label:label});} 4276return label;} 4277function getOperatorInfo(operator,fieldDefType,negate=false){const key=toKey(operator,negate);const label=getOperatorLabel(operator,fieldDefType,negate);return[key,label];} 4278__exports.getOperatorEditorInfo=getOperatorEditorInfo;function getOperatorEditorInfo(operators,fieldDef){const defaultOperator=operators[0];const operatorsInfo=operators.map((operator)=>getOperatorInfo(operator,fieldDef?.type));return{component:Select,extractProps:({update,value:[operator,negate]})=>{const[operatorKey,operatorLabel]=getOperatorInfo(operator,fieldDef?.type,negate);const options=[...operatorsInfo];if(!options.some(([key])=>key===operatorKey)){options.push([operatorKey,operatorLabel]);} 4279return{value:operatorKey,update:(operatorKey)=>update(...toOperator(operatorKey)),options,};},defaultValue:()=>defaultOperator,isSupported:([operator])=>typeof operator==="string"&&operator in OPERATOR_DESCRIPTIONS,message:_t("Operator not supported"),stringify:([operator,negate])=>getOperatorLabel(operator,fieldDef?.type,negate),};} 4280return __exports;});; 4281 4282/* /web/static/src/core/tree_editor/tree_editor_value_editors.js */ 4283odoo.define('@web/core/tree_editor/tree_editor_value_editors',['@web/core/datetime/datetime_input','@web/core/domain','@web/core/l10n/dates','@web/core/l10n/translation','@web/core/registry','@web/core/tree_editor/condition_tree','@web/core/tree_editor/tree_editor_autocomplete','@web/core/tree_editor/tree_editor_components','@web/core/tree_editor/utils','@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{DateTimeInput}=require("@web/core/datetime/datetime_input");const{Domain}=require("@web/core/domain");const{deserializeDate,deserializeDateTime,serializeDate,serializeDateTime,}=require("@web/core/l10n/dates");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{connector,formatValue,isTree}=require("@web/core/tree_editor/condition_tree");const{DomainSelectorAutocomplete,DomainSelectorSingleAutocomplete,}=require("@web/core/tree_editor/tree_editor_autocomplete");const{Input,InRange,List,Range,Select}=require("@web/core/tree_editor/tree_editor_components");const{disambiguate,getResModel,isId}=require("@web/core/tree_editor/utils");const{unique}=require("@web/core/utils/arrays");const{DateTime}=luxon;const formatters=registry.category("formatters");const parsers=registry.category("parsers");function parseValue(fieldType,value){const parser=parsers.get(fieldType,(value)=>value);try{return parser(value);}catch{return value;}} 4284function isParsable(fieldType,value){const parser=parsers.get(fieldType,(value)=>value);try{parser(value);}catch{return false;} 4285return true;} 4286function genericSerializeDate(type,value){return type==="date"?serializeDate(value):serializeDateTime(value);} 4287function genericDeserializeDate(type,value){return type==="date"?deserializeDate(value):deserializeDateTime(value);} 4288function placeholderForSelect(displayPlaceholder){if(displayPlaceholder){return _t(`Select one or several criteria`);}} 4289function placeholderForInput(displayPlaceholder){if(displayPlaceholder){return _t(`Press "Enter" to add criterion`);}} 4290const STRING_EDITOR={component:Input,extractProps:({value,update,displayPlaceholder})=>({value,update,placeholder:placeholderForInput(displayPlaceholder),}),isSupported:(value)=>typeof value==="string",defaultValue:()=>"",};function makeSelectEditor(options,params={}){const getOption=(value)=>options.find(([v])=>v===value)||null;return{component:Select,extractProps:({value,update,displayPlaceholder})=>({value,update,options,addBlankOption:params.addBlankOption,placeholder:placeholderForSelect(displayPlaceholder),}),isSupported:(value)=>Boolean(getOption(value)),defaultValue:()=>
4290options[0]?.[0]??false,stringify:(value,disambiguate)=>{const option=getOption(value);return option?option[1]:disambiguate?formatValue(value):String(value);},message:_t("Value not in selection"),};} 4291function getDomain(fieldDef){if(fieldDef.type==="many2one"){return[];} 4292try{return new Domain(fieldDef.domain||[]).toList();}catch{return[];}} 4293function makeAutoCompleteEditor(fieldDef){return{component:DomainSelectorAutocomplete,extractProps:({value,update})=>({resModel:getResModel(fieldDef),fieldString:fieldDef.string,domain:getDomain(fieldDef),update:(value)=>update(unique(value)),resIds:unique(value),placeholder:placeholderForSelect(true),}),isSupported:(value)=>Array.isArray(value),defaultValue:()=>[],};} 4294function isLitteralObject(value){return typeof value==="object"&&!Array.isArray(value)&&value!==null;} 4295function getPartialValueEditorInfo(fieldDef,operator,params={}){switch(operator){case"set":case"not set":return{component:null,extractProps:null,isSupported:(value)=>value===false||(fieldDef.type==="boolean"&&value===true),defaultValue:()=>false,};case"=like":case"=ilike":case"like":case"not like":case"ilike":case"not ilike":return STRING_EDITOR;case"between":{const editorInfo=getValueEditorInfo(fieldDef,"=",params);const{defaultValue}=getValueEditorInfo(fieldDef,"=",{...params,forBetween:true,});return{component:Range,extractProps:({value,update})=>({value,update,editorInfo,}),isSupported:(value)=>Array.isArray(value)&&value.length===2,defaultValue:()=>{const value=defaultValue();return isLitteralObject(value)?[value.start,value.end]:[value,value];},shouldResetValue:(value)=>!editorInfo.isSupported(value[0])||!editorInfo.isSupported(value[1]),};} 4296case"in range":{return{component:InRange,extractProps:({value,update})=>({value,update,valueTypeEditorInfo:makeSelectEditor(InRange.options,params),betweenEditorInfo:getValueEditorInfo(fieldDef,"between",params),}),isSupported:(value)=>Array.isArray(value)&&value.length===4&&value[0]===fieldDef.type&&InRange.options.some(([t])=>t===value[1]),defaultValue:()=>[fieldDef.type,"today",false,false],};} 4297case"in":case"not in":{switch(fieldDef.type){case"tags":return STRING_EDITOR;case"many2one":case"many2many":case"one2many":return makeAutoCompleteEditor(fieldDef);default:{const editorInfo=getValueEditorInfo(fieldDef,"=",{...params,addBlankOption:true,startEmpty:true,});return{component:List,extractProps:({value,update})=>{if(!disambiguate(value)){const{stringify}=editorInfo;editorInfo.stringify=(val)=>stringify(val,false);} 4298return{value,update,editorInfo,};},isSupported:(value)=>Array.isArray(value),defaultValue:()=>[],shouldResetValue:(value)=>!value.every(editorInfo.isSupported),};}}} 4299case"any":case"not any":{switch(fieldDef.type){case"many2one":case"many2many":case"one2many":{return{component:null,extractProps:null,isSupported:isTree,defaultValue:()=>connector("&"),};}}}} 4300const{type}=fieldDef;switch(type){case"integer":case"float":case"monetary":{const formatType=type==="integer"?"integer":"float";const typeFormatter=formatters.get(formatType,null);const formatter=(value)=>{let v=value;if(typeFormatter){try{v=typeFormatter(value);}catch{}} 4301return String(v);};return{component:Input,extractProps:({value,update,displayPlaceholder})=>({value:formatter(value),update:(value)=>update(parseValue(formatType,value)),startEmpty:params.startEmpty,placeholder:placeholderForInput(displayPlaceholder),}),isSupported:()=>true,defaultValue:()=>1,shouldResetValue:(value)=>parseValue(formatType,value)===value,};} 4302case"date":case"datetime":return{component:DateTimeInput,extractProps:({value,update,displayPlaceholder})=>({value:params.startEmpty||value===false?false:genericDeserializeDate(type,value),type,onApply:(value)=>{if(!params.startEmpty||value){update(genericSerializeDate(type,value||DateTime.local().startOf("day")));}},placeholder:placeholderForSelect(displayPlaceholder),}),isSupported:(value)=>typeof value==="string"&&isParsable(type,value),defaultValue:(operator)=>{const datetime=DateTime.local();if(operator===">"){return genericSerializeDate(type,datetime.endOf("day"));} 4303const start=genericSerializeDate(type,datetime.startOf("day"));if(params.forBetween){return{start,end:genericSerializeDate(type,datetime.endOf("day"))};} 4304return start;},shouldResetValue:()=>true,stringify:(value)=>{if(value===false){return _t("False");} 4305if(typeof value==="string"&&isParsable(type,value)){const formatter=formatters.get(type,formatValue);return formatter(genericDeserializeDate(type,value));} 4306return formatValue(value);},message:_t("Not a valid %s",type),};case"char":case"html":case"text":return STRING_EDITOR;case"many2one":{if(["=","!="].includes(operator)){return{component:DomainSelectorSingleAutocomplete,extractProps:({value,update})=>({resModel:getResModel(fieldDef),fieldString:fieldDef.string,update,resId:value,}),isSupported:()=>true,defaultValue:()=>false,shouldResetValue:(value)=>value!==false&&!isId(value),};}else if(["parent_of","child_of"].includes(operator)){return makeAutoCompleteEditor(fieldDef);} 4307break;} 4308case"many2many":case"one2many":if(["=","!="].includes(operator)){return makeAutoCompleteEditor(fieldDef);} 4309break;case"selection":{const options=fieldDef.selection||[];return makeSelectEditor(options,params);} 4310case undefined:{const options=[[1,"1"]];return makeSelectEditor(options,params);}} 4311return{component:Input,extractProps:({value,update})=>({value:String(value),update,}),isSupported:()=>true,defaultValue:()=>"",};} 4312__exports.getValueEditorInfo=getValueEditorInfo;function getValueEditorInfo(fieldDef,operator,options={}){const info=getPartialValueEditorInfo(fieldDef||{},operator,options);return{extractProps:({value,update})=>({value,update}),message:_t("Value not supported"),stringify:(val,disambiguate=true)=>{if(disambiguate){return formatValue(val);} 4313return String(val);},...info,};} 4314__exports.getDefaultValue=getDefaultValue;function getDefaultValue(fieldDef,operator,value=null){const{isSupported,shouldResetValue,defaultValue}=getValueEditorInfo(fieldDef,operator);if(value===null||!isSupported(value)||shouldResetValue?.(value)){return defaultValue(operator);} 4315return value;} 4316return __exports;});; 4317 4318/* /web/static/src/core/tree_editor/tree_from_domain.js */ 4319odoo.define('@web/core/tree_editor/tree_from_domain',['@web/core/tree_editor/construct_tree_from_domain','@web/core/tree_editor/virtual_operators'],function(require){'use strict';let __exports={};const{constructTreeFromDomain}=require("@web/core/tree_editor/construct_tree_from_domain");const{introduceVirtualOperators}=require("@web/core/tree_editor/virtual_operators");__exports.treeFromDomain=treeFromDomain;function treeFromDomain(domain,options={}){const tree=constructTreeFromDomain(domain,options.distributeNot);return introduceVirtualOperators(tree,options);} 4320return __exports;});; 4321 4322/* /web/static/src/core/tree_editor/tree_from_expression.js */ 4323odoo.define('@web/core/tree_editor/tree_from_expression',['@web/core/tree_editor/construct_tree_from_expression','@web/core/tree_editor/virtual_operators'],function(require){'use strict';let __exports={};const{constructTreeFromExpression}=require("@web/core/tree_editor/construct_tree_from_expression");const{introduceVirtualOperators}=require("@web/core/tree_editor/virtual_operators");__exports.treeFromExpression=treeFromExpression;function treeFromExpression(expression,options={}){const tree=constructTreeFromExpression(expression,options);return introduceVirtualOperators(tree,options);} 4324return __exports;});; 4325 4326/* /web/static/src/core/tree_editor/tree_processor.js */ 4327odoo.define('@web/core/tree_editor/tree_processor',['@web/core/l10n/dates','@web/core/l10n/translation','@web/core/registry','@web/core/tree_editor/tree_editor_operator_editor','@web/core/utils/arrays','@web/core/tree_editor/condition_tree','@web/core/tree_editor/construct_tree_from_domain','@web/core/tree_editor/utils','@web/core/tree_editor/virtual_operators','@web/core/tree_editor/tree_editor_components'],function(require){'use strict';let __exports={};const{deserializeDate,deserializeDateTime,formatDate,formatDateTime,}=require("@web/core/l10n/dates");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{getOperatorLabel}=require("@web/core/tree_editor/tree_editor_operator_editor");const{unique,zip}=require("@web/core/utils/arrays");const{condition,Expression,isTree,normalizeValue}=require("@web/core/tree_editor/condition_tree");const{constructTreeFromDomain}=require("@web/core/tree_editor/construct_tree_from_domain");const{disambiguate,getResModel,isId}=require("@web/core/tree_editor/utils");const{introduceVirtualOperators}=require("@web/core/tree_editor/virtual_operators");const{InRange}=require("@web/core/tree_editor/tree_editor_components");
4327function formatValue(val,disambiguate,fieldDef,displayNames){if(val instanceof Expression){return val.toString();} 4328if(displayNames&&isId(val)){if(typeof displayNames[val]==="string"){val=displayNames[val];}else{return _t("Inaccessible/missing record ID: %s",val);}} 4329if(fieldDef?.type==="selection"){const[,label]=(fieldDef.selection||[]).find(([v])=>v===val)||[];if(label!==undefined){val=label;}} 4330if(typeof val==="string"){if(fieldDef?.type==="datetime"){return formatDateTime(deserializeDateTime(val));} 4331if(fieldDef?.type==="date"){return formatDate(deserializeDate(val));}} 4332if(disambiguate&&typeof val==="string"){return JSON.stringify(val);} 4333return val;} 4334function getPathsInTree(tree,lookInSubTrees=false){const paths=[];if(tree.type==="condition"){paths.push(tree.path);if(typeof tree.path==="string"&&lookInSubTrees&&isTree(tree.value)){const subTreePaths=getPathsInTree(tree.value,lookInSubTrees);for(const p of subTreePaths){if(typeof p==="string"){paths.push(`${tree.path}.${p}`);}}}} 4335if(tree.type==="connector"&&tree.children){for(const child of tree.children){paths.push(...getPathsInTree(child,lookInSubTrees));}} 4336return unique(paths);} 4337function simplifyTree(tree){if(tree.type==="condition"){return tree;} 4338const processedChildren=tree.children.map(simplifyTree);if(tree.value==="&"){return{...tree,children:processedChildren};} 4339const children=[];const childrenByPath={};for(let index=0;index<processedChildren.length;index++){const child=processedChildren[index];if(child.type==="connector"||typeof child.path!=="string"||!["=","in"].includes(child.operator)){children.push(child);}else{if(!childrenByPath[child.path]){childrenByPath[child.path]={elems:[],index};children.push(child);} 4340childrenByPath[child.path].elems.push(child);}}
4341for(const path in childrenByPath){if(childrenByPath[path].elems.length===1){continue;} 4342const value=[];for(const child of childrenByPath[path].elems){if(child.operator==="="){value.push(child.value);}else{value.push(...child.value);}} 4343children[childrenByPath[path].index]=condition(path,"in",normalizeValue(unique(value)));} 4344if(children.length===1){return{...children[0]};} 4345return{...tree,children};} 4346function _extractIdsRecursive(tree,getFieldDef,idsByModel){if(tree.type==="condition"){const fieldDef=getFieldDef(tree.path);if(["many2one","many2many","one2many"].includes(fieldDef?.type)){const value=tree.value;const values=Array.isArray(value)?value:[value];const ids=values.filter((val)=>isId(val));const resModel=getResModel(fieldDef);if(ids.length){if(!idsByModel[resModel]){idsByModel[resModel]=[];} 4347idsByModel[resModel].push(...ids);}}} 4348if(tree.type==="connector"){for(const child of tree.children){_extractIdsRecursive(child,getFieldDef,idsByModel);}} 4349return idsByModel;} 4350function extractIdsFromTree(tree,getFieldDef){const idsByModel=_extractIdsRecursive(tree,getFieldDef,{});for(const resModel in idsByModel){idsByModel[resModel]=unique(idsByModel[resModel]);} 4351return idsByModel;} 4352const treeProcessorService=__exports.treeProcessorService={dependencies:["field","name"],async:["getDomainTreeDescription","getDomainTreeTooltip","makeGetConditionDescription","makeGetFieldDef","treeFromDomain",],start(_,{field:fieldService,name:nameService}){async function getDisplayNames(tree,getFieldDef){const resIdsByModel=extractIdsFromTree(tree,getFieldDef);const proms=[];const resModels=[];for(const[resModel,resIds]of Object.entries(resIdsByModel)){resModels.push(resModel);proms.push(nameService.loadDisplayNames(resModel,resIds));} 4353return Object.fromEntries(zip(resModels,await Promise.all(proms)));} 4354async function makeGetPathDescriptions(resModel,tree,limit){const paths=getPathsInTree(tree);const promises=[];const pathDescriptions=new Map();for(const path of paths){promises.push(fieldService.loadPathDescription(resModel,path).then(({displayNames})=>{pathDescriptions.set(path,`${displayNames.slice(0, limit).join(" \u2794 ")}${ 4355 displayNames.length > limit ? "..." : "" 4356 }`);}));} 4357await Promise.all(promises);return(path)=>pathDescriptions.get(path);} 4358async function makeGetConditionDescription(resModel,tree,limit,pathLimit){tree=simplifyTree(tree);const[getFieldDef,getPathDescription]=await Promise.all([makeGetFieldDef(resModel,tree),makeGetPathDescriptions(resModel,tree,pathLimit),]);const displayNames=await getDisplayNames(tree,getFieldDef);return(node)=>_getConditionDescription(node,getFieldDef,getPathDescription,displayNames,limit);} 4359function _getConditionDescription(node,getFieldDef,getPathDescription,displayNames,limit=5){let{operator,negate,value,path}=node;if(operator==="in range"&&value[1]==="custom range"){operator="between";value=value.slice(2);} 4360if(["=","!="].includes(operator)&&value===false){operator=operator==="="?"not set":"set";} 4361const fieldDef=getFieldDef(path);const operatorLabel=getOperatorLabel(operator,fieldDef?.type,negate,(operator)=>{switch(operator){case"=":case"in":return"=";case"!=":case"not in":return _t("not =");case"any":return":";case"not any":return _t(": not");}});const pathDescription=getPathDescription(path);const description={pathDescription,operatorDescription:operatorLabel,valueDescription:null,};if(isTree(node.value)){return description;} 4362if(["set","not set"].includes(operator)){return description;} 4363const coModeldisplayNames=displayNames[getResModel(fieldDef)];const dis=disambiguate(value,coModeldisplayNames);let values;if(operator==="in range"){const valueType=value[1];values=[InRange.options.find(([t])=>t===valueType)[1].toString()];}else{values=(Array.isArray(value)?value:[value]).slice(0,limit).map((val,index)=>index<limit-1?formatValue(val,dis,fieldDef,coModeldisplayNames):"...");} 4364let join;let addParenthesis=Array.isArray(value);switch(operator){case"between":join=_t("and");addParenthesis=false;break;case"in range":join=_t(" ");addParenthesis=false;break;case"in":case"not in":addParenthesis=values.length===0;default:join=_t("or");} 4365description.valueDescription={values,join,addParenthesis};return description;} 4366async function getDomainTreeDescription(resModel,tree,isSubExpression=false,limit=undefined,pathLimit=undefined){tree=simplifyTree(tree);if(tree.type==="connector"){const childDescriptions=tree.children.map((node)=>getDomainTreeDescription(resModel,node,true));const separator=tree.value==="&"?_t("and"):_t("or");let description=await Promise.all(childDescriptions);description=description.join(` ${separator} `);if(isSubExpression||tree.negate){description=`( ${description} )`;} 4367if(tree.negate){description=`! ${description}`;} 4368return description;} 4369const getFieldDef=await makeGetFieldDef(resModel,tree);const getConditionDescription=await makeGetConditionDescription(resModel,tree,limit,pathLimit);const{pathDescription,operatorDescription,valueDescription}=getConditionDescription(tree);const stringDescription=[pathDescription,operatorDescription];if(valueDescription){const{values,join,addParenthesis}=valueDescription;const jointedValues=values.join(` ${join} `);stringDescription.push(addParenthesis?`( ${jointedValues} )`:jointedValues);}else if(isTree(tree.value)){const _fieldDef=getFieldDef(tree.path);const _resModel=getResModel(_fieldDef);const _tree=tree.value;const description=await getDomainTreeDescription(_resModel,_tree);stringDescription.push(`( ${description} )`);} 4370return stringDescription.join(" ");} 4371async function getTooltipLines(resModel,tree,depth=0){const tabs=" ".repeat(depth*4);tree=simplifyTree(tree);if(tree.type==="connector"){let connector=tree.value==="&"?_t("all"):_t("any");if(tree.negate){connector=tree.value==="&"?_t("not all"):_t("none");} 4372connector=`${tabs}${connector}`;const childrenTooltipLines=await Promise.all(tree.children.map((node)=>getTooltipLines(resModel,node,depth+1)));return[connector,...childrenTooltipLines].flat();} 4373const getFieldDef=await makeGetFieldDef(resModel,tree);const getConditionDescription=await makeGetConditionDescription(resModel,tree,20);const{pathDescription,operatorDescription,valueDescription}=getConditionDescription(tree);const descr=[];const stringDescriptions=[pathDescription,operatorDescription];if(valueDescription){const{values,join,addParenthesis}=valueDescription;const jointedValues=values.join(` ${join} `);stringDescriptions.push(addParenthesis?`( ${jointedValues} )`:jointedValues);} 4374descr.push(`${tabs}${stringDescriptions.join(" ")}`);
4374if(isTree(tree.value)){const _fieldDef=getFieldDef(tree.path);const _resModel=getResModel(_fieldDef);const _tree=tree.value;const tooltipLines=await getTooltipLines(_resModel,_tree,depth+1);descr.push(...tooltipLines);} 4375return descr;} 4376async function getDomainTreeTooltip(resModel,tree){const descriptions=await getTooltipLines(resModel,tree);return descriptions.join("\n");} 4377async function makeGetFieldDef(resModel,tree){const paths=new Set(getPathsInTree(tree,true));const promises=[];const fieldDefs={};for(const path of paths){promises.push(fieldService.loadFieldInfo(resModel,path).then(({fieldDef})=>{fieldDefs[path]=fieldDef;}));} 4378await Promise.all(promises);return(path)=>{if(typeof path==="string"){return fieldDefs[path];} 4379return null;};} 4380async function treeFromDomain(resModel,domain,distributeNot=true){const tree=constructTreeFromDomain(domain,distributeNot);const getFieldDef=await makeGetFieldDef(resModel,tree);return introduceVirtualOperators(tree,{getFieldDef});} 4381return{getDomainTreeDescription,getDomainTreeTooltip,makeGetConditionDescription,makeGetFieldDef,treeFromDomain,};},};registry.category("services").add("tree_processor",treeProcessorService);return __exports;});; 4382 4383/* /web/static/src/core/tree_editor/utils.js */ 4384odoo.define('@web/core/tree_editor/utils',[],function(require){'use strict';let __exports={};__exports.disambiguate=disambiguate;function disambiguate(value,displayNames){if(!Array.isArray(value)){return value==="";} 4385let hasSomeString=false;let hasSomethingElse=false;for(const val of value){if(val===""){return true;} 4386if(typeof val==="string"||(displayNames&&isId(val))){hasSomeString=true;}else{hasSomethingElse=true;}} 4387return hasSomeString&&hasSomethingElse;} 4388__exports.isId=isId;function isId(value){return Number.isInteger(value)&&value>=1;} 4389__exports.getResModel=getResModel;function getResModel(fieldDef){if(fieldDef){return fieldDef.is_property?fieldDef.comodel:fieldDef.relation;} 4390return null;} 4391const SPECIAL_FIELDS=["country_id","user_id","partner_id","stage_id","id"];__exports.getDefaultPath=getDefaultPath;function getDefaultPath(fieldDefs){for(const name of SPECIAL_FIELDS){const fieldDef=fieldDefs[name];if(fieldDef){return fieldDef.name;}} 4392const name=Object.keys(fieldDefs)[0];if(name){return name;} 4393throw new Error(`No field found`);} 4394return __exports;});; 4395 4396/* /web/static/src/core/tree_editor/virtual_operators.js */ 4397odoo.define('@web/core/tree_editor/virtual_operators',['@web/core/tree_editor/condition_tree'],function(require){'use strict';let __exports={};const{applyTransformations,areEqualTrees,cloneTree,condition,connector,expression,FALSE_TREE,isTree,normalizeValue,operate,rewriteNConsecutiveChildren,TRUE_TREE,}=require("@web/core/tree_editor/condition_tree");function splitPath(path,is_property){if(typeof path!=="string"||path===""){return{initialPath:"",lastPart:""};} 4398const pathParts=path.split(".");if(is_property&&pathParts.length>=2){return{initialPath:pathParts.slice(0,-2).join("."),lastPart:pathParts.slice(-2).join("."),};} 4399const lastPart=pathParts.pop()||"";const initialPath=pathParts.join(".");return{initialPath,lastPart};} 4400function isSimplePath(path,isProperty){return typeof path==="string"&&!splitPath(path,isProperty).initialPath;} 4401function wrapInAny(tree,initialPath,negate){let con=cloneTree(tree);if(initialPath){con=condition(initialPath,"any",con);} 4402con.negate=negate;return con;} 4403function introduceSetOperators(tree,options={}){function _introduceSetOperator(c,options={}){const{negate,path,operator,value}=c;const fieldType=options.getFieldDef?.(path)?.type;if(["=","!="].includes(operator)){if(fieldType){if(fieldType==="boolean"&&value===true){return condition(path,operator==="="?"set":"not set",value,negate);}else if(!["many2one","date","datetime"].includes(fieldType)&&value===false){return condition(path,operator==="="?"not set":"set",value,negate);}}}} 4404return operate(_introduceSetOperator,tree,options);} 4405function eliminateSetOperators(tree){function _removeSetOperator(c){const{negate,path,operator,value,isProperty}=c;if(["set","not set"].includes(operator)){if(value===true){return condition(path,operator==="set"?"=":"!=",value,negate,isProperty);} 4406return condition(path,operator==="set"?"!=":"=",value,negate,isProperty);}} 4407return operate(_removeSetOperator,tree);} 4408function introduceStartsWithOperators(tree,options){function _introduceStartsWithOperator(c,options){const{negate,path,operator,value,isProperty}=c;const fieldType=options.getFieldDef?.(path)?.type;if(["char","text","html"].includes(fieldType)&&operator==="=ilike"&&typeof value==="string"){if(value.endsWith("%")){return condition(path,"starts with",value.slice(0,-1),negate,isProperty);}}} 4409return operate(_introduceStartsWithOperator,tree,options);} 4410function eliminateStartsWithOperators(tree){function _eliminateStartsWithOperator(c){const{negate,path,operator,value,isProperty}=c;if(operator==="starts with"){return condition(path,"=ilike",`${value}%`,negate,isProperty);}} 4411return operate(_eliminateStartsWithOperator,tree);} 4412function isSimpleAnd(c){if(c.type==="connector"&&c.value==="&"&&!c.negate&&c.children.length===2&&c.children.every((child)=>child.type==="condition"&&!child.negate)){return true;} 4413return false;} 4414function isBetween(c){if(isSimpleAnd(c)){const[{path:p1,operator:op1,value:value1},{path:p2,operator:op2,value:value2},]=c.children;if(p1===p2&&op1===">="&&op2==="<="){return{path:p1,value1,value2};}} 4415return false;} 4416function makeBetween(path,value1,value2,isProperty){return connector("&",[condition(path,">=",value1,false,isProperty),condition(path,"<=",value2,false,isProperty),]);} 4417function isStrictBetween(c){if(isSimpleAnd(c)){const[{path:p1,operator:op1,value:value1},{path:p2,operator:op2,value:value2},]=c.children;if(p1===p2&&op1===">="&&op2==="<"){return{path:p1,value1,value2};}} 4418return false;} 4419function makeStrictBetween(path,value1,value2,isProperty){return connector("&",[condition(path,">=",value1,false,isProperty),condition(path,"<",value2,false,isProperty),]);} 4420function boundDate(delta){if(!delta){return expression(`context_today().strftime("%Y-%m-%d")`);} 4421return expression(`(context_today() + relativedelta(${delta})).strftime('%Y-%m-%d')`);} 4422function boundDatetime(delta){if(!delta){return expression(`datetime.datetime.combine(context_today(), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")`);} 4423return expression(`datetime.datetime.combine(context_today() + relativedelta(${delta}), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")`);} 4424const BOUNDS_SMART_DATES=[["today","today","today +1d"],["last 7 days","today -7d","today"],["last 30 days","today -30d","today"],["month to date","today =1d","today +1d"],["last month","today =1d -1m","today =1d"],["year to date","today =1m =1d","today +1d"],["last 12 months","today =1d -12m","today =1d"],];const DELTAS=[["today","","days = 1"],["last 7 days","days = -7",""],["last 30 days","days = -30",""],["month to date","day = 1","days = 1"],["last month","day = 1, months = -1","day = 1"],["year to date","day = 1, month
4424= 1","days = 1"],["last 12 months","day = 1, months = -12","day = 1"],];const BOUNDS_DATE=DELTAS.map(([k,l,r])=>[k,boundDate(l),boundDate(r)]);const BOUNDS_DATETIME=DELTAS.map(([k,l,r])=>[k,boundDatetime(l),boundDatetime(r)]);function getBounds(generateSmartDates,fieldType){return generateSmartDates?BOUNDS_SMART_DATES:fieldType==="date"?BOUNDS_DATE:BOUNDS_DATETIME;} 4425function introduceInRangeOperators(tree,options={}){function _introduceInRangeOperator(c,options){const res1=isStrictBetween(c);if(res1){const generateSmartDates="generateSmartDates"in options?options.generateSmartDates:true;const{path,value1,value2}=res1;const fieldDef=options.getFieldDef?.(path);const fieldType=fieldDef?.type;const isProperty=fieldDef?.is_property;if(["date","datetime"].includes(fieldType)&&isSimplePath(path,isProperty)){const bounds=getBounds(generateSmartDates,fieldType);for(const[valueType,leftBound,rightBound]of bounds){if(generateSmartDates?value1===leftBound&&value2===rightBound:value1._expr===leftBound._expr&&value2._expr===rightBound._expr){return condition(path,"in range",[fieldType,valueType,false,false],false,isProperty);}}}} 4426const res2=isBetween(c);if(res2){const{path,value1,value2}=res2;const fieldDef=options.getFieldDef?.(path);const fieldType=fieldDef?.type;const isProperty=fieldDef?.is_property;if(["date","datetime"].includes(fieldType)&&isSimplePath(path,isProperty)){return condition(path,"in range",[fieldType,"custom range",...normalizeValue([value1,value2]),],false,isProperty);}}} 4427return operate(rewriteNConsecutiveChildren(_introduceInRangeOperator),tree,options,"connector");} 4428function eliminateInRangeOperators(tree,options={}){function _eliminateInRangeOperator(c,options){const{negate,path,operator,value,isProperty}=c;if(operator!=="in range"){return;} 4429const{initialPath,lastPart}=splitPath(path,isProperty);const[fieldType,valueType,value1,value2]=value;let tree;if(valueType==="custom range"){tree=makeBetween(lastPart,value1,value2,isProperty);}else{const generateSmartDates="generateSmartDates"in options?options.generateSmartDates:true;const bounds=getBounds(generateSmartDates,fieldType);const[,leftBound,rightBound]=bounds.find(([v])=>v===valueType);tree=makeStrictBetween(lastPart,leftBound,rightBound,isProperty);} 4430return wrapInAny(tree,initialPath,negate);} 4431return operate(_eliminateInRangeOperator,tree,options);} 4432function introduceBetweenOperators(tree,options={}){function _introduceBetweenOperator(c,options){const res=isBetween(c);if(!res){return;} 4433const{path,value1,value2}=res;const fieldType=options.getFieldDef?.(path)?.type;if(["integer","float","monetary"].includes(fieldType)&&isSimplePath(path)){return condition(path,"between",normalizeValue([value1,value2]));}} 4434return operate(rewriteNConsecutiveChildren(_introduceBetweenOperator),tree,options,"connector");} 4435function eliminateBetweenOperators(tree){function _eliminateBetweenOperator(c){const{negate,path,operator,value,isProperty}=c;if(operator!=="between"){return;} 4436const{initialPath,lastPart}=splitPath(path,isProperty);return wrapInAny(makeBetween(lastPart,value[0],value[1],isProperty),initialPath,negate);} 4437return operate(_eliminateBetweenOperator,tree);} 4438function _eliminateAnyOperator(c){const{path,operator,value,negate}=c;if(operator==="any"&&isTree(value)&&value.type==="condition"&&typeof path==="string"&&typeof value.path==="string"&&!negate&&!value.negate&&["between","in range"].includes(value.operator)){return condition(`${path}.${value.path}`,value.operator,value.value,false,value.isProperty);}} 4439function eliminateAnyOperators(tree){return operate(_eliminateAnyOperator,tree);} 4440function removeFalseTrueLeaves(tree){function _removeFalseTrueLeave(c){const{path,operator,value,negate,isProperty}=c;if(areEqualTrees(condition(path,operator,value,false,isProperty),FALSE_TREE)){return connector(negate?"&":"|",[]);} 4441if(areEqualTrees(condition(path,operator,value,false,isProperty),TRUE_TREE)){return connector(negate?"|":"&",[]);}} 4442return operate(_removeFalseTrueLeave,tree);} 4443__exports.introduceVirtualOperators=introduceVirtualOperators;function introduceVirtualOperators(tree,options={}){return applyTransformations([eliminateAnyOperators,introduceSetOperators,introduceStartsWithOperators,introduceBetweenOperators,introduceInRangeOperators,],tree,options);} 4444__exports.eliminateVirtualOperators=eliminateVirtualOperators;function eliminateVirtualOperators(tree,options={}){return applyTransformations([eliminateInRangeOperators,eliminateBetweenOperators,eliminateStartsWithOperators,eliminateSetOperators,],tree,options);} 4445__exports.areEquivalentTrees=areEquivalentTrees;function areEquivalentTrees(tree,otherTree){const simplifiedTree=removeFalseTrueLeaves(eliminateVirtualOperators(tree));const otherSimplifiedTree=removeFalseTrueLeaves(eliminateVirtualOperators(otherTree));return areEqualTrees(simplifiedTree,otherSimplifiedTree);} 4446return __exports;});; 4447 4448/* /web/static/src/core/ui/block_ui.js */ 4449odoo.define('@web/core/ui/block_ui',['@web/core/l10n/translation','@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{browser}=require("@web/core/browser/browser");const{EventBus,Component,useState}=require("@odoo/owl");const BlockUI=__exports.BlockUI=class BlockUI extends Component{static props={bus:EventBus,};static template="web.BlockUI";setup(){this.messagesByDuration=[{time:20,l1:_t("Loading...")},{time:40,l1:_t("Still loading...")},{time:60,l1:_t("Still loading..."),l2:_t("Please be patient."),},{time:180,l1:_t("Don't leave yet,"),l2:_t("it's still loading..."),},{time:120,l1:_t("You may not believe it,"),l2:_t("but the application is actually loading..."),},{time:3180,l1:_t("Take a minute to get a coffee,"),l2:_t("because it's loading..."),},{time:null,l1:_t("Maybe you should consider reloading the application by pressing F5..."),},];this.BLOCK_STATES={UNBLOCKED:0,BLOCKED:1,VISIBLY_BLOCKED:2};this.state=useState({blockState:this.BLOCK_STATES.UNBLOCKED,line1:"",line2:"",});this.props.bus.addEventListener("BLOCK",this.block.bind(this));this.props.bus.addEventListener("UNBLOCK",this.unblock.bind(this));} 4450replaceMessage(index){const message=this.messagesByDuration[index];this.state.line1=message.l1;this.state.line2=message.l2||"";if(message.time!==null){this.msgTimer=browser.setTimeout(()=>{this.replaceMessage(index+1);},message.time*1000);}} 4451block(ev){const showBlockedUI=()=>(this.state.blockState=this.BLOCK_STATES.VISIBLY_BLOCKED);const delay=ev.detail?.delay;if(delay){this.state.blockState=this.BLOCK_STATES.BLOCKED;this.showBlockedUITimer=setTimeout(showBlockedUI,delay);}else{showBlockedUI();} 4452if(ev.detail?.message){this.state.line1=ev.detail.message;}else{this.replaceMessage(0);}} 4453unblock(){this.state.blockState=this.BLOCK_STATES.UNBLOCKED;clearTimeout(this.showBlockedUITimer);clearTimeout(this.msgTimer);this.state.line1="";this.state.line2="";}} 4454return __exports;});; 4455 4456/* /web/static/src/core/ui/ui_service.js */ 4457odoo.define('@web/core/ui/ui_service',['@web/core/utils/hooks','@web/core/registry','@web/core/ui/block_ui','@web/core/utils/ui','@web/core/h
4457otkeys/hotkey_service','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const{BlockUI}=require("@web/core/ui/block_ui");const{getTabableElements,isFocusable}=require("@web/core/utils/ui");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{EventBus,reactive,useEffect,useRef}=require("@odoo/owl");const SIZES=__exports.SIZES={XS:0,SM:1,MD:2,LG:3,XL:4,XXL:5};__exports.getFirstAndLastTabableElements=getFirstAndLastTabableElements;function getFirstAndLastTabableElements(el){const tabableEls=getTabableElements(el);return[tabableEls[0],tabableEls[tabableEls.length-1]];} 4458__exports.useActiveElement=useActiveElement;function useActiveElement(refName){if(!refName){throw new Error("refName not given to useActiveElement");} 4459const uiService=useService("ui");const ref=useRef(refName);function trapFocus(e){const hotkey=getActiveHotkey(e);if(!["tab","shift+tab"].includes(hotkey)){return;} 4460const el=e.currentTarget;const[firstTabableEl,lastTabableEl]=getFirstAndLastTabableElements(el);if(!firstTabableEl&&!lastTabableEl){e.preventDefault();e.stopPropagation();return;} 4461switch(hotkey){case"tab":if(document.activeElement===lastTabableEl){firstTabableEl.focus();e.preventDefault();e.stopPropagation();} 4462break;case"shift+tab":if(document.activeElement===firstTabableEl){lastTabableEl.focus();e.preventDefault();e.stopPropagation();} 4463break;}} 4464useEffect((el)=>{if(el){const[firstTabableEl]=getFirstAndLastTabableElements(el);if(!firstTabableEl&&!isFocusable(el)){return;} 4465const oldActiveElement=document.activeElement;uiService.activateElement(el);el.addEventListener("keydown",trapFocus);if(firstTabableEl){if(!el.contains(document.activeElement)){firstTabableEl.focus();}}else if(el!==document.activeElement){el.focus();} 4466return async()=>{await Promise.resolve();uiService.deactivateElement(el);el.removeEventListener("keydown",trapFocus);if(el.contains(document.activeElement)||document.activeElement===document.body){oldActiveElement.focus();}};}},()=>[ref.el]);} 4467const MEDIAS_BREAKPOINTS=__exports.MEDIAS_BREAKPOINTS=[{maxWidth:575},{minWidth:576,maxWidth:767},{minWidth:768,maxWidth:991},{minWidth:992,maxWidth:1199},{minWidth:1200,maxWidth:1399},{minWidth:1400},];__exports.getMediaQueryLists=getMediaQueryLists;function getMediaQueryLists(){return MEDIAS_BREAKPOINTS.map(({minWidth,maxWidth})=>{if(!maxWidth){return window.matchMedia(`(min-width: ${minWidth}px)`);} 4468if(!minWidth){return window.matchMedia(`(max-width: ${maxWidth}px)`);} 4469return window.matchMedia(`(min-width: ${minWidth}px) and (max-width: ${maxWidth}px)`);});} 4470let MEDIAS=getMediaQueryLists();let updateSizeHandler=null;const utils=__exports.utils={getSize(){return MEDIAS.findIndex((media)=>media.matches);},isSmall(ui={}){return(ui.size||utils.getSize())<=SIZES.SM;},};const bus=new EventBus();__exports.listenSizeChange=listenSizeChange;function listenSizeChange(callback){bus.addEventListener("resize",callback);return()=>bus.removeEventListener("resize",callback);} 4471const uiService=__exports.uiService={start(env){registry.category("main_components").add("BlockUI",{Component:BlockUI,props:{bus}});let blockCount=0;function block(data){blockCount++;if(blockCount===1){bus.trigger("BLOCK",{message:data?.message,delay:data?.delay,});}} 4472function unblock(){blockCount--;if(blockCount<0){console.warn("Unblock ui was called more times than block, you should only unblock the UI if you have previously blocked it.");blockCount=0;} 4473if(blockCount===0){bus.trigger("UNBLOCK");}} 4474let activeElems=[document];function activateElement(el){activeElems.push(el);bus.trigger("active-element-changed",el);} 4475function deactivateElement(el){activeElems=activeElems.filter((x)=>x!==el);bus.trigger("active-element-changed",ui.activeElement);} 4476function getActiveElementOf(el){for(const activeElement of[...activeElems].reverse()){if(activeElement.contains(el)){return activeElement;}}} 4477if(updateSizeHandler){MEDIAS.forEach((m)=>m.removeEventListener?.("change",updateSizeHandler));MEDIAS=getMediaQueryLists();} 4478const ui=reactive({bus,size:utils.getSize(),get activeElement(){return activeElems[activeElems.length-1];},get isBlocked(){return blockCount>0;},isSmall:utils.isSmall(),block,unblock,activateElement,deactivateElement,getActiveElementOf,});updateSizeHandler=(ev)=>{if(ev.matches){ui.size=MEDIAS.indexOf(ev.target);
4478ui.isSmall=utils.isSmall(ui);bus.trigger("resize");}};MEDIAS.forEach((m)=>m.addEventListener?.("change",updateSizeHandler));Object.defineProperty(env,"isSmall",{get(){return ui.isSmall;},});return ui;},};registry.category("services").add("ui",uiService);return __exports;});; 4479 4480/* /web/static/src/core/user.js */ 4481odoo.define('@web/core/user',['@web/core/browser/browser','@web/core/l10n/utils/locales','@web/core/network/rpc','@web/core/utils/cache','@web/session','@web/core/utils/arrays','@web/core/browser/cookie','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{pyToJsLocale}=require("@web/core/l10n/utils/locales");const{rpc}=require("@web/core/network/rpc");const{Cache}=require("@web/core/utils/cache");const{session}=require("@web/session");const{ensureArray,sortBy}=require("@web/core/utils/arrays");const{cookie}=require("@web/core/browser/cookie");const{EventBus}=require("@odoo/owl");const userBus=__exports.userBus=new EventBus();function getCookieCompanyIds(){if(cookie.get("cids")){const cids=cookie.get("cids");if(typeof cids==="string"){return cids.split("-").map(Number);} 4482if(typeof cids==="number"){return[cids];}} 4483return[];} 4484__exports._makeUser=_makeUser;function _makeUser(session){const{home_action_id:homeActionId,is_admin:isAdmin,is_internal_user:isInternalUser,is_system:isSystem,is_public:isPublic,name,partner_id:partnerId,show_effect:showEffect,uid:userId,username:login,user_context:context,user_settings,partner_write_date:writeDate,user_companies:userCompanies,groups={},}=session;const settings=user_settings||{};function updateActiveCompanies(cids,allowedCompanies,defaultCompanyId){activeCompanies=[];cids.forEach((cid)=>{activeCompanies.push(allowedCompanies.find((c)=>c.id===cid));});if(activeCompanies.length===0||activeCompanies.length!==activeCompanies.filter(Boolean).length){activeCompanies=[defaultCompanyId];} 4485activeCompanies=[activeCompanies[0]].concat(sortBy(activeCompanies.slice(1),(c)=>c.id));cookie.set("cids",activeCompanies.map((c)=>c.id).join("-"));Object.assign(context,{allowed_company_ids:activeCompanies.map((c)=>c.id)});userBus.trigger("ACTIVE_COMPANIES_CHANGED");} 4486let allowedCompanies=[];const allowedCompaniesWithAncestors=[];let activeCompanies=[];let defaultCompany;if(userCompanies){allowedCompanies=Object.values(userCompanies.allowed_companies);allowedCompaniesWithAncestors.push(...Object.values(userCompanies.allowed_companies));if(userCompanies.disallowed_ancestor_companies){allowedCompaniesWithAncestors.push(...Object.values(userCompanies.disallowed_ancestor_companies));} 4487defaultCompany=allowedCompanies.find((c)=>c.id===userCompanies.current_company);updateActiveCompanies(getCookieCompanyIds(),allowedCompanies,defaultCompany);} 4488delete session.home_action_id;delete session.is_admin;delete session.is_internal_user;delete session.is_system;delete session.name;delete session.partner_id;delete session.show_effect;delete session.uid;delete session.username;delete session.user_context;delete session.user_settings;delete session.partner_write_date;delete session.user_companies;delete session.groups;const getGroupCacheValue=(group,context)=>{if(!userId){return Promise.resolve(false);} 4489return rpc("/web/dataset/call_kw/res.users/has_group",{model:"res.users",method:"has_group",args:[userId,group],kwargs:{context},});};const getGroupCacheKey=(group)=>group;const groupCache=new Cache(getGroupCacheValue,getGroupCacheKey);if(isInternalUser!==undefined){groupCache.cache["base.group_user"]=Prom
4489ise.resolve(isInternalUser);} 4490if(isSystem!==undefined){groupCache.cache["base.group_system"]=Promise.resolve(isSystem);} 4491if(isAdmin!==undefined){groupCache.cache["base.group_erp_manager"]=Promise.resolve(isAdmin);} 4492if(isPublic!==undefined){groupCache.cache["base.group_public"]=Promise.resolve(isPublic);} 4493for(const group in groups){groupCache.cache[group]=Promise.resolve(!!groups[group]);} 4494const getAccessRightCacheValue=(model,operation,ids,context)=>{const url=`/web/dataset/call_kw/${model}/has_access`;return rpc(url,{model,method:"has_access",args:[ids,operation],kwargs:{context},});};const getAccessRightCacheKey=(model,operation,ids)=>JSON.stringify([model,operation,ids]);const accessRightCache=new Cache(getAccessRightCacheValue,getAccessRightCacheKey);const lang=pyToJsLocale(context?.lang);return{name,login,isAdmin,isSystem,isInternalUser,partnerId,homeActionId,showEffect,userId,writeDate,get context(){return Object.assign({},context,{uid:this.userId});},get lang(){return lang;},get tz(){return this.context.tz;},get settings(){return Object.assign({},settings);},updateContext(update){Object.assign(context,update);},hasGroup(group){return groupCache.read(group,this.context);},checkAccessRight(model,operation,ids=[]){return accessRightCache.read(model,operation,ensureArray(ids),this.context);},async setUserSettings(key,value){const model="res.users.settings";const method="set_res_users_settings";const changedSettings=await rpc(`/web/dataset/call_kw/${model}/${method}`,{model,method,args:[[this.settings.id]],kwargs:{new_settings:{[key]:value,},context:this.context,},});Object.assign(settings,changedSettings);},updateUserSettings(key,value){settings[key]=value;},defaultCompany,allowedCompanies,allowedCompaniesWithAncestors,get activeCompanies(){return activeCompanies;},get activeCompany(){return activeCompanies?.[0];},async activateCompanies(companyIds,options={includeChildCompanies:true,reload:true}){const newCompanyIds=companyIds.length?companyIds:[activeCompanies[0].id];function addCompanies(companyIds){for(const companyId of companyIds){if(!newCompanyIds.includes(companyId)){newCompanyIds.push(companyId);addCompanies(allowedCompanies.find((c)=>c.id===companyId).child_ids);}}} 4495if(options.includeChildCompanies){addCompanies(companyIds.flatMap((companyId)=>allowedCompanies.find((c)=>c.id===companyId).child_ids));} 4496updateActiveCompanies(newCompanyIds,allowedCompanies,defaultCompany);if(options.reload){browser.location.reload();}},};} 4497const user=__exports.user=_makeUser(session);const LAST_CONNECTED_USER_KEY="web.lastConnectedUser";const getLastConnectedUsers=__exports.getLastConnectedUsers=()=>{const lastConnectedUsers=browser.localStorage.getItem(LAST_CONNECTED_USER_KEY);return lastConnectedUsers?JSON.parse(lastConnectedUsers):[];};const setLastConnectedUsers=__exports.setLastConnectedUsers=(users)=>{browser.localStorage.setItem(LAST_CONNECTED_USER_KEY,JSON.stringify(users.slice(0,5)));};if(!session.quick_login){browser.localStorage.removeItem(LAST_CONNECTED_USER_KEY);}else if(user.login&&user.login!=="__system__"){const users=getLastConnectedUsers();const lastConnectedUsers=[{login:user.login,name:user.name,partnerId:user.partnerId,partnerWriteDate:user.writeDate,userId:user.userId,},...users.filter((u)=>u.userId!==user.userId),];setLastConnectedUsers(lastConnectedUsers);} 4498delete session.quick_login;return __exports;});; 4499 4500/* /web/static/src/core/user_switch/user_switch.js */ 4501odoo.define('@web/core/user_switch/user_switch',['@odoo/owl','@web/core/registry','@web/core/user','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{Component,useRef,useState,useEffect}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{getLastConnectedUsers,setLastConnectedUsers}=require("@web/core/user");const{imageUrl}=require("@web/core/utils/urls");const UserSwitch=__exports.UserSwitch=class UserSwitch extends Component{static template="web.login_user_switch";static props={};setup(){const users=getLastConnectedUsers();this.root=useRef("root");this.state=useState({users,displayUserChoice:users.length>1,});this.form=document.querySelector("form.oe_login_form");this.form.classList.toggle("d-none",users.length>1);this.form.querySelector(":placeholder-shown")?.focus();useEffect((el)=>el?.querySelector("button.list-group-item-action")?.focus(),()=>[this.root.el]);} 4502toggleFormDisplay(){this.state.displayUserChoice=!this.state.displayUserChoice&&this.state.users.length;this.form.classList.toggle("d-none",this.state.displayUserChoice);this.form.querySelector(":placeholder-shown")?.focus();} 4503getAvatarUrl({partnerId,partnerWriteDate:unique}){return imageUrl("res.partner",partnerId,"avatar_128",{unique});} 4504remove(deletedUser){this.state.users=this.state.users.filter((user)=>user!==deletedUser);setLastConnectedUsers(this.state.users);if(!this.state.users.length){this.fillForm();}} 4505fillForm(login=""){this.form.querySelector("input#login").value=login;this.form.querySelector("input#password").value="";this.toggleFormDisplay();}} 4506registry.category("public_components").add("web.user_switch",UserSwitch);return __exports;});; 4507 4508/* /web/static/src/core/utils/arrays.js */ 4509odoo.define('@web/core/utils/arrays',['@web/core/utils/objects'],function(require){'use strict';let __exports={};const{shallowEqual:_shallowEqual}=require("@web/core/utils/objects");function _cartesian(...args){if(args.length===0){return[undefined];} 4510const firstArray=args.shift().map((elem)=>[elem]);if(args.length===0){return firstArray;} 4511const result=[];const productOfOtherArrays=_cartesian(...args);for(const array of firstArray){for(const tuple of productOfOtherArrays){result.push([...array,...tuple]);}} 4512return result;} 4513function _getExtractorFrom(criterion){if(criterion){switch(typeof criterion){case"string":return(element)=>element[criterion];case"function":return criterion;default:throw new Error(`Expected criterion of type 'string' or 'function' and got '${typeof criterion}'`);}}else{return(element)=>element;}}
4514__exports.ensureArray=ensureArray;function ensureArray(value){return isIterable(value)?[...value]:[value];} 4515__exports.intersection=intersection;function intersection(iter1,iter2){const set2=new Set(iter2);return unique(iter1).filter((v)=>set2.has(v));} 4516__exports.isIterable=isIterable;function isIterable(value){return Boolean(value&&typeof value==="object"&&value[Symbol.iterator]);} 4517__exports.groupBy=groupBy;function groupBy(iterable,criterion){const extract=_getExtractorFrom(criterion);const groups={};for(const element of iterable){const group=String(extract(element));if(!(group in groups)){groups[group]=[];} 4518groups[group].push(element);} 4519return groups;} 4520__exports.sortBy=sortBy;function sortBy(iterable,criterion,order="asc"){const extract=_getExtractorFrom(criterion);return[...iterable].sort((elA,elB)=>{const a=extract(elA);const b=extract(elB);let result;if(isNaN(a)&&isNaN(b)){result=a>b?1:a<b?-1:0;}else{result=a-b;} 4521return order==="asc"?result:-result;});} 4522__exports.symmetricalDifference=symmetricalDifference;function symmetricalDifference(iter1,iter2){const array1=[...iter1];const array2=[...iter2];return[...array1.filter((value)=>!array2.includes(value)),...array2.filter((value)=>!array1.includes(value)),];} 4523__exports.cartesian=cartesian;function cartesian(...args){if(args.length===0){return[undefined];}else if(args.length===1){return args[0];}else{return _cartesian(...args);}} 4524const shallowEqual=__exports.shallowEqual=_shallowEqual;__exports.sections=sections;function sections(iterable){const array=[...iterable];const sections=[];for(let i=0;i<array.length+1;i++){sections.push(array.slice(0,i));} 4525return sections;} 4526__exports.unique=unique;function unique(iterable){return[...new Set(iterable)];} 4527__exports.zip=zip;function zip(iter1,iter2,fill=false){const array1=[...iter1];const array2=[...iter2];const result=[];const getLength=fill?Math.max:Math.min;for(let i=0;i<getLength(array1.length,array2.length);i++){result.push([array1[i],array2[i]]);} 4528return result;} 4529__exports.zipWith=zipWith;function zipWith(iter1,iter2,mapFn){return zip(iter1,iter2).map(([e1,e2])=>mapFn(e1,e2));} 4530__exports.slidingWindow=slidingWindow;function slidingWindow(arr,width){const res=[];for(let i=0;i<=arr.length-width;i++){res.push(arr.slice(i,i+width));} 4531return res;} 4532__exports.rotate=rotate;function rotate(i,arr,inc=1){return(arr.length+i+inc)%arr.length;} 4533return __exports;});; 4534 4535/* /web/static/src/core/utils/autoresize.js */ 4536odoo.define('@web/core/utils/autoresize',['@odoo/owl','@web/core/utils/functions'],function(require){'use strict';let __exports={};const{useEffect}=require("@odoo/owl");const{memoize}=require("@web/core/utils/functions");__exports.useAutoresize=useAutoresize;function useAutoresize(ref,options={}){let wasProgrammaticallyResized=false;let resize=null;useEffect((el)=>{if(el){resize=(programmaticResize=false)=>{wasProgrammaticallyResized=programmaticResize;if(options.ignoreIfEmpty&&!el.value){return;} 4537if(el instanceof HTMLInputElement){resizeInput(el);}else{resizeTextArea(el,options);} 4538options.onResize?.(el,options);};el.addEventListener("input",()=>resize(true));const resizeObserver=new ResizeObserver(()=>{if(wasProgrammaticallyResized){wasProgrammaticallyResized=false;return;} 4539resize();});resizeObserver.observe(el);return()=>{el.removeEventListener("input",resize);resizeObserver.unobserve(el);resizeObserver.disconnect();resize=null;};}},()=>[ref.el]);useEffect(()=>{if(resize){resize(true);}});} 4540const doesScrollWidthExcludePadding=memoize(()=>{const input=document.createElement("input");input.style.cssText=` 4541 position: absolute; 4542 visibility: hidden; 4543 padding: 0; 4544 border: 0; 4545 width: auto; 4546 `;document.body.appendChild(input);const widthWithoutPadding=input.scrollWidth;input.style.padding="10px";const widthWithPadding=input.scrollWidth;input.remove();return widthWithPadding===widthWithoutPadding;});function resizeInput(input){const style=window.getComputedStyle(input);input.style.width="100%";const maxWidth=input.clientWidth;input.style.width="10px";if(input.value===""&&input.placeholder!==""){input.style.width="auto";return;} 4547let boxExtraWidth=parseFloat(style.borderLeftWidth)+parseFloat(style.borderRightWidth);if(doesScrollWidthExcludePadding()){const padding=parseFloat(style.paddingLeft)+parseFloat(style.paddingRight);boxExtraWidth+=padding;} 4548const desiredWidth=input.scrollWidth+boxExtraWidth+1;if(desiredWidth>maxWidth){input.style.width="100%";return;} 4549input.style.width=`${desiredWidth}px`;} 4550__exports.resizeTextArea=resizeTextArea;function resizeTextArea(textarea,options={}){const minimumHeight=options.minimumHeight||0;let heightOffset=0;const style=window.getComputedStyle(textarea);if(style.boxSizing==="border-box"){const paddingHeight=parseFloat(style.paddingTop)+parseFloat(style.paddingBottom);const borderHeight=parseFloat(style.borderTopWidth)+parseFloat(style.borderBottomWidth);heightOffset=borderHeight+paddingHeight;} 4551const previousStyle={borderTopWidth:style.borderTopWidth,borderBottomWidth:style.borderBottomWidth,padding:style.padding,};Object.assign(textarea.style,{height:"auto",borderTopWidth:0,borderBottomWidth:0,paddingTop:0,paddingBottom:0,});textarea.style.height="auto";const height=Math.max(minimumHeight,textarea.scrollHeight+heightOffset);Object.assign(textarea.style,previousStyle,{height:`${height}px`});textarea.parentElement.style.height=`${height}px`;} 4552return __exports;});; 4553 4554/* /web/static/src/core/utils/binary.js */ 4555odoo.define('@web/core/utils/binary',['@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);__exports.isBinarySize=isBinarySize;function isBinarySize(value){return/^\d+(\.\d*)? [^0-9]+$/.test(value);} 4556__exports.toBase64Length=toBase64Length;function toBase64Length(maxBytes){return Math.ceil(maxBytes*4/3);} 4557__exports.humanSize=humanSize;function humanSize(size){const units=_t("Bytes|Kb|Mb|Gb|Tb|Pb|Eb|Zb|Yb").split("|");let i=0;while(size>=1024){size/=1024;++i;} 4558return`${size.toFixed(2)} ${units[i].trim()}`;} 4559return __exports;});; 4560 4561/* /web/static/src/core/utils/cache.js */ 4562odoo.define('@web/core/utils/cache',[],function(require){'use strict';let __exports={};const Cache=__exports.Cache=class Cache{constructor(getValue,getKey){this.cache={};this.getKey=getKey;this.getValue=getValue;} 4563_getCacheAndKey(...path){let cache=this.cache;let key;if(this.getKey){key=this.getKey(...path);}else{for(let i=0;i<path.length-1;i++){cache=cache[path[i]]=cache[path[i]]||{};} 4564key=path[path.length-1];} 4565return{cache,key};} 4566clear(...path){const{cache,key}=this._getCacheAndKey(...path);delete cache[key];} 4567invalidate(){this.cache={};} 4568read(...path){const{cache,key}=this._getCacheAndKey(...path);if(!(key in cache)){cache[key]=this.getValue(...path);} 4569return cache[key];}} 4570return __exports;});; 4571 4572/* /web/static/src/core/utils/classname.js */ 4573odoo.define('@web/core/utils/classname',[],function(require){'use strict';let __exports={};__exports.addClassesToElement=addClassesToElement;function addClassesToElement(el,...classes){for(const classDefinition of classes){const classObj=toClassObj(classDefinition);for(const className in classObj){if(classObj[className]){el.classList.add(className.trim());}}}} 4574__exports.mergeClasses=mergeClasses;function mergeClasses(...classes){const classObj={};for(const classDefinition of classes){Object.assign(classObj,toClassObj(classDefinition));} 4575return classObj;} 4576function toClassObj(classDefinition){if(!classDefinition){return{};}else if(typeof classDefinition==="object"){return classDefinition;}else if(typeof classDefinition==="string"){const classObj={};
4576classDefinition.trim().split(/\s+/).forEach((s)=>{classObj[s]=true;});return classObj;}else{console.warn(`toClassObj only supports strings, objects and undefined className (got ${typeof classProp})`);return{};}} 4577return __exports;});; 4578 4579/* /web/static/src/core/utils/colors.js */ 4580odoo.define('@web/core/utils/colors',[],function(require){'use strict';let __exports={};__exports.applyOpacityToGradient=applyOpacityToGradient;function applyOpacityToGradient(gradient,opacity=100){if(opacity===100){return gradient;} 4581return gradient.replace(/rgb\(([^)]+)\)/g,`rgba($1, ${opacity / 100.0})`);} 4582__exports.convertRgbToHsl=convertRgbToHsl;function convertRgbToHsl(r,g,b){if(typeof r!=="number"||isNaN(r)||r<0||r>255||typeof g!=="number"||isNaN(g)||g<0||g>255||typeof b!=="number"||isNaN(b)||b<0||b>255){return false;} 4583var red=r/255;var green=g/255;var blue=b/255;var maxColor=Math.max(red,green,blue);var minColor=Math.min(red,green,blue);var delta=maxColor-minColor;var hue=0;var saturation=0;var lightness=(maxColor+minColor)/2;if(delta){if(maxColor===red){hue=(green-blue)/delta;} 4584if(maxColor===green){hue=2+(blue-red)/delta;} 4585if(maxColor===blue){hue=4+(red-green)/delta;} 4586if(maxColor){saturation=delta/(1-Math.abs(2*lightness-1));}} 4587hue=60*hue;return{hue:hue<0?hue+360:hue,saturation:saturation*100,lightness:lightness*100,};} 4588__exports.convertHslToRgb=convertHslToRgb;function convertHslToRgb(h,s,l){if(typeof h!=="number"||isNaN(h)||h<0||h>360||typeof s!=="number"||isNaN(s)||s<0||s>100||typeof l!=="number"||isNaN(l)||l<0||l>100){return false;} 4589var huePrime=h/60;var saturation=s/100;var lightness=l/100;var chroma=saturation*(1-Math.abs(2*lightness-1));var secondComponent=chroma*(1-Math.abs((huePrime%2)-1));var lightnessAdjustment=lightness-chroma/2;var precision=255;chroma=Math.round((chroma+lightnessAdjustment)*precision);secondComponent=Math.round((secondComponent+lightnessAdjustment)*precision);lightnessAdjustment=Math.round(lightnessAdjustment*precision);if(huePrime>=0&&huePrime<1){return{red:chroma,green:secondComponent,blue:lightnessAdjustment,};} 4590if(huePrime>=1&&huePrime<2){return{red:secondComponent,green:chroma,blue:lightnessAdjustment,};} 4591if(huePrime>=2&&huePrime<3){return{red:lightnessAdjustment,green:chroma,blue:secondComponent,};} 4592if(huePrime>=3&&huePrime<4){return{red:lightnessAdjustment,green:secondComponent,blue:chroma,};} 4593if(huePrime>=4&&huePrime<5){return{red:secondComponent,green:lightnessAdjustment,blue:chroma,};} 4594if(huePrime>=5&&huePrime<=6){return{red:chroma,green:lightnessAdjustment,blue:secondComponent,};} 4595return false;} 4596__exports.convertRgbaToCSSColor=convertRgbaToCSSColor;function convertRgbaToCSSColor(r,g,b,a){if(typeof r!=="number"||isNaN(r)||r<0||r>255||typeof g!=="number"||isNaN(g)||g<0||g>255||typeof b!=="number"||isNaN(b)||b<0||b>255){return false;} 4597const rr=r<16?"0"+r.toString(16):r.toString(16);const gg=g<16?"0"+g.toString(16):g.toString(16);const bb=b<16?"0"+b.toString(16):b.toString(16);if(typeof a!=="number"||isNaN(a)||a<0||a>100||Math.abs(a-100)<Number.EPSILON){return`#${rr}${gg}${bb}`.toUpperCase();} 4598const alpha=Math.round((a/100)*255);const aa=alpha<16?"0"+alpha.toString(16):alpha.toString(16);return`#${rr}${gg}${bb}${aa}`.toUpperCase();} 4599__exports.convertCSSColorToRgba=convertCSSColorToRgba;function convertCSSColorToRgba(cssColor=""){const rgba=cssColor.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d*(?:\.\d+)?))?\)$/);if(rgba){if(rgba[4]===undefined){rgba[4]=1;} 4600return{red:parseInt(rgba[1]),green:parseInt(rgba[2]),blue:parseInt(rgba[3]),opacity:Math.round(parseFloat(rgba[4])*100),};} 4601if(/^#([0-9a-f]{3})$/i.test(cssColor)){return{red:parseInt(cssColor[1]+cssColor[1],16),green:parseInt(cssColor[2]+cssColor[2],16),blue:parseInt(cssColor[3]+cssColor[3],16),opacity:100,};} 4602if(/^#([0-9A-F]{6}|[0-9A-F]{8})$/i.test(cssColor)){return{red:parseInt(cssColor.substr(1,2),16),green:parseInt(cssColor.substr(3,2),16),blue:parseInt(cssColor.substr(5,2),16),opacity:(cssColor.length===9?parseInt(cssColor.substr(7,2),16)/255:1)*100,};} 4603if(/color\(.+\)/.test(cssColor)){const canvasEl=document.createElement("canvas");canvasEl.height=1;canvasEl.width=1;const ctx=canvasEl.getContext("2d");ctx.fillStyle=cssColor;ctx.fillRect(0,0,1,1);const data=ctx.getImageData(0,0,1,1).data;return{red:data[0],green:data[1],blue:data[2],opacity:data[3]/2.55,};} 4604return false;} 4605__exports.normalizeCSSColor=normalizeCSSColor;function normalizeCSSColor(cssColor){const rgba=convertCSSColorToRgba(cssColor);if(!rgba){return cssColor;} 4606return convertRgbaToCSSColor(rgba.red,rgba.green,rgba.blue,rgba.opacity);} 4607__exports.isCSSColor=isCSSColor;function isCSSColor(cssColor){return convertCSSColorToRgba(cssColor)!==false;} 4608__exports.mixCssColors=mixCssColors;function mixCssColors(cssColor1,cssColor2,weight){const rgba1=convertCSSColorToRgba(cssColor1);const rgba2=convertCSSColorToRgba(cssColor2);const rgb1=[rgba1.red,rgba1.green,rgba1.blue];const rgb2=[rgba2.red,rgba2.green,rgba2.blue];const[r,g,b]=rgb1.map((_,idx)=>Math.round(rgb2[idx]+(rgb1[idx]-rgb2[idx])*weight));return convertRgbaToCSSColor(r,g,b);} 4609__exports.isColorGradient=isColorGradient;function isColorGradient(value){return value&&value.includes("-gradient(");} 4610__exports.standardizeGradient=standardizeGradient;function standardizeGradient(gradient){if(isColorGradient(gradient)){const el=document.createElement("div");el.style.setProperty("background-image",gradient);gradient=el.style.getPropertyValue("background-image");} 4611return gradient;} 4612const RGBA_REGEX=__exports.RGBA_REGEX=/[\d.]{1,5}/g;__exports.rgbToHex=rgbToHex;function rgbToHex(rgb="",node=null){if(rgb.startsWith("#")){return rgb;}else if(rgb.startsWith("rgba")){const values=rgb.match(RGBA_REGEX)||[];
4612const alpha=parseFloat(values.pop());let bgRgbValues=[];if(node){let bgColor=getComputedStyle(node).backgroundColor;if(bgColor.startsWith("rgba")){bgColor=rgbToHex(bgColor,node.parentElement);} 4613if(bgColor&&bgColor.startsWith("#")){bgRgbValues=(bgColor.match(/[\da-f]{2}/gi)||[]).map((val)=>parseInt(val,16));}else if(bgColor&&bgColor.startsWith("rgb")){bgRgbValues=(bgColor.match(RGBA_REGEX)||[]).map((val)=>parseInt(val));}} 4614bgRgbValues=bgRgbValues.length?bgRgbValues:[255,255,255];return("#"+ 4615values.map((value,index)=>{const converted=Math.floor(alpha*parseInt(value)+(1-alpha)*bgRgbValues[index]);const hex=parseInt(converted).toString(16);return hex.length===1?"0"+hex:hex;}).join(""));}else{return("#"+ 4616(rgb.match(/\d{1,3}/g)||[]).map((x)=>{x=parseInt(x).toString(16);return x.length===1?"0"+x:x;}).join(""));}} 4617__exports.rgbaToHex=rgbaToHex;function rgbaToHex(rgba=""){if(rgba.startsWith("#")){return rgba;}else if(rgba.startsWith("rgba")){const values=rgba.match(RGBA_REGEX)||[];return convertRgbaToCSSColor(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]),parseFloat(values[3])*100);}else{return rgbToHex(rgba);}} 4618__exports.blendColors=blendColors;function blendColors(color,node){if(!color.startsWith("rgba")){return rgbaToHex(color);} 4619let bgRgbValues=[255,255,255];if(node){let bgColor=getComputedStyle(node).backgroundColor;if(bgColor.startsWith("rgba")){bgColor=blendColors(bgColor,node.parentElement);} 4620if(bgColor.startsWith("#")){bgRgbValues=(bgColor.match(/[\da-f]{2}/gi)||[]).map((val)=>parseInt(val,16));}else if(bgColor.startsWith("rgb")){bgRgbValues=(bgColor.match(/[\d.]{1,5}/g)||[]).map((val)=>parseInt(val));}} 4621const values=color.match(/[\d.]{1,5}/g)||[];const alpha=values.length===4?parseFloat(values.pop()):1;return("#"+ 4622values.map((value,index)=>{const converted=Math.round(alpha*parseInt(value)+(1-alpha)*bgRgbValues[index]);const hex=parseInt(converted).toString(16);return hex.length===1?"0"+hex:hex;}).join(""));} 4623return __exports;});; 4624 4625/* /web/static/src/core/utils/components.js */ 4626odoo.define('@web/core/utils/components',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onError,xml}=require("@odoo/owl");const ErrorHandler=__exports.ErrorHandler=class ErrorHandler extends Component{static template=xml`<t t-slot="default" />`;static props=["onError","slots"];setup(){onError((error)=>{this.props.onError(error);});}} 4627return __exports;});; 4628 4629/* /web/static/src/core/utils/concurrency.js */ 4630odoo.define('@web/core/utils/concurrency',[],function(require){'use strict';let __exports={};__exports.delay=delay;function delay(wait){return new Promise(function(resolve){setTimeout(resolve,wait);});} 4631const KeepLast=__exports.KeepLast=class KeepLast{constructor(){this._id=0;} 4632add(promise){this._id++;const currentId=this._id;return new Promise((resolve,reject)=>{promise.then((value)=>{if(this._id===currentId){resolve(value);}}).catch((reason)=>{if(this._id===currentId){reject(reason);}});});}} 4633const Mutex=__exports.Mutex=class Mutex{constructor(){this._lock=Promise.resolve();this._queueSize=0;this._unlockedProm=undefined;this._unlock=undefined;} 4634async exec(action){this._queueSize++;if(!this._unlockedProm){this._unlockedProm=new Promise((resolve)=>{this._unlock=()=>{resolve();this._unlockedProm=undefined;};});} 4635const always=()=>{return Promise.resolve(action()).finally(()=>{if(--this._queueSize===0){this._unlock();}});};this._lock=this._lock.then(always,always);return this._lock;} 4636getUnlockedDef(){return this._unlockedProm||Promise.resolve();}} 4637const Race=__exports.Race=class Race{constructor(){this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;} 4638add(promise){if(!this.currentProm){this.currentProm=new Promise((resolve,reject)=>{this.currentPromResolver=(value)=>{this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;resolve(value);};this.currentPromRejecter=(error)=>{this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;reject(error);};});} 4639promise.then(this.currentPromResolver).catch(this.currentPromRejecter);return this.currentProm;} 4640getCurrentProm(){return this.currentProm;}} 4641const Deferred=__exports.Deferred=class Deferred extends Promise{constructor(){let resolve;let reject;
4641const prom=new Promise((res,rej)=>{resolve=res;reject=rej;});return Object.assign(prom,{resolve,reject});}} 4642return __exports;});; 4643 4644/* /web/static/src/core/utils/draggable.js */ 4645odoo.define('@web/core/utils/draggable',['@web/core/utils/draggable_hook_builder_owl','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const{pick}=require("@web/core/utils/objects");const useDraggable=__exports.useDraggable=makeDraggableHook({name:"useDraggable",onWillStartDrag:({ctx})=>pick(ctx.current,"element"),onDragStart:({ctx})=>pick(ctx.current,"element"),onDrag:({ctx})=>pick(ctx.current,"element"),onDragEnd:({ctx})=>pick(ctx.current,"element"),onDrop:({ctx})=>pick(ctx.current,"element"),});return __exports;});; 4646 4647/* /web/static/src/core/utils/draggable_hook_builder.js */ 4648odoo.define('@web/core/utils/draggable_hook_builder',['@web/core/utils/numbers','@web/core/utils/objects','@web/core/utils/scrolling','@web/core/utils/timing','@web/core/browser/browser','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{clamp}=require("@web/core/utils/numbers");const{omit}=require("@web/core/utils/objects");const{closestScrollableX,closestScrollableY}=require("@web/core/utils/scrolling");const{setRecurringAnimationFrame}=require("@web/core/utils/timing");const{browser}=require("@web/core/browser/browser");const{hasTouch,isBrowserFirefox,isIOS}=require("@web/core/browser/feature_detection");const DRAGGABLE_CLASS="o_draggable";const DRAGGED_CLASS=__exports.DRAGGED_CLASS="o_dragged";const DEFAULT_ACCEPTED_PARAMS={allowDisconnected:[Boolean],enable:[Boolean,Function],preventDrag:[Function],ref:[Object],elements:[String],handle:[String,Function],ignore:[String,Function],cursor:[String],edgeScrolling:[Object,Function],delay:[Number],tolerance:[Number],touchDelay:[Number],iframeWindow:[Object,Function],};const DEFAULT_DEFAULT_PARAMS={allowDisconnected:false,elements:`.${DRAGGABLE_CLASS}`,enable:true,preventDrag:()=>false,edgeScrolling:{speed:10,threshold:30,},delay:0,tolerance:10,touchDelay:300,};const LEFT_CLICK=0;const MANDATORY_PARAMS=["ref"];const WHITE_LISTED_KEYS=["Alt","Control","Meta","Shift"];const elCache={};function camelToKebab(str){return str.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();} 4649function getReturnValue(valueOrFn){if(typeof valueOrFn==="function"){return valueOrFn();} 4650return valueOrFn;} 4651function getScrollParents(el){return[closestScrollableX(el),closestScrollableY(el)];} 4652function makeCleanupManager(defaultCleanupFn){const add=(cleanupFn)=>typeof cleanupFn==="function"&&cleanups.push(cleanupFn);const cleanup=()=>{while(cleanups.length){cleanups.pop()();} 4653add(defaultCleanupFn);};const cleanups=[];add(defaultCleanupFn);return{add,cleanup};} 4654function makeDOMHelpers(cleanup){const addClass=(el,...classNames)=>{if(!el||!classNames.length){return;} 4655cleanup.add(()=>el.classList.remove(...classNames));el.classList.add(...classNames);};const addListener=(el,event,callback,options={})=>{if(!el||!event||!callback){return;} 4656const{noAddedStyle}=options;delete options.noAddedStyle;el.addEventListener(event,callback,options);if(!noAddedStyle&&/mouse|pointer|touch/.test(event)){addStyle(el,{pointerEvents:"auto"});} 4657cleanup.add(()=>el.removeEventListener(event,callback,options));};const addStyle=(el,style)=>{if(!el||!style||!Object.keys(style).length){return;} 4658cleanup.add(saveAttribute(el,"style"));for(const key in style){const[value,priority]=String(style[key]).split(/\s*!\s*/);el.style.setProperty(camelToKebab(key),value,priority);}};const getRect=(el,options={})=>{if(!el){return{};} 4659const rect=el.getBoundingClientRect();rect.height=el.offsetHeight;if(options.adjust){const style=getComputedStyle(el);const[pl,pr,pt,pb]=["padding-left","padding-right","padding-top","padding-bottom",].map((prop)=>pixelValueToNumber(style.getPropertyValue(prop)));rect.x+=pl;rect.y+=pt;rect.width-=pl+pr;rect.height-=pt+pb;} 4660return rect;};const removeAttribute=(el,attribute)=>{if(!el||!attribute){return;} 4661cleanup.add(saveAttribute(el,attribute));el.removeAttribute(attribute);};const removeClass=(el,...classNames)=>{if(!el||!classNames.length){return;} 4662cleanup.add(saveAttribute(el,"class"));el.classList.remove(...classNames);};const removeStyle=(el,...properties)=>{if(!el||!properties.length){return;} 4663cleanup.add(saveAttribute(el,"style"));for(const key of properties){el.style.removeProperty(camelToKebab(key));}};const setAttribute=(el,attribute,value)=>
4663{if(!el||!attribute){return;} 4664cleanup.add(saveAttribute(el,attribute));el.setAttribute(attribute,String(value));};return{addClass,addListener,addStyle,getRect,removeAttribute,removeClass,removeStyle,setAttribute,};} 4665function pixelValueToNumber(val){return Number(val.endsWith("px")?val.slice(0,-2):val);} 4666function safePrevent(ev,{stop}={}){if(ev.cancelable){ev.preventDefault();if(stop){ev.stopPropagation();}}} 4667function saveAttribute(el,attribute){const restoreAttribute=()=>{cache.delete(el);if(hasAttribute){el.setAttribute(attribute,originalValue);}else{el.removeAttribute(attribute);}};if(!(attribute in elCache)){elCache[attribute]=new Set();} 4668const cache=elCache[attribute];if(cache.has(el)){return;} 4669cache.add(el);const hasAttribute=el.hasAttribute(attribute);const originalValue=el.getAttribute(attribute);return restoreAttribute;} 4670function toFunction(value){return typeof value==="function"?value:()=>value;} 4671__exports.makeDraggableHook=makeDraggableHook;function makeDraggableHook(hookParams){hookParams=getReturnValue(hookParams);const hookName=hookParams.name||"useAnonymousDraggable";const{setupHooks}=hookParams;const allAcceptedParams={...DEFAULT_ACCEPTED_PARAMS,...hookParams.acceptedParams};const defaultParams={...DEFAULT_DEFAULT_PARAMS,...hookParams.defaultParams};const computeParams=(params)=>{const computedParams={enable:()=>true};for(const prop in allAcceptedParams){if(prop in params){if(prop==="enable"){computedParams[prop]=toFunction(params[prop]);}else if(allAcceptedParams[prop].length===1&&allAcceptedParams[prop][0]===Function){computedParams[prop]=params[prop];}else{computedParams[prop]=getReturnValue(params[prop]);}}} 4672return Object.entries(computedParams);};const makeError=(reason)=>new Error(`Error in hook ${hookName}: ${reason}.`);let preventClick=false;return{[hookName](params){const callBuildHandler=(hookHandlerName,arg)=>{if(typeof hookParams[hookHandlerName]!=="function"){return;} 4673const returnValue=hookParams[hookHandlerName]({ctx,...helpers,...arg});if(returnValue){callHandler(hookHandlerName,returnValue);}};const callHandler=(handlerName,arg)=>{if(typeof params[handlerName]!=="function"){return;} 4674try{params[handlerName]({...dom,...ctx.pointer,...arg});}catch(err){dragEnd(null,true);throw err;}};const canStartDrag=()=>{const{pointer,current:{initialPosition},}=ctx;return(!ctx.tolerance||Math.hypot(pointer.x-initialPosition.x,pointer.y-initialPosition.y)>=ctx.tolerance);};const dragStart=()=>{state.dragging=true;state.willDrag=false;const isDocumentScrollingElement=ctx.current.container===ctx.current.container.ownerDocument.scrollingElement;[ctx.current.scrollParentX,ctx.current.scrollParentY]=isDocumentScrollingElement?[ctx.current.container,ctx.current.container]:getScrollParents(ctx.current.container);updateRects();const{x,y,width,height}=ctx.current.elementRect;ctx.current.offset={x:ctx.current.initialPosition.x-x,y:ctx.current.initialPosition.y-y,};if(ctx.followCursor){dom.addStyle(ctx.current.element,{width:`${width}px`,height:`${height}px`,"max-width":`${width}px`,"max-height":`${height}px`,position:"fixed !important",});updateElementPosition();} 4675dom.addClass(document.body,"pe-none","user-select-none");if(params.iframeWindow){for(const iframe of document.getElementsByTagName("iframe")){if(iframe.contentWindow===params.iframeWindow){dom.addClass(iframe,"pe-none","user-select-none");}}} 4676if(ctx.cursor){dom.addStyle(document.body,{cursor:ctx.cursor});} 4677if((ctx.current.scrollParentX||ctx.current.scrollParentY)&&ctx.edgeScrolling.enabled){const cleanupFn=setRecurringAnimationFrame(handleEdgeScrolling);cleanup.add(cleanupFn);} 4678dom.addClass(ctx.current.element,DRAGGED_CLASS);callBuildHandler("onDragStart");};const dragEnd=(target,inErrorState)=>{if(state.dragging){preventClick=true;if(!inErrorState){if(target&&(params.allowDisconnected||ctx.current.element.isConnected)){callBuildHandler("onDrop",{target});} 4679callBuildHandler("onDragEnd");}} 4680cleanup.cleanup();};const handleEdgeScrolling=(deltaTime)=>{updateRects();const{x:pointerX,y:pointerY}=ctx.pointer;const xRect=ctx.current.scrollParentXRect;const yRect=ctx.current.scrollParentYRect;const scrollParentYEl=ctx.current.scrollParentY;if(scrollParentYEl===ctx.current.container.ownerDocument.scrollingElement){y
4680Rect.y+=scrollParentYEl.scrollTop;} 4681const{direction,speed,threshold}=ctx.edgeScrolling;const correctedSpeed=(speed/16)*deltaTime;const diff={};ctx.current.scrollingEdge=null;if(xRect){const maxWidth=xRect.x+xRect.width;if(pointerX-xRect.x<threshold){diff.x=[pointerX-xRect.x,-1];ctx.current.scrollingEdge="left";}else if(maxWidth-pointerX<threshold){diff.x=[maxWidth-pointerX,1];ctx.current.scrollingEdge="right";}} 4682if(yRect){const maxHeight=yRect.y+yRect.height;if(pointerY-yRect.y<threshold){diff.y=[pointerY-yRect.y,-1];ctx.current.scrollingEdge="top";}else if(maxHeight-pointerY<threshold){diff.y=[maxHeight-pointerY,1];ctx.current.scrollingEdge="bottom";}} 4683const diffToScroll=([delta,sign])=>(1-Math.max(delta,0)/threshold)*correctedSpeed*sign;if((!direction||direction==="vertical")&&diff.y){ctx.current.scrollParentY.scrollBy({top:diffToScroll(diff.y)});} 4684if((!direction||direction==="horizontal")&&diff.x){ctx.current.scrollParentX.scrollBy({left:diffToScroll(diff.x)});} 4685callBuildHandler("onDrag");};const onClick=(ev)=>{if(preventClick){safePrevent(ev,{stop:true});}};const onKeyDown=(ev)=>{if(!state.dragging||!ctx.enable()){return;} 4686if(!WHITE_LISTED_KEYS.includes(ev.key)){safePrevent(ev,{stop:true});dragEnd(null);}};const onPointerCancel=()=>{dragEnd(null);};const onVisibilityChange=(ev)=>{if(ev.target.visibilityState==="hidden"){dragEnd(null);}};const onPointerDown=(ev)=>{preventClick=false;updatePointerPosition(ev);const initiationDelay=ev.pointerType==="touch"?ctx.touchDelay:ctx.delay;dragEnd(null);const fullSelectorEl=ev.target.closest(ctx.fullSelector);if(ev.button!==LEFT_CLICK||!ctx.enable()||!fullSelectorEl||(ctx.ignoreSelector&&ev.target.closest(ctx.ignoreSelector))||ctx.preventDrag(fullSelectorEl)){return;} 4687safePrevent(ev);ev.target.focus();let activeElement=document.activeElement;while(activeElement?.nodeName==="IFRAME"){activeElement=activeElement.contentDocument?.activeElement;} 4688if(activeElement&&!activeElement.contains(ev.target)){activeElement.blur();} 4689const{currentTarget,pointerId,target}=ev;ctx.current.initialPosition={...ctx.pointer};if(target.hasPointerCapture(pointerId)){target.releasePointerCapture(pointerId);} 4690if(initiationDelay){if(hasTouch()){if(ev.pointerType==="touch"){dom.addClass(target.closest(ctx.elementSelector),"o_touch_bounce");} 4691if(isBrowserFirefox()){const links=[...currentTarget.querySelectorAll("[href]")];if(currentTarget.hasAttribute("href")){links.unshift(currentTarget);} 4692for(const link of links){dom.removeAttribute(link,"href");}} 4693if(isIOS()){for(const image of currentTarget.getElementsByTagName("img")){dom.setAttribute(image,"draggable",false);}}} 4694ctx.current.timeout=browser.setTimeout(()=>{ctx.current.initialPosition={...ctx.pointer};willStartDrag(target);const{x:px,y:py}=ctx.pointer;const{x,y,width,height}=dom.getRect(ctx.current.element);if(px<x||x+width<px||py<y||y+height<py){dragEnd(null);}},initiationDelay);cleanup.add(()=>browser.clearTimeout(ctx.current.timeout));}else{willStartDrag(target);}};const onPointerMove=(ev)=>{updatePointerPosition(ev);if(!ctx.current.element||!ctx.enable()){return;} 4695safePrevent(ev);if(!state.dragging){if(!canStartDrag()){return;} 4696dragStart();}else if(!params.allowDisconnected&&!ctx.current.element.isConnected){return dragEnd(null);} 4697if(ctx.followCursor){updateElementPosition();} 4698callBuildHandler("onDrag");};const onPointerUp=(ev)=>{updatePointerPosition(ev);dragEnd(ev.target);};const updateElementPosition=()=>{const{containerRect,element,elementRect,offset}=ctx.current;const{width:ew,height:eh}=elementRect;const{x:cx,y:cy,width:cw,height:ch}=containerRect;dom.addStyle(element,{left:`${clamp(ctx.pointer.x - offset.x, cx, cx + cw - ew)}px`,top:`${clamp(ctx.pointer.y - offset.y, cy, cy + ch - eh)}px`,});};const updatePointerPosition=(ev)=>{ctx.pointer.x=ev.clientX;ctx.pointer.y=ev.clientY;};const updateRects=()=>{const{current}=ctx;const{container,element,scrollParentX,scrollParentY}=current;current.containerRect=dom.getRect(container,{adjust:true});let iframeOffsetX=0;let iframeOffsetY=0;const iframeEl=container.ownerDocument.defaultView.frameElement;if(iframeEl&&!iframeEl.contentDocument?.contains(element)){const{x,y}=dom.getRect(iframeEl);iframeOffsetX=x;iframeOffsetY=y;current.containerRect.x+=iframeOffsetX;current.containerRect.y+=iframeOffsetY;} 4699current.containerRect.width=container.scrollWidth;current.containerRect.height=container.scrollHeight;
4699current.scrollParentXRect=null;current.scrollParentYRect=null;if(ctx.edgeScrolling.enabled){if(scrollParentX){current.scrollParentXRect=dom.getRect(scrollParentX,{adjust:true});current.scrollParentXRect.x+=iframeOffsetX;current.scrollParentXRect.y+=iframeOffsetY;const right=Math.min(current.containerRect.left+container.scrollWidth,current.scrollParentXRect.right);current.containerRect.x=Math.max(current.containerRect.x,current.scrollParentXRect.x);current.containerRect.width=right-current.containerRect.x;} 4700if(scrollParentY){current.scrollParentYRect=dom.getRect(scrollParentY,{adjust:true});current.scrollParentYRect.x+=iframeOffsetX;current.scrollParentYRect.y+=iframeOffsetY;const bottom=Math.min(current.containerRect.top+container.scrollHeight,current.scrollParentYRect.bottom);current.containerRect.y=Math.max(current.containerRect.y,current.scrollParentYRect.y);current.containerRect.height=bottom-current.containerRect.y;}} 4701ctx.current.elementRect=dom.getRect(element);};const willStartDrag=(target)=>{ctx.current.element=target.closest(ctx.elementSelector);ctx.current.container=ctx.ref.el;cleanup.add(()=>(ctx.current={}));state.willDrag=true;callBuildHandler("onWillStartDrag");if(hasTouch()){dom.addListener(window,"touchmove",safePrevent,{passive:false,noAddedStyle:true,});if(params.iframeWindow){dom.addListener(params.iframeWindow,"touchmove",safePrevent,{passive:false,noAddedStyle:true,});}}};const cleanup=makeCleanupManager(()=>(state.dragging=false));const effectCleanup=makeCleanupManager();const dom=makeDOMHelpers(cleanup);const helpers={...dom,addCleanup:cleanup.add,addEffectCleanup:effectCleanup.add,callHandler,};const state=setupHooks.wrapState({dragging:false});for(const prop in allAcceptedParams){const type=typeof params[prop];const acceptedTypes=allAcceptedParams[prop].map((t)=>t.name.toLowerCase());if(params[prop]){if(!acceptedTypes.includes(type)){throw makeError(`invalid type for property "${prop}" in parameters: expected { ${acceptedTypes.join( 4702 ", " 4703 )} } and got ${type}`);}}else if(MANDATORY_PARAMS.includes(prop)&&!defaultParams[prop]){throw makeError(`missing required property "${prop}" in parameters`);}} 4704const ctx={enable:()=>false,preventDrag:()=>false,ref:params.ref,ignoreSelector:null,fullSelector:null,followCursor:true,cursor:null,pointer:{x:0,y:0},edgeScrolling:{enabled:true},get dragging(){return state.dragging;},get willDrag(){return state.willDrag;},current:{},};setupHooks.setup((...deps)=>{const params=Object.fromEntries(deps);const actualParams={...defaultParams,...omit(params,"edgeScrolling")};if(params.edgeScrolling){actualParams.edgeScrolling={...actualParams.edgeScrolling,...params.edgeScrolling,};} 4705if(!ctx.ref.el){return;} 4706ctx.enable=actualParams.enable;if(actualParams.preventDrag){ctx.preventDrag=actualParams.preventDrag;} 4707ctx.elementSelector=actualParams.elements;if(!ctx.elementSelector){throw makeError(`no value found by "elements" selector: ${ctx.elementSelector}`);} 4708const allSelectors=[ctx.elementSelector];ctx.cursor=actualParams.cursor||null;if(actualParams.handle){allSelectors.push(actualParams.handle);} 4709if(actualParams.ignore){ctx.ignoreSelector=actualParams.ignore;} 4710ctx.fullSelector=allSelectors.join(" ");Object.assign(ctx.edgeScrolling,actualParams.edgeScrolling);ctx.delay=actualParams.delay;ctx.touchDelay=actualParams.delay||actualParams.touchDelay;ctx.tolerance=actualParams.tolerance;callBuildHandler("onComputeParams",{params:actualParams});return effectCleanup.cleanup;},()=>computeParams(params));const useMouseEvents=isBrowserFirefox()&&!hasTouch()&¶ms.iframeWindow;setupHooks.setup((el)=>{if(el){const{add,cleanup}=makeCleanupManager();const{addListener}=makeDOMHelpers({add});const event=useMouseEvents?"mousedown":"pointerdown";addListener(el,event,onPointerDown,{noAddedStyle:true});addListener(el,"click",onClick);if(hasTouch()){addListener(el,"contextmenu",safePrevent);addListener(el,"touchstart",()=>{},{passive:false,noAddedStyle:true,});} 4711return cleanup;}},()=>[ctx.ref.el]);const addWindowListener=(type,listener,options)=>{if(params.iframeWindow){setupHooks.addListener(params.iframeWindow,type,listener,options);} 4712setupHooks.addListener(window,type,listener,options);};const throttledOnPointerMove=setupHooks.throttle(onPointerMove);addWindowListener(useMouseEvents?"mousemove":"pointermove",throttledOnPointerMove,{passive:false});addWindowListener(useMouseEvents?"mouseup":"pointerup",onPointerUp);addWindowListener("pointercancel",onPointerCancel);addWindowListener("keydown",onKeyDown,{capture:true});setupHooks.addListener(document,"visibilitychange",onVisibilityChange);setupHooks.teardown(()=>dragEnd(null));return state;},}[hookName];} 4713return __exports;});; 4714 4715/* /web/static/src/core/utils/draggable_hook_builder_owl.js */ 4716odoo.define('@web/core/utils/draggable_hook_builder_owl',['@odoo/owl','@web/core/utils/timing','@web/core/utils/draggable_hook_builder'],function(require){'use strict';let __exports={};const{onWillUnmount,reactive,useEffect,useExternalListener}=require("@odoo/owl");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{makeDraggableHook:nativeMakeDraggableHook}=require("@web/core/utils/draggable_hook_builder");__exports.makeDraggableHook=makeDraggableHook;function makeDraggableHook(params){return nativeMakeDraggableHook({...params,setupHooks:{addListener:useExternalListener,setup:useEffect,teardown:onWillUnmount,throttle:useThrottleForAnimation,wrapState:reactive,},});} 4717return __exports;});; 4718 4719/* /web/static/src/core/utils/dvu.js */ 4720odoo.define('@web/core/utils/dvu',['@web/core/utils/timing','@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{throttleForAnimation}=require("@web/core/utils/timing");const{onWillUnmount}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isVirtualKeyboardSupported}=require("@web/core/browser/feature_detection");const viewport={listeners:[],addListener(listener){this.listeners.push(listener);return()=>{const index=this.listeners.indexOf(listener);if(index!==-1){this.listeners.splice(index,1);}};}
4720,notifyListeners(){this.listeners.forEach((listener)=>listener());},};if(typeof window!=="undefined"){const throttledUpdate=throttleForAnimation(()=>viewport.notifyListeners());if(browser.visualViewport){browser.visualViewport.addEventListener("resize",throttledUpdate);} 4721if(isVirtualKeyboardSupported()){browser.navigator.virtualKeyboard.addEventListener("geometrychange",throttledUpdate);} 4722browser.addEventListener("resize",throttledUpdate);} 4723__exports.getViewportDimensions=getViewportDimensions;function getViewportDimensions(){return{width:browser.visualViewport?.width||browser.innerWidth,height:browser.visualViewport?.height||browser.innerHeight,};} 4724__exports.onViewportChange=onViewportChange;function onViewportChange(callback){return viewport.addListener(callback);} 4725__exports.useViewportChange=useViewportChange;function useViewportChange(callback){const removeListener=onViewportChange(callback);onWillUnmount(()=>removeListener());} 4726return __exports;});; 4727 4728/* /web/static/src/core/utils/files.js */ 4729odoo.define('@web/core/utils/files',['@web/core/utils/numbers','@web/core/utils/hooks','@web/session','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{humanNumber}=require("@web/core/utils/numbers");const{useService}=require("@web/core/utils/hooks");const{session}=require("@web/session");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const DEFAULT_MAX_FILE_SIZE=__exports.DEFAULT_MAX_FILE_SIZE=128*1024*1024;__exports.checkFileSize=checkFileSize;function checkFileSize(fileSize,notificationService){const maxUploadSize=session.max_file_upload_size||DEFAULT_MAX_FILE_SIZE;if(fileSize>maxUploadSize){notificationService.add(_t("The selected file (%(size)sB) is larger than the maximum allowed file size (%(maxSize)sB).",{size:humanNumber(fileSize),maxSize:humanNumber(maxUploadSize)}),{type:"danger",});return false;} 4730return true;} 4731__exports.useFileUploader=useFileUploader;function useFileUploader(){const http=useService("http");const notification=useService("notification");return async(route,params)=>{if((params.ufile&¶ms.ufile.length)||params.file){const fileSize=(params.ufile&¶ms.ufile[0].size)||params.file.size;if(!checkFileSize(fileSize,notification)){return null;}} 4732const fileData=await http.post(route,params,"text");const parsedFileData=JSON.parse(fileData);if(parsedFileData.error){throw new Error(parsedFileData.error);} 4733return parsedFileData;};} 4734__exports.resizeBlobImg=resizeBlobImg;function resizeBlobImg(blob,params={}){if(!blob.type||!blob.type.startsWith("image/")){return Promise.reject(new Error(_t("The file is not an image, resizing is not possible")));} 4735const{width,height,offsetX,offsetY}={width:256,height:256,offsetX:0.5,offsetY:0.5,...params,};return new Promise((resolve,reject)=>{const img=new Image();img.onload=()=>{if(width<img.width||height<img.height){const canvas=document.createElement("canvas");canvas.width=width;canvas.height=height;const ctx=canvas.getContext("2d");ctx.imageSmoothingQuality="high";ctx.mozImageSmoothingEnabled=true;ctx.webkitImageSmoothingEnabled=true;ctx.msImageSmoothingEnabled=true;ctx.imageSmoothingEnabled=true;const srcRatio=img.width/img.height;const dWidth=Math.min(Math.floor(height*srcRatio),width);const dHeight=Math.min(Math.floor(width/srcRatio),height);const dx=Math.round((width-dWidth)*offsetX);const dy=Math.round((height-dHeight)*offsetY);ctx.drawImage(img,0,0,img.width,img.height,dx,dy,dWidth,dHeight);canvas.toBlob(resolve);}else{resolve(blob);}};img.onerror=()=>{reject(new Error(_t("The resizing of the image failed")));};img.src=URL.createObjectURL(blob);});} 4736return __exports;});; 4737 4738/* /web/static/src/core/utils/functions.js */ 4739odoo.define('@web/core/utils/functions',[],function(require){'use strict';let __exports={};__exports.memoize=memoize;function memoize(func){const cache=new Map();const funcName=func.name?func.name+" (memoized)":"memoized";return{[funcName](...args){if(!cache.has(args[0])){cache.set(args[0],func(...args));} 4740return cache.get(...args);},}[funcName];} 4741__exports.uniqueId=uniqueId;function uniqueId(prefix=""){return`${prefix}${++uniqueId.nextId}`;} 4742uniqueId.nextId=0;return __exports;});; 4743 4744/* /web/static/src/core/utils/hooks.js */ 4745odoo.define('@web/core/utils/hooks',['@web/core/browser/feature_detection','@odoo/owl'],function(require){'use strict';let __exports={};const{hasTouch,isMobileOS}=require("@web/core/browser/feature_detection");const{status,useComponent,useEffect,useRef,onWillUnmount,useState,toRaw}=require("@odoo/owl");__exports.useAutofocus=useAutofocus;function useAutofocus({refName,selectAll,mobile}={}){const ref=useRef(refName||"autofocus");const uiService=useService("ui");if(!mobile&&hasTouch()){return ref;} 4746if(!mobile&&isMobileOS()){return ref;} 4747function isFocusable(el){if(!el){return;} 4748if(!uiService.activeElement||uiService.activeElement.contains(el)){return true;} 4749const rootNode=el.getRootNode();return rootNode instanceof ShadowRoot&&uiService.activeElement.contains(rootNode.host);} 4750useEffect((el)=>{if(isFocusable(el)){el.focus();if(["INPUT","TEXTAREA"].includes(el.tagName)&&el.type!=="number"){el.selectionEnd=el.value.length;el.selectionStart=selectAll?0:el.value.length;}}},()=>[ref.el]);return ref;} 4751__exports.useBus=useBus;function useBus(bus,eventName,callback){const component=useComponent();useEffect(()=>{const listener=callback.bind(component);bus.addEventListener(eventName,listener);return()=>bus.removeEventListener(eventName,listener);},()=>[]);} 4752const useServiceProtectMethodHandling=__exports.useServiceProtectMethodHandling={fn(){return this.original();},mocked(){return new Promise(()=>{});},original(){return Promise.reject(new Error("Component is destroyed"));},};function _protectMethod(component,fn){return function(...args){if(status(component)==="destroyed"){return useServiceProtectMethodHandling.fn();} 4753const prom=Promise.resolve(fn.call(this,...args));const protectedProm=prom.then((result)=>status(component)==="destroyed"?new Promise(()=>{}):result);return Object.assign(protectedProm,{abort:prom.abort,cancel:prom.cancel,});};} 4754const SERVICES_METADATA=__exports.SERVICES_METADATA={};__exports.useService=useService;function useService(serviceName){const component=useComponent();const{services}=component.env;if(!(serviceName in services)){throw new Error(`Service ${serviceName} is not available`);} 4755const service=services[serviceName];if(SERVICES_METADATA[serviceName]){if(service instanceof Function){return _protectMethod(component,service);}else{const methods=SERVICES_METADATA[serviceName]??[];const result=Object.create(service);for(const method of methods){result[method]=_protectMethod(component,service[method]);} 4756return result;}} 4757if(toRaw(service)!==service){return useState(service);} 4758return service;}
4759__exports.useSpellCheck=useSpellCheck;function useSpellCheck({refName}={}){const elements=[];const ref=useRef(refName||"spellcheck");function toggleSpellcheck(ev){ev.target.spellcheck=document.activeElement===ev.target;} 4760useEffect((el)=>{if(el){const inputs=["INPUT","TEXTAREA"].includes(el.nodeName)||el.isContentEditable?[el]:el.querySelectorAll("input, textarea, [contenteditable=true]");inputs.forEach((input)=>{if(input.spellcheck!==false){elements.push(input);input.addEventListener("focus",toggleSpellcheck);input.addEventListener("blur",toggleSpellcheck);}});} 4761return()=>{elements.forEach((input)=>{input.removeEventListener("focus",toggleSpellcheck);input.removeEventListener("blur",toggleSpellcheck);});};},()=>[ref.el]);} 4762__exports.useChildRef=useChildRef;function useChildRef(){let defined=false;let value;return function ref(v){value=v;if(defined){return;} 4763Object.defineProperty(ref,"el",{get(){return value.el;},});defined=true;};} 4764__exports.useForwardRefToParent=useForwardRefToParent;function useForwardRefToParent(refName){const component=useComponent();const ref=useRef(refName);if(component.props[refName]){component.props[refName](ref);} 4765return ref;} 4766__exports.useOwnedDialogs=useOwnedDialogs;function useOwnedDialogs(){const dialogService=useService("dialog");const cbs=[];onWillUnmount(()=>{cbs.forEach((cb)=>cb());});const addDialog=(...args)=>{const close=dialogService.add(...args);cbs.push(close);return close;};return addDialog;} 4767__exports.useRefListener=useRefListener;function useRefListener(ref,...listener){useEffect((el)=>{el?.addEventListener(...listener);return()=>el?.removeEventListener(...listener);},()=>[ref.el]);} 4768return __exports;});; 4769 4770/* /web/static/src/core/utils/html.js */ 4771odoo.define('@web/core/utils/html',['@odoo/owl','@web/core/l10n/utils','@web/core/utils/arrays','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{htmlEscape,markup}=require("@odoo/owl");const{formatList,normalizedMatches}=require("@web/core/l10n/utils");const{unique}=require("@web/core/utils/arrays");const{escapeRegExp,mapSubstitutions,sprintf}=require("@web/core/utils/strings");const Markup=markup().constructor;__exports.createDocumentFragmentFromContent=createDocumentFragmentFromContent;function createDocumentFragmentFromContent(content){return new document.defaultView.DOMParser().parseFromString(htmlEscape(content),"text/html");} 4772__exports.createElementWithContent=createElementWithContent;function createElementWithContent(elementName,content){const element=document.createElement(elementName);setElementContent(element,content);return element;} 4773__exports.highlightText=highlightText;function highlightText(query,text,classes){if(!query||!text){return text;} 4774let result=text;const isQueryMarkup=isMarkup(query);const matches=unique(normalizedMatches(result,query).map((m)=>isQueryMarkup?markup(m.match.toLowerCase()):m.match.toLowerCase()));for(const match of matches){const regex=new RegExp(`(?<!&[^;]{0,5})(${escapeRegExp(htmlEscape(match))})(?=(?:[^>]*<[^<]*>)*[^<>]*$)`,"ig");result=htmlReplace(result,regex,(_,match)=>{match=markup(match);return markup`<span class="${classes}">${match}</span>`;});} 4775return result;} 4776__exports.htmlFormatList=htmlFormatList;function htmlFormatList(values,options){return markup(formatList(Array.from(values,htmlEscape),options));} 4777__exports.htmlJoin=htmlJoin;function htmlJoin(list,separator=""){return markup(Array.from(list,htmlEscape).join(htmlEscape(separator)));} 4778__exports.htmlReplace=htmlReplace;function htmlReplace(content,search,replacer){const isReplacerFn=typeof replacer==="function";if(search instanceof RegExp&&!isReplacerFn){throw new TypeError("htmlReplace: replacer must be a function when search is a RegExp.");} 4779content=htmlEscape(content);if(typeof search==="string"||search instanceof String){search=htmlEscape(search);} 4780const safeReplacement=isReplacerFn?(...args)=>htmlEscape(replacer(...args)):htmlEscape(replacer);return markup(content.replace(search,safeReplacement));} 4781__exports.htmlReplaceAll=htmlReplaceAll;function htmlReplaceAll(content,search,replacer){const isReplacerFn=typeof replacer==="function";if(search instanceof RegExp&&!isReplacerFn){throw new TypeError("htmlReplaceAll: replacer must be a function when search is a RegExp.");} 4782content=htmlEscape(content);
4782if(typeof search==="string"||search instanceof String){search=htmlEscape(search);} 4783const safeReplacement=isReplacerFn?(...args)=>htmlEscape(replacer(...args)):htmlEscape(replacer);return markup(content.replaceAll(search,safeReplacement));} 4784__exports.htmlSprintf=htmlSprintf;function htmlSprintf(str,...substitutions){const replaced=sprintf(htmlEscape(str),...mapSubstitutions(substitutions,htmlEscape));return markup(replaced);} 4785__exports.htmlTrim=htmlTrim;function htmlTrim(content){content=htmlEscape(content);return markup(content.trim());} 4786__exports.isHtmlEmpty=isHtmlEmpty;function isHtmlEmpty(content=""){return createElementWithContent("div",content).textContent.trim()==="";} 4787__exports.isMarkup=isMarkup;function isMarkup(content){return content instanceof Markup;} 4788__exports.odoomark=odoomark;function odoomark(text){const replacers=[["\n",markup`<br>`],["\t",markup`<span style="margin-left: 2em"></span>`],[/\*\*(.+?)\*\*/g,(_,content)=>markup(`<b>${content}</b>`)],[/--(.+?)--/g,(_,content)=>markup(`<span class="text-muted">${content}</span>`)],[/`(.+?)`/g,(_,content)=>markup(`<span class="o_tag position-relative d-inline-flex align-items-center mw-100 o_badge badge rounded-pill lh-1 o_tag_color_0">${content}</span>`),],];for(const[pattern,replacer]of replacers){text=htmlReplaceAll(text,pattern,replacer);} 4789return text;} 4790__exports.setElementContent=setElementContent;function setElementContent(element,content){if(isMarkup(content)){element.innerHTML=content;}else{element.textContent=content;}} 4791return __exports;});; 4792 4793/* /web/static/src/core/utils/indexed_db.js */ 4794odoo.define('@web/core/utils/indexed_db',['@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{Mutex}=require("@web/core/utils/concurrency");const VERSION_TABLE="__DBVersion__";const VERSION_KEY="__version__";const IDBQuotaExceededError=__exports.IDBQuotaExceededError=class IDBQuotaExceededError extends Error{} 4795function formatStorageSize(size){const units=["b","Kb","Mb","Gb"];while(size>=1000&&units.length>1){size/=1000;units.splice(0,1);} 4796return`${size.toFixed(2)}${units[0]}`;} 4797const IndexedDB=__exports.IndexedDB=class IndexedDB{constructor(name,version){this.name=name;this._tables=new Set([VERSION_TABLE]);this.mutex=new Mutex();this.mutex.exec(()=>this._checkVersion(version));} 4798async read(table,key){this._tables.add(table);return this.execute((db)=>{if(db){return this._read(db,table,key);}});} 4799async write(table,key,value){this._tables.add(table);return this.execute((db)=>{if(db){return this._write(db,table,key,value);}});} 4800async invalidate(tables=null){return this.execute((db)=>{if(db){return this._invalidate(db,typeof tables==="string"?[tables]:tables);}});} 4801async deleteDatabase(){return this.mutex.exec(()=>this._deleteDatabase(()=>{}));} 4802async execute(callback){return this.mutex.exec(()=>this._execute(callback));} 4803async _deleteDatabase(callback){return new Promise((resolve)=>{const request=indexedDB.deleteDatabase(this.name);request.onsuccess=()=>{Promise.resolve(callback()).then(resolve);};request.onerror=(event)=>{console.error(`IndexedDB delete error: ${event.target.error?.message}`);Promise.resolve(callback()).then(resolve);};});} 4804async _checkVersion(version){return new Promise((resolve)=>{this._execute((db)=>{if(db){return this._read(db,VERSION_TABLE,VERSION_KEY);}}).then((currentVersion)=>{if(!currentVersion){this._execute((db)=>{if(db){this._write(db,VERSION_TABLE,VERSION_KEY,version);}}).then(resolve);}else if(currentVersion!==version){this._deleteDatabase(()=>{this._execute((db)=>{if(db){this._write(db,VERSION_TABLE,VERSION_KEY,version);}});}).then(resolve);}else{resolve();}});});} 4805async _execute(callback,idbVersion){return new Promise((resolve,reject)=>{const request=indexedDB.open(this.name,idbVersion);request.onupgradeneeded=(event)=>{const db=event.target.result;const dbTables=new Set(db.objectStoreNames);const newTables=this._tables.difference(dbTables);newTables.forEach((table)=>db.createObjectStore(table));};request.onsuccess=(event)=>{const db=event.target.result;const dbTables=new Set(db.objectStoreNames);const newTables=this._tables.difference(dbTables);if(newTables.size!==0){db.close();const version=db.version+1;return this._execute(callback,version).then(resolve);}
4806Promise.resolve(callback(db)).then(resolve).catch(async(e)=>{if(e.name==="QuotaExceededError"){const{quota,usage}=await navigator.storage.estimate();console.error(`IndexedDB error: Quota Exceeded (${formatStorageSize( 4807 usage 4808 )} out of ${formatStorageSize(quota)} used)`);reject(new IDBQuotaExceededError());}else{reject(e);}}).finally(()=>db.close());};request.onerror=(event)=>{console.error(`IndexedDB error: ${event.target.error?.message}`);Promise.resolve(callback()).then(resolve);};});} 4809async _write(db,table,key,record){return new Promise((resolve,reject)=>{const transaction=db.transaction(table,"readwrite",{durability:"relaxed"});transaction.objectStore(table).put(record,key);transaction.onerror=(ev)=>reject(ev.target.error);transaction.onabort=(ev)=>reject(ev.target.error);transaction.oncomplete=resolve;transaction.commit();});} 4810async _invalidate(db,tables){return new Promise((resolve,reject)=>{const objectStoreNames=[...db.objectStoreNames].filter((table)=>table!==VERSION_TABLE);tables=tables?objectStoreNames.filter((t)=>tables.includes(t)):objectStoreNames;if(tables.length===0){return resolve();} 4811const transaction=db.transaction(tables,"readwrite",{durability:"relaxed"});const proms=tables.map((table)=>new Promise((resolve)=>{const objectStore=transaction.objectStore(table);const request=objectStore.clear();request.onsuccess=resolve;}));transaction.onerror=()=>reject(transaction.error);Promise.all(proms).then(resolve);transaction.commit();});} 4812async _read(db,table,key){return new Promise((resolve,reject)=>{const transaction=db.transaction(table,"readonly");const objectStore=transaction.objectStore(table);const r=objectStore.get(key);r.onsuccess=()=>resolve(r.result);transaction.onerror=()=>reject(transaction.error);});}} 4813return __exports;});; 4814 4815/* /web/static/src/core/utils/misc.js */ 4816odoo.define('@web/core/utils/misc',[],function(require){'use strict';let __exports={};const eventHandledWeakMap=new WeakMap();__exports.isEventHandled=isEventHandled;function isEventHandled(ev,markName){if(!eventHandledWeakMap.get(ev)){return false;} 4817return eventHandledWeakMap.get(ev).includes(markName);} 4818__exports.markEventHandled=markEventHandled;function markEventHandled(ev,markName){if(!eventHandledWeakMap.get(ev)){eventHandledWeakMap.set(ev,[]);} 4819eventHandledWeakMap.get(ev).push(markName);} 4820return __exports;});; 4821 4822/* /web/static/src/core/utils/nested_sortable.js */ 4823odoo.define('@web/core/utils/nested_sortable',['@web/core/l10n/localization','@web/core/utils/draggable_hook_builder_owl'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const useNestedSortable=__exports.useNestedSortable=makeDraggableHook({name:"useNestedSortable",acceptedParams:{groups:[String,Function],connectGroups:[Boolean,Function],nest:[Boolean],listTagName:[String],nestInterval:[Number],maxLevels:[Number],isAllowed:[Function],useElementSize:[Boolean],},defaultParams:{connectGroups:false,currentGroup:null,cursor:"grabbing",edgeScrolling:{speed:20,threshold:60},elements:"li",groupSelector:null,nest:false,listTagName:"ul",nestInterval:15,maxLevels:0,isAllowed:(ctx)=>true,useElementSize:false,},onComputeParams({ctx,params}){ctx.groupSelector=params.groups||null;if(ctx.groupSelector){ctx.fullSelector=[ctx.groupSelector,ctx.fullSelector].join(" ");} 4824ctx.connectGroups=params.connectGroups;ctx.nest=params.nest;ctx.listTagName=params.listTagName;ctx.nestInterval=params.nestInterval;ctx.isRTL=localization.direction==="rtl";ctx.maxLevels=params.maxLevels||0;ctx.isAllowed=params.isAllowed??(()=>true);ctx.useElementSize=params.useElementSize;},onWillStartDrag({ctx,addCleanup}){if(ctx.groupSelector){ctx.currentGroup=ctx.current.element.closest(ctx.groupSelector);if(!ctx.connectGroups){ctx.current.container=ctx.currentGroup;}} 4825if(ctx.nest){ctx.prevNestX=ctx.pointer.x;} 4826ctx.current.placeHolder=ctx.current.element.cloneNode(false);ctx.current.placeHolder.removeAttribute("id");ctx.current.placeHolder.classList.add("w-100","d-block");if(ctx.useElementSize){ctx.current.placeHolder.style.height=getComputedStyle(ctx.current.element).height;ctx.current.placeHolder.classList.add("o_nested_sortable_placeholder_realsize");}else{ctx.current.placeHolder.classList.add("o_nested_sortable_placeholder");} 4827addCleanup(()=>ctx.current.placeHolder.remove());},onDragStart({ctx,addStyle}){ctx.selectorX=ctx.isRTL?ctx.current.elementRect.left+1:ctx.current.elementRect.right-1;ctx.current.element.after(ctx.current.placeHolder);addStyle(ctx.current.element,{opacity:0.5});addStyle(document.body,{"pointer-events":"auto"});addStyle(document.querySelector(".o_navbar"),{"pointer-events":"none"});addStyle(document.querySelector(".o_action_manager"),{"pointer-events":"none"});addStyle(ctx.current.container,{"pointer-events":"auto"});return{element:ctx.current.element,group:ctx.currentGroup,};},_getDeepestChildLevel(ctx,node,depth=0){let result=0;const childSelector=`${ctx.listTagName} ${ctx.elementSelector}`;for(const childNode of node.querySelectorAll(childSelector)){result=Math.max(this._getDeepestChildLevel(ctx,childNode,depth+1),result);} 4828return depth?result+1:result;},_hasReachMaxAllowedLevel(ctx){if(!ctx.nest||ctx.maxLevels<1){return false;} 4829let level=this._getDeepestChildLevel(ctx,ctx.current.element);let list=ctx.current.placeHolder.closest(ctx.listTagName);while(list){level++;list=list.parentNode.closest(ctx.listTagName);} 4830return level>ctx.maxLevels;},_isAllowedNodeMove(ctx){return(!this._hasReachMaxAllowedLevel(ctx)&&ctx.isAllowed(ctx.current,ctx.elementSelector));},onDrag({ctx,callHandler}){const onMove=(prevPos)=>{if(!ctx.isAllowed(ctx.current,ctx.elementSelector)){ctx.current.placeHolder.classList.add("d-none");return;}else if(this._hasReachMaxAllowedLevel(ctx)){const previousSiblingEl=ctx.current.placeHolder.closest(ctx.listTagName).closest(ctx.elementSelector);previousSiblingEl.after(ctx.current.placeHolder);return;} 4831ctx.current.placeHolder.classList.remove("d-none");callHandler("onMove",{element:ctx.current.element,previous:ctx.current.placeHolder.previousElementSibling,next:ctx.current.placeHolder.nextElementSibling,parent:ctx.nest?ctx.current.placeHolder.parentElement.closest(ctx.elementSelector):false,group:ctx.currentGroup,newGroup:ctx.connectGroups?ctx.current.placeHolder.closest(ctx.groupSelector):ctx.currentGroup,prevPos,placeholder:ctx.current.placeHolder,});};const getChildList=(el)=>{let list=el.querySelector(ctx.listTagName);if(!list){list=document.createElement(ctx.listTagName);el.appendChild(list);} 4832return list;};const getPosition=(el)=>{return{previous:el.previousElementSibling,next:el.nextElementSibling,parent:el.parentElement?.closest(ctx.elementSelector)||null,group:ctx.groupSelector?el.closest(ctx.groupSelector):false,};};const position=getPosition(ctx.current.placeHolder);if(ctx.nest){const xInterval=ctx.prevNestX-ctx.pointer.x;if(ctx.nestInterval-(-1)**ctx.isRTL*xInterval<1){let nextElement=position.next;if(nextElement===ctx.current.element){nextElement=nextElement.nextElementSibling;} 4833if(!nextElement){const newSibling=position.parent;if(newSibling){newSibling.after(ctx.current.placeHolder);onMove(position);}} 4834ctx.prevNestX=ctx.pointer.x;return;}else if(ctx.nestInterval+(-1)**ctx.isRTL*xInterval<1){let parent=position.previous;if(parent===ctx.current.element){parent=parent.previousElementSibling;} 4835if(parent&&parent.matches(ctx.elementSelector)){getChildList(parent).appendChild(ctx.current.placeHolder);onMove(position);} 4836ctx.prevNestX=ctx.pointer.x;return;}} 4837const currentTop=ctx.pointer.y-ctx.current.offset.y;const closestEl=document.elementFromPoint(ctx.selectorX,currentTop);
4837if(!closestEl){return;} 4838const element=closestEl.closest(ctx.elementSelector);if(element&&element!==ctx.current.placeHolder){const elementPosition=getPosition(element);const eRect=element.getBoundingClientRect();const pos=ctx.current.placeHolder.compareDocumentPosition(element);if(currentTop-eRect.y<10){if(pos&Node.DOCUMENT_POSITION_PRECEDING&&(ctx.nest||elementPosition.parent===position.parent)){element.before(ctx.current.placeHolder);onMove(position);ctx.prevNestX=ctx.pointer.x;}}else if(currentTop-eRect.y>15&&pos===Node.DOCUMENT_POSITION_FOLLOWING){if(ctx.nest){const elementChildList=getChildList(element);if(elementChildList.querySelector(ctx.elementSelector)){elementChildList.prepend(ctx.current.placeHolder);onMove(position);}else{element.after(ctx.current.placeHolder);onMove(position);} 4839ctx.prevNestX=ctx.pointer.x;}else if(elementPosition.parent===position.parent){element.after(ctx.current.placeHolder);onMove(position);}}}else{const group=closestEl.closest(ctx.groupSelector);if(group&&group!==position.group&&(ctx.nest||!position.parent)){if(group.compareDocumentPosition(position.group)===Node.DOCUMENT_POSITION_PRECEDING){getChildList(group).prepend(ctx.current.placeHolder);onMove(position);}else{getChildList(group).appendChild(ctx.current.placeHolder);onMove(position);} 4840ctx.prevNestX=ctx.pointer.x;callHandler("onGroupEnter",{group,placeholder:ctx.current.placeHolder});callHandler("onGroupLeave",{group:position.group,placeholder:ctx.current.placeHolder,});}}},onDrop({ctx}){if(!this._isAllowedNodeMove(ctx)){return;} 4841const previous=ctx.current.placeHolder.previousElementSibling;const next=ctx.current.placeHolder.nextElementSibling;if(previous!==ctx.current.element&&next!==ctx.current.element){return{element:ctx.current.element,group:ctx.currentGroup,previous,next,newGroup:ctx.groupSelector&&ctx.current.placeHolder.closest(ctx.groupSelector),parent:ctx.current.placeHolder.parentElement.closest(ctx.elementSelector),placeholder:ctx.current.placeHolder,};}},onDragEnd({ctx}){return{element:ctx.current.element,group:ctx.currentGroup,};},});return __exports;});; 4842 4843/* /web/static/src/core/utils/numbers.js */ 4844odoo.define('@web/core/utils/numbers',['@web/core/l10n/localization','@web/core/l10n/translation','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{localization:l10n}=require("@web/core/l10n/localization");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{intersperse}=require("@web/core/utils/strings");__exports.clamp=clamp;function clamp(num,min,max){return Math.max(Math.min(num,max),min);} 4845__exports.range=range;function range(start,stop,step=1){const array=[];const nsteps=Math.floor((stop-start)/step);for(let i=0;i<nsteps;i++){array.push(start+step*i);} 4846return array;} 4847__exports.roundPrecision=roundPrecision;function roundPrecision(value,precision,method="HALF-UP"){if(!value){return 0;}else if(!precision||precision<0){precision=1;} 4848let roundingFactor=precision;let normalize=(val)=>val/roundingFactor;let denormalize=(val)=>val*roundingFactor;if(roundingFactor<1){roundingFactor=invertFloat(roundingFactor);[normalize,denormalize]=[denormalize,normalize];} 4849const normalizedValue=normalize(value);const sign=Math.sign(normalizedValue);const epsilonMagnitude=Math.log2(Math.abs(normalizedValue));const epsilon=Math.pow(2,epsilonMagnitude-50);let roundedValue;switch(method){case"DOWN":{roundedValue=Math.trunc(normalizedValue+sign*epsilon);break;} 4850case"HALF-DOWN":{roundedValue=Math.round(normalizedValue-sign*epsilon);break;} 4851case"HALF-UP":{roundedValue=Math.round(normalizedValue+sign*epsilon);break;} 4852case"HALF-EVEN":{const integral=Math.floor(normalizedValue);const remainder=Math.abs(normalizedValue-integral);const isHalf=Math.abs(0.5-remainder)<epsilon;roundedValue=isHalf?integral+(integral&1):Math.round(normalizedValue);break;} 4853case"UP":{roundedValue=Math.trunc(normalizedValue+sign*(1-epsilon));break;} 4854default:{throw new Error(`Unknown rounding method: ${method}`);}} 4855return denormalize(roundedValue);} 4856function formatFixedDecimals(value,decimals){const rounded=roundDecimals(value,decimals);const[intPart,decPart=""]=rounded.toString().split(".");const paddedDecimals=decPart.padEnd(decimals,"0").slice(0,decimals);return decimals===0?intPart:`${intPart}.${paddedDecimals}`;} 4857__exports.roundDecimals=roundDecimals;function roundDecimals(value,decimals){return roundPrecision(value,parseFloat("1e"+-decimals));} 4858__exports.floatIsZero=floatIsZero;function floatIsZero(value,decimals){return value===0||roundDecimals(value,decimals)===0;} 4859__exports.insertThousandsSep=insertThousandsSep;function insertThousandsSep(number,thousandsSep=",",grouping=[]){const negative=number[0]==="-";number=negative?number.slice(1):number;return(negative?"-":"")+intersperse(number,grouping,thousandsSep);} 4860__exports.humanNumber=humanNumber;function humanNumber(number,options={decimals:0,minDigits:1}){const decimals=options.decimals||0;const minDigits=options.minDigits||1;const d2=Math.pow(10,decimals);const numberMagnitude=+number.toExponential().split("e+")[1];number=Math.round(number*d2)/d2;if(numberMagnitude>=21){number=Math.round(number*Math.pow(10,decimals-numberMagnitude))/d2;return`${number}e+${numberMagnitude}`;} 4861const unitSymbols=_t("kMGTPE").toString();const sign=Math.sign(number);number=Math.abs(number);let symbol="";for(let i=unitSymbols.length;i>0;i--){const s=Math.pow(10,i*3);
4861if(s<=number/Math.pow(10,minDigits-1)){number=Math.round((number*d2)/s)/d2;symbol=unitSymbols[i-1];break;}} 4862const{decimalPoint,grouping,thousandsSep}=l10n;const decimalsToKeep=number>=1000?0:decimals;number=sign*number;const[integerPart,decimalPart]=formatFixedDecimals(number,decimalsToKeep).split(".");const int=insertThousandsSep(integerPart,thousandsSep,grouping);if(!decimalPart){return int+symbol;} 4863return int+decimalPoint+decimalPart+symbol;} 4864__exports.formatFloat=formatFloat;function formatFloat(value,options={}){let precision;if(options.digits&&options.digits[1]!==undefined){precision=options.digits[1];}else if(options.minDigits){precision=6;}else{precision=2;} 4865const intDigitsCount=(value!==0)?Math.floor(Math.log10(Math.abs(value)))+1:1;const maxDecDigits=Math.max(14-intDigitsCount,0);precision=Math.min(precision,maxDecDigits);const minPrecision=options.minDigits||precision;if(floatIsZero(value,precision)){value=0.0;} 4866if(options.humanReadable){return humanNumber(value,options);} 4867const grouping=options.grouping||l10n.grouping;const thousandsSep="thousandsSep"in options?options.thousandsSep:l10n.thousandsSep;const decimalPoint="decimalPoint"in options?options.decimalPoint:l10n.decimalPoint;const formatted=formatFixedDecimals(value,precision).split(".");formatted[0]=insertThousandsSep(formatted[0],thousandsSep,grouping);if(formatted[1]){formatted[1]=formatted[1].replace(/0+$/,"");if(options.trailingZeros!==false){formatted[1]=formatted[1].padEnd(minPrecision,"0");}} 4868return formatted[1]?formatted.join(decimalPoint):formatted[0];} 4869const _INVERTDICT=Object.freeze({1e-1:1e1,1e-2:1e2,1e-3:1e3,1e-4:1e4,1e-5:1e5,1e-6:1e6,1e-7:1e7,1e-8:1e8,1e-9:1e9,1e-10:1e10,2e-1:5,2e-2:5e1,2e-3:5e2,2e-4:5e3,2e-5:5e4,2e-6:5e5,2e-7:5e6,2e-8:5e7,2e-9:5e8,2e-10:5e9,5e-1:2,5e-2:2e1,5e-3:2e2,5e-4:2e3,5e-5:2e4,5e-6:2e5,5e-7:2e6,5e-8:2e7,5e-9:2e8,5e-10:2e9,});__exports.invertFloat=invertFloat;function invertFloat(value){let res=_INVERTDICT[value];if(res===undefined){const[coeff,expt]=value.toExponential().split("e").map(Number.parseFloat);res=Number.parseFloat(`${coeff}e${-expt}`)/Math.pow(coeff,2);} 4870return res;} 4871return __exports;});; 4872 4873/* /web/static/src/core/utils/objects.js */ 4874odoo.define('@web/core/utils/objects',[],function(require){'use strict';let __exports={};__exports.shallowEqual=shallowEqual;function shallowEqual(obj1,obj2,comparisonFn=(a,b)=>a===b){if(obj1!==Object(obj1)||obj2!==Object(obj2)){return obj1===obj2;} 4875const obj1Keys=Reflect.ownKeys(obj1);return(obj1Keys.length===Reflect.ownKeys(obj2).length&&obj1Keys.every((key)=>comparisonFn(obj1[key],obj2[key])));} 4876const deepEqual=__exports.deepEqual=(obj1,obj2)=>shallowEqual(obj1,obj2,deepEqual);__exports.deepCopy=deepCopy;function deepCopy(object){return object&&JSON.parse(JSON.stringify(object));} 4877__exports.isObject=isObject;function isObject(value){return Object.prototype.toString.call(value)==="[object Object]";} 4878__exports.omit=omit;function omit(object,...properties){const result={};const propertiesSet=new Set(properties);for(const key in object){if(!propertiesSet.has(key)){result[key]=object[key];}} 4879return result;} 4880__exports.pick=pick;function pick(object,...properties){return Object.fromEntries(properties.filter((prop)=>prop in object).map((prop)=>[prop,object[prop]]));} 4881__exports.deepMerge=deepMerge;function deepMerge(target,extension){if(!isObject(target)&&!isObject(extension)){return;} 4882target=target||{};const output=Object.assign({},target);if(isObject(extension)){for(const key of Reflect.ownKeys(extension)){if(key in target&&isObject(extension[key])&&!Array.isArray(extension[key])&&typeof extension[key]!=="function"){output[key]=deepMerge(target[key],extension[key]);}else{Object.assign(output,{[key]:extension[key]});}}} 4883return output;} 4884return __exports;});; 4885 4886/* /web/static/src/core/utils/patch.js */ 4887odoo.define('@web/core/utils/patch',[],function(require){'use strict';let __exports={};const patchDescriptions=new WeakMap();function getPatchDescription(objToPatch){if(!patchDescriptions.has(objToPatch)){patchDescriptions.set(objToPatch,{originalProperties:new Map(),skeleton:Object.create(Object.getPrototypeOf(objToPatch)),extensions:new Set(),});} 4888return patchDescriptions.get(objToPatch);} 4889function isClassPrototype(objToPatch){return(Object.hasOwn(objToPatch,"constructor")&&objToPatch.constructor?.prototype===objToPatch);}
4890function findAncestorPropertyDescriptor(objToPatch,key){let descriptor=null;let prototype=objToPatch;do{descriptor=Object.getOwnPropertyDescriptor(prototype,key);prototype=Object.getPrototypeOf(prototype);}while(!descriptor&&prototype);return descriptor;} 4891__exports.patch=patch;function patch(objToPatch,extension){if(typeof extension==="string"){throw new Error(`Patch "${extension}": Second argument is not the patch name anymore, it should be the object containing the patched properties`);} 4892const description=getPatchDescription(objToPatch);description.extensions.add(extension);const properties=Object.getOwnPropertyDescriptors(extension);for(const[key,newProperty]of Object.entries(properties)){const oldProperty=Object.getOwnPropertyDescriptor(objToPatch,key);if(oldProperty){Object.defineProperty(description.skeleton,key,oldProperty);} 4893if(!description.originalProperties.has(key)){description.originalProperties.set(key,oldProperty);} 4894if(isClassPrototype(objToPatch)){newProperty.enumerable=false;} 4895if((newProperty.get&&1)^(newProperty.set&&1
4895)){const ancestorProperty=findAncestorPropertyDescriptor(objToPatch,key);newProperty.get=newProperty.get??ancestorProperty?.get;newProperty.set=newProperty.set??ancestorProperty?.set;} 4896Object.defineProperty(objToPatch,key,newProperty);} 4897description.skeleton=Object.setPrototypeOf(extension,description.skeleton);return()=>{patchDescriptions.delete(objToPatch);for(const[key,property]of description.originalProperties){if(property){Object.defineProperty(objToPatch,key,property);}else{delete objToPatch[key];}} 4898description.extensions.delete(extension);for(const extension of description.extensions){patch(objToPatch,extension);}};} 4899return __exports;});; 4900 4901/* /web/static/src/core/utils/pdfjs.js */ 4902odoo.define('@web/core/utils/pdfjs',['@web/core/browser/feature_detection','@web/core/assets'],function(require){'use strict';let __exports={};const{isMobileOS}=require("@web/core/browser/feature_detection");const{loadJS}=require("@web/core/assets");__exports.hidePDFJSButtons=hidePDFJSButtons;function hidePDFJSButtons(rootElement,options={}){const hiddenElements=["#editorModeButtons","button#openFile","button#secondaryOpenFile","a#viewBookmark","a#secondaryViewBookmark",];if(options.hideDownload||isMobileOS()){hiddenElements.push(["button#downloadButton","button#secondaryDownload"]);} 4903if(options.hidePrint||isMobileOS()){hiddenElements.push(["button#printButton","button#secondaryPrint"]);} 4904if(options.hidePresentation){hiddenElements.push("button#presentationMode");} 4905if(options.hideRotation){hiddenElements.push("button#pageRotateCw");hiddenElements.push("button#pageRotateCcw");} 4906const cssStyle=document.createElement("style");cssStyle.rel="stylesheet";cssStyle.textContent=`${hiddenElements.join(", ")} { 4907 display: none !important; 4908}`;const iframe=rootElement.tagName==="IFRAME"?rootElement:rootElement.querySelector("iframe");if(iframe){if(!iframe.dataset.hideButtons){iframe.dataset.hideButtons="true";iframe.addEventListener("load",(event)=>{if(iframe.contentDocument&&iframe.contentDocument.head){iframe.contentDocument.head.appendChild(cssStyle);}});}}else{console.warn("No IFRAME found");}} 4909__exports.loadPDFJSAssets=loadPDFJSAssets;async function loadPDFJSAssets(){return Promise.all([loadJS("/web/static/lib/pdfjs/build/pdf.js"),loadJS("/web/static/lib/pdfjs/build/pdf.worker.js"),]);} 4910return __exports;});; 4911 4912/* /web/static/src/core/utils/reactive.js */ 4913odoo.define('@web/core/utils/reactive',['@odoo/owl'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const Reactive=__exports.Reactive=class Reactive{constructor(){return reactive(this);}} 4914__exports.effect=effect;function effect(cb,deps){const reactiveDeps=reactive(deps,()=>{cb(...reactiveDeps);});cb(...reactiveDeps);} 4915__exports.withComputedProperties=withComputedProperties;function withComputedProperties(obj,sources,descriptor){for(const[key,compute]of Object.entries(descriptor)){effect((obj,sources)=>{obj[key]=compute.call(obj,...sources);},[obj,sources]);} 4916return obj;} 4917return __exports;});; 4918 4919/* /web/static/src/core/utils/render.js */ 4920odoo.define('@web/core/utils/render',['@odoo/owl','@web/core/templates','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{App,blockDom,Component,markup}=require("@odoo/owl");const{getTemplate}=require("@web/core/templates");const{appTranslateFn}=require("@web/core/l10n/translation");__exports.renderToElement=renderToElement;function renderToElement(template,context={}){const el=render(template,context).firstElementChild;if(el?.nextElementSibling){throw new Error(`The rendered template '${template}' contains multiple root `+`nodes that will be ignored using renderToElement, you should `+`consider using renderToFragment or refactoring the template.`);} 4921el?.remove();return el;} 4922__exports.renderToFragment=renderToFragment;function renderToFragment(template,context={}){const frag=document.createDocumentFragment();for(const el of[...render(template,context).children]){frag.appendChild(el);} 4923return frag;} 4924__exports.renderToString=renderToString;function renderToString(template,context={}){return render(template,context).innerHTML;} 4925let app;Object.defineProperty(renderToString,"app",{get:()=>{if(!app){app=new App(Component,{name:"renderToString",getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,});} 4926return app;},});function render(template,context={}){const app=renderToString.app;const templateFn=app.getTemplate(template);const bdom=templateFn(context,{});const div=document.createElement("div");blockDom.mount(bdom,div);return div;} 4927__exports.renderToMarkup=renderToMarkup;function renderToMarkup(template,context={}){return markup(renderToString(template,context));} 4928return __exports;});; 4929 4930/* /web/static/src/core/utils/scrolling.js */ 4931odoo.define('@web/core/utils/scrolling',[],function(require){'use strict';let __exports={};__exports.isScrollableX=isScrollableX;function isScrollableX(el){if(el.scrollWidth>el.clientWidth&&el.clientWidth>0){return couldBeScrollableX(el);} 4932return false;} 4933__exports.couldBeScrollableX=couldBeScrollableX;function couldBeScrollableX(el){if(el){const overflow=getComputedStyle(el).getPropertyValue("overflow-x");
4933if(/\bauto\b|\bscroll\b/.test(overflow)){return true;}} 4934return false;} 4935__exports.closestScrollableX=closestScrollableX;function closestScrollableX(el){if(!el){return null;} 4936if(isScrollableX(el)){return el;} 4937return closestScrollableX(el.parentElement);} 4938__exports.isScrollableY=isScrollableY;function isScrollableY(el){if(el&&el.scrollHeight>el.clientHeight&&el.clientHeight>0){return couldBeScrollableY(el);} 4939return false;} 4940__exports.couldBeScrollableY=couldBeScrollableY;function couldBeScrollableY(el){if(el){const overflow=getComputedStyle(el).getPropertyValue("overflow-y");if(/\bauto\b|\bscroll\b/.test(overflow)){return true;}} 4941return false;} 4942__exports.closestScrollableY=closestScrollableY;function closestScrollableY(el){if(!el){return null;} 4943if(isScrollableY(el)){return el;} 4944return closestScrollableY(el.parentElement);} 4945__exports.scrollTo=scrollTo;function scrollTo(element,options={}){const{behavior="auto",isAnchor=false,offset=0}=options;const scrollable=closestScrollableY(options.scrollable||element.parentElement);if(!scrollable){return;} 4946const scrollBottom=scrollable.getBoundingClientRect().bottom;const scrollTop=scrollable.getBoundingClientRect().top;const elementBottom=element.getBoundingClientRect().bottom;const elementTop=element.getBoundingClientRect().top;const scrollPromises=[];if(elementBottom>scrollBottom&&!isAnchor){scrollPromises.push(new Promise((resolve)=>{scrollable.addEventListener("scrollend",()=>resolve(),{once:true});}));scrollable.scrollTo({top:scrollable.scrollTop+ 4947elementTop- 4948scrollBottom+ 4949Math.ceil(element.getBoundingClientRect().height)+ 4950offset,behavior,});}else if(elementTop<scrollTop||isAnchor){scrollPromises.push(new Promise((resolve)=>{scrollable.addEventListener("scrollend",()=>resolve(),{once:true});}));scrollable.scrollTo({top:scrollable.scrollTop-scrollTop+elementTop+offset,behavior,});if(options.isAnchor){const parentScrollable=closestScrollableY(scrollable.parentElement);if(parentScrollable){scrollPromises.push(scrollTo(scrollable,{behavior,isAnchor:true,scrollable:parentScrollable,}));}}} 4951return Promise.all(scrollPromises);} 4952__exports.compensateScrollbar=compensateScrollbar;function compensateScrollbar(el,add=true,isScrollElement=true,cssProperty="padding-right"){if(!el){return;} 4953const scrollableEl=isScrollElement?el:closestScrollableY(el.parentElement);if(!scrollableEl){return;} 4954const isRTL=scrollableEl.classList.contains(".o_rtl");if(isRTL){cssProperty=cssProperty.replace("right","left");} 4955el.style.removeProperty(cssProperty);if(!add){return;} 4956const style=window.getComputedStyle(el);const borderLeftWidth=Math.ceil(parseFloat(style.borderLeftWidth.replace("px","")));const borderRightWidth=Math.ceil(parseFloat(style.borderRightWidth.replace("px","")));const bordersWidth=borderLeftWidth+borderRightWidth;const newValue=parseInt(style[cssProperty])+ 4957scrollableEl.offsetWidth- 4958scrollableEl.clientWidth- 4959bordersWidth;el.style.setProperty(cssProperty,`${newValue}px`,"important");} 4960__exports.getScrollingElement=getScrollingElement;function getScrollingElement(document=window.document){const baseScrollingElement=document.scrollingElement;if(isScrollableY(baseScrollingElement)){return baseScrollingElement;} 4961const bodyHeight=window.getComputedStyle(document.body).height;for(const el of document.body.children){if(bodyHeight-el.scrollHeight>1.5){continue;} 4962if(isScrollableY(el)){return el;}} 4963return baseScrollingElement;} 4964__exports.getScrollingTarget=getScrollingTarget;function getScrollingTarget(scrollingElement=window.document){const document=scrollingElement.ownerDocument;return scrollingElement===document.scrollingElement?document.defaultView:scrollingElement;} 4965return __exports;});; 4966 4967/* /web/static/src/core/utils/search.js */ 4968odoo.define('@web/core/utils/search',['@web/core/l10n/utils'],function(require){'use strict';let __exports={};const{normalize}=require("@web/core/l10n/utils");function match(pattern,strs){if(!Array.isArray(strs)){strs=[strs];} 4969let globalScore=0;for(const str of strs){globalScore=Math.max(globalScore,_match(pattern,str));} 4970return globalScore;} 4971function _match(pattern,str){let totalScore=0;let currentScore=0;let patternIndex=0;pattern=normalize(pattern);str=normalize(str);const len=str.length;for(let i=0;i<len;i++){if(str[i]===pattern[patternIndex]){patternIndex++;
4971currentScore+=100+currentScore-i/200;}else{currentScore=0;} 4972totalScore=totalScore+currentScore;} 4973return patternIndex===pattern.length?totalScore:0;} 4974__exports.fuzzyLookup=fuzzyLookup;function fuzzyLookup(pattern,list,fn){const results=[];list.forEach((data)=>{const score=match(pattern,fn(data));if(score>0){results.push({score,elem:data});}});results.sort((a,b)=>b.score-a.score);return results.map((r)=>r.elem);} 4975__exports.fuzzyTest=fuzzyTest;function fuzzyTest(pattern,string){return _match(pattern,string)!==0;} 4976__exports.fuzzyLevenshteinLookup=fuzzyLevenshteinLookup;function fuzzyLevenshteinLookup(pattern,list,errorRatio=3){const maxNbrCorrection=Math.round(pattern.length/errorRatio);const results=[];list.forEach((candidate)=>{let score=-1;if(candidate.includes(pattern)){score=0;results.push({score,elem:pattern});}else{score=getLevenshteinScore(pattern,candidate);if(score>=0&&score<=maxNbrCorrection){results.push({score,elem:candidate});}}});results.sort((a,b)=>a.score-b.score);return results.map((r)=>r.elem);} 4977function getLevenshteinScore(a,b){let aLength=a.length;let bLength=b.length;let distanceMatrix=[];for(let i=0;i<=aLength;i++){distanceMatrix[i]=[];for(let j=0;j<=bLength;j++){distanceMatrix[i][j]=0;}} 4978for(let i=0;i<=aLength;i++){for(let j=0;j<=bLength;j++){if(Math.min(i,j)===0){distanceMatrix[i][j]=Math.max(i,j);}else{if(a[i-1]===b[j-1]){distanceMatrix[i][j]=distanceMatrix[i-1][j-1];}else{distanceMatrix[i][j]=Math.min(distanceMatrix[i-1][j]+1,distanceMatrix[i][j-1]+1,distanceMatrix[i-1][j-1]+1);}}}} 4979return distanceMatrix[aLength][bLength];} 4980return __exports;});; 4981 4982/* /web/static/src/core/utils/sortable.js */ 4983odoo.define('@web/core/utils/sortable',['@web/core/utils/draggable_hook_builder','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{DRAGGED_CLASS,makeDraggableHook:nativeMakeDraggableHook,}=require("@web/core/utils/draggable_hook_builder");const{pick}=require("@web/core/utils/objects");const hookParams={name:"useSortable",acceptedParams:{groups:[String,Function],connectGroups:[Boolean,Function],clone:[Boolean],placeholderClasses:[Object],applyChangeOnDrop:[Boolean],followingElementClasses:[Object],},defaultParams:{connectGroups:false,edgeScrolling:{speed:20,threshold:60},groupSelector:null,clone:true,placeholderClasses:[],applyChangeOnDrop:false,followingElementClasses:[],},onComputeParams({ctx,params}){ctx.groupSelector=params.groups||null;if(ctx.groupSelector){ctx.fullSelector=[ctx.groupSelector,ctx.fullSelector].join(" ");} 4984ctx.connectGroups=params.connectGroups;ctx.placeholderClone=params.clone;ctx.placeholderClasses=params.placeholderClasses;ctx.applyChangeOnDrop=params.applyChangeOnDrop;ctx.followingElementClasses=params.followingElementClasses;},onDragStart({ctx,addListener,addStyle,callHandler}){const onElementPointerEnter=(ev)=>{const element=ev.currentTarget;if(connectGroups||!groupSelector||current.group===element.closest(groupSelector)){const pos=current.placeHolder.compareDocumentPosition(element);if(pos===Node.DOCUMENT_POSITION_PRECEDING){element.before(current.placeHolder);}else if(pos===Node.DOCUMENT_POSITION_FOLLOWING){element.after(current.placeHolder);}} 4985callHandler("onElementEnter",{element});};const onElementPointerLeave=(ev)=>{const element=ev.currentTarget;callHandler("onElementLeave",{element});};const onElementComplexPointerEnter=(ev)=>{if(ctx.haveAlreadyChanged){return;} 4986const element=ev.currentTarget;const siblingArray=[...element.parentElement.children].filter((el)=>el===current.placeHolder||(el.matches(elementSelector)&&!el.classList.contains(DRAGGED_CLASS)));const elementIndex=siblingArray.indexOf(element);const placeholderIndex=siblingArray.indexOf(current.placeHolder);const isDirectSibling=Math.abs(elementIndex-placeholderIndex)===1;if(connectGroups||!groupSelector||current.group===element.closest(groupSelector)){const pos=current.placeHolder.compareDocumentPosition(element);if(isDirectSibling){if(pos===Node.DOCUMENT_POSITION_PRECEDING){element.before(current.placeHolder);ctx.haveAlreadyChanged=true;}else if(pos===Node.DOCUMENT_POSITION_FOLLOWING){element.after(current.placeHolder);ctx.haveAlreadyChanged=true;}}else{if(pos===Node.DOCUMENT_POSITION_FOLLOWING){element.before(current.placeHolder);ctx.haveAlreadyChanged=true;}else if(pos===Node.DOCUMENT_POSITION_PRECEDING){element.after(current.placeHolder);ctx.haveAlreadyChanged=true;}}} 4987callHandler("onElementEnter",{element});};const onElementComplexPointerLeave=(ev)=>{if(ctx.haveAlreadyChanged){return;} 4988const element=ev.currentTarget;const elementRect=element.getBoundingClientRect();const relatedElement=ev.relatedTarget;const relatedElementRect=element.getBoundingClientRect();const siblingArray=[...element.parentElement.children].filter((el)=>el===current.placeHolder||(el.matches(elementSelector)&&!el.classList.contains(DRAGG
4988ED_CLASS)));const pointerOnSiblings=siblingArray.indexOf(relatedElement)>-1;const elementIndex=siblingArray.indexOf(element);const isFirst=elementIndex===0;const isAbove=relatedElementRect.top<=elementRect.top;const isLast=elementIndex===siblingArray.length-1;const isBelow=relatedElementRect.bottom>=elementRect.bottom;const pos=current.placeHolder.compareDocumentPosition(element);if(!pointerOnSiblings){if(isFirst&&isAbove&&pos===Node.DOCUMENT_POSITION_PRECEDING){element.before(current.placeHolder);ctx.haveAlreadyChanged=true;}else if(isLast&&isBelow&&pos===Node.DOCUMENT_POSITION_FOLLOWING){element.after(current.placeHolder);ctx.haveAlreadyChanged=true;}} 4989callHandler("onElementLeave",{element});};const onGroupPointerEnter=(ev)=>{const group=ev.currentTarget;group.appendChild(current.placeHolder);callHandler("onGroupEnter",{group});};const onGroupPointerLeave=(ev)=>{const group=ev.currentTarget;callHandler("onGroupLeave",{group});};const{connectGroups,current,elementSelector,groupSelector,ref}=ctx;if(ctx.placeholderClone){const{width,height}=current.elementRect;addStyle(current.placeHolder,{visibility:"hidden",display:"block",width:`${width}px`,height:`${height}px`,});} 4990if(connectGroups&&groupSelector){for(const siblingGroup of ref.el.querySelectorAll(groupSelector)){addListener(siblingGroup,"pointerenter",onGroupPointerEnter);addListener(siblingGroup,"pointerleave",onGroupPointerLeave);}} 4991for(const siblingEl of ref.el.querySelectorAll(elementSelector)){if(siblingEl!==current.element&&siblingEl!==current.placeHolder){if(ctx.placeholderClone){addListener(siblingEl,"pointerenter",onElementPointerEnter);addListener(siblingEl,"pointerleave",onElementPointerLeave);}else{addListener(siblingEl,"pointerenter",onElementComplexPointerEnter);addListener(siblingEl,"pointerleave",onElementComplexPointerLeave);}}} 4992current.element.after(current.placeHolder);return pick(current,"element","group");},onDrag({ctx}){ctx.haveAlreadyChanged=false;},onDragEnd({ctx}){return pick(ctx.current,"element","group");},onDrop({ctx}){const{current,groupSelector}=ctx;const previous=current.placeHolder.previousElementSibling;const next=current.placeHolder.nextElementSibling;if(previous!==current.element&&next!==current.element){const element=current.element;if(ctx.applyChangeOnDrop){if(previous){previous.after(element);}else if(next){next.before(element);}} 4993return{element,group:current.group,previous,next,parent:groupSelector&¤t.placeHolder.closest(groupSelector),};}},onWillStartDrag({ctx,addCleanup}){const{connectGroups,current,groupSelector}=ctx;if(groupSelector){current.group=current.element.closest(groupSelector);if(!connectGroups){current.container=current.group;}} 4994if(ctx.placeholderClone){current.placeHolder=current.element.cloneNode(false);}else{current.placeHolder=document.createElement("div");} 4995current.placeHolder.classList.add(...ctx.placeholderClasses);current.element.classList.add(...ctx.followingElementClasses);addCleanup(()=>current.element.classList.remove(...ctx.followingElementClasses));addCleanup(()=>current.placeHolder.remove());return pick(current,"element","group");},};const useSortable=__exports.useSortable=(sortableParams)=>{const{setupHooks}=sortableParams;delete sortableParams.setupHooks;return nativeMakeDraggableHook({...hookParams,setupHooks})(sortableParams);};return __exports;});; 4996 4997/* /web/static/src/core/utils/sortable_owl.js */ 4998odoo.define('@web/core/utils/sortable_owl',['@odoo/owl','@web/core/utils/timing','@web/core/utils/sortable'],function(require){'use strict';let __exports={};const{onWillUnmount,reactive,useEffect,useExternalListener}=require("@odoo/owl");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{useSortable:nativeUseSortable}=require("@web/core/utils/sortable");__exports.useSortable=useSortable;function useSortable(params){return nativeUseSortable({...params,setupHooks:{addListener:useExternalListener,setup:useEffect,teardown:onWillUnmount,throttle:useThrottleForAnimation,wrapState:reactive,},});} 4999return __exports;});; 5000 5001/* /web/static/src/core/utils/sortable_service.js */ 5002odoo.define('@web/core/utils/sortable_service',['@web/core/registry','@web/core/utils/sortable','@web/core/utils/timing','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{useSortable}=require("@web/core/utils/sortable");const{throttleForAnimation}=require("@web/core/utils/timing");const{reactive}=require("@odoo/owl");const DEFAULT_SORTABLE_ID=Symbol.for("defaultSortable");const sortableService=__exports.sortableService={start(){const boundElements=new Map();return{create:(hookParams)=>{const element=hookParams.ref.el;const sortableId=hookParams.sortableId??DEFAULT_SORTABLE_ID;if(boundElements.has(element)){const boundElement=boundElements.get(element);if(sortableId in boundElement){return{enable(){return{cleanup:boundElement[sortableId],};},};}} 5003const setupFunctions=new Map();const cleanupFunctions=[];const cleanup=()=>{const boundElement=boundElements.get(element);if(sortableId in boundElement){delete boundElement[sortableId];if(boundElement.length===0){boundElements.delete(element);}} 5004cleanupFunctions.forEach((fn)=>fn());};const setupHooks={wrapState:reactive,throttle:throttleForAnimation,addListener:(el,type,listener)=>{el.addEventListener(type,listener);cleanupFunctions.push(()=>el.removeEventListener(type,listener));},setup:(setupFn,dependenciesFn)=>setupFunctions.set(setupFn,dependenciesFn),teardown:(fn)=>cleanupFunctions.push(fn),};useSortable({setupHooks,...hookParams});const boundElement=boundElements.get(element);if(boundElement){boundElement[sortableId]=cleanup;}else{boundElements.set(element,{[sortableId]:cleanup});} 5005return{enable(){setupFunctions.forEach((dependenciesFn,setupFn)=>setupFn(...dependenciesFn()));return{cleanup,};},};},};},};registry.category("services").add("sortable",sortableService);return __exports;});; 5006 5007/* /web/static/src/core/utils/strings.js */ 5008odoo.define('@web/core/utils/strings',['@web/core/utils/objects'],function(require){'use strict';let __exports={};const{isObject}=require("@web/core/utils/objects");function hasSubstitutionDict(substitutions){return substitutions.length===1&&isObject(substitutions[0]);} 5009const HTML_ESCAPED_CHARACTERS=[["&","&"],["<","<"],[">",">"],["'","'"],['"',"""],["`","`"],];const R_EMAIL=/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;const R_FALSY=/^false|0$/i;const R_KEYED_SUBSTITUTION=/%\((?<key>[^)]+)\)s/g;const R_NUMERIC=/^\d+$/;const R_REGEX_SPECIAL_CHARS=/[.*+?^${}()|[\]\\]/g;const nbsp=__exports.nbsp="\u00a0";__exports.capitalize=capitalize;function capitalize(str){return str?str[0].toUpperCase()+str.slice(1):"";} 5010__exports.escape=escape;function escape(value){if(typeof value!=="string"){return String(value??"");} 5011for(const[char,replacer]of HTML_ESCAPED_CHARACTERS){value=value.replaceAll(char,replacer);} 5012return value;} 5013__exports.escapeRegExp=escapeRegExp;function escapeRegExp(pattern){return pattern.replaceAll(R_REGEX_SPECIAL_CHARS,"\\$&");} 5014__exports.exprToBoolean=exprToBoolean;function exprToBoolean(str,trueIfEmpty=false){return str?!R_FALSY.test(str):trueIfEmpty;} 5015__exports.hashCode=hashCode;function hashCode(...strings){const str=strings.join("\x1C");let hash=0;for(let i=0;i<str.length;i++){hash=(hash<<5)-hash+str.charCodeAt(i);hash|=0;} 5016return(hash+16**8).toString(16).slice(-8);} 5017__exports.intersperse=intersperse;function intersperse(str,indices,separator){const result=[];let last=str.length;for(let i=0;i<indices.length;++i){let section=indices[i];if(section===-1||last<=0){break;}else if(section===0&&i===0){break;}else if(section===0){section=indices[--i];} 5018result.unshift(str.substring(last-section,last));last-=section;} 5019const substr=str.substring(0,last);if(substr){result.unshift(substr);} 5020return result.join(separator||"");} 5021__exports.isEmail=isEmail;function isEmail(value){return R_EMAIL.test(value);} 5022__exports.isNumeric=isNumeric;function isNumeric(value){return R_NUMERIC.test(value);} 5023__exports.mapSubstitutions=mapSubstitutions;function mapSubstitutions(substitutions,mapFn){if(hasSubstitutionDict(substitutions)){const substitutionDict={};for(const[key,value]of Object.entries(substitutions[0])){substitutionDict[key]=mapFn(value);} 5024return[substitutionDict];}else{return substitutions.map(mapFn);}} 5025__exports.sprintf=sprintf;function sprintf(str,...substitutions){if(!substitutions.length){return str;} 5026if(hasSubstitutionDict(substitutions)){const dict=substitutions[0];return str.replaceAll(R_KEYED_SUBSTITUTION,(_match,key)=>dict[key]??"");}else{const raw=[""];for(let i=0;i<str.length;i++){if(str[i]==="%"){if(str[i+1]==="%"){raw[raw.length-1]+=str[++i];continue;} 5027if(str[i+1]==="s"){i++;raw.push("");continue;}} 5028raw[raw.length-1]+=str[i];} 5029return String.raw({raw},...substitutions);}} 5030__exports.uuid=uuid;function uuid(){let id="";for(const b of crypto.getRandomValues(new Uint8Array(8))){id+=b.toString(16).padStart(2,"0");} 5031return id;} 5032return __exports;});; 5033 5034/* /web/static/src/core/utils/timing.js */ 5035odoo.define('@web/core/utils/timing',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{onWillUnmount,useComponent}=require("@odoo/owl");__exports.batched=batched;function batched(callback,synchronize=()=>Promise.resolve()){let scheduled=false;return async(...args)=>{if(!scheduled){scheduled=true;await synchronize();scheduled=false;callback(...args);}};} 5036__exports.debounce=debounce;function debounce(func,delay,options){let handle;const funcName=func.name?func.name+" (debounce)":"debounce";const useAnimationFrame=delay==="animationFrame";
5036const setFnName=useAnimationFrame?"requestAnimationFrame":"setTimeout";const clearFnName=useAnimationFrame?"cancelAnimationFrame":"clearTimeout";let lastArgs;let leading=false;let trailing=true;if(typeof options==="boolean"){leading=options;trailing=!options;}else if(options){leading=options.leading??leading;trailing=options.trailing??trailing;} 5037return Object.assign({[funcName](...args){return new Promise((resolve)=>{if(leading&&!handle){Promise.resolve(func.apply(this,args)).then(resolve);}else{lastArgs=args;} 5038browser[clearFnName](handle);handle=browser[setFnName](()=>{handle=null;if(trailing&&lastArgs){Promise.resolve(func.apply(this,lastArgs)).then(resolve);lastArgs=null;}},delay);});},}[funcName],{cancel(execNow=false){browser[clearFnName](handle);if(execNow&&lastArgs){func.apply(this,lastArgs);}},});} 5039__exports.setRecurringAnimationFrame=setRecurringAnimationFrame;function setRecurringAnimationFrame(callback){const handler=(timestamp)=>{callback(timestamp-lastTimestamp);lastTimestamp=timestamp;handle=browser.requestAnimationFrame(handler);};const stop=()=>{browser.cancelAnimationFrame(handle);};let lastTimestamp=browser.performance.now();let handle=browser.requestAnimationFrame(handler);return stop;} 5040__exports.throttleForAnimation=throttleForAnimation;function throttleForAnimation(func){let handle=null;const calls=new Set();const funcName=func.name?`${func.name} (throttleForAnimation)`:"throttleForAnimation";const pending=()=>{if(calls.size){handle=browser.requestAnimationFrame(pending);const{args,resolve}=[...calls].pop();calls.clear();Promise.resolve(func.apply(this,args)).then(resolve);}else{handle=null;}};return Object.assign({[funcName](...args){return new Promise((resolve)=>{const isNew=handle===null;if(isNew){handle=browser.requestAnimationFrame(pending);Promise.resolve(func.apply(this,args)).then(resolve);}else{calls.add({args,resolve});}});},}[funcName],{cancel(){browser.cancelAnimationFrame(handle);calls.clear();handle=null;},});} 5041__exports.useDebounced=useDebounced;function useDebounced(callback,delay,{execBeforeUnmount=false,immediate=false,trailing=!immediate}={}){const component=useComponent();const debounced=debounce(callback.bind(component),delay,{leading:immediate,trailing});onWillUnmount(()=>debounced.cancel(execBeforeUnmount));return debounced;} 5042__exports.useThrottleForAnimation=useThrottleForAnimation;function useThrottleForAnimation(func){const component=useComponent();const throttledForAnimation=throttleForAnimation(func.bind(component));onWillUnmount(()=>throttledForAnimation.cancel());return throttledForAnimation;} 5043return __exports;});; 5044 5045/* /web/static/src/core/utils/ui.js */ 5046odoo.define('@web/core/utils/ui',[],function(require){'use strict';let __exports={};__exports.closest=closest;function closest(elements,targetPos){let closestEl=null;let closestDistance=Infinity;for(const el of elements){const rect=el.getBoundingClientRect();const distance=getQuadrance(rect,targetPos);if(!closestEl||distance<closestDistance){closestEl=el;closestDistance=distance;}} 5047return closestEl;} 5048__exports.isVisible=isVisible;function isVisible(el){if(el===document||el===window){return true;} 5049if(!el){return false;} 5050let _isVisible=false;if("offsetWidth"in el&&"offsetHeight"in el){_isVisible=el.offsetWidth>0&&el.offsetHeight>0;}else if("getBoundingClientRect"in el){const rect=el.getBoundingClientRect();_isVisible=rect.width>0&&rect.height>0;} 5051if(!_isVisible&&getComputedStyle(el).display==="contents"){for(const child of el.children){if(isVisible(child)){return true;}}} 5052return _isVisible;} 5053__exports.getQuadrance=getQuadrance;function getQuadrance(rect,pos){let q=0;if(pos.x<rect.x){q+=(rect.x-pos.x)**2;}else if(rect.x+rect.width<pos.x){q+=(pos.x-(rect.x+rect.width))**2;} 5054if(pos.y<rect.y){q+=(rect.y-pos.y)**2;}else if(rect.y+rect.height<pos.y){q+=(pos.y-(rect.y+rect.height))**2;} 5055return q;} 5056__exports.getVisibleElements=getVisibleElements;function getVisibleElements(activeElement,selector){const visibleElements=[];const elements=activeElement.querySelectorAll(selector);for(const el of elements){if(isVisible(el)){visibleElements.push(el);}} 5057return visibleElements;} 5058__exports.touching=touching;function touching(elements,targetRect){const r1={x:0,y:0,width:0,height:0,...targetRect};return[...elements].filter((el)=>{const r2=el.getBoundingClientRect();return(r2.x+r2.width>=r1.x&&r2.x<=r1.x+r1.width&&r2.y+r2.height>=r1.y&&r2.y<=r1.y+r1.height);});} 5059const FOCUSABLE_SELECTORS=["[tabindex]","a","area","button","frame","iframe","input","object","select","textarea","details > summary:nth-child(1)",].map((sel)=>`${sel}:not(:disabled)`);const TABABLE_SELECTORS=FOCUSABLE_SELECTORS.map((sel)=>`${sel}:not([tabindex="-1"])`);__exports.isFocusable=isFocusable;function isFocusable(el){return el.matches(FOCUSABLE_SELECTORS.join(","))&&isVisible(el)&&!el.closest("[inert]");} 5060__exports.getTabableElements=getTabableElements;function getTabableElements(container=document.body){const elements=[...container.querySelectorAll(TABABLE_SELECTORS.join(","))].filter((el)=>isVisible(el)&&!el.closest("[inert]"));const byTabIndex={};for(const el of[...elements]){if(!byTabIndex[el.tabIndex]){byTabIndex[el.tabIndex]=[];} 5061byTabIndex[el.tabIndex].push(el);} 5062const withTabIndexZero=byTabIndex[0]||[];delete byTabIndex[0];return[...Object.values(byTabIndex).flat(),...withTabIndexZero];} 5063__exports.getNextTabableElement=getNextTabableElement;function getNextTabableElement(container=document.body){const tabableElements=getTabableElements(container);const index=tabableElements.indexOf(document.activeElement);return index===-1?tabableElements[0]:tabableElements[index+1]||null;} 5064__exports.getPreviousTabableElement=getPreviousTabableElement;function getPreviousTabableElement(container=document.body){const tabableElements=getTabableElements(container);const index=tabableElements.indexOf(document.activeElement);return index===-1?tabableElements[tabableElements.length-1]:tabableElements[index-1]||null;} 5065__exports.addLoadingEffect=addLoadingEffect;function addLoadingEffect(btnEl){btnEl.classList.add("o_btn_loading","disabled","pe-none");btnEl.disabled=true;const loaderEl=document.createElement("span");loaderEl.classList.add("fa","fa-circle-o-notch","fa-spin","me-2");btnEl.prepend(loaderEl);return()=>{btnEl.classList.remove("o_btn_loading","disabled","pe-none");btnEl.disabled=false;loaderEl.remove();};} 5066return __exports;});; 5067 5068/* /web/static/src/core/utils/urls.js */ 5069odoo.define('@web/core/utils/urls',['@web/session','@web/core/browser/browser','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{session}=require("@web/session");const{browser}=require("@web/core/browser/browser");const{shallowEqual}=require("@web/core/utils/objects");const{DateTime}=luxon;const RedirectionError=__exports.RedirectionError=class RedirectionError extends
5069Error{} 5070__exports.objectToUrlEncodedString=objectToUrlEncodedString;function objectToUrlEncodedString(obj){return Object.entries(obj).map(([k,v])=>`${encodeURIComponent(k)}=${encodeURIComponent(v || "")}`).join("&");} 5071__exports.getOrigin=getOrigin;function getOrigin(origin){if(origin){origin=origin.replace(/\/+$/,"");}else{const{host,protocol}=browser.location;origin=`${protocol}//${host}`;} 5072return origin;} 5073__exports.url=url;function url(route,queryParams,options={}){const origin=getOrigin(options.origin??session.origin);if(!route){return origin;} 5074let queryString=objectToUrlEncodedString(queryParams||{});queryString=queryString.length>0?`?${queryString}`:queryString;let prefix=["http://","https://","//"].some((el)=>route.length>=el.length&&route.slice(0,el.length)===el);prefix=prefix?"":origin;return`${prefix}${route}${queryString}`;} 5075__exports.imageUrl=imageUrl;function imageUrl(model,id,field,{access_token,crop,filename,height,unique,width}={}){let route=`/web/image/${model}/${id}/${field}`;if(width&&height){route=`${route}/${width}x${height}`;} 5076if(filename){route=`${route}/${filename}`;} 5077const urlParams={};if(access_token){Object.assign(urlParams,{access_token});} 5078if(crop){Object.assign(urlParams,{crop});} 5079if(unique){if(unique instanceof DateTime){urlParams.unique=unique.ts;}else{const dateTimeFromUnique=DateTime.fromSQL(unique);if(dateTimeFromUnique.isValid){urlParams.unique=dateTimeFromUnique.ts;}else if(typeof unique==="string"&&unique.length>0){urlParams.unique=unique;}}} 5080return url(route,urlParams);} 5081__exports.getDataURLFromFile=getDataURLFromFile;function getDataURLFromFile(file){if(!file){return Promise.reject();} 5082return new Promise((resolve,reject)=>{const reader=new FileReader();reader.addEventListener("load",()=>{if(reader.result==="data:"){resolve(`data:${file.type};base64,`);}else{resolve(reader.result);}});reader.addEventListener("abort",reject);reader.addEventListener("error",reject);reader.readAsDataURL(file);});} 5083__exports.redirect=redirect;function redirect(url){const{origin,pathname}=browser.location;const _url=new URL(url,`${origin}${pathname}`);if(_url.origin!==origin){throw new RedirectionError("Can't redirect to another origin");} 5084browser.location.assign(_url.href);} 5085__exports.compareUrls=compareUrls;function compareUrls(_url1,_url2){const url1=new URL(_url1);const url2=new URL(_url2);return(url1.origin===url2.origin&&url1.pathname===url2.pathname&&shallowEqual(Object.fromEntries(url1.searchParams),Object.fromEntries(url2.searchParams))&&url1.hash===url2.hash);} 5086return __exports;});; 5087 5088/* /web/static/src/core/utils/xml.js */ 5089odoo.define('@web/core/utils/xml',['@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{isIterable}=require("@web/core/utils/arrays");const serializer=new XMLSerializer();const parser=new DOMParser();const xmlDocument=parser.parseFromString("<templates/>","text/xml");function hasParsingError(parsedDocument){return parsedDocument.getElementsByTagName("parsererror").length>0;} 5090__exports.parseXML=parseXML;function parseXML(str){const xml=parser.parseFromString(str,"text/xml");if(hasParsingError(xml)){throw new Error(`An error occured while parsing ${str}: ${xml.getElementsByTagName("parsererror")}`);} 5091return xml.documentElement;} 5092__exports.serializeXML=serializeXML;function serializeXML(xml){return serializer.serializeToString(xml);} 5093__exports.visitXML=visitXML;function visitXML(xml,callback){const visit=(el)=>{if(el){let didVisitChildren=false;const visitChildren=()=>{for(const child of el.children){visit(child);} 5094didVisitChildren=true;};const shouldVisitChildren=callback(el,visitChildren);if(shouldVisitChildren!==false&&!didVisitChildren){visitChildren();}}};const xmlDoc=typeof xml==="string"?parseXML(xml):xml;visit(xmlDoc);} 5095__exports.append=append;function append(parent,node){const nodes=Array.isArray(node)?node:[node];parent.append(...nodes.filter(Boolean));return parent;} 5096__exports.combineAttributes=combineAttributes;function combineAttributes(el,attr,parts,glue=" "){const allValues=[];if(el.hasAttribute(attr)){allValues.push(el.getAttribute(attr));}
5097parts=Array.isArray(parts)?parts:[parts];parts=parts.filter((part)=>!!part);allValues.push(...parts);el.setAttribute(attr,allValues.join(glue));} 5098__exports.createElement=createElement;function createElement(tagName,...args){const el=xmlDocument.createElement(tagName);for(const arg of args){if(!arg){continue;} 5099if(isIterable(arg)){el.append(...arg);}else if(typeof arg==="object"){for(const name in arg){el.setAttribute(name,arg[name]);}}} 5100return el;} 5101__exports.createTextNode=createTextNode;function createTextNode(data){return xmlDocument.createTextNode(data);} 5102__exports.extractAttributes=extractAttributes;function extractAttributes(el,attributes){const attrs=Object.create(null);for(const attr of attributes){attrs[attr]=el.getAttribute(attr)||"";el.removeAttribute(attr);} 5103return attrs;} 5104__exports.getTag=getTag;function getTag(node,lower=false){const tag=(node&&node.nodeName)||"";return lower?tag.toLowerCase():tag;} 5105__exports.setAttributes=setAttributes;function setAttributes(node,attributes){for(const[name,value]of Object.entries(attributes)){node.setAttribute(name,value);}} 5106return __exports;});; 5107 5108/* /web/static/src/core/virtual_grid_hook.js */ 5109odoo.define('@web/core/virtual_grid_hook',['@odoo/owl','@web/core/utils/objects','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{useComponent,useEffect,useExternalListener}=require("@odoo/owl");const{pick,shallowEqual}=require("@web/core/utils/objects");const{useThrottleForAnimation}=require("@web/core/utils/timing");const BUFFER_COEFFICIENT=1;function getIndexes({sizes,start,span,prevStartIndex,bufferCoef=BUFFER_COEFFICIENT}){if(!sizes||!sizes.length){return[];} 5110if(sizes.at(-1)<span){return[0,sizes.length-1];} 5111const bufferSize=Math.round(span*bufferCoef);const bufferStart=start-bufferSize;const bufferEnd=start+span+bufferSize;let startIndex=prevStartIndex??0;while(startIndex>0&&sizes[startIndex]>bufferStart){startIndex--;} 5112while(startIndex<sizes.length-1&&sizes[startIndex]<=bufferStart){startIndex++;} 5113let endIndex=startIndex;while(endIndex<sizes.length-1&&(sizes[endIndex-1]??0)<bufferEnd){endIndex++;} 5114while(endIndex>startIndex&&(sizes[endIndex-1]??0)>=bufferEnd){endIndex--;} 5115return[startIndex,endIndex];} 5116__exports.useVirtualGrid=useVirtualGrid;function useVirtualGrid({scrollableRef,initialScroll,onChange,bufferCoef}){const comp=useComponent();onChange||=()=>comp.render();const current={columnsIndexes:[],rowsIndexes:[],scroll:{top:0,left:0,...initialScroll},};
5116const computeVirtualIndexes=()=>{const changed=[];const columnsVisibleIndexes=computeColumnsIndexes();if(!shallowEqual(columnsVisibleIndexes,current.columnsIndexes)){current.columnsIndexes=columnsVisibleIndexes;changed.push("columnsIndexes");} 5117const rowsVisibleIndexes=computeRowsIndexes();if(!shallowEqual(rowsVisibleIndexes,current.rowsIndexes)){current.rowsIndexes=rowsVisibleIndexes;changed.push("rowsIndexes");} 5118if(changed.length){onChange(pick(current,...changed));}};const computeColumnsIndexes=()=>{return getIndexes({sizes:current.summedColumnsWidths,start:Math.abs(current.scroll.left),span:window.innerWidth,prevStartIndex:current.columnsIndexes?.[0],bufferCoef,});};const computeRowsIndexes=()=>{return getIndexes({sizes:current.summedRowsHeights,start:current.scroll.top,span:window.innerHeight,prevStartIndex:current.rowsIndexes?.[0],bufferCoef,});};const throttledCompute=useThrottleForAnimation(computeVirtualIndexes);const scrollListener=({currentTarget})=>{current.scroll.left=currentTarget.scrollLeft;current.scroll.top=currentTarget.scrollTop;throttledCompute();};useEffect((el)=>{if(!el){return;}
5119computeVirtualIndexes();el.addEventListener("scroll",scrollListener);return()=>el.removeEventListener("scroll",scrollListener);},()=>[scrollableRef.el]);useExternalListener(window,"resize",throttledCompute);return{get columnsIndexes(){return current.columnsIndexes;},get rowsIndexes(){return current.rowsIndexes;},setColumnsWidths(widths){let acc=0;current.summedColumnsWidths=widths.map((w)=>(acc+=w));delete current.columnsIndexes;current.columnsIndexes=computeColumnsIndexes();},setRowsHeights(heights){let acc=0;current.summedRowsHeights=heights.map((h)=>(acc+=h));delete current.rowsIndexes;current.rowsIndexes=computeRowsIndexes();},};} 5120return __exports;});; 5121 5122/* /web/static/src/views/fields/formatters.js */ 5123odoo.define('@web/views/fields/formatters',['@web/core/l10n/dates','@web/core/l10n/localization','@web/core/l10n/translation','@web/core/registry','@web/core/utils/binary','@web/core/utils/numbers','@web/core/utils/strings','@odoo/owl','@web/core/currency'],function(require){'use strict';let __exports={};const{formatDate:_formatDate,formatDateTime:_formatDateTime,toLocaleDateString,toLocaleDateTimeString,}=require("@web/core/l10n/dates");const{localization:l10n}=require("@web/core/l10n/localization");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{registry}=require("@web/core/registry");const{isBinarySize}=require("@web/core/utils/binary");const{formatFloat:formatFloatNumber,humanNumber,insertThousandsSep,}=require("@web/core/utils/numbers");const{exprToBoolean}=require("@web/core/utils/strings");const{markup}=require("@odoo/owl");const{formatCurrency}=require("@web/core/currency");function humanSize(value){if(!value){return"";} 5124const suffix=value<1024?" "+_t("Bytes"):"b";return(humanNumber(value,{decimals:2,})+suffix);} 5125__exports.formatBinary=formatBinary;function formatBinary(value){if(!isBinarySize(value)){return humanSize(value.length/1.37);} 5126return value;} 5127__exports.formatBoolean=formatBoolean;function formatBoolean(value){return markup` 5128 <div class="o-checkbox d-inline-block me-2"> 5129 <input id="boolean_checkbox" type="checkbox" class="form-check-input" disabled ${ 5130 value ? "checked" : "" 5131 }/> 5132 <label for="boolean_checkbox" class="form-check-label"/> 5133 </div>`;} 5134__exports.formatChar=formatChar;function formatChar(value,options){if(options&&options.isPassword){return"*".repeat(value?value.length:0);} 5135return value||"";} 5136formatChar.extractOptions=({attrs})=>({isPassword:exprToBoolean(attrs.password),});__exports.formatDate=formatDate;function formatDate(value,options={}){if(options.numeric){return _formatDate(value,options);}else{return toLocaleDateString(value);}} 5137formatDate.extractOptions=({options})=>({numeric:exprToBoolean(options.numeric??false),});__exports.formatDateTime=formatDateTime;function formatDateTime(value,options={}){if(options.numeric){if(options.showTime===false){return _formatDate(value,options);} 5138return _formatDateTime(value,options);}else{return toLocaleDateTimeString(value,options);}} 5139formatDateTime.extractOptions=({attrs,options})=>({...formatDate.extractOptions({attrs,options}),showSeconds:exprToBoolean(options.show_seconds??false),showTime:exprToBoolean(options.show_time??true),showDate:exprToBoolean(options.show_date??true),});__exports.formatFloat=formatFloat;function formatFloat(value,options={}){if(value===false){return"";} 5140if(!options.digits&&options.field){options.digits=options.field.digits;} 5141if(!options.minDigits&&options.field){options.minDigits=options.field.min_display_digits;} 5142return formatFloatNumber(value,options);} 5143formatFloat.extractOptions=({attrs,options})=>{let digits;if(attrs.digits){digits=JSON.parse(attrs.digits);}else if(options.digits){digits=options.digits;} 5144const minDigits=options.minDigits;const humanReadable=!!options.human_readable;const decimals=options.decimals||0;const trailingZeros=!options.hide_trailing_zeros;return{decimals,digits,minDigits,humanReadable,trailingZeros};};__exports.formatFloatFactor=formatFloatFactor;function formatFloatFactor(value,options={}){if(value===false){return"";} 5145const factor=options.factor||1;if(!options.digits&&options.field){options.digits=options.field.digits;} 5146return formatFloatNumber(value*factor,options);} 5147formatFloatFactor.extractOptions=({attrs,options})=>({...formatFloat.extractOptions({attrs,options}),factor:options.factor,});__exports.formatFloatTime=formatFloatTime;function formatFloatTime(value,options={}){if(value===false){return"";} 5148const isNegative=value<0;value=Math.abs(value);let hour=Math.floor(value);const milliSecLeft=Math.round(value*3600000)-hour*3600000;let min=milliSecLeft/60000;if(options.displaySeconds){min=Math.floor(min);}else{min=Math.round(min);} 5149if(min===60){min=0;hour=hour+1;} 5150min=String(min).padStart(2,"0");if(!options.noLeadingZeroHour){hour=String(hour).padStart(2,"0");} 5151let sec="";if(options.displaySeconds){sec=":"+String(Math.floor((milliSecLeft%60000)/1000)).padStart(2,"0");} 5152return`${isNegative ? "-" : ""}${hour}:${min}${sec}`;} 5153formatFloatTime.extractOptions=({options})=>({displaySeconds:options.displaySeconds,});__exports.formatInteger=formatInteger;function formatInteger(value,options={}){if(value===false||value===null){return"";} 5154if(options.isPassword){return"*".repeat(value.length);} 5155if(options.humanReadable){return humanNumber(value,options);} 5156const grouping=options.grouping||l10n.grouping;
5156const thousandsSep="thousandsSep"in options?options.thousandsSep:l10n.thousandsSep;return insertThousandsSep(value.toFixed(0),thousandsSep,grouping);} 5157formatInteger.extractOptions=({attrs,options})=>({decimals:options.decimals||0,humanReadable:!!options.human_readable,isPassword:exprToBoolean(attrs.password),});__exports.formatMany2one=formatMany2one;function formatMany2one(value,options){if(!value){value="";}else if("display_name"in value?value.display_name:value[1]){value="display_name"in value?value.display_name:value[1];}else{value=_t("Unnamed");} 5158if(options&&options.escape){value=encodeURIComponent(value);} 5159return value;} 5160__exports.formatX2many=formatX2many;function formatX2many(value){const count=value.currentIds.length;if(count===0){return _t("No records");}else if(count===1){return _t("1 record");}else{return _t("%s records",count);}} 5161__exports.formatMonetary=formatMonetary;function formatMonetary(value,options={}){if(value===false){return"";} 5162let currencyId=options.currencyId;if(!currencyId&&options.data){const currencyField=options.currencyField||(options.field&&options.field.currency_field)||"currency_id";const dataValue=options.data[currencyField];currencyId=dataValue?.id??dataValue;} 5163return formatCurrency(value,currencyId,options);} 5164formatMonetary.extractOptions=({options})=>
5164({noSymbol:options.no_symbol,currencyField:options.currency_field,trailingZeros:!options.hide_trailing_zeros,});__exports.formatPercentage=formatPercentage;function formatPercentage(value,options={}){value=value||0;options=Object.assign({trailingZeros:false,thousandsSep:""},options);if(!options.digits&&options.field){options.digits=options.field.digits;} 5165const formatted=formatFloatNumber(value*100,options);return`${formatted}${options.noSymbol ? "" : "%"}`;} 5166formatPercentage.extractOptions=formatFloat.extractOptions;function formatProperties(value,field){if(!value||!value.length){return"";} 5167return value.map((property)=>property["string"]).join(", ");} 5168__exports.formatReference=formatReference;function formatReference(value,options){return formatMany2one(value?{id:value.resId,display_name:value.displayName}:false,options);} 5169__exports.formatMany2oneReference=formatMany2oneReference;function formatMany2oneReference(value){return value?formatMany2one({id:value.resId,display_name:value.displayName}):"";} 5170__exports.formatSelection=formatSelection;function formatSelection(value,options={}){const selection=options.selection||(options.field&&options.field.selection)||[];const option=selection.find((option)=>option[0]===value);return option?option[1]:"";} 5171__exports.formatText=formatText;function formatText(value){return value?value.toString():"";} 5172__exports.formatHtml=formatHtml;function formatHtml(value){return value||"";} 5173__exports.formatJson=formatJson;function formatJson(value){return(value&&JSON.stringify(value))||"";} 5174registry.category("formatters").add("binary",formatBinary).add("boolean",formatBoolean).add("char",formatChar).add("date",formatDate).add("datetime",formatDateTime).add("float",formatFloat).add("float_factor",formatFloatFactor).add("float_time",formatFloatTime).add("html",formatHtml).add("integer",formatInteger).add("json",formatJson).add("many2one",formatMany2one).add("many2one_reference",formatMany2oneReference).add("one2many",formatX2many).add("many2many",formatX2many).add("monetary",formatMonetary).add("percentage",formatPercentage).add("properties",formatProperties).add("properties_definition",formatProperties).add("reference",formatReference).add("selection",formatSelection).add("text",formatText);return __exports;});; 5175 5176/* /web/static/src/views/fields/file_handler.js */ 5177odoo.define('@web/views/fields/file_handler',['@web/core/l10n/translation','@web/core/utils/hooks','@web/core/utils/urls','@web/core/utils/files','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web",...args);const{useService}=require("@web/core/utils/hooks");const{getDataURLFromFile}=require("@web/core/utils/urls");const{checkFileSize}=require("@web/core/utils/files");const{Component,useRef,useState}=require("@odoo/owl");const FileUploader=__exports.FileUploader=class FileUploader extends Component{static template="web.FileUploader";static props={onClick:{type:Function,optional:true},onUploaded:Function,onUploadComplete:{type:Function,optional:true},multiUpload:{type:Boolean,optional:true},checkSize:{type:Boolean,optional:true},inputName:{type:String,optional:true},fileUploadClass:{type:String,optional:true},acceptedFileExtensions:{type:String,optional:true},slots:{type:Object,optional:true},showUploadingText:{type:Boolean,optional:true},allowedMIMETypes:{type:String,optional:true},};static defaultProps={checkSize:true,showUploadingText:true,};setup(){this.notification=useService("notification");this.fileInputRef=useRef("fileInput");this.state=useState({isUploading:false,});} 5178async onFileChange(ev){const files=[...ev.target.files].filter(file=>this.validFileType(file));if(!files.length){return;} 5179const{target}=ev;for(const file of files){if(this.props.checkSize&&!checkFileSize(file.size,this.notification)){return null;} 5180this.state.isUploading=true;const data=await getDataURLFromFile(file);if(!file.size){console.warn(`Error while uploading file : ${file.name}`);this.notification.add(_t("There was a problem while uploading your file."),{type:"danger",});} 5181try{await this.props.onUploaded({name:file.name,size:file.size,type:file.type,data:data.split(",")[1],objectUrl:file.type==="application/pdf"?URL.createObjectURL(file):null,});}finally{this.state.isUploading=false;}} 5182target.value=null;if(this.props.multiUpload&&this.props.onUploadComplete){this.props.onUploadComplete({});}} 5183validFileType(file){if(this.props.allowedMIMETypes&&!this.props.allowedMIMETypes.includes(file.type)){this.notification.add(_t(`Oops! '%(fileName)s' didnât upload since its format isnât allowed.`,{fileName:file.name,}),{type:"danger",});return false;} 5184return true;} 5185async onSelectFileButtonClick(ev){if(this.props.onClick){const ok=await this.props.onClick(ev);if(ok!==undefined&&!ok){return;}} 5186this.fileInputRef.el.click();}} 5187return __exports;});; 5188 5189/* /bus/static/src/bus_parameters_service.js */ 5190odoo.define('@bus/bus_parameters_service',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const busParametersService=__exports.busParametersService={start(){return{serverURL:window.origin,};},};registry.category("services").add("bus.parameters",busParametersService);return __exports;});; 5191 5192/* /bus/static/src/legacy_multi_tab_service.js */ 5193odoo.define('@bus/legacy_multi_tab_service',['@web/core/registry','@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{browser}=require("@web/core/browser/browser");const{EventBus}=require("@odoo/owl");const legacyMultiTabService=__exports.legacyMultiTabService={start(){const bus=new EventBus();const sanitizedOrigin=location.origin.replace(/:\/{0,2}/g,"_");const localStoragePrefix=`${this.name}.${sanitizedOrigin}.`;function generateLocalStorageKey(baseKey){return localStoragePrefix+baseKey;} 5194function getItemFromStorage(key,defaultValue){const item=browser.localStorage.getItem(generateLocalStorageKey(key));try{return item?JSON.parse(item):defaultValue;}catch{return item;}} 5195function setItemInStorage(key,value){browser.localStorage.setItem(generateLocalStorageKey(key),JSON.stringify(value));} 5196function onStorage({key,newValue}){if(key&&key.includes(localStoragePrefix)){const baseKey=key.replace(localStoragePrefix,"");bus.trigger("shared_value_updated",{key:baseKey,newValue});}} 5197browser.addEventListener("storage",onStorage);return{bus,generateLocalStorageKey,getItemFromStorage,setItemInStorage,getSharedValue(key,defaultValue){return getItemFromStorage(key,defaultValue);},setSharedValue(key,value){if(value===undefined){return this.removeSharedValue(key);} 5198setItemInStorage(key,value);},removeSharedValue(key){browser.localStorage.removeItem(generateLocalStorageKey(key));},};},};registry.category("services").add("legacy_multi_tab",legacyMultiTabService);return __exports;});; 5199 5200/* /bus/static/src/misc.js */ 5201odoo.define('@bus/misc',['@web/core/browser/browser'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");function throttle(func,wait,options){let timeout,context,args,result;let previous=0;if(!options){options={};} 5202const later=function(){previous=options.leading===false?0:luxon.DateTime.now().ts;timeout=null;result=func.apply(context,args);if(!timeout){context=args=null;}};const throttled=function(){const _now=luxon.DateTime.now().ts;if(!previous&&options.leading===false){previous=_now;}
5203const remaining=wait-(_now-previous);context=this;args=arguments;if(remaining<=0||remaining>wait){if(timeout){browser.clearTimeout(timeout);timeout=null;} 5204previous=_now;result=func.apply(context,args);if(!timeout){context=args=null;}}else if(!timeout&&options.trailing!==false){timeout=browser.setTimeout(later,remaining);} 5205return result;};throttled.cancel=function(){browser.clearTimeout(timeout);previous=0;timeout=context=args=null;};return throttled;} 5206const timings=__exports.timings={throttle,};return __exports;});; 5207 5208/* /bus/static/src/multi_tab_fallback_service.js */ 5209odoo.define('@bus/multi_tab_fallback_service',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{EventBus}=require("@odoo/owl");let multiTabId=0;const multiTabFallbackService=__exports.multiTabFallbackService={start(env){const bus=new EventBus();const TAB_HEARTBEAT_PERIOD=10000;const MAIN_TAB_HEARTBEAT_PERIOD=1500;const HEARTBEAT_OUT_OF_DATE_PERIOD=5000;const HEARTBEAT_KILL_OLD_PERIOD=15000;let _isOnMainTab=false;let lastHeartbeat=0;let heartbeatTimeout;const now=new Date().getTime();const tabId=`${this.name}${multiTabId++}:${now}`;function startElection(){if(_isOnMainTab){return;} 5210const now=new Date().getTime();const lastPresenceByTab=JSON.parse(localStorage.getItem("multi_tab_service.lastPresenceByTab"))??{};const heartbeatKillOld=now-HEARTBEAT_KILL_OLD_PERIOD;let newMain;for(const[tab,lastPresence]of Object.entries(lastPresenceByTab)){if(lastPresence<heartbeatKillOld){continue;} 5211newMain=tab;break;} 5212if(newMain===tabId){lastHeartbeat=now;localStorage.setItem("multi_tab_service.heartbeat",lastHeartbeat);localStorage.setItem("multi_tab_service.main",true);_isOnMainTab=true;bus.trigger("become_main_tab");delete lastPresenceByTab[newMain];localStorage.setItem("multi_tab_service.lastPresenceByTab",JSON.stringify(lastPresenceByTab));}} 5213function heartbeat(){const now=new Date().getTime();let heartbeatValue=parseInt(localStorage.getItem("multi_tab_service.heartbeat")??0);const lastPresenceByTab=JSON.parse(localStorage.getItem("multi_tab_service.lastPresenceByTab"))??{};if(heartbeatValue+HEARTBEAT_OUT_OF_DATE_PERIOD<now){startElection();heartbeatValue=parseInt(localStorage.getItem("multi_tab_service.heartbeat")??0);} 5214if(_isOnMainTab){const cleanedTabs={};for(const[tabId,lastPresence]of Object.entries(lastPresenceByTab)){if(lastPresence+HEARTBEAT_KILL_OLD_PERIOD>now){cleanedTabs[tabId]=lastPresence;}} 5215if(heartbeatValue!==lastHeartbeat){_isOnMainTab=false;lastHeartbeat=0;lastPresenceByTab[tabId]=now;localStorage.setItem("multi_tab_service.lastPresenceByTab",JSON.stringify(lastPresenceByTab));bus.trigger("no_longer_main_tab");}else{lastHeartbeat=now;localStorage.setItem("multi_tab_service.heartbeat",now);localStorage.setItem("multi_tab_service.lastPresenceByTab",JSON.stringify(cleanedTabs));}}else{lastPresenceByTab[tabId]=now;localStorage.setItem("multi_tab_service.lastPresenceByTab",JSON.stringify(lastPresenceByTab));} 5216const hbPeriod=_isOnMainTab?MAIN_TAB_HEARTBEAT_PERIOD:TAB_HEARTBEAT_PERIOD;heartbeatTimeout=browser.setTimeout(heartbeat,hbPeriod);} 5217function onStorage({key,newValue}){if(key==="multi_tab_service.main"&&!newValue){startElection();}} 5218function unregister(){clearTimeout(heartbeatTimeout);const lastPresenceByTab=JSON.parse(localStorage.getItem("multi_tab_service.lastPresenceByTab"))??{};delete lastPresenceByTab[tabId];localStorage.setItem("multi_tab_service.lastPresenceByTab",JSON.stringify(lastPresenceByTab));if(_isOnMainTab){_isOnMainTab=false;bus.trigger("no_longer_main_tab");browser.localStorage.removeItem("multi_tab_service.main");}} 5219browser.addEventListener("pagehide",unregister);browser.addEventListener("storage",onStorage);const lastPresenceByTab=JSON.parse(localStorage.getItem("multi_tab_service.lastPresenceByTab"))??{};lastPresenceByTab[tabId]=now;localStorage.setItem("multi_tab_service.lastPresenceByTab",JSON.stringify(lastPresenceByTab));if(!localStorage.getItem("multi_tab_service.main")){startElection();} 5220heartbeat();return{bus,async isOnMainTab(){return _isOnMainTab;},unregister,};},};return __exports;});; 5221 5222/* /bus/static/src/multi_tab_service.js */ 5223odoo.define('@bus/multi_tab_service',['@web/core/browser/browser','@web/core/registry','@bus/multi_tab_fallback_service','@bus/multi_tab_shared_worker_service'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{multiTabFallbackService}=require("@bus/multi_tab_fallback_service");const{multiTabSharedWorkerService}=require("@bus/multi_tab_shared_worker_service");const multiTabService=__exports.multiTabService=browser.SharedWorker?multiTabSharedWorkerService:multiTabFallbackService;registry.category("services").add("multi_tab",multiTabService);return __exports;});; 5224 5225/* /bus/static/src/multi_tab_shared_worker_service.js */ 5226odoo.define('@bus/multi_tab_shared_worker_service',['@web/core/browser/browser','@web/core/utils/concurrency','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Deferred}=require("@web/core/utils/concurrency");const{EventBus}=require("@odoo/owl");
5226const STATE=Object.freeze({INIT:"INIT",MASTER:"MASTER",REGISTERED:"REGISTERED",UNREGISTERED:"UNREGISTERED",});const multiTabSharedWorkerService=__exports.multiTabSharedWorkerService={dependencies:["worker_service"],start(env,{worker_service:workerService}){const bus=new EventBus();let responseDeferred=null;let state=STATE.INIT;browser.addEventListener("pagehide",unregister);function messageHandler(messageEv){const{type,data}=messageEv.data;if(!type?.startsWith("ELECTION:")){return;} 5227switch(type){case"ELECTION:IS_MASTER_RESPONSE":responseDeferred?.resolve(data.answer);responseDeferred=null;break;case"ELECTION:HEARTBEAT_REQUEST":workerService.send("ELECTION:HEARTBEAT");break;case"ELECTION:ASSIGN_MASTER":state=STATE.MASTER;bus.trigger("become_main_tab");break;case"ELECTION:UNASSIGN_MASTER":if(state!==STATE.UNREGISTERED){state=STATE.REGISTERED;} 5228bus.trigger("no_longer_main_tab");break;default:console.warn("multiTabSharedWorkerService received unknown message type:",type);}} 5229async function startWorker(){await workerService.ensureWorkerStarted();await workerService.registerHandler(messageHandler);workerService.send("ELECTION:REGISTER");state=STATE.REGISTERED;} 5230function unregister(){workerService.send("ELECTION:UNREGISTER");state=STATE.UNREGISTERED;} 5231return{bus,isOnMainTab:async()=>{if(state===STATE.UNREGISTERED){return false;} 5232if(state===STATE.INIT){await startWorker();} 5233if(!responseDeferred){responseDeferred=new Deferred();workerService.send("ELECTION:IS_MASTER?");} 5234return responseDeferred;},unregister,};},};return __exports;});; 5235 5236/* /bus/static/src/services/bus_monitoring_service.js */ 5237odoo.define('@bus/services/bus_monitoring_service',['@bus/workers/websocket_worker','@odoo/owl','@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{WORKER_STATE}=require("@bus/workers/websocket_worker");const{reactive}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const BusMonitoringService=__exports.BusMonitoringService=class BusMonitoringService{isConnectionLost=false;constructor(env,services){const reactiveThis=reactive(this);reactiveThis.setup(env,services);return reactiveThis;} 5238setup(env,{bus_service}){bus_service.addEventListener("BUS:WORKER_STATE_UPDATED",({detail})=>this.workerStateOnChange(detail));browser.addEventListener("offline",()=>(this.isReconnecting=false));} 5239workerStateOnChange(state){switch(state){case WORKER_STATE.CONNECTING:{this.isReconnecting=true;break;} 5240case WORKER_STATE.CONNECTED:{this.isReconnecting=false;this.isConnectionLost=false;break;} 5241case WORKER_STATE.DISCONNECTED:{if(this.isReconnecting){this.isConnectionLost=true;this.isReconnecting=false;} 5242break;}}}} 5243const busMonitoringservice=__exports.busMonitoringservice={dependencies:["bus_service"],start(env,services){return new BusMonitoringService(env,services);},};registry.category("services").add("bus.monitoring_service",busMonitoringservice);return __exports;});; 5244 5245/* /bus/static/src/services/bus_service.js */ 5246odoo.define('@bus/services/bus_service',['@web/core/browser/browser','@web/core/l10n/translation','@web/core/utils/concurrency','@web/core/registry','@web/session','@odoo/owl','@web/core/user'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"bus",...args);const{Deferred}=require("@web/core/utils/concurrency");const{registry}=require("@web/core/registry");const{session}=require("@web/session");const{EventBus,reactive}=require("@odoo/owl");const{user}=require("@web/core/user");const INTERNAL_EVENTS=new Set(["BUS:INITIALIZED","BUS:OUTDATED","BUS:NOTIFICATION","BUS:PROVIDE_LOGS",]);const BACK_ONLINE_RECONNECT_DELAY=__exports.BACK_ONLINE_RECONNECT_DELAY=5000;const busService=__exports.busService={dependencies:["bus.parameters","localization","multi_tab","legacy_multi_tab","notification","worker_service",],start(env,{multi_tab:multiTab,legacy_multi_tab:legacyMultiTab,notification,"bus.parameters":params,worker_service:workerService,}){const bus=new EventBus();const notificationBus=new EventBus();const subscribeFnToWrapper=new Map();let backOnlineTimeout;const startedAt=luxon.DateTime.now().set({milliseconds:0});let connectionInitializedDeferred;function handleMessage(messageEv){const{type,data}=messageEv.data;switch(type){case"BUS:PROVIDE_LOGS":{const blob=new Blob([JSON.stringify(data,null,2)],{type:"application/json",});const url=URL.createObjectURL(blob);const a=document.createElement("a");a.href=url;a.download=`bus_logs_${luxon.DateTime.now().toFormat( 5247 "yyyy-LL-dd-HH-mm-ss" 5248 )}.json`;a.click();URL.revokeObjectURL(url);break;} 5249case"BUS:NOTIFICATION":{const notifications=data.map(({id,message})=>({id,...message}));state.lastNotificationId=notifications.at(-1).id;legacyMultiTab.setSharedValue("last_notification_id",state.lastNotificationId);for(const{id,type,payload}of notifications){notificationBus.trigger(type,{id,payload});busService._onMessage(env,id,type,payload);} 5250break;} 5251case"BUS:INITIALIZED":{connectionInitializedDeferred.resolve();break;}
5252case"BUS:WORKER_STATE_UPDATED":state.workerState=data;break;case"BUS:OUTDATED":{multiTab.unregister();notification.add(_t("Save your work and refresh to get the latest updates and avoid potential issues."),{title:_t("The page is out of date"),type:"warning",sticky:true,buttons:[{name:_t("Refresh"),primary:true,onClick:()=>{browser.location.reload();},},],});break;}} 5253if(!INTERNAL_EVENTS.has(type)){bus.trigger(type,data);}} 5254async function ensureWorkerStarted(){if(!connectionInitializedDeferred){connectionInitializedDeferred=new Deferred();let uid=Array.isArray(session.user_id)?session.user_id[0]:user.userId;if(!uid&&uid!==undefined){uid=false;} 5255await workerService.ensureWorkerStarted();await workerService.registerHandler(handleMessage);workerService.send("BUS:INITIALIZE_CONNECTION",{websocketURL:`${params.serverURL.replace("http", "ws")}/websocket?version=${ 5256 session.websocket_worker_version 5257 }`,db:session.db,debug:odoo.debug,lastNotificationId:legacyMultiTab.getSharedValue("last_notification_id",0),uid,startTs:startedAt.valueOf(),});} 5258await connectionInitializedDeferred;} 5259browser.addEventListener("pagehide",({persisted})=>{if(!persisted){workerService.send("BUS:LEAVE");}});browser.addEventListener("online",()=>{backOnlineTimeout=browser.setTimeout(()=>{if(state.isActive){workerService.send("BUS:START");}},BACK_ONLINE_RECONNECT_DELAY);},{capture:true});browser.addEventListener("offline",()=>{clearTimeout(backOnlineTimeout);workerService.send("BUS:STOP");},{capture:true,});const state=reactive({addEventListener:bus.addEventListener.bind(bus),addChannel:async(channel)=>{await ensureWorkerStarted();workerService.send("BUS:ADD_CHANNEL",channel);workerService.send("BUS:START");state.isActive=true;},deleteChannel:(channel)=>{workerService.send("BUS:DELETE_CHANNEL",channel);},setLoggingEnabled:(isEnabled)=>workerService.send("BUS:SET_LOGGING_ENABLED",isEnabled),downloadLogs:()=>workerService.send("BUS:REQUEST_LOGS"),forceUpdateChannels:()=>workerService.send("BUS:FORCE_UPDATE_CHANNELS"),trigger:bus.trigger.bind(bus),removeEventListener:bus.removeEventListener.bind(bus),send:(eventName,data)=>workerService.send("BUS:SEND",{event_name:eventName,data}),start:async()=>{await ensureWorkerStarted();workerService.send("BUS:START");state.isActive=true;},stop:()=>{workerService.send("BUS:LEAVE");state.isActive=false;},isActive:false,subscribe(notificationType,callback){const wrapper=({detail})=>{const{id,payload}=detail;callback(JSON.parse(JSON.stringify(payload)),{id});};subscribeFnToWrapper.set(callback,wrapper);notificationBus.addEventListener(notificationType,wrapper);},unsubscribe(notificationType,callback){notificationBus.removeEventListener(notificationType,subscribeFnToWrapper.get(callback));subscribeFnToWrapper.delete(callback);},startedAt,workerState:null,lastNotificationId:null,});return state;},_onMessage(env,id,type,payload){},};registry.category("services").add("bus_service",busService);return __exports;});; 5260 5261/* /bus/static/src/services/presence_service.js */ 5262odoo.define('@bus/services/presence_service',['@odoo/owl','@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{EventBus}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const presenceService=__exports.presenceService={start(env){const LOCAL_STORAGE_PREFIX="presence";const bus=new EventBus();let isOdooFocused=true;let lastPresenceTime=browser.localStorage.getItem(`${LOCAL_STORAGE_PREFIX}.lastPresence`)||luxon.DateTime.now().ts;function onPresence(){lastPresenceTime=luxon.DateTime.now().ts;browser.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}.lastPresence`,lastPresenceTime);bus.trigger("presence");} 5263function onFocusChange(isFocused){try{isFocused=parent.document.hasFocus();}catch{} 5264isOdooFocused=isFocused;browser.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}.focus`,isOdooFocused);if(isOdooFocused){lastPresenceTime=luxon.DateTime.now().ts;env.bus.trigger("window_focus",isOdooFocused);}} 5265function onStorage({key,newValue}){if(key===`${LOCAL_STORAGE_PREFIX}.focus`){isOdooFocused=JSON.parse(newValue);env.bus.trigger("window_focus",newValue);} 5266if(key===`${LOCAL_STORAGE_PREFIX}.lastPresence`){lastPresenceTime=JSON.parse(newValue);bus.trigger("presence");}} 5267browser.addEventListener("storage",onStorage);browser.addEventListener("focus",()=>onFocusChange(true));browser.addEventListener("blur",()=>onFocusChange(false));browser.addEventListener("pagehide",()=>onFocusChange(false));browser.addEventListener("click",onPresence,true);browser.addEventListener("keydown",onPresence,true);return{bus,getLastPresence(){return lastPresenceTime;},isOdooFocused(){return isOdooFocused;},getInactivityPeriod(){return luxon.DateTime.now().ts-this.getLastPresence();},};},};registry.category("services").add("presence",presenceService);return __exports;});; 5268 5269/* /bus/static/src/services/worker_service.js */ 5270odoo.define('@bus/services/worker_service',['@web/core/browser/browser','@web/core/registry','@web/core/utils/concurrency','@web/session'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Deferred}=require("@web/core/utils/concurrency");const{session}=require("@web/session");const WORKER_STATE=__exports.WORKER_STATE=Object.freeze({UNINITIALIZED:"UNINITIALIZED",INITIALIZING:"INITIALIZING",INITIALIZED:"INITIALIZED",FAILED:"FAILED",});
5270const WorkerService=__exports.WorkerService=class WorkerService{constructor(env,services){this.params=services["bus.parameters"];this.worker=null;this.isUsingSharedWorker=Boolean(browser.SharedWorker);this._state=WORKER_STATE.UNINITIALIZED;this.connectionInitializedDeferred=new Deferred();} 5271startWorker(){this._state=WORKER_STATE.INITIALIZING;let workerURL=`${this.params.serverURL}/bus/websocket_worker_bundle?v=${session.websocket_worker_version}`;if(this.params.serverURL!==window.origin){const source=`importScripts("${workerURL}");`;workerURL="data:application/javascript;base64,"+window.btoa(source);} 5272const workerClass=this.isUsingSharedWorker?browser.SharedWorker:browser.Worker;this.worker=new workerClass(workerURL,{name:this.isUsingSharedWorker?"odoo:bus_shared_worker":"odoo:bus_worker",});this.worker.onerror=(e)=>this.onInitError(e);this._registerHandler((ev)=>{if(ev.data.type==="BASE:INITIALIZED"){this._state=WORKER_STATE.INITIALIZED;this.connectionInitializedDeferred.resolve();}});if(this.isUsingSharedWorker){this.worker.port.start();} 5273this._send("BASE:INIT");} 5274async ensureWorkerStarted(){if(this._state===WORKER_STATE.UNINITIALIZED){this.startWorker();} 5275await this.connectionInitializedDeferred;} 5276onInitError(e){if(this._state===WORKER_STATE.INITIALIZING&&this.isUsingSharedWorker){console.warn("Error while loading SharedWorker, fallback on Worker: ",e);this.isUsingSharedWorker=false;this.worker?.port?.close?.();this.startWorker();}else if(this._state===WORKER_STATE.INITIALIZING){this._state=WORKER_STATE.FAILED;this.connectionInitializedDeferred.resolve();console.warn("Worker service failed to initialize: ",e);}} 5277_registerHandler(handler){if(this.isUsingSharedWorker){this.worker.port.addEventListener("message",handler);}else{this.worker.addEventListener("message",handler);}} 5278_send(action,data){const message={action,data};if(this.isUsingSharedWorker){this.worker.port.postMessage(message);}else{this.worker.postMessage(message);}} 5279async send(action,data){if(this._state===WORKER_STATE.UNINITIALIZED){return;} 5280await this.connectionInitializedDeferred;if(this._state===WORKER_STATE.FAILED){console.warn("Worker service failed to initialize, cannot send message.");} 5281this._send(action,data);} 5282async registerHandler(handler){if(this._state===WORKER_STATE.UNINITIALIZED){this.startWorker();} 5283await this.connectionInitializedDeferred;if(this._state===WORKER_STATE.FAILED){console.warn("Worker service failed to initialize, cannot register handler.");} 5284this._registerHandler(handler);} 5285get state(){return this._state;}} 5286const workerService=__exports.workerService={dependencies:["bus.parameters"],start(env,services){return new WorkerService(env,services);},};registry.category("services").add("worker_service",workerService);return __exports;});; 5287 5288/* /bus/static/src/workers/base_worker.js */ 5289odoo.define('@bus/workers/base_worker',[],function(require){'use strict';let __exports={};const BaseWorker=__exports.BaseWorker=class BaseWorker{constructor(name){this.name=name;this.client=null;} 5290handleMessage(event){const{action}=event.data;if(action==="BASE:INIT"){if(this.name.includes("shared")){event.target.postMessage({type:"BASE:INITIALIZED"});}else{(this.client||globalThis).postMessage({type:"BASE:INITIALIZED"});}}}} 5291return __exports;});; 5292 5293/* /bus/static/src/workers/bus_worker_utils.js */ 5294odoo.define('@bus/workers/bus_worker_utils',[],function(require){'use strict';let __exports={};__exports.debounce=debounce;function debounce(func,wait,immediate){let timeout;return function(){const context=this;const args=arguments;function later(){timeout=null;if(!immediate){func.apply(context,args);}} 5295const callNow=immediate&&!timeout;clearTimeout(timeout);timeout=setTimeout(later,wait);if(callNow){func.apply(context,args);}};} 5296const Deferred=__exports.Deferred=class Deferred extends Promise{constructor(){let resolve;let reject;const prom=new Promise((res,rej)=>{resolve=res;reject=rej;});return Object.assign(prom,{resolve,reject});}} 5297const Logger=__exports.Logger=class Logger{static LOG_TTL=24*60*60*1000;static gcInterval=null;static instances=[];_db;static async gcOutdatedLogs(){const threshold=Date.now()-Logger.LOG_TTL;for(const logger of this.instances){try{await logger._ensureDatabaseAvailable();await new Promise((res,rej)=>{const transaction=logger._db.transaction("logs","readwrite");const store=transaction.objectStore("logs");const req=store.index("timestamp").openCursor(IDBKeyRange.upperBound(threshold));req.onsuccess=(event)=>{const cursor=event.target.result;if(cursor){cursor.delete();cursor.continue();}};req.onerror=(e)=>rej(e.target.error);transaction.oncomplete=res;transaction.onerror=(e)=>rej(e.target.error);});}catch(error){console.error(`Failed to clear logs for logger "${logger._name}":`,error);}}} 5298constructor(name){this._name=name;Logger.instances.push(this);Logger.gcOutdatedLogs();clearInterval(Logger.gcInterval);Logger.gcInterval=setInterval(()=>Logger.gcOutdatedLogs(),Logger.LOG_TTL);} 5299async _ensureDatabaseAvailable(){if(this._db){return;} 5300return new Promise((res,rej)=>{const request=indexedDB.open(this._name,1);request.onsuccess=(event)=>{this._db=event.target.result;res();};request.onupgradeneeded=(event)=>{if(!event.target.result.objectStoreNames.contains("logs")){const store=event.target.result.createObjectStore("logs",{autoIncrement:true,});store.createIndex("timestamp","timestamp",{unique:false});}};request.onerror=rej;});} 5301async log(message){await this._ensureDatabaseAvailable();const transaction=this._db.transaction("logs","readwrite");const store=transaction.objectStore("logs");const addRequest=store.add({timestamp:Date.now(),message});return new Promise((res,rej)=>{addRequest.onsuccess=res;addRequest.onerror=rej;});} 5302async getLogs(){await Logger.gcOutdatedLogs();await this._ensureDatabaseAvailable();const transaction=this._db.transaction("logs","readonly");const store=transaction.objectStore("logs");const request=store.getAll();return new Promise((res,rej)=>{request.onsuccess=(ev)=>res(ev.target.result.map(({message})=>message));request.onerror=rej;});}} 5303return __exports;});; 5304 5305/* /bus/static/src/workers/election_worker.js */ 5306odoo.define('@bus/workers/election_worker',['@bus/workers/bus_worker_utils'],function(require){'use strict';let __exports={};const{Deferred}=require("@bus/workers/bus_worker_utils");const ElectionWorker=__exports.ElectionWorker=class ElectionWorker{MAIN_TAB_TIMEOUT_PERIOD=3000;candidates=new Set();electionDeferred=null;heartbeatRequestInterval=null;lastHeartbeat=Date.now();masterReplyDeferred=null;masterTab=null;constructor(){setInterval(()=>{if(Date.now()-this.lastHeartbeat>this.MAIN_TAB_TIMEOUT_PERIOD){this.startElection();}},this.MAIN_TAB_TIMEOUT_PERIOD);} 5307requestHeartbeat(messagePort){if(messagePort){messagePort.postMessage({type:"ELECTION:HEARTBEAT_REQUEST"});return;} 5308for(const candidate of this.candidates){candidate.postMessage({type:"ELECTION:HEARTBEAT_REQUEST"});}} 5309async ensureMasterPresence(){this.masterReplyDeferred??=new Deferred();if(this.masterTab){this.requestHeartbeat(this.masterTab);}else{this.startElection();} 5310await this.masterReplyDeferred;} 5311startElection(){clearInterval(this.heartbeatRequestInterval);this.masterTab?.postMessage({type:"ELECTION:UNASSIGN_MASTER"});this.masterTab=null;this.electionDeferred??=new Deferred();this.requestHeartbeat();} 5312finishElection(messagePort){this.masterTab=messagePort;messagePort.postMessage({type:"ELECTION:ASSIGN_MASTER"});this.electionDeferred.resolve();this.electionDeferred=null;this.heartbeatRequestInterval=setInterval(()=>this.requestHeartbeat(this.masterTab),this.MAIN_TAB_TIMEOUT_PERIOD/2);} 5313async handleMessage(event){const{action}=event.data;if(!action?.startsWith("ELECTION:")){return;} 5314switch(action){case"ELECTION:REGISTER":this.candidates.add(event.target);await this.electionDeferred;if(!this.masterTab){this.startElection();} 5315break;case"ELECTION:UNREGISTER":this.candidates.delete(event.target);if(this.masterTab===event.target){this.startElection();} 5316break;case"ELECTION:IS_MASTER?":await this.ensureMasterPresence();event.target.postMessage({type:"ELECTION:IS_MASTER_RESPONSE",data:{answer:this.masterTab===event.target},});break;case"ELECTION:HEARTBEAT":if(this.electionDeferred){this.finishElection(event.target);} 5317if(this.masterTab===event.target){this.lastHeartbeat=Date.now();this.masterReplyDeferred?.resolve();this.masterReplyDeferred=null;} 5318break;default:console.warn("Unknown message action:",action);}}} 5319return __exports;});; 5320 5321/* /bus/static/src/workers/websocket_worker.js */ 5322odoo.define('@bus/workers/websocket_worker',['@bus/workers/bus_worker_utils'],function(require){'use strict';let __exports={};const{debounce,Deferred,Logger}=require("@bus/workers/bus_worker_utils");const WEBSOCKET_CLOSE_CODES=__exports.WEBSOCKET_CLOSE_CODES=Object.freeze({CLEAN:1000,GOING_AWAY:1001,PROTOCOL_ERROR:1002,INCORRECT_DATA:1003,ABNORMAL_CLOSURE:1006,INCONSISTENT_DATA:1007,MESSAGE_VIOLATING_POLICY:1008,MESSAGE_TOO_BIG:1009,EXTENSION_NEGOTIATION_FAILED:1010,SERVER_ERROR:1011,RESTART:1012,TRY_LATER:1013,BAD_GATEWAY:1014,SESSION_EXPIRED:4001,KEEP_ALIVE_TIMEOUT:4002,RECONNECTING:4003,CLOSING_HANDSHAKE_ABORTED:4004,});const WORKER_STATE=__exports.WORKER_STATE=Object.freeze({CONNECTED:"CONNECTED",DISCONNECTED:"DISCONNECTED",IDLE:"IDLE",CONNECTING:"CONNECTING",});const MAXIMUM_RECONNECT_DELAY=120_000;const IMMEDIATE_RECONNECT_CLOSE_CODES=[WEBSOCKET_CLOSE_CODES.KEEP_ALIVE_TIMEOUT,WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED,];const UUID=Date.now().toString(36)+Math.random().toString(36).substring(2);const logger=new Logger("bus_websocket_worker");const WebsocketWorker=__exports.WebsocketWorker=class WebsocketWorker{INITIAL_RECONNECT_DELAY=1000;RECONNECT_JITTER=30000;CONNECTION_CHECK_DELAY=60_000;constructor(name){this.name=name;this.newestStartTs=undefined;this.websocketURL="";this.currentUID=null;this.currentDB=null;this.isWaitingForNewUID=true;this.channelsByClient=new Map();this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.connectTimeout=null;this.debugModeByClient=new Map();this.isDebug=false;this.active=true;this.state=WORKER_STATE.IDLE;this.isReconnecting=false;this.lastChannelSubscription=null;this.loggingEnabled=null;this.firstSubscribeDeferred=new Deferred();this.lastNotificationId=0;this.messageWaitQueue=[];this._forceUpdateChannels=debounce(this._forceUpdateChannels,300);this._debouncedUpdateChannels=debounce(this._updateChannels,300);this._debouncedSendToServer=debounce(this._sendToServer,300);this._onWebsocketClose=this._onWebsocketClose.bind(this);this._onWebsocketError=this._onWebsocketError.bind(this);this._onWebsocketMessage=this._onWebsocketMessage.bind(this);this._onWebsocketOpen=this._onWebsocketOpen.bind(this);globalThis.addEventListener("error",({error})=>{const params=error instanceof Error?[error.constructor.name,error.stack]:[error];this._logDebug("Unhandled error",...params);});globalThis.addEventListener("unhandledrejection",({reason})=>{const params=reason instanceof Error?[reason.constructor.name,reason.stack]:[reason];this._logDebug("Unhandled rejection",params);});} 5323broadcast(type,data){this._logDebug("broadcast",type,data);for(const client of this.channelsByClient.keys()){client.postMessage({type,data:data?JSON.parse(JSON.stringify(data)):undefined});}} 5324registerClient(messagePort){messagePort.addEventListener("message",(ev)=>{this._onClientMessage(messagePort,ev.data);});this.channelsByClient.set(messagePort,[]);} 5325sendToClient(client,type,data){if(type!=="BUS:PROVIDE_LOGS"){this._logDebug("sendToClient",type,data);} 5326client.postMessage({type,data:data?JSON.parse(JSON.stringify(data)):undefined});} 5327_onClientMessage(client,{action,data}){this._logDebug("_onClientMessage",action,data);switch(action){case"BUS:SEND":{if(data["event_name"]==="update_presence"){this._debouncedSendToServer(data);}else{this._sendToServer(data);} 5328return;} 5329case"BUS:START":return this._start();case"BUS:STOP":return this._stop();case"BUS:LEAVE":return this._unregisterClient(client);case"BUS:ADD_CHANNEL":return this._addChannel(client,data);case"BUS:DELETE_CHANNEL":return this._deleteChannel(client,data);case"BUS:FORCE_UPDATE_CHANNELS":return this._forceUpdateChannels();case"BUS:SET_LOGGING_ENABLED":this.loggingEnabled=data;break;case"BUS:REQUEST_LOGS":logger.getLogs().then((logs)=>{const workerInfo={UUID,active:this.active,channels:[...new Set([].concat.apply([],[...this.channelsByClient.values()])),].sort(),db:this.currentDB,is_reconnecting:this.isReconnecting,last_subscription:this.lastChannelSubscription,name:this.name,number_of_clients:this.channelsByClient.size,reconnect_delay:this.connectRetryDelay,uid:this.currentUID,websocket_url:this.websocketURL,};this.sendToClient(client,"BUS:PROVIDE_LOGS",{workerInfo,logs});});break;case"BUS:INITIALIZE_CONNECTION":return this._initializeConnection(client,data);}} 5330_addChannel(client,channel){this.channelsByClient.get(client).push(channel);this._debouncedUpdateChannels();} 5331_deleteChannel(client,channel){const clientChannels=this.channelsByClient.get(client);if(!clientChannels){return;} 5332const channelIndex=clientChannels.indexOf(channel);if(channelIndex!==-1){clientChannels.splice(channelIndex,1);this._debouncedUpdateChannels();}} 5333_forceUpdateChannels(){this._updateChannels({force:true});} 5334_unregisterClient(client){this.channelsByClient.delete(client);this.debugModeByClient.delete(client);this.isDebug=[...this.debugModeByClient.values()].some(Boolean);this._debouncedUpdateChannels();} 5335_initializeConnection(client,{db,debug,lastNotificationId,uid,websocketURL,startTs}){if(this.newestStartTs&&this.newestStartTs>startTs){this.debugModeByClient.set(client,debug);this.isDebug=[...this.debugModeByClient.values()].some(Boolean);this.sendToClient(client,"BUS:WORKER_STATE_UPDATED",this.state);this.sendToClient(client,"BUS:INITIALIZED");return;} 5336this.newestStartTs=startTs;this.websocketURL=websocketURL;this.lastNotificationId=lastNotificationId;this.debugModeByClient.set(client,debug);this.isDebug=[...this.debugModeByClient.values()].some(Boolean);const isCurrentUserKnown=uid!==undefined;if(this.isWaitingForNewUID&&isCurrentUserKnown){this.isWaitingForNewUID=false;this.currentUID=uid;} 5337this.currentDB||=db;if((this.currentUID!==uid&&isCurrentUserKnown)||(db&&this.currentDB!==db)){this.currentUID=uid;this.currentDB=db||this.currentDB;if(this.websocket){this.websocket.close(WEBSOCKET_CLOSE_CODES.CLEAN);} 5338this.channelsByClient.forEach((_,key)=>this.channelsByClient.set(key,[]));} 5339this.sendToClient(client,"BUS:WORKER_STATE_UPDATED",this.state);this.sendToClient(client,"BUS:INITIALIZED");if(!this.active){this.sendToClient(client,"BUS:OUTDATED");}} 5340_isWebsocketConnected(){return this.websocket&&this.websocket.readyState===1;} 5341_isWebsocketConnecting(){return this.websocket&&this.websocket.readyState===0;} 5342_isWebsocketClosing(){return this.websocket&&this.websocket.readyState===2;}
5343_onWebsocketClose({code,reason}){clearInterval(this._connectionCheckInterval);this._logDebug("_onWebsocketClose",code,reason);this._updateState(WORKER_STATE.DISCONNECTED);this.lastChannelSubscription=null;this.firstSubscribeDeferred=new Deferred();if(IMMEDIATE_RECONNECT_CLOSE_CODES.includes(code)){this.connectRetryDelay=0;} 5344if(this.isReconnecting){if(code===WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED){this._retryConnectionWithDelay();} 5345return;} 5346this.broadcast("BUS:DISCONNECT",{code,reason});if(code===WEBSOCKET_CLOSE_CODES.CLEAN){if(reason==="OUTDATED_VERSION"){console.warn("Worker deactivated due to an outdated version.");this.active=false;this.broadcast("BUS:OUTDATED");} 5347return;} 5348this.broadcast("BUS:RECONNECTING",{closeCode:code});this.isReconnecting=true;if(code===WEBSOCKET_CLOSE_CODES.SESSION_EXPIRED){this.isWaitingForNewUID=true;} 5349this._retryConnectionWithDelay();} 5350_onWebsocketError(){this._logDebug("_onWebsocketError");this._retryConnectionWithDelay();} 5351_onWebsocketMessage(messageEv){this._restartConnectionCheckInterval();const notifications=JSON.parse(messageEv.data);this._logDebug("_onWebsocketMessage",notifications);this.lastNotificationId=notifications[notifications.length-1].id;this.broadcast("BUS:NOTIFICATION",notifications);} 5352async _logDebug(title,...args){if(this.loggingEnabled){try{await logger.log({dt:new Date().toISOString(),event:title,args,worker:UUID,});}catch(e){console.error(e);}}} 5353_onWebsocketOpen(){this._logDebug("_onWebsocketOpen");this._updateState(WORKER_STATE.CONNECTED);this.broadcast(this.isReconnecting?"BUS:RECONNECT":"BUS:CONNECT");this._debouncedUpdateChannels();this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.connectTimeout=null;this.isReconnecting=false;this.firstSubscribeDeferred.then(()=>{if(!this.websocket){return;} 5354this.messageWaitQueue.forEach((msg)=>this.websocket.send(msg));this.messageWaitQueue=[];});this._restartConnectionCheckInterval();} 5355_restartConnectionCheckInterval(){clearInterval(this._connectionCheckInterval);this._connectionCheckInterval=setInterval(()=>{if(this._isWebsocketConnected()){this.websocket.send(new Uint8Array([0x00]));this._logDebug("connection_checked");}},this.CONNECTION_CHECK_DELAY);} 5356_retryConnectionWithDelay(){clearTimeout(this.connectTimeout);this.connectRetryDelay=Math.min(this.connectRetryDelay,MAXIMUM_RECONNECT_DELAY)+ 5357this.RECONNECT_JITTER*Math.random();this._logDebug("_retryConnectionWithDelay",this.connectRetryDelay);this.connectTimeout=setTimeout(this._start.bind(this),this.connectRetryDelay);} 5358_sendToServer(message){this._logDebug("_sendToServer",message);const payload=JSON.stringify(message);if(!this._isWebsocketConnected()){if(message["event_name"]==="subscribe"){this.messageWaitQueue=this.messageWaitQueue.filter((msg)=>JSON.parse(msg).event_name!=="subscribe");this.messageWaitQueue.unshift(payload);}else{this.messageWaitQueue.push(payload);}}else{if(message["event_name"]==="subscribe"){this.websocket.send(payload);}else{this.firstSubscribeDeferred.then(()=>this.websocket.send(payload));} 5359this._restartConnectionCheckInterval();}} 5360_removeWebsocketListeners(){this.websocket?.removeEventListener("open",this._onWebsocketOpen);this.websocket?.removeEventListener("message",this._onWebsocketMessage);this.websocket?.removeEventListener("error",this._onWebsocketError);this.websocket?.removeEventListener("close",this._onWebsocketClose);} 5361_start(){this._logDebug("_start");if(!this.active||this._isWebsocketConnected()||this._isWebsocketConnecting()){return;} 5362this._removeWebsocketListeners();if(this._isWebsocketClosing()){this._onWebsocketClose(new CloseEvent("close",{code:WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED}));this.websocket=null;return;} 5363this._updateState(WORKER_STATE.CONNECTING);this.websocket=new WebSocket(this.websocketURL);this.websocket.addEventListener("open",this._onWebsocketOpen);this.websocket.addEventListener("error",this._onWebsocketError);this.websocket.addEventListener("message",this._onWebsocketMessage);this.websocket.addEventListener("close",this._onWebsocketClose);} 5364_stop(){this._logDebug("_stop");clearTimeout(this.connectTimeout);this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.isReconnecting=false;this.lastChannelSubscription=null;const shouldBroadcastClose=this.websocket&&this.websocket.readyState!==WebSocket.CLOSED;this.websocket?.close();this._removeWebsocketListeners();this.websocket=null;if(shouldBroadcastClose){this.broadcast("BUS:DISCONNECT",{code:WEBSOCKET_CLOSE_CODES.CLEAN});}} 5365_updateChannels({force=false}={}){const allTabsChannels=[...new Set([].concat.apply([],[...this.channelsByClient.values()])),].sort();const allTabsChannelsString=JSON.stringify(allTabsChannels);const shouldUpdateChannelSubscription=allTabsChannelsString!==this.lastChannelSubscription;if(force||shouldUpdateChannelSubscription){this.lastChannelSubscription=allTabsChannelsString;this._sendToServer({event_name:"subscribe",data:{channels:allTabsChannels,last:this.lastNotificationId},});this.firstSubscribeDeferred.resolve();}} 5366_updateState(newState){this.state=newState;this.broadcast("BUS:WORKER_STATE_UPDATED",newState);}} 5367return __exports;});; 5368 5369/* /mail_enterprise/static/src/core/common/message_patch.js */ 5370odoo.define('@mail_enterprise/core/common/message_patch',['@web/core/utils/patch','@mail/core/common/message'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{Message}=require("@mail/core/common/message");patch(Message,{SHADOW_LINK_COLOR:"#017e84",SHADOW_LINK_HOVER_COLOR:"#016b70",});return __exports;});; 5371 5372/* /hr/static/src/core/common/hr_department_model.js */ 5373odoo.define('@hr/core/common/hr_department_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const HrDepartment=__exports.HrDepartment=class HrDepartment extends Record{static _name="hr.department";static id="id";id;name;} 5374HrDepartment.register();return __exports;});; 5375 5376/* /hr/static/src/core/common/hr_employee_model.js */ 5377odoo.define('@hr/core/common/hr_employee_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record,fields}=require("@mail/core/common/record");const HrEmployee=__exports.HrEmployee=class HrEmployee extends Record{static _name="hr.employee";static id="id";active;id;company_id=fields.One("res.company");department_id=fields.One("hr.department");job_title;work_contact_id=fields.One("res.partner");user_id=fields.One("res.users");work_email;work_location_id=fields.One("hr.work.location");
5377work_phone;} 5378HrEmployee.register();return __exports;});; 5379 5380/* /hr/static/src/core/common/hr_work_location_model.js */ 5381odoo.define('@hr/core/common/hr_work_location_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const HrWorkLocation=__exports.HrWorkLocation=class HrWorkLocation extends Record{static _name="hr.work.location";static id="id";id;location_type;name;} 5382HrWorkLocation.register();return __exports;});; 5383 5384/* /hr/static/src/core/common/res_partner_model_patch.js */ 5385odoo.define('@hr/core/common/res_partner_model_patch',['@mail/core/common/res_partner_model','@mail/model/misc','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ResPartner}=require("@mail/core/common/res_partner_model");const{fields}=require("@mail/model/misc");const{patch}=require("@web/core/utils/patch");patch(ResPartner.prototype,{employeeId:undefined,setup(){super.setup();this.employee_ids=fields.Many("hr.employee",{inverse:"work_contact_id",});this.employee_id=fields.One("hr.employee",{compute(){return this.store.getRelevantEmployee(this.employee_ids);},});},});return __exports;});; 5386 5387/* /hr/static/src/core/common/res_users_model_patch.js */ 5388odoo.define('@hr/core/common/res_users_model_patch',['@web/core/utils/patch','@mail/model/misc','@mail/core/common/res_users_model','@web/core/user'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{fields}=require("@mail/model/misc");const{ResUsers}=require("@mail/core/common/res_users_model");const{user}=require("@web/core/user");patch(ResUsers.prototype,{setup(){super.setup();this.employee_ids=fields.Many("hr.employee",{inverse:"user_id",});this.employee_id=fields.One("hr.employee",{compute(){return this.employee_ids.find((employee)=>employee.company_id?.id===user.activeCompany.id);},});},});return __exports;});; 5389 5390/* /ai/static/src/discuss/core/common/chat_window_model_patch.js */ 5391odoo.define('@ai/discuss/core/common/chat_window_model_patch',['@web/core/network/rpc','@web/core/utils/patch','@mail/core/common/chat_window_model'],function(require){'use strict';let __exports={};const{rpc}=require("@web/core/network/rpc");const{patch}=require("@web/core/utils/patch");const{ChatWindow}=require("@mail/core/common/chat_window_model");patch(ChatWindow.prototype,{computeCanShow(){if(this.store.aiInsertButtonTarget&&this.store.discuss.isActive){return this.thread?.channel_type==="ai_chat";} 5392return super.computeCanShow();},async _onClose(){const thread=this.thread;if(thread?.ai_agent_id){await rpc("/ai/close_ai_chat",{channel_id:thread.id});} 5393await super._onClose(...arguments);},});return __exports;});; 5394 5395/* /ai/static/src/discuss/core/common/thread_model_patch.js */ 5396odoo.define('@ai/discuss/core/common/thread_model_patch',['@mail/core/common/thread_model','@web/core/utils/patch','@web/core/network/rpc','@ai/discuss/core/common/view_details','@web/session'],function(require){'use strict';let __exports={};const{Thread}=require("@mail/core/common/thread_model");const{patch}=require("@web/core/utils/patch");const{rpc}=require("@web/core/network/rpc");const{getCurrentViewInfo}=require("@ai/discuss/core/common/view_details");const{session}=require("@web/session");patch(Thread.prototype,{async post(body,postData={},extraData={}){const message=await super.post(body,postData,extraData);const aiMember=this.channel_member_ids?.find((member)=>member.partner_id?.im_status=="agent");if(message?.thread?.ai_agent_id){try{if(aiMember){aiMember.isTyping=true;} 5397await rpc("/ai/generate_response",{mail_message_id:message.id,channel_id:this.id,current_view_info:await getCurrentViewInfo(this.store.env.bus),ai_session_identifier:session.ai_session_identifier,});}finally{if(aiMember){aiMember.isTyping=false;}}} 5398return message;},});return __exports;});; 5399 5400/* /ai/static/src/discuss/core/common/view_details.js */ 5401odoo.define('@ai/discuss/core/common/view_details',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{useComponent}=require("@odoo/owl");const{useBus}=require("@web/core/utils/hooks");__exports.getCurrentViewInfo=getCurrentViewInfo;async function getCurrentViewInfo(bus){return new Promise((resolve)=>{const listener=({detail})=>{bus.removeEventListener("SEND_VIEW_DETAILS!",listener);clearTimeout(timeout);resolve(detail);};const timeout=setTimeout(()=>{bus.removeEventListener("SEND_VIEW_DETAILS!",listener);resolve(null);},100);bus.addEventListener("SEND_VIEW_DETAILS!",listener);bus.trigger("REQUEST_VIEW_DETAILS?");});} 5402__exports.useViewDetailsGetter=useViewDetailsGetter;function useViewDetailsGetter(getter){const component=useComponent();const bus=component.env.bus;if(!bus){throw new Error("Bus is not available in the current environment.");} 5403useBus(bus,"REQUEST_VIEW_DETAILS?",async()=>{bus.trigger("SEND_VIEW_DETAILS!",await getter());});} 5404return __exports;});; 5405 5406/* /web/static/lib/dompurify/DOMpurify.js */ 5407(function(global,factory){typeof exports==='object'&&typeof module!=='undefined'?module.exports=factory():typeof define==='function'&&define.amd?define(factory):(global=typeof globalThis!=='undefined'?globalThis:global||self,global.DOMPurify=factory());})(this,(function(){'use strict';const{entries,setPrototypeOf,isFrozen,getPrototypeOf,getOwnPropertyDescriptor}=Object;let{freeze,seal,create}=Object;let{apply,construct}=typeof Reflect!=='undefined'&&Reflect;if(!freeze){freeze=function freeze(x){return x;};} 5408if(!seal){seal=function seal(x){return x;};} 5409if(!apply){apply=function apply(fun,thisValue,args){return fun.apply(thisValue,args);};} 5410if(!construct){construct=function construct(Func,args){return new Func(...args);};} 5411const arrayForEach=unapply(Array.prototype.forEach);const arrayPop=unapply(Array.prototype.pop);const arrayPush=unapply(Array.prototype.push);const stringToLowerCase=unapply(String.prototype.toLowerCase);
vendor: 4,730 bytes, lines 5411-5429
5411const stringToString=unapply(String.prototype.toString);const stringMatch=unapply(String.prototype.match);const stringReplace=unapply(String.prototype.replace);const stringIndexOf=unapply(String.prototype.indexOf);const stringTrim=unapply(String.prototype.trim);const objectHasOwnProperty=unapply(Object.prototype.hasOwnProperty);const regExpTest=unapply(RegExp.prototype.test);const typeErrorCreate=unconstruct(TypeError);function unapply(func){return function(thisArg){for(var _len=arguments.length,args=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++){args[_key-1]=arguments[_key];} 5412return apply(func,thisArg,args);};} 5413function unconstruct(func){return function(){for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++){args[_key2]=arguments[_key2];} 5414return construct(func,args);};} 5415function addToSet(set,array){let transformCaseFunc=arguments.length>2&&arguments[2]!==undefined?arguments[2]:stringToLowerCase;if(setPrototypeOf){setPrototypeOf(set,null);} 5416let l=array.length;while(l--){let element=array[l];if(typeof element==='string'){const lcElement=transformCaseFunc(element);if(lcElement!==element){if(!isFrozen(array)){array[l]=lcElement;} 5417element=lcElement;}} 5418set[element]=true;} 5419return set;} 5420function cleanArray(array){for(let index=0;index<array.length;index++){const isPropertyExist=objectHasOwnProperty(array,index);if(!isPropertyExist){array[index]=null;}} 5421return array;} 5422function clone(object){const newObject=create(null);for(const[property,value]of entries(object)){const isPropertyExist=objectHasOwnProperty(object,property);if(isPropertyExist){if(Array.isArray(value)){newObject[property]=cleanArray(value);}else if(value&&typeof value==='object'&&value.constructor===Object){newObject[property]=clone(value);}else{newObject[property]=value;}}} 5423return newObject;} 5424function lookupGetter(object,prop){while(object!==null){const desc=getOwnPropertyDescriptor(object,prop);if(desc){if(desc.get){return unapply(desc.get);} 5425if(typeof desc.value==='function'){return unapply(desc.value);}} 5426object=getPrototypeOf(object);} 5427function fallbackValue(){return null;} 5428return fallbackValue;} 5429const html$1=freeze(['a','abbr','acronym','address','area','article','aside','audio','b','bdi','bdo','big','blink','blockquote','body','br','button','canvas','caption','center','cite','code','col','colgroup','content','data','datalist','dd','decorator','del','details','dfn','dialog','dir','div','dl','dt','element','em','fieldset','figcaption','figure','font','footer','form','h1','h2','h3','h4','h5','h6','head','header','hgroup','hr','html','i','img','input','ins','kbd','label','legend','li','main','map','mark','marquee','menu','menuitem','meter','nav','nobr','ol','optgroup','option','output','p','picture','pre','progress','q','rp','rt','ruby','s','samp','section','select','shadow','small','source','spacer','span','strike','strong','style','sub','summary','sup','table','tbody','td','template','textarea','tfoot','th','thead','time','tr','track','tt','u','ul','var','video','wbr']);const svg$1=freeze(['svg','a','altglyph','altglyphdef','altglyphitem','animatecolor','animatemotion','animatetransform','circle','clippath','defs','desc','ellipse','filter','font','g','glyph','glyphref','hkern','image','line','lineargradient','marker','mask','metadata','mpath','path','pattern','polygon','polyline','radialgradient','rect','stop','style','switch','symbol','text','textpath','title','tref','tspan','view','vkern']);const svgFilters=freeze(['feBlend','feColorMatrix','feComponentTransfer','feComposite','feConvolveMatrix','feDiffuseLighting','feDisplacementMap','feDistantLight','feDropShadow','feFlood','feFuncA','feFuncB','feFuncG','feFuncR','feGaussianBlur','feImage','feMerge','feMergeNode','feMorphology','feOffset','fePointLight','feSpecularLighting','feSpotLight','feTile','feTurbulence']);const svgDisallowed=freeze(['animate','color-profile','cursor','discard','font-face','font-face-format','font-face-name','font-face-src','font-face-uri','foreignobject','hatch','hatchpath','mesh','meshgradient','meshpatch','meshrow','missing-glyph','script','set','solidcolor','unknown','use']);const mathMl$1=freeze(['math','menclose','merror','mfenced','mfrac','mglyph','mi','mlabeledtr','mmultiscripts','mn','mo','mover','mpadded','mphantom','mroot','mrow','ms','mspace','msqrt','mstyle','msub','msup','msubsup','mtable','mtd','mtext','mtr','munder','munderover','mprescripts']);const mathMlDisallowed=freeze(['maction','maligngroup','malignmark','mlongdiv','mscarries','mscarry','msgroup','mstack','msline','msrow','semantics','annotation','annotation-xml','mprescripts','none']);const text=freeze(['#text']);const html=freeze(['accept','action','align','alt','autocapitalize','autocomplete','auto
5429pictureinpicture','autoplay','background','bgcolor','border','capture','cellpadding','cellspacing','checked','cite','class','clear','color','cols','colspan','controls','controlslist','coords','crossorigin','datetime','decoding','default','dir','disabled','disablepictureinpicture','disableremoteplayback','download','draggable','enctype','enterkeyhint','face','for','headers','height','hidden','high','href','hreflang','id','inputmode','integrity','ismap','kind','label','lang','list','loading','loop','low','max','maxlength','media','method','min','minlength','multiple','muted','name','nonce','noshade','novalidate','nowrap','open','optimum','pattern','placeholder','playsinline','popover','popovertarget','popovertargetaction','poster','preload','pubdate','radiogroup','readonly','rel','required','rev','reversed','role','rows','rowspan','spellcheck','scope','selected','shape','size','sizes','span','srclang','start','src','srcset','step','style','summary','tabindex','title','translate','type','usemap','valign','value','width','wrap','xmlns','slot']);const svg=freeze(['accent-height','accumulate','additive','alignment-baseline','amplitude','ascent','attributename','attributetype','azimuth','basefrequency','baseline-shift','begin','bias','by','class','clip','clippathunits','clip-path','clip-rule','color','color-interpolation','color-interpolation-filters','color-profile','color-rendering','cx','cy','d','dx','dy','diffuseconstant','direction','display','divisor','dur','edgemode','elevation','end','exponent','fill','fill-opacity','fill-rule','filter','filterunits','flood-color','flood-opacity','font-family','font-size','font-size-adjust','font-stretch','font-style','font-variant','font-weight','fx','fy','g1','g2','glyph-name','glyphref','gradientunits','gradienttransform','height','href','id','image-rendering','in','in2','intercept','k','k1','k2','k3','k4','kerning','keypoints','keysplines','keytimes','lang','lengthadjust','letter-spacing','kernelmatrix','kernelunitlength','lighting-color','local','marker-end','marker-mid','marker-start','markerheight','markerunits','markerwidth','maskcontentunits','maskunits','max','mask','media','method','mode','min','name','numoctaves','offset','operator','opacity','order','orient','orientation','origin','overflow','paint-order','path','pathlength','patterncontentunits','patterntransform','patternunits','points','preservealpha','preserveaspectratio','primitiveunits','r','rx','ry','radius','refx','refy','repeatcount','repeatdur','restart','result','rotate','scale','seed','shape-rendering','slope','specularconstant','specularexponent','spreadmethod','startoffset','stddeviation','stitchtiles','stop-color','stop-opacity','stroke-dasharray','stroke-dashoffset','stroke-linecap','stroke-linejoin','stroke-miterlimit','stroke-opacity','stroke','stroke-width','style','surfacescale','systemlanguage','tabindex','tablevalues','targetx','targety','transform','transform-origin','text-anchor','text-decoration','text-rendering','textlength','type','u1','u2','unicode','values','viewbox','visibility','version','vert-adv-y','vert-origin-x','vert-origin-y','width','word-spacing','wrap','writing-mode','xchannelselector','ychannelselector','x','x1','x2','xmlns','y','y1','y2','z','zoomandpan']);const mathMl=freeze(['accent','accentunder','align','bevelled','close','columnsalign','columnlines','columnspan','denomalign','depth','dir','display','displaystyle','encoding','fence','frame','height','href','id','largeop','length','linethickness','lspace','lquote','mathbackground','mathcolor','mathsize','mathvariant','maxsize','minsize','movablelimits','notation','numalign','open','rowalign','rowlines','rowspacing','rowspan','rspace','rquote','scriptlevel','scriptminsize','scriptsizemultiplier','selection','separator','separators','stretchy','subscriptshift','supscriptshift','symmetric','voffset','width','xmlns']);const xml=freeze(['xlink:href','xml:id','xlink:title','xml:space','xmlns:xlink']);const MUSTACHE_EXPR=seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);const ERB_EXPR=seal(/<%[\w\W]*|[\w\W]*%>/gm);const TMPLIT_EXPR=seal(/\${[\w\W]*}/gm);const DATA_ATTR=seal(/^data-[\-\w.\u00B7-\uFFFF]/);const ARIA_ATTR=seal(/^aria-[\-\w]+$/);
vendor: 25,440 bytes, lines 5429-5529
5429const IS_ALLOWED_URI=seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);const IS_SCRIPT_OR_DATA=seal(/^(?:\w+script|data):/i);const ATTR_WHITESPACE=seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);const DOCTYPE_NAME=seal(/^html$/i);const CUSTOM_ELEMENT=seal(/^[a-z][.\w]*(-[.\w]+)+$/i);var EXPRESSIONS=Object.freeze({__proto__:null,MUSTACHE_EXPR:MUSTACHE_EXPR,ERB_EXPR:ERB_EXPR,TMPLIT_EXPR:TMPLIT_EXPR,DATA_ATTR:DATA_ATTR,ARIA_ATTR:ARIA_ATTR,IS_ALLOWED_URI:IS_ALLOWED_URI,IS_SCRIPT_OR_DATA:IS_SCRIPT_OR_DATA,ATTR_WHITESPACE:ATTR_WHITESPACE,DOCTYPE_NAME:DOCTYPE_NAME,CUSTOM_ELEMENT:CUSTOM_ELEMENT});const NODE_TYPE={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12};const getGlobal=function getGlobal(){return typeof window==='undefined'?null:window;};const _createTrustedTypesPolicy=function _createTrustedTypesPolicy(trustedTypes,purifyHostElement){if(typeof trustedTypes!=='object'||typeof trustedTypes.createPolicy!=='function'){return null;} 5430let suffix=null;const ATTR_NAME='data-tt-policy-suffix';if(purifyHostElement&&purifyHostElement.hasAttribute(ATTR_NAME)){suffix=purifyHostElement.getAttribute(ATTR_NAME);} 5431const policyName='dompurify'+(suffix?'#'+suffix:'');try{return trustedTypes.createPolicy(policyName,{createHTML(html){return html;},createScriptURL(scriptUrl){return scriptUrl;}});}catch(_){console.warn('TrustedTypes policy '+policyName+' could not be created.');return null;}};function createDOMPurify(){let window=arguments.length>0&&arguments[0]!==undefined?arguments[0]:getGlobal();const DOMPurify=root=>createDOMPurify(root);DOMPurify.version='3.1.7';DOMPurify.removed=[];if(!window||!window.document||window.document.nodeType!==NODE_TYPE.document){DOMPurify.isSupported=false;return DOMPurify;} 5432let{document}=window;const originalDocument=document;const currentScript=originalDocument.currentScript;const{DocumentFragment,HTMLTemplateElement,Node,Element,NodeFilter,NamedNodeMap=window.NamedNodeMap||window.MozNamedAttrMap,HTMLFormElement,DOMParser,trustedTypes}=window;const ElementPrototype=Element.prototype;const cloneNode=lookupGetter(ElementPrototype,'cloneNode');const remove=lookupGetter(ElementPrototype,'remove');const getNextSibling=lookupGetter(ElementPrototype,'nextSibling');const getChildNodes=lookupGetter(ElementPrototype,'childNodes');const getParentNode=lookupGetter(ElementPrototype,'parentNode');if(typeof HTMLTemplateElement==='function'){const template=document.createElement('template');if(template.content&&template.content.ownerDocument){document=template.content.ownerDocument;}} 5433let trustedTypesPolicy;let emptyHTML='';const{implementation,createNodeIterator,createDocumentFragment,getElementsByTagName}=document;const{importNode}=originalDocument;let hooks={};DOMPurify.isSupported=typeof entries==='function'&&typeof getParentNode==='function'&&implementation&&implementation.createHTMLDocument!==undefined;const{MUSTACHE_EXPR,ERB_EXPR,TMPLIT_EXPR,DATA_ATTR,ARIA_ATTR,IS_SCRIPT_OR_DATA,ATTR_WHITESPACE,CUSTOM_ELEMENT}=EXPRESSIONS;let{IS_ALLOWED_URI:IS_ALLOWED_URI$1}=EXPRESSIONS;let ALLOWED_TAGS=null;const DEFAULT_ALLOWED_TAGS=addToSet({},[...html$1,...svg$1,...svgFilters,...mathMl$1,...text]);let ALLOWED_ATTR=null;const DEFAULT_ALLOWED_ATTR=addToSet({},[...html,...svg,...mathMl,...xml]);let CUSTOM_ELEMENT_HANDLING=Object.seal(create(null,{tagNameCheck:{writable:true,configurable:false,enumerable:true,value:null},attributeNameCheck:{writable:true,configurable:false,enumerable:true,value:null},allowCustomizedBuiltInElements:{writable:true,configurable:false,enumerable:true,value:false}}));let FORBID_TAGS=null;let FORBID_ATTR=null;let ALLOW_ARIA_ATTR=true;let ALLOW_DATA_ATTR=true;let ALLOW_UNKNOWN_PROTOCOLS=false;let ALLOW_SELF_CLOSE_IN_ATTR=true;let SAFE_FOR_TEMPLATES=false;let SAFE_FOR_XML=true;let WHOLE_DOCUMENT=false;let SET_CONFIG=false;let FORCE_BODY=false;let RETURN_DOM=false;let RETURN_DOM_FRAGMENT=false;let RETURN_TRUSTED_TYPE=false;let SANITIZE_DOM=true;let SANITIZE_NAMED_PROPS=false;const SANITIZE_NAMED_PROPS_PREFIX='user-content-';let KEEP_CONTENT=true;let IN_PLACE=false;let USE_PROFILES={};let FORBID_CONTENTS=null;const DEFAULT_FORBID_CONTENTS=addToSet({},['annotation-xml','audio','colgroup','desc','foreignobject','head','iframe','math','mi','mn','mo','ms','mtext','noembed','noframes','noscript','plaintext','script','style','svg','template','thead','title','video','xmp']);let DATA_URI_TAGS=null;const DEFAULT_DATA_URI_TAGS=addToSet({},['audio','video','img','source','image','track']);let URI_SAFE_ATTRIBUTES=null;const DEFAULT_URI_SAFE_ATTRIBUTES=addToSet({},['alt','class','for','id','label','name','pattern','placeholder','role','summary','title','value','style','xmlns']);const MATHML_NAMESPACE='http://www.w3.org/1998/Math/MathML';const SVG_NAMESPACE='http://www.w3.org/2000/svg';const HTML_NAMESPACE='http://www.w3.org/1999/xhtml';let NAMESPACE=HTML_NAMESPACE;let IS_EMPTY_INPUT=false;let ALLOWED_NAMESPACES=null;const DEFAULT_ALLOWED_NAMESPACES=addToSet({},[MATHML_NAMESPACE,SVG_NAMESPACE,HTML_NAMESPACE],stringToString);let PARSER_MEDIA_TYPE=null;const SUPPORTED_PARSER_MEDIA_TYPES=['application/xhtml+xml','text/html'];const DEFAULT_PARSER_MEDIA_TYPE='text/html';let transformCaseFunc=null;let CONFIG=null;const formElement=document.createElement('form');const isRegexOrFunction=function isRegexOrFunction(testValue){return testValue instanceof RegExp||testValue instanceof Function;};const _parseConfig=function _parseConfig(){let cfg=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};if(CONFIG&&CONFIG===cfg){return;} 5434if(!cfg||typeof cfg!=='object'){cfg={};} 5435cfg=clone(cfg);PARSER_MEDIA_TYPE=SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE)===-1?DEFAULT_PARSER_MEDIA_TYPE:cfg.PARSER_MEDIA_TYPE;transformCaseFunc=PARSER_MEDIA_TYPE==='application/xhtml+xml'?stringToString:stringToLowerCase;ALLOWED_TAGS=objectHasOwnProperty(cfg,'ALLOWED_TAGS')?addToSet({},cfg.ALLOWED_TAGS,transformCaseFunc):DEFAULT_ALLOWED_TAGS;ALLOWED_ATTR=objectHasOwnProperty(cfg,'ALLOWED_ATTR')?addToSet({},cfg.ALLOWED_ATTR,transformCaseFunc):DEFAULT_ALLOWED_ATTR;ALLOWED_NAMESPACES=objectHasOwnProperty(cfg,'ALLOWED_NAMESPACES')?addToSet({},cfg.ALLOWED_NAMESPACES,stringToString):DEFAULT_ALLOWED_NAMESPACES;URI_SAFE_ATTRIBUTES=objectHasOwnProperty(cfg,'ADD_URI_SAFE_ATTR')?addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),cfg.ADD_URI_SAFE_ATTR,transformCaseFunc):DEFAULT_URI_SAFE_ATTRIBUTES;DATA_URI_TAGS=objectHasOwnProperty(cfg,'ADD_DATA_URI_TAGS')?addToSet(clone(DEFAULT_DATA_URI_TAGS),cfg.ADD_DATA_URI_TAGS,transformCaseFunc):DEFAULT_DATA_URI_TAGS;FORBID_CONTENTS=objectHasOwnProperty(cfg,'FORBID_CONTENTS')?addToSet({},cfg.FORBID_CONTENTS,transformCaseFunc):DEFAULT_FORBID_CONTENTS;FORBID_TAGS=objectHasOwnProperty(cfg,'FORBID_TAGS')?addToSet({},cfg.FORBID_TAGS,transformCaseFunc):{};FORBID_ATTR=objectHasOwnProperty(cfg,'FORBID_ATTR')?addToSet({},cfg.FORBID_ATTR,transformCaseFunc):{};USE_PROFILES=objectHasOwnProperty(cfg,'USE_PROFILES')?cfg.USE_PROFILES:false;ALLOW_ARIA_ATTR=cfg.ALLOW_ARIA_ATTR!==false;ALLOW_DATA_ATTR=cfg.ALLOW_DATA_ATTR!==false;ALLOW_UNKNOWN_PROTOCOLS=cfg.ALLOW_UNKNOWN_PROTOCOLS||false;ALLOW_SELF_CLOSE_IN_ATTR=cfg.ALLOW_SELF_CLOSE_IN_ATTR!==false;SAFE_FOR_TEMPLATES=cfg.SAFE_FOR_TEMPLATES||false;SAFE_FOR_XML=cfg.SAFE_FOR_XML!==false;WHOLE_DOCUMENT=cfg.WHOLE_DOCUMENT||false;RETURN_DOM=cfg.RETURN_DOM||false;RETURN_DOM_FRAGMENT=cfg.RETURN_DOM_FRAGMENT||false;RETURN_TRUSTED_TYPE=cfg.RETURN_TRUSTED_TYPE||false;FORCE_BODY=cfg.FORCE_BODY||false;SANITIZE_DOM=cfg.SANITIZE_DOM!==false;SANITIZE_NAMED_PROPS=cfg.SANITIZE_NAMED_PROPS||false;KEEP_CONTENT=cfg.KEEP_CONTENT!==false;IN_PLACE=cfg.IN_PLACE||false;IS_ALLOWED_URI$1=cfg.ALLOWED_URI_REGEXP||IS_ALLOWED_URI;NAMESPACE=cfg.NAMESPACE||HTML_NAMESPACE;CUSTOM_ELEMENT_HANDLING=cfg.CUSTOM_ELEMENT_HANDLING||{};if(cfg.CUSTOM_ELEMENT_HANDLING&&isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)){CUSTOM_ELEMENT_HANDLING.tagNameCheck=cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;} 5436if(cfg.CUSTOM_ELEMENT_HANDLING&&isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)){CUSTOM_ELEMENT_HANDLING.attributeNameCheck=cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;} 5437if(cfg.CUSTOM_ELEMENT_HANDLING&&typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements==='boolean'){CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;} 5438if(SAFE_FOR_TEMPLATES){ALLOW_DATA_ATTR=false;} 5439if(RETURN_DOM_FRAGMENT){RETURN_DOM=true;} 5440if(USE_PROFILES){ALLOWED_TAGS=addToSet({},text);ALLOWED_ATTR=[];if(USE_PROFILES.html===true){addToSet(ALLOWED_TAGS,html$1);addToSet(ALLOWED_ATTR,html);} 5441if(USE_PROFILES.svg===true){addToSet(ALLOWED_TAGS,svg$1);addToSet(ALLOWED_ATTR,svg);addToSet(ALLOWED_ATTR,xml);} 5442if(USE_PROFILES.svgFilters===true){addToSet(ALLOWED_TAGS,svgFilters);addToSet(ALLOWED_ATTR,svg);addToSet(ALLOWED_ATTR,xml);} 5443if(USE_PROFILES.mathMl===true){addToSet(ALLOWED_TAGS,mathMl$1);addToSet(ALLOWED_ATTR,mathMl);addToSet(ALLOWED_ATTR,xml);}} 5444if(cfg.ADD_TAGS){if(ALLOWED_TAGS===DEFAULT_ALLOWED_TAGS){ALLOWED_TAGS=clone(ALLOWED_TAGS);} 5445addToSet(ALLOWED_TAGS,cfg.ADD_TAGS,transformCaseFunc);} 5446if(cfg.ADD_ATTR){if(ALLOWED_ATTR===DEFAULT_ALLOWED_ATTR){ALLOWED_ATTR=clone(ALLOWED_ATTR);} 5447addToSet(ALLOWED_ATTR,cfg.ADD_ATTR,transformCaseFunc);} 5448if(cfg.ADD_URI_SAFE_ATTR){addToSet(URI_SAFE_ATTRIBUTES,cfg.ADD_URI_SAFE_ATTR,transformCaseFunc);} 5449if(cfg.FORBID_CONTENTS){if(FORBID_CONTENTS===DEFAULT_FORBID_CONTENTS){FORBID_CONTENTS=clone(FORBID_CONTENTS);} 5450addToSet(FORBID_CONTENTS,cfg.FORBID_CONTENTS,transformCaseFunc);} 5451if(KEEP_CONTENT){ALLOWED_TAGS['#text']=true;} 5452if(WHOLE_DOCUMENT){addToSet(ALLOWED_TAGS,['html','head','body']);} 5453if(ALLOWED_TAGS.table){addToSet(ALLOWED_TAGS,['tbody']);delete FORBID_TAGS.tbody;} 5454if(cfg.TRUSTED_TYPES_POLICY){if(typeof cfg.TRUSTED_TYPES_POLICY.createHTML!=='function'){throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');} 5455if(typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL!=='function'){throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');} 5456trustedTypesPolicy=cfg.TRUSTED_TYPES_POLICY;emptyHTML=trustedTypesPolicy.createHTML('');}else{if(trustedTypesPolicy===undefined){trustedTypesPolicy=_createTrustedTypesPolicy(trustedTypes,currentScript);} 5457if(trustedTypesPolicy!==null&&typeof emptyHTML==='string'){emptyHTML=trustedTypesPolicy.createHTML('');}} 5458if(freeze){freeze(cfg);} 5459CONFIG=cfg;};const MATHML_TEXT_INTEGRATION_POINTS=addToSet({},['mi','mo','mn','ms','mtext']);const HTML_INTEGRATION_POINTS=addToSet({},['annotation-xml']);const COMMON_SVG_AND_HTML_ELEMENTS=addToSet({},['title','style','font','a','script']);const ALL_SVG_TAGS=addToSet({},[...svg$1,...svgFilters,...svgDisallowed]);const ALL_MATHML_TAGS=addToSet({},[...mathMl$1,...mathMlDisallowed]);const _checkValidNamespace=function _checkValidNamespace(element){let parent=getParentNode(element);if(!parent||!parent.tagName){parent={namespaceURI:NAMESPACE,tagName:'template'};} 5460const tagName=stringToLowerCase(element.tagName);const parentTagName=stringToLowerCase(parent.tagName);if(!ALLOWED_NAMESPACES[element.namespaceURI]){return false;} 5461if(element.namespaceURI===SVG_NAMESPACE){if(parent.namespaceURI===HTML_NAMESPACE){return tagName==='svg';} 5462if(parent.namespaceURI===MATHML_NAMESPACE){return tagName==='svg'&&(parentTagName==='annotation-xml'||MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);} 5463return Boolean(ALL_SVG_TAGS[tagName]);} 5464if(element.namespaceURI===MATHML_NAMESPACE){if(parent.namespaceURI===HTML_NAMESPACE){return tagName==='math';} 5465if(parent.namespaceURI===SVG_NAMESPACE){return tagName==='math'&&HTML_INTEGRATION_POINTS[parentTagName];} 5466return Boolean(ALL_MATHML_TAGS[tagName]);} 5467if(element.namespaceURI===HTML_NAMESPACE){if(parent.namespaceURI===SVG_NAMESPACE&&!HTML_INTEGRATION_POINTS[parentTagName]){return false;} 5468if(parent.namespaceURI===MATHML_NAMESPACE&&!MATHML_TEXT_INTEGRATION_POINTS[parentTagName]){return false;} 5469return!ALL_MATHML_TAGS[tagName]&&(COMMON_SVG_AND_HTML_ELEMENTS[tagName]||!ALL_SVG_TAGS[tagName]);} 5470if(PARSER_MEDIA_TYPE==='application/xhtml+xml'&&ALLOWED_NAMESPACES[element.namespaceURI]){return true;} 5471return false;};const _forceRemove=function _forceRemove(node){arrayPush(DOMPurify.removed,{element:node});try{getParentNode(node).removeChild(node);}catch(_){remove(node);}};const _removeAttribute=function _removeAttribute(name,node){try{arrayPush(DOMPurify.removed,{attribute:node.getAttributeNode(name),from:node});}catch(_){arrayPush(DOMPurify.removed,{attribute:null,from:node});} 5472node.removeAttribute(name);if(name==='is'&&!ALLOWED_ATTR[name]){if(RETURN_DOM||RETURN_DOM_FRAGMENT){try{_forceRemove(node);}catch(_){}}else{try{node.setAttribute(name,'');}catch(_){}}}};const _initDocument=function _initDocument(dirty){let doc=null;let leadingWhitespace=null;if(FORCE_BODY){dirty='<remove></remove>'+dirty;}else{const matches=stringMatch(dirty,/^[\r\n\t ]+/);leadingWhitespace=matches&&matches[0];} 5473if(PARSER_MEDIA_TYPE==='application/xhtml+xml'&&NAMESPACE===HTML_NAMESPACE){dirty='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+dirty+'</body></html>';} 5474const dirtyPayload=trustedTypesPolicy?trustedTypesPolicy.createHTML(dirty):dirty;if(NAMESPACE===HTML_NAMESPACE){try{doc=new DOMParser().parseFromString(dirtyPayload,PARSER_MEDIA_TYPE);}catch(_){}} 5475if(!doc||!doc.documentElement){doc=implementation.createDocument(NAMESPACE,'template',null);try{doc.documentElement.innerHTML=IS_EMPTY_INPUT?emptyHTML:dirtyPayload;}catch(_){}} 5476const body=doc.body||doc.documentElement;if(dirty&&leadingWhitespace){body.insertBefore(document.createTextNode(leadingWhitespace),body.childNodes[0]||null);} 5477if(NAMESPACE===HTML_NAMESPACE){return getElementsByTagName.call(doc,WHOLE_DOCUMENT?'html':'body')[0];} 5478return WHOLE_DOCUMENT?doc.documentElement:body;};const _createNodeIterator=function _createNodeIterator(root){return createNodeIterator.call(root.ownerDocument||root,root,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_TEXT|NodeFilter.SHOW_PROCESSING_INSTRUCTION|NodeFilter.SHOW_CDATA_SECTION,null);};const _isClobbered=function _isClobbered(elm){return elm instanceof HTMLFormElement&&(typeof elm.nodeName!=='string'||typeof elm.textContent!=='string'||typeof elm.removeChild!=='function'||!(elm.attributes instanceof NamedNodeMap)||typeof elm.removeAttribute!=='function'||typeof elm.setAttribute!=='function'||typeof elm.namespaceURI!=='string'||typeof elm.insertBefore!=='function'||typeof elm.hasChildNodes!=='function');};const _isNode=function _isNode(object){return typeof Node==='function'&&object instanceof Node;};const _executeHook=function _executeHook(entryPoint,currentNode,data){if(!hooks[entryPoint]){return;} 5479arrayForEach(hooks[entryPoint],hook=>{hook.call(DOMPurify,currentNode,data,CONFIG);});};const _sanitizeElements=function _sanitizeElements(currentNode){let content=null;_executeHook('beforeSanitizeElements',currentNode,null);if(_isClobbered(currentNode)){_forceRemove(currentNode);return true;} 5480const tagName=transformCaseFunc(currentNode.nodeName);_executeHook('uponSanitizeElement',currentNode,{tagName,allowedTags:ALLOWED_TAGS});if(currentNode.hasChildNodes()&&!_isNode(currentNode.firstElementChild)&®ExpTest(/<[/\w]/g,currentNode.innerHTML)&®ExpTest(/<[/\w]/g,currentNode.textContent)){_forceRemove(currentNode);return true;} 5481if(currentNode.nodeType===NODE_TYPE.progressingInstruction){_forceRemove(currentNode);return true;} 5482if(SAFE_FOR_XML&¤tNode.nodeType===NODE_TYPE.comment&®ExpTest(/<[/\w]/g,currentNode.data)){_forceRemove(currentNode);return true;} 5483if(!ALLOWED_TAGS[tagName]||FORBID_TAGS[tagName]){if(!FORBID_TAGS[tagName]&&_isBasicCustomElement(tagName)){if(CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp&®ExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck,tagName)){return false;} 5484if(CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function&&CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)){return false;}} 5485if(KEEP_CONTENT&&!FORBID_CONTENTS[tagName]){const parentNode=getParentNode(currentNode)||currentNode.parentNode;const childNodes=getChildNodes(currentNode)||currentNode.childNodes;if(childNodes&&parentNode){const childCount=childNodes.length;for(let i=childCount-1;i>=0;--i){const childClone=cloneNode(childNodes[i],true);childClone.__removalCount=(currentNode.__removalCount||0)+1;parentNode.insertBefore(childClone,getNextSibling(currentNode));}}} 5486_forceRemove(currentNode);return true;} 5487if(currentNode instanceof Element&&!_checkValidNamespace(currentNode)){_forceRemove(currentNode);return true;} 5488if((tagName==='noscript'||tagName==='noembed'||tagName==='noframes')&®ExpTest(/<\/no(script|embed|frames)/i,currentNode.innerHTML)){_forceRemove(currentNode);return true;} 5489if(SAFE_FOR_TEMPLATES&¤tNode.nodeType===NODE_TYPE.text){content=currentNode.textContent;arrayForEach([MUSTACHE_EXPR,ERB_EXPR,TMPLIT_EXPR],expr=>{content=stringReplace(content,expr,' ');});if(currentNode.textContent!==content){arrayPush(DOMPurify.removed,{element:currentNode.cloneNode()});currentNode.textContent=content;}} 5490_executeHook('afterSanitizeElements',currentNode,null);return false;};const _isValidAttribute=function _isValidAttribute(lcTag,lcName,value){if(SANITIZE_DOM&&(lcName==='id'||lcName==='name')&&(value in document||value in formElement)){return false;} 5491if(ALLOW_DATA_ATTR&&!FORBID_ATTR[lcName]&®ExpTest(DATA_ATTR,lcName));else if(ALLOW_ARIA_ATTR&®ExpTest(ARIA_ATTR,lcName));else if(!ALLOWED_ATTR[lcName]||FORBID_ATTR[lcName]){if(_isBasicCustomElement(lcTag)&&(CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp&®ExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck,lcTag)||CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function&&CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag))&&(CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp&®ExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck,lcName)||CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function&&CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName))||lcName==='is'&&CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp&®ExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck,value)||CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function&&CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)));else{return false;}}else if(URI_SAFE_ATTRIBUTES[lcName]);else if(regExpTest(IS_ALLOWED_URI$1,stringReplace(value,ATTR_WHITESPACE,'')));else if((lcName==='src'||lcName==='xlink:href'||lcName==='href')&&lcTag!=='script'&&stringIndexOf(value,'data:')===0&&DATA_URI_TAGS[lcTag]);else if(ALLOW_UNKNOWN_PROTOCOLS&&!regExpTest(IS_SCRIPT_OR_DATA,stringReplace(value,ATTR_WHITESPACE,'')));else if(value){return false;}else;return true;};const _isBasicCustomElement=function _isBasicCustomElement(tagName){return tagName!=='annotation-xml'&&stringMatch(tagName,CUSTOM_ELEMENT);};const _sanitizeAttributes=function _sanitizeAttributes(currentNode){_executeHook('beforeSanitizeAttributes',currentNode,null);const{attributes}=currentNode;if(!attributes){return;} 5492const hookEvent={attrName:'',attrValue:'',keepAttr:true,allowedAttributes:ALLOWED_ATTR};let l=attributes.length;while(l--){const attr=attributes[l];const{name,namespaceURI,value:attrValue}=attr;const lcName=transformCaseFunc(name);let value=name==='value'?attrValue:stringTrim(attrValue);hookEvent.attrName=lcName;hookEvent.attrValue=value;hookEvent.keepAttr=true;hookEvent.forceKeepAttr=undefined;_executeHook('uponSanitizeAttribute',currentNode,hookEvent);value=hookEvent.attrValue;if(hookEvent.forceKeepAttr){continue;} 5493_removeAttribute(name,currentNode);if(!hookEvent.keepAttr){continue;} 5494if(!ALLOW_SELF_CLOSE_IN_ATTR&®ExpTest(/\/>/i,value)){_removeAttribute(name,currentNode);continue;} 5495if(SAFE_FOR_TEMPLATES){arrayForEach([MUSTACHE_EXPR,ERB_EXPR,TMPLIT_EXPR],expr=>{value=stringReplace(value,expr,' ');});} 5496const lcTag=transformCaseFunc(currentNode.nodeName);if(!_isValidAttribute(lcTag,lcName,value)){continue;} 5497if(SANITIZE_NAMED_PROPS&&(lcName==='id'||lcName==='name')){_removeAttribute(name,currentNode);value=SANITIZE_NAMED_PROPS_PREFIX+value;} 5498if(SAFE_FOR_XML&®ExpTest(/((--!?|])>)|<\/(style|title)/i,value)){_removeAttribute(name,currentNode);continue;} 5499if(trustedTypesPolicy&&typeof trustedTypes==='object'&&typeof trustedTypes.getAttributeType==='function'){if(namespaceURI);else{switch(trustedTypes.getAttributeType(lcTag,lcName)){case'TrustedHTML':{value=trustedTypesPolicy.createHTML(value);break;} 5500case'TrustedScriptURL':{value=trustedTypesPolicy.createScriptURL(value);break;}}}} 5501try{if(namespaceURI){currentNode.setAttributeNS(namespaceURI,name,value);}else{currentNode.setAttribute(name,value);} 5502if(_isClobbered(currentNode)){_forceRemove(currentNode);}else{arrayPop(DOMPurify.removed);}}catch(_){}} 5503_executeHook('afterSanitizeAttributes',currentNode,null);};const _sanitizeShadowDOM=function _sanitizeShadowDOM(fragment){let shadowNode=null;const shadowIterator=_createNodeIterator(fragment);_executeHook('beforeSanitizeShadowDOM',fragment,null);while(shadowNode=shadowIterator.nextNode()){_executeHook('uponSanitizeShadowNode',shadowNode,null);if(_sanitizeElements(shadowNode)){continue;} 5504if(shadowNode.content instanceof DocumentFragment){_sanitizeShadowDOM(shadowNode.content);} 5505_sanitizeAttributes(shadowNode);} 5506_executeHook('afterSanitizeShadowDOM',fragment,null);};DOMPurify.sanitize=function(dirty){let cfg=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};let body=null;let importedNode=null;let currentNode=null;let returnNode=null;IS_EMPTY_INPUT=!dirty;if(IS_EMPTY_INPUT){dirty='<!-->';} 5507if(typeof dirty!=='string'&&!_isNode(dirty)){if(typeof dirty.toString==='function'){dirty=dirty.toString();if(typeof dirty!=='string'){throw typeErrorCreate('dirty is not a string, aborting');}}else{throw typeErrorCreate('toString is not a function');}} 5508if(!DOMPurify.isSupported){return dirty;} 5509if(!SET_CONFIG){_parseConfig(cfg);} 5510DOMPurify.removed=[];if(typeof dirty==='string'){IN_PLACE=false;} 5511if(IN_PLACE){if(dirty.nodeName){const tagName=transformCaseFunc(dirty.nodeName);if(!ALLOWED_TAGS[tagName]||FORBID_TAGS[tagName]){throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');}}}else if(dirty instanceof Node){body=_initDocument('<!---->');importedNode=body.ownerDocument.importNode(dirty,true);if(importedNode.nodeType===NODE_TYPE.element&&importedNode.nodeName==='BODY'){body=importedNode;}else if(importedNode.nodeName==='HTML'){body=importedNode;}else{body.appendChild(importedNode);}}else{if(!RETURN_DOM&&!SAFE_FOR_TEMPLATES&&!WHOLE_DOCUMENT&&dirty.indexOf('<')===-1){return trustedTypesPolicy&&RETURN_TRUSTED_TYPE?trustedTypesPolicy.createHTML(dirty):dirty;} 5512body=_initDocument(dirty);if(!body){return RETURN_DOM?null:RETURN_TRUSTED_TYPE?emptyHTML:'';}} 5513if(body&&FORCE_BODY){_forceRemove(body.firstChild);} 5514const nodeIterator=_createNodeIterator(IN_PLACE?dirty:body);while(currentNode=nodeIterator.nextNode()){if(_sanitizeElements(currentNode)){continue;} 5515if(currentNode.content instanceof DocumentFragment){_sanitizeShadowDOM(currentNode.content);} 5516_sanitizeAttributes(currentNode);} 5517if(IN_PLACE){return dirty;} 5518if(RETURN_DOM){if(RETURN_DOM_FRAGMENT){returnNode=createDocumentFragment.call(body.ownerDocument);while(body.firstChild){returnNode.appendChild(body.firstChild);}}else{returnNode=body;} 5519if(ALLOWED_ATTR.shadowroot||ALLOWED_ATTR.shadowrootmode){returnNode=importNode.call(originalDocument,returnNode,true);} 5520return returnNode;} 5521let serializedHTML=WHOLE_DOCUMENT?body.outerHTML:body.innerHTML;if(WHOLE_DOCUMENT&&ALLOWED_TAGS['!doctype']&&body.ownerDocument&&body.ownerDocument.doctype&&body.ownerDocument.doctype.name&®ExpTest(DOCTYPE_NAME,body.ownerDocument.doctype.name)){serializedHTML='<!DOCTYPE '+body.ownerDocument.doctype.name+'>\n'+serializedHTML;} 5522if(SAFE_FOR_TEMPLATES){arrayForEach([MUSTACHE_EXPR,ERB_EXPR,TMPLIT_EXPR],expr=>{serializedHTML=stringReplace(serializedHTML,expr,' ');});} 5523return trustedTypesPolicy&&RETURN_TRUSTED_TYPE?trustedTypesPolicy.createHTML(serializedHTML):serializedHTML;};DOMPurify.setConfig=function(){let cfg=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};_parseConfig(cfg);SET_CONFIG=true;};DOMPurify.clearConfig=function(){CONFIG=null;SET_CONFIG=false;};DOMPurify.isValidAttribute=function(tag,attr,value){if(!CONFIG){_parseConfig({});} 5524const lcTag=transformCaseFunc(tag);const lcName=transformCaseFunc(attr);return _isValidAttribute(lcTag,lcName,value);};DOMPurify.addHook=function(entryPoint,hookFunction){if(typeof hookFunction!=='function'){return;} 5525hooks[entryPoint]=hooks[entryPoint]||[];arrayPush(hooks[entryPoint],hookFunction);};DOMPurify.removeHook=function(entryPoint){if(hooks[entryPoint]){return arrayPop(hooks[entryPoint]);}};DOMPurify.removeHooks=function(entryPoint){if(hooks[entryPoint]){hooks[entryPoint]=[];}};DOMPurify.removeAllHooks=function(){hooks={};};return DOMPurify;} 5526var purify=createDOMPurify();return purify;}));; 5527 5528/* /html_editor/static/src/components/switch/switch.js */ 5529odoo.define('@html_editor/components/switch/switch',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,xml}=require("@odoo/owl");const NO_OP=()=>{};const Switch=__exports.Switch=class Switch extends Component{static props={value:{type:Boolean,optional:true}
5529,extraClasses:String,disabled:{type:Boolean,optional:true},label:{type:String,optional:true},description:{type:String,optional:true},onChange:{Function,optional:true},};static defaultProps={onChange:NO_OP,};static template=xml` 5530 <label t-att-class="'o_switch' + extraClasses"> 5531 <input type="checkbox" 5532 name="switch" 5533 class="visually-hidden" 5534 t-att-checked="props.value" 5535 t-att-disabled="props.disabled" 5536 t-on-change="(ev) => props.onChange(ev.target.checked)" 5537 t-on-keyup="onKeyup"/> 5538 <span/> 5539 <span t-if="props.label" t-esc="props.label" class="ms-2"/> 5540 <span t-if="props.description" class="text-muted ms-2" t-esc="props.description"/> 5541 </label> 5542 `;setup(){this.extraClasses=this.props.extraClasses?` ${this.props.extraClasses}`:"";} 5543onKeyup(ev){if(ev.key==="Enter"){ev.currentTarget.checked=!ev.currentTarget.checked;}}} 5544return __exports;});; 5545 5546/* /html_editor/static/src/main/media/media_dialog/document_selector.js */ 5547odoo.define('@html_editor/main/media/media_dialog/document_selector',['@web/core/l10n/translation','@html_editor/main/media/media_dialog/file_selector','@web/core/utils/render'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Attachment,FileSelector,IMAGE_MIMETYPES}=require("@html_editor/main/media/media_dialog/file_selector");const{renderToElement}=require("@web/core/utils/render");const DocumentAttachment=__exports.DocumentAttachment=class DocumentAttachment extends Attachment{static template="html_editor.DocumentAttachment";} 5548const DocumentSelector=__exports.DocumentSelector=class DocumentSelector extends FileSelector{static mediaSpecificClasses=["o_file_box"];static mediaSpecificStyles=[];static mediaExtraClasses=[];static tagNames=["SPAN"];static attachmentsListTemplate="html_editor.DocumentsListTemplate";static components={...FileSelector.components,DocumentAttachment,};setup(){super.setup();this.uploadText=_t("Upload a document");this.urlPlaceholder="https://www.odoo.com/mydocument";this.addText=_t("Add URL");this.searchPlaceholder=_t("Search a document");this.allLoadedText=_t("All documents have been loaded");} 5549get attachmentsDomain(){const domain=super.attachmentsDomain;domain.push(["mimetype","not in",IMAGE_MIMETYPES],"!",["mimetype","=like","font/%"],["description","not like","CSS font face for"],["name","!=","googleFontMetadata"]);domain.unshift("&","|",["url","=",null],"!",["url","=like","/web/assets/%"]);return domain;} 5550async onClickDocument(document){this.selectAttachment(document);await this.props.save();} 5551selectInitialMedia(){return super.selectInitialMedia()&&this.props.media.classList.contains("o_file_box");} 5552async fetchAttachments(...args){const attachments=await super.fetchAttachments(...args);if(this.selectInitialMedia()){for(const attachment of attachments){if(`/web/content/${attachment.id}`===this.props.media.querySelector("a")?.getAttribute("href")?.replace(/[?].*/,"")){this.selectAttachment(attachment);}}} 5553return attachments;} 5554static async createElements(selectedMedia,{orm}){return Promise.all(selectedMedia.map(async(attachment)=>{let url=`/web/content/${encodeURIComponent( 5555 attachment.id 5556 )}?unique=${encodeURIComponent(attachment.checksum)}&download=true`;if(!attachment.public){let accessToken=attachment.access_token;if(!accessToken){[accessToken]=await orm.call("ir.attachment","generate_access_token",[attachment.id,]);} 5557url+=`&access_token=${encodeURIComponent(accessToken)}`;} 5558return this.renderFileElement(attachment,url);}));} 5559static renderFileElement(attachment,downloadUrl){return renderStaticFileBox(attachment.name,attachment.mimetype,downloadUrl,attachment.id);}} 5560__exports.renderStaticFileBox=renderStaticFileBox;
5560function renderStaticFileBox(filename,mimetype,downloadUrl,id){const rootSpan=document.createElement("span");rootSpan.classList.add("o_file_box","o-contenteditable-false");rootSpan.contentEditable=false;rootSpan.dataset.attachmentId=id;const bannerElement=renderToElement("html_editor.StaticFileBox",{fileModel:{filename,mimetype,downloadUrl},});rootSpan.append(bannerElement);return rootSpan;} 5561return __exports;});; 5562 5563/* /html_editor/static/src/main/media/media_dialog/file_selector.js */ 5564odoo.define('@html_editor/main/media/media_dialog/file_selector',['@web/core/l10n/translation','@web/core/network/rpc','@web/core/utils/hooks','@web/core/confirmation_dialog/confirmation_dialog','@web/core/dialog/dialog','@web/core/utils/concurrency','@web/core/utils/timing','@html_editor/main/media/media_dialog/search_media','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{rpc}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const{ConfirmationDialog}=require("@web/core/confirmation_dialog/confirmation_dialog");const{Dialog}=require("@web/core/dialog/dialog");const{KeepLast}=require("@web/core/utils/concurrency");const{useDebounced}=require("@web/core/utils/timing");const{SearchMedia}=require("@html_editor/main/media/media_dialog/search_media");const{Component,xml,useState,useRef,onWillStart,useEffect}=require("@odoo/owl");const IMAGE_MIMETYPES=__exports.IMAGE_MIMETYPES=["image/jpg","image/jpeg","image/jpe","image/png","image/svg+xml","image/gif","image/webp",];const IMAGE_EXTENSIONS=__exports.IMAGE_EXTENSIONS=[".jpg",".jpeg",".jpe",".png",".svg",".gif",".webp"];class RemoveButton extends Component{static template=xml`<i class="fa fa-trash o_existing_attachment_remove position-absolute top-0 end-0 p-2 bg-white-25 cursor-pointer opacity-0 opacity-100-hover z-1 transition-base" t-att-title="removeTitle" role="img" t-att-aria-label="removeTitle" t-on-click="this.remove"/>`;static props=["model?","remove"];setup(){this.removeTitle=_t("This file is attached to the current record.");if(this.props.model==="ir.ui.view"){this.removeTitle=_t("This file is a public view attachment.");}} 5565remove(ev){ev.stopPropagation();this.props.remove();}} 5566const AttachmentError=__exports.AttachmentError=class AttachmentError extends Component{static components={Dialog};static template="html_editor.AttachmentError";static props=["views","close"];setup(){this.title=_t("Alert");}} 5567const Attachment=__exports.Attachment=class Attachment extends Component{static template="";static components={RemoveButton,};static props=["*"];setup(){this.dialogs=useService("dialog");} 5568remove(){this.dialogs.add(ConfirmationDialog,{body:_t("Are you sure you want to delete this file?"),confirm:async()=>{const prevented=await rpc("/html_editor/attachment/remove",{ids:[this.props.id],});if(!Object.keys(prevented).length){this.props.onRemoved(this.props.id);}else{this.dialogs.add(AttachmentError,{views:prevented[this.props.id],});}},});}} 5569const FileSelectorControlPanel=__exports.FileSelectorControlPanel=class FileSelectorControlPanel extends Component{static template="html_editor.FileSelectorControlPanel";static components={SearchMedia,};static props={uploadUrl:Function,validateUrl:Function,uploadFiles:Function,changeSearchService:Function,changeShowOptimized:Function,search:Function,accept:{type:String,optional:true},addText:{type:String,optional:true},multiSelect:{type:true,optional:true},needle:{type:String,optional:true},searchPlaceholder:{type:String,optional:true},searchService:{type:String,optional:true},showOptimized:{type:Boolean,optional:true},showOptimizedOption:{type:String,optional:true},uploadText:{type:String,optional:true},urlPlaceholder:{type:String,optional:true},urlWarningTitle:{type:String,optional:true},useMediaLibrary:{type:Boolean,optional:true},useUnsplash:{type:Boolean,optional:true},};setup(){this.state=useState({showUrlInput:false,urlInput:"",isValidUrl:false,isValidFileFormat:false,isValidatingUrl:false,});this.debouncedValidateUrl=useDebounced(this.props.validateUrl,500);this.fileInput=useRef("file-input");const urlInputRef=useRef("urlInput");useEffect(()=>{if(this.state.showUrlInput){urlInputRef.el.focus();}},()=>[this.state.showUrlInput]);} 5570get showSearchServiceSelect(){return this.props.searchService&&this.props.needle;} 5571get enableUrlUploadClick(){return(!this.state.showUrlInput||(this.state.urlInput&&this.state.isValidUrl&&this.state.isValidFileFormat));} 5572async onUrlUploadClick(){if(!this.state.showUrlInput){this.state.showUrlInput=true;}else{await this.props.uploadUrl(this.state.urlInput);this.state.urlInput="";}} 5573async onUrlInput(ev){this.state.isValidatingUrl=true;const{isValidUrl,isValidFileFormat}=await this.debouncedValidateUrl(ev.target.value);this.state.isValidFileFormat=isValidFileFormat;this.state.isValidUrl=isValidUrl;this.state.isValidatingUrl=false;}
5574onClickUpload(){this.fileInput.el.click();} 5575async onChangeFileInput(){const inputFiles=this.fileInput.el.files;if(!inputFiles.length){return;} 5576await this.props.uploadFiles(inputFiles);const fileInputEl=this.fileInput.el;if(fileInputEl){fileInputEl.value="";}}} 5577const FileSelector=__exports.FileSelector=class FileSelector extends Component{static template="html_editor.FileSelector";static components={FileSelectorControlPanel,};static props=["*"];setup(){this.notificationService=useService("notification");this.orm=useService("orm");this.uploadService=useService("upload");this.keepLast=new KeepLast();this.loadMoreButtonRef=useRef("load-more-button");this.existingAttachmentsRef=useRef("existing-attachments");this.state=useState({attachments:[],canScrollAttachments:false,canLoadMoreAttachments:false,isFetchingAttachments:false,needle:"",});this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY=30;onWillStart(async()=>{this.state.attachments=await this.fetchAttachments(this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY,0);});this.debouncedOnScroll=useDebounced(this.updateScroll,15);this.debouncedScrollUpdate=useDebounced(this.updateScroll,500);useEffect((modalEl)=>{if(modalEl){modalEl.addEventListener("scroll",this.debouncedOnScroll);return()=>{modalEl.removeEventListener("scroll",this.debouncedOnScroll);};}},()=>[this.props.modalRef.el?.querySelector("main.modal-body")]);useEffect(()=>{this.loadMoreButtonRef.el.classList.add("o_hide_loading");this.state.canScrollAttachments=false;this.debouncedScrollUpdate();},()=>[this.allAttachments.length]);} 5578get canLoadMore(){return this.state.canLoadMoreAttachments;} 5579get hasContent(){return this.state.attachments.length;} 5580get isFetching(){return this.state.isFetchingAttachments;} 5581get selectedAttachmentIds(){return this.props.selectedMedia[this.props.id].filter((media)=>media.mediaType==="attachment").map(({id})=>id);} 5582get attachmentsDomain(){const domain=["&",["res_model","=",this.props.resModel],["res_id","=",this.props.resId||0],];domain.unshift("|",["public","=",true]);domain.push(["name","ilike",this.state.needle]);return domain;} 5583get allAttachments(){return this.state.attachments;} 5584validateUrl(url){const path=url.split("?")[0];const isValidUrl=/^.+\..+$/.test(path);const isValidFileFormat=true;return{isValidUrl,isValidFileFormat,path};} 5585async fetchAttachments(limit,offset){this.state.isFetchingAttachments=true;let attachments=[];try{attachments=await this.orm.call("ir.attachment","search_read",[],{domain:this.attachmentsDomain,fields:["name","mimetype","description","checksum","url","type","res_id","res_model","public","access_token","image_src","image_width","image_height","original_id",],order:"id desc",limit,offset,});attachments.forEach((attachment)=>(attachment.mediaType="attachment"));}catch(e){if(e.exceptionName!=="odoo.exceptions.AccessError"){throw e;}} 5586this.state.canLoadMoreAttachments=attachments.length>=this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY;this.state.isFetchingAttachments=false;return attachments;} 5587async handleLoadMore(){await this.loadMore();} 5588async loadMore(){return this.keepLast.add(this.fetchAttachments(this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY,this.state.attachments.length)).then((newAttachments)=>{this.state.attachments.push(...newAttachments);});} 5589async handleSearch(needle){await this.search(needle);} 5590async search(needle){this.state.attachments=[];this.state.needle=needle;return this.keepLast.add(this.fetchAttachments(this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY,0)).then((attachments)=>{this.state.attachments=attachments;});} 5591async uploadFiles(files){await this.uploadService.uploadFiles(files,{resModel:this.props.resModel,resId:this.props.resId},(attachment)=>this.onUploaded(attachment));} 5592async uploadUrl(url){await fetch(url).then(async(result)=>{const blob=await result.blob();blob.id=new Date().getTime();blob.name=new URL(url,window.location.href).pathname.split("/").findLast((s)=>s);await this.uploadFiles([blob]);}).catch(async()=>{await new Promise((resolve)=>{const imageEl=document.createElement("img");imageEl.onerror=()=>{this.notificationService.add(_t("An error occurred while fetching the entered URL."),{type:"danger",sticky:true,});resolve();};imageEl.onload=()=>{this.onLoadUploadedUrl(url,resolve);};imageEl.src=url;});});} 5593async onLoadUploadedUrl(url,resolve){await this.uploadService.uploadUrl(url,{resModel:this.props.resModel,resId:this.props.resId,},(attachment)=>this.onUploaded(attachment));resolve();} 5594async onUploaded(attachment){this.state.attachments=[attachment,...this.state.attachments.filter((attach)=>attach.id!==attachment.id),];this.selectAttachment(attachment);if(!this.props.multiSelect){await this.props.save();} 5595if(this.props.onAttachmentChange){this.props.onAttachmentChange(attachment);}} 5596onRemoved(attachmentId){this.state.attachments=this.state.attachments.filter((attachment)=>attachment.id!==attachmentId);} 5597selectAttachment(attachment){this.props.selectMedia({...attachment,mediaType:"attachment"});} 5598selectInitialMedia(){return(this.props.media&&this.constructor.tagNames.includes(this.props.media.tagName)&&!this.selectedAttachmentIds.length);}
5599updateScroll(){const loadMoreTop=this.loadMoreButtonRef.el.getBoundingClientRect().top;const modalEl=this.props.modalRef.el.querySelector("main.modal-body");const modalBottom=modalEl.getBoundingClientRect().bottom;this.state.canScrollAttachments=loadMoreTop>=modalBottom;this.loadMoreButtonRef.el.classList.remove("o_hide_loading");} 5600isAttachmentHidden(attachmentEl){const attachmentBottom=Math.round(attachmentEl.getBoundingClientRect().bottom);const modalEl=this.props.modalRef.el.querySelector("main.modal-body");const modalBottom=modalEl.getBoundingClientRect().bottom;return attachmentBottom>modalBottom;} 5601handleScrollAttachments(){let scrollToEl=this.loadMoreButtonRef.el;const attachmentEls=[...this.existingAttachmentsRef.el.querySelectorAll(".o_existing_attachment_cell"),];const firstHiddenAttachmentEl=attachmentEls.find((el)=>this.isAttachmentHidden(el));if(firstHiddenAttachmentEl){const attachmentBottom=firstHiddenAttachmentEl.getBoundingClientRect().bottom;const attachmentIndex=attachmentEls.indexOf(firstHiddenAttachmentEl);const firstNextRowAttachmentEl=attachmentEls.slice(attachmentIndex).find((el)=>el.getBoundingClientRect().bottom>attachmentBottom);scrollToEl=firstNextRowAttachmentEl||scrollToEl;} 5602scrollToEl.scrollIntoView({block:"end",inline:"nearest",behavior:"smooth"});}} 5603return __exports;});; 5604 5605/* /html_editor/static/src/main/media/media_dialog/icon_selector.js */ 5606odoo.define('@html_editor/main/media/media_dialog/icon_selector',['@html_editor/main/media/media_dialog/search_media','@html_editor/utils/fonts','@odoo/owl'],function(require){'use strict';let __exports={};const{SearchMedia}=require("@html_editor/main/media/media_dialog/search_media");const{fonts}=require("@html_editor/utils/fonts");const{Component,useState}=require("@odoo/owl");const IconSelector=__exports.IconSelector=class IconSelector extends Component{static mediaSpecificClasses=["fa"];static mediaSpecificStyles=["color","background-color"];static mediaExtraClasses=[/^text-\S+$/,/^bg-\S+$/,/^fa-\S+$/];static tagNames=["SPAN","I"];static template="html_editor.IconSelector";static components={SearchMedia,};static props=["*"];setup(){this.state=useState({fonts:this.props.fonts,needle:"",});} 5607get selectedMediaIds(){return this.props.selectedMedia[this.props.id].map(({id})=>id);} 5608search(needle){this.state.needle=needle;if(!this.state.needle){this.state.fonts=this.props.fonts;}else{this.state.fonts=this.props.fonts.map((font)=>{const icons=font.icons.filter((icon)=>icon.alias.indexOf(this.state.needle.toLowerCase())>=0);return{...font,icons};});}} 5609async onClickIcon(font,icon){this.props.selectMedia({...icon,fontBase:font.base,initialIconChanged:this.props.media&&!icon.names.some((name)=>this.props.media.classList.contains(name)),});await this.props.save();} 5610static createElements(selectedMedia){return selectedMedia.map((icon)=>{const iconEl=document.createElement("span");iconEl.classList.add(icon.fontBase,icon.names[0]);return iconEl;});} 5611static initFonts(){fonts.computeFonts();const allFonts=fonts.fontIcons.map(({cssData,base})=>{const uniqueIcons=Array.from(new Map(cssData.map((icon)=>{const alias=icon.names.join(",");const id=`${base}_${alias}`;return[id,{...icon,alias,id}];})).values());return{base,icons:uniqueIcons};});return allFonts;}} 5612return __exports;});; 5613 5614/* /html_editor/static/src/main/media/media_dialog/image_selector.js */ 5615odoo.define('@html_editor/main/media/media_dialog/image_selector',['@odoo/owl','@web/core/l10n/translation','@web/core/network/rpc','@web/core/utils/concurrency','@html_editor/utils/color','@html_editor/utils/formatting','@html_editor/main/media/media_dialog/file_selector','@html_editor/utils/image'],function(require){'use strict';let __exports={};const{useRef,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{rpc}=require("@web/core/network/rpc");const{KeepLast}=require("@web/core/utils/concurrency");const{DEFAULT_PALETTE}=require("@html_editor/utils/color");const{getCSSVariableValue,getHtmlStyle}=require("@html_editor/utils/formatting");const{Attachment,FileSelector,IMAGE_EXTENSIONS,IMAGE_MIMETYPES}=require("@html_editor/main/media/media_dialog/file_selector");const{isSrcCorsProtected}=require("@html_editor/utils/image");const AutoResizeImage=__exports.AutoResizeImage=class AutoResizeImage extends Attachment{static template="html_editor.AutoResizeImage";setup(){super.setup();this.image=useRef("auto-resize-image");this.container=useRef("auto-resize-image-container");this.state=useState({loaded:false,});} 5616async onImageLoaded(){if(!this.image.el){return;} 5617if(this.props.onLoaded){await this.props.onLoaded(this.image.el);if(!this.image.el){return;}} 5618const aspectRatio=this.image.el.offsetWidth/this.image.el.offsetHeight;const width=aspectRatio*this.props.minRowHeight;this.container.el.style.flexGrow=width;this.container.el.style.flexBasis=`${width}px`;this.state.loaded=true;}} 5619const newLocal="img-fluid";const ImageSelector=__exports.ImageSelector=class ImageSelector extends FileSelector{static mediaSpecificClasse
5619s=["img",newLocal,"o_we_custom_image"];static mediaSpecificStyles=["transform","width"];static mediaExtraClasses=["rounded-circle","rounded","img-thumbnail","shadow","w-25","w-50","w-75","w-100",];static tagNames=["IMG"];static attachmentsListTemplate="html_editor.ImagesListTemplate";static components={...FileSelector.components,AutoResizeImage,};setup(){super.setup();this.keepLastLibraryMedia=new KeepLast();this.state.libraryMedia=[];this.state.libraryResults=null;this.state.isFetchingLibrary=false;this.state.searchService="all";this.state.showOptimized=false;this.NUMBER_OF_MEDIA_TO_DISPLAY=10;this.uploadText=_t("Upload an image");this.urlPlaceholder="https://www.odoo.com/logo.png";this.addText=_t("Add URL");this.searchPlaceholder=_t("Search an image");this.urlWarningTitle=_t("Uploaded image's format is not supported. Try with: "+IMAGE_EXTENSIONS.join(", "));this.allLoadedText=_t("All images have been loaded");this.showOptimizedOption=this.env.debug;this.MIN_ROW_HEIGHT=128;this.fileMimetypes=IMAGE_MIMETYPES.join(",");this.isImageField=!!this.props.media?.closest("[data-oe-type=image]")||!!this.props.addFieldImage;this.isProcessingClick=false;} 5620get canLoadMore(){if(this.state.searchService==="media-library"){return(this.state.libraryResults&&this.state.libraryMedia.length<this.state.libraryResults);} 5621return super.canLoadMore;} 5622get hasContent(){if(this.state.searchService==="all"){return super.hasContent||!!this.state.libraryMedia.length;}else if(this.state.searchService==="media-library"){return!!this.state.libraryMedia.length;} 5623return super.hasContent;} 5624get isFetching(){return super.isFetching||this.state.isFetchingLibrary;} 5625get selectedMediaIds(){return this.props.selectedMedia[this.props.id].filter((media)=>media.mediaType==="libraryMedia").map(({id})=>id);} 5626get allAttachments(){return[...super.allAttachments,...this.state.libraryMedia];} 5627get attachmentsDomain(){const domain=super.attachmentsDomain;domain.push(["mimetype","in",IMAGE_MIMETYPES]);if(!this.props.useMediaLibrary){domain.push("|",["url","=",false],"!","|",["url","=ilike","/html_editor/shape/%"],["url","=ilike","/web_editor/shape/%"]);} 5628domain.push("!",["name","=like","%.crop"]);domain.push("|",["type","=","binary"],"!",["url","=like","/%/static/%"]);if(!this.env.debug){const subDomain=[false];const originalId=this.props.media&&this.props.media.dataset.originalId;if(originalId){subDomain.push(originalId);} 5629domain.push(["original_id","in",subDomain]);} 5630return domain;} 5631async uploadFiles(files){let abortFn;const uploadPromise=this.uploadService.uploadFiles(files,{resModel:this.props.resModel,resId:this.props.resId,isImage:true,},(attachment)=>this.onUploaded(attachment),(abort)=>{abortFn=abort;});this.props.setAbortUploadsCallback(()=>abortFn?.());await uploadPromise;} 5632async validateUrl(...args){const{isValidUrl,path}=super.validateUrl(...args);const isValidFileFormat=isValidUrl&&(await new Promise((resolve)=>{const img=new Image();img.src=path;img.onload=()=>resolve(true);img.onerror=()=>resolve(false);}));return{isValidFileFormat,isValidUrl};} 5633async onLoadUploadedUrl(url,resolve){const urlPathname=new URL(url,window.location.href).pathname;const imageExtension=IMAGE_EXTENSIONS.find((format)=>urlPathname.endsWith(format));if(this.isImageField&&imageExtension===".webp"){this.notificationService.add(_t("You can not replace a field by this image. If you want to use this image, first save it on your computer and then upload it here."),{type:"danger",sticky:true,});return resolve();} 5634super.onLoadUploadedUrl(url,resolve);} 5635isInitialMedia(attachment){if(this.props.media.dataset.originalSrc){return this.props.media.dataset.originalSrc===attachment.image_src;} 5636return this.props.media.getAttribute("src")===attachment.image_src;} 5637async fetchAttachments(limit,offset){const attachments=await super.fetchAttachments(limit,offset);if(this.isImageField){for(const attachment of attachments){if(attachment.mimetype==="image/webp"&&(await isSrcCorsProtected(attachment.image_src))){attachment.unselectable=true;}}} 5638const primaryColors={};const htmlStyle=getHtmlStyle(document);for(let color=1;color<=5;color++){primaryColors[color]=getCSSVariableValue("o-color-"+color,htmlStyle);} 5639return attachments.map((attachment)=>{if(attachment.image_src.startsWith("/")){const newURL=new URL(attachment.image_src,window.location.origin);if(attachment.image_src.startsWith("/html_editor/shape/")||attachment.image_src.startsWith("/web_editor/shape/")){newURL.searchParams.forEac
5639h((value,key)=>{const match=key.match(/^c([1-5])$/);if(match){newURL.searchParams.set(key,primaryColors[match[1]]);}});}else{newURL.searchParams.set("height",2*this.MIN_ROW_HEIGHT);} 5640attachment.thumbnail_src=newURL.pathname+newURL.search;} 5641if(this.selectInitialMedia()&&this.isInitialMedia(attachment)){this.selectAttachment(attachment);} 5642return attachment;});} 5643async fetchLibraryMedia(offset){if(!this.state.needle){return{media:[],results:null};} 5644this.state.isFetchingLibrary=true;try{const response=await rpc("/html_editor/media_library_search",{query:this.state.needle,offset:offset,},{silent:true,});this.state.isFetchingLibrary=false;const media=(response.media||[]).slice(0,this.NUMBER_OF_MEDIA_TO_DISPLAY);media.forEach((record)=>(record.mediaType="libraryMedia"));return{media,results:response.results};}catch{console.error(`Couldn't reach API endpoint.`);this.state.isFetchingLibrary=false;return{media:[],results:null};}} 5645async loadMore(...args){await super.loadMore(...args);if(!this.props.useMediaLibrary||this.state.searchService!=="media-library"){return;} 5646return this.keepLastLibraryMedia.add(this.fetchLibraryMedia(this.state.libraryMedia.length)).then(({media})=>{this.state.libraryMedia.push(...media);});} 5647async search(...args){await super.search(...args);if(!this.props.useMediaLibrary){return;} 5648if(!this.state.needle){this.state.searchService="all";} 5649this.state.libraryMedia=[];this.state.libraryResults=0;return this.keepLastLibraryMedia.add(this.fetchLibraryMedia(0)).then(({media,results})=>{this.state.libraryMedia=media;this.state.libraryResults=results;});} 5650async onClickAttachment(attachment){if(this.isProcessingClick){return;} 5651this.isProcessingClick=true;if(attachment.unselectable){this.notificationService.add(_t("You can not replace a field by this image. If you want to use this image, first save it on your computer and then upload it here."),{type:"danger",sticky:true,});return;} 5652this.selectAttachment(attachment);if(!this.props.multiSelect){await this.props.save();} 5653requestAnimationFrame(()=>{this.isProcessingClick=false;});} 5654async onClickMedia(media){this.props.selectMedia({...media,mediaType:"libraryMedia"});if(!this.props.multiSelect){await this.props.save();}} 5655static async createElements(selectedMedia,{orm}){const toSave=Object.fromEntries(selectedMedia.filter((media)=>media.mediaType==="libraryMedia").map((media)=>[media.id,{query:media.query||"",is_dynamic_svg:!!media.isDynamicSVG,dynamic_colors:media.dynamicColors,},]));let savedMedia=[];if(Object.keys(toSave).length!==0){savedMedia=await rpc("/html_editor/save_library_media",{media:toSave});} 5656const selected=selectedMedia.filter((media)=>media.mediaType==="attachment").concat(savedMedia).map((attachment)=>{if(attachment.image_src&&(attachment.image_src.startsWith("/html_editor/shape/")||attachment.image_src.startsWith("/web_editor/shape/"))){const colorCustomizedURL=new URL(attachment.image_src,window.location.origin);const htmlStyle=getHtmlStyle(document);colorCustomizedURL.searchParams.forEach((value,key)=>{const match=key.match(/^c([1-5])$/);if(match){colorCustomizedURL.searchParams.set(key,getCSSVariableValue(`o-color-${match[1]}`,htmlStyle));}});attachment.image_src=colorCustomizedURL.pathname+colorCustomizedURL.search;} 5657return attachment;});return Promise.all(selected.map(async(attachment)=>{const imageEl=document.createElement("img");let src=attachment.image_src;if(!attachment.public&&!attachment.url){let accessToken=attachment.access_token;if(!accessToken){[accessToken]=await orm.call("ir.attachment","generate_access_token",[attachment.id,]);} 5658src+=`?access_token=${encodeURIComponent(accessToken)}`;} 5659imageEl.src=src;imageEl.alt=attachment.description||"";imageEl.dataset.attachmentId=attachment.id;return imageEl;}));} 5660async onImageLoaded(imgEl,attachment){this.debouncedScrollUpdate();if(attachment.mediaType==="libraryMedia"&&!imgEl.src.startsWith("blob")){await this.onLibraryImageLoaded(imgEl,attachment);}} 5661async onLibraryImageLoaded(imgEl,media){const mediaUrl=imgEl.src;try{const response=await fetch(mediaUrl);if(response.headers.get("content-type").startsWith("image/svg+xml")){let svg=await response.text();const dynamicColors={};const combinedColorsRegex=new RegExp(Object.values(DEFAULT_PALETTE).join("|"),"gi");const htmlStyle=getHtmlStyle(document);svg=svg.replace(combinedColorsRegex,(match)=>{const colorId=Object.keys(DEFAULT_PALETTE).find((key)=>DEFAULT_PALETTE[key]===match.toUpperCase());const colorKey="c"+colorId;dynamicColors[colorKey]=getCSSVariableValue("o-color-"+colorId,htmlStyle);return dynamicColors[colorKey];});const fileName=mediaUrl.split("/").pop();const file=new File([svg],fileName,{type:"image/svg+xml",});imgEl.src=URL.createObjectURL(file);if(Object.keys(dynamicColors).length){media.isDynamicSVG=true;media.dynamicColors=dynamicColors;}}}catch{console.error("CORS is misconfigured on the API server, image will be treated as non-dynamic.");}}} 5662return __exports;});; 5663 5664/* /html_editor/static/src/main/media/media_dialog/media_dialog.js */ 5665odoo.define('@html_editor/main/media/media_dialog/media_dialog',['@web/core/l10n/translation','@web/core/utils/hooks','@web/core/dialog/dialog','@web/core/notebook/notebook','@html_editor/main/media/media_dialog/image_selector','@html_editor/main/media/media_dialog/icon_selector','@odoo/owl','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{useService,useChildRef}=require("@web/core/utils/hooks");const{Dialog}=require("@web/core/dialog/dialog");const{Notebook}=require("@web/core/notebook/notebook");const{ImageSelector}=require("@html_editor/main/media/media_dialog/image_selector");const{IconSelector}=require("@html_editor/main/media/media_dialog/icon_selector");const{Component,useState,useRef,useEffect}=require("@odoo/owl");const{iconClasses}=require("@html_editor/utils/dom_info");const TABS=__exports.TABS={IMAGES:{id:"IMAGES",title:_t("Images"),Component:ImageSelector,sequence:10,},ICONS:{id:"ICONS",title:_t("Icons"),Component:IconSelector,sequence:20,},};const DEFAULT_SEQUENCE=50;const sequence=(tab)=>tab.sequence??DEFAULT_SEQUENCE;const MediaDialog=__exports.MediaDialog=class MediaDialog extends Component{static template="html_editor.MediaDialog";static defaultProps={useMediaLibrary:true,extraTabs:[],};static components={Dialog,Notebook,};static props={extraTabs:{type:Array,optional:true,element:Object},visibleTabs:{type:Array,optional:true,element:String},activeTab:{type:String,optional:true},"*":true,};setup(){this.size="xl";this.contentClass="o_select_media_dialog h-100";this.title=_t("Select a media");this.modalRef=useChildRef();this.orm=useService("orm");this.notificationService=useService("notification");this.selectedMedia=useState({});this.addButtonRef=useRef("add-button");this.initialIconClasses=[];this.notebookPages=[];this.addTabs();this.notebookPages.sort((a,b)=>
5665sequence(a)-sequence(b));this.tabs=Object.fromEntries(this.notebookPages.map((tab)=>[tab.id,tab]));this.errorMessages={};this.state=useState({activeTab:this.initialActiveTab,isSaving:false,});useEffect((nbSelectedAttachments)=>{this.addButtonRef.el.toggleAttribute("disabled",!nbSelectedAttachments||this.state.isSaving);},()=>[this.selectedMedia[this.state.activeTab].length,this.state.isSaving]);this.abortUploads=null;} 5666get initialActiveTab(){if(this.props.activeTab){return this.props.activeTab;} 5667if(this.props.media){const correspondingTab=Object.keys(this.tabs).find((id)=>this.tabs[id].Component.mediaSpecificClasses.some((cls)=>[...this.props.media.classList].includes(cls)))||Object.keys(this.tabs).find((id)=>this.tabs[id].Component.tagNames.includes(this.props.media.tagName));if(correspondingTab){return correspondingTab;}} 5668return this.notebookPages[0].id;} 5669addTab(tab,additionalProps={}){if(this.props.visibleTabs&&!this.props.visibleTabs.includes(tab.id)){return;} 5670this.selectedMedia[tab.id]=[];this.notebookPages.push({...tab,props:{...tab.props,...additionalProps,id:tab.id,resModel:this.props.resModel,resId:this.props.resId,media:this.props.media,selectedMedia:this.selectedMedia,selectMedia:(...args)=>this.selectMedia(...args,tab.id,additionalProps.multiSelect),save:this.save.bind(this),setAbortUploadsCallback:(abortFunc)=>(this.abortUploads=abortFunc),onAttachmentChange:this.props.onAttachmentChange,errorMessages:(errorMessage)=>(this.errorMessages[tab.id]=errorMessage),modalRef:this.modalRef,},});} 5671addTabs(){const onlyImages=this.props.onlyImages||(this.props.media&&this.props.media.parentElement&&(this.props.media.parentElement.dataset.oeField==="image"||this.props.media.parentElement.dataset.oeType==="image"));if(!this.props.noImages){this.addTab(TABS.IMAGES,{useMediaLibrary:this.props.useMediaLibrary,multiSelect:this.props.multiImages,addFieldImage:this.props.addFieldImage,});} 5672if(onlyImages){return;} 5673const addIcons=!this.props.visibleTabs||this.props.visibleTabs.includes(TABS.ICONS.id);if(addIcons){const fonts=TABS.ICONS.Component.initFonts();this.addTab(TABS.ICONS,{fonts,});if(this.props.media&&TABS.ICONS.Component.tagNames.includes(this.props.media.tagName)){const classes=this.props.media.className.split(/\s+/);const predefinedMediaFont=fonts.find((font)=>classes.includes(font.base));if(predefinedMediaFont){const selectedIcon=predefinedMediaFont.icons.find((icon)=>icon.names.some((name)=>classes.includes(name)));if(selectedIcon){this.initialIconClasses.push(...selectedIcon.names);this.selectMedia(selectedIcon,TABS.ICONS.id);}}else{const iconRegex=new RegExp(`\\b(?:${iconClasses.join("|")})(?:-\\S+)?\\b`);const fallbackIconClasses=classes.filter((cls)=>iconRegex.test(cls));this.initialIconClasses.push(...fallbackIconClasses);}}} 5674this.props.extraTabs.forEach((tab)=>this.addTab(tab));} 5675async renderMedia(selectedMedia){const elements=await this.tabs[this.state.activeTab].Component.createElements(selectedMedia,{orm:this.orm});elements.forEach((element)=>{if(this.props.media){element.classList.add(...this.props.media.classList);const style=this.props.media.getAttribute("style");if(style){element.setAttribute("style",style);}} 5676for(const otherTab of Object.keys(this.tabs).filter((key)=>key!==this.state.activeTab)){for(const property of this.tabs[otherTab].Component.mediaSpecificStyles){element.style.removeProperty(property);} 5677element.classList.remove(...this.tabs[otherTab].Component.mediaSpecificClasses);const extraClassesToRemove=[];for(const name of this.tabs[otherTab].Component.mediaExtraClasses){if(typeof name==="string"){extraClassesToRemove.push(name);}else{for(const className of element.classList){if(className.match(name)){extraClassesToRemove.push(className);}}}} 5678element.classList.remove(...extraClassesToRemove.filter((candidateName)=>{for(const name of this.tabs[this.state.activeTab].Component.mediaExtraClasses){if(typeof name==="string"){if(candidateName===name){return false;}}else{if(candidateName.match(name)){return false;}}} 5679return true;}));} 5680element.classList.remove(...this.initialIconClasses);element.classList.remove("o_modified_image_to_save");element.classList.remove("oe_edited_link");element.classList.add(...this.tabs[this.state.activeTab].Component.mediaSpecificClasse
5680s);});return elements;} 5681selectMedia(media,tabId,multiSelect){if(media&&!Object.keys(media).length){this.selectedMedia[tabId]=[];return;} 5682if(multiSelect){const isMediaSelected=this.selectedMedia[tabId].map(({id})=>id).includes(media.id);if(!isMediaSelected){this.selectedMedia[tabId].push(media);}else{this.selectedMedia[tabId]=this.selectedMedia[tabId].filter((m)=>m.id!==media.id);}}else{this.selectedMedia[tabId]=[media];}} 5683async save(){if(this.errorMessages[this.state.activeTab]){this.notificationService.add(this.errorMessages[this.state.activeTab],{type:"danger",});return;} 5684const selectedMedia=this.selectedMedia[this.state.activeTab];const saveSelectedMedia=selectedMedia.length&&(this.state.activeTab!==TABS.ICONS.id||selectedMedia[0].initialIconChanged||!this.props.media);this.state.isSaving=true;if(saveSelectedMedia){const elements=await this.renderMedia(selectedMedia);if(this.props.multiImages){await this.props.save(elements,selectedMedia,this.state.activeTab);}else{await this.props.save(elements[0],selectedMedia,this.state.activeTab);}} 5685this.props.close();this.state.isSaving=false;} 5686onTabChange(tab){this.state.activeTab=tab;} 5687async close(){if(this.abortUploads){this.abortUploads();delete this.abortUploads;} 5688this.state.isSaving=false;await this.props.close();}} 5689return __exports;});; 5690 5691/* /html_editor/static/src/main/media/media_dialog/search_media.js */ 5692odoo.define('@html_editor/main/media/media_dialog/search_media',['@web/core/utils/timing','@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useDebounced}=require("@web/core/utils/timing");const{useAutofocus}=require("@web/core/utils/hooks");const{Component,useEffect,useState}=require("@odoo/owl");const SearchMedia=__exports.SearchMedia=class SearchMedia extends Component{static template="html_editor.SearchMedia";static props=["searchPlaceholder","search","needle"];setup(){useAutofocus({mobile:true});this.debouncedSearch=useDebounced(this.props.search,1000);this.state=useState({input:this.props.needle||"",});useEffect((input)=>{if(this.hasRendered){this.debouncedSearch(input);}else{this.hasRendered=true;}},()=>[this.state.input]);}} 5693return __exports;});; 5694 5695/* /html_editor/static/src/main/media/media_dialog/upload_progress_toast/upload_progress_toast.js */ 5696odoo.define('@html_editor/main/media/media_dialog/upload_progress_toast/upload_progress_toast',['@web/core/l10n/translation','@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{useService}=require("@web/core/utils/hooks");const{Component,useState}=require("@odoo/owl");const ProgressBar=__exports.ProgressBar=class ProgressBar extends Component{static template="html_editor.ProgressBar";static props={progress:{type:Number,optional:true},hasError:{type:Boolean,optional:true},uploaded:{type:Boolean,optional:true},name:String,size:{type:String,optional:true},errorMessage:{type:String,optional:true},};static defaultProps={progress:0,hasError:false,uploaded:false,size:"",errorMessage:"",};get errorMessage(){return this.props.errorMessage||_t("File could not be saved");} 5697get progress(){return Math.round(this.props.progress);}} 5698const UploadProgressToast=__exports.UploadProgressToast=class UploadProgressToast extends Component{static template="html_editor.UploadProgressToast";static components={ProgressBar,};static props={close:Function,};setup(){this.uploadService=useService("upload");this.state=useState(this.uploadService.progressToast);}} 5699return __exports;});; 5700 5701/* /html_editor/static/src/main/media/media_dialog/upload_progress_toast/upload_service.js */ 5702odoo.define('@html_editor/main/media/media_dialog/upload_progress_toast/upload_service',['@web/core/network/rpc','@web/core/registry','@html_editor/main/media/media_dialog/upload_progress_toast/upload_progress_toast','@web/core/l10n/translation','@web/core/utils/files','@web/core/utils/numbers','@web/core/utils/urls','@odoo/owl'],function(require){'use strict';let __exports={};const{rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const{UploadProgressToast}=require("@html_editor/main/media/media_dialog/upload_progress_toast/upload_progress_toast");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{checkFileSize}=require("@web/core/utils/files");const{humanNumber}=require("@web/core/utils/numbers");const{getDataURLFromFile}=require("@web/core/utils/urls");const{reactive}=require("@odoo/owl");const AUTOCLOSE_DELAY=__exports.AUTOCLOSE_DELAY=3000;const AUTOCLOSE_DELAY_LONG=__exports.AUTOCLOSE_DELAY_LONG=8000;
5702const uploadService=__exports.uploadService={dependencies:["notification"],start(env,{notification}){let fileId=0;const progressToast=reactive({files:{},isVisible:false,});registry.category("main_components").add("UploadProgressToast",{Component:UploadProgressToast,props:{close:()=>(progressToast.isVisible=false),},});const addFile=(file)=>{progressToast.files[file.id]=file;progressToast.isVisible=true;return progressToast.files[file.id];};const deleteFile=(fileId)=>{delete progressToast.files[fileId];if(!Object.keys(progressToast.files).length){progressToast.isVisible=false;}};const convertWebpToJpeg=async(dataURL,name,attachmentId)=>{const image=document.createElement("img");image.src=`data:image/webp;base64,${dataURL.split(",")[1]}`;await new Promise((res,rej)=>{image.onload=res;image.onerror=rej;});const canvas=document.createElement("canvas");canvas.width=image.width;canvas.height=image.height;const ctx=canvas.getContext("2d");ctx.fillStyle="white";ctx.fillRect(0,0,canvas.width,canvas.height);ctx.drawImage(image,0,0
5702);const altDataURL=canvas.toDataURL("image/jpeg",0.75);await rpc("/web_editor/attachment/add_data",{name:name.replace(/\.webp$/,".jpg"),data:altDataURL.split(",")[1],res_id:attachmentId,res_model:"ir.attachment",is_image:true,width:0,quality:0,});};return{get progressToast(){return progressToast;},get fileId(){return fileId;},addFile,deleteFile,incrementId(){fileId++;},uploadUrl:async(url,{resModel,resId},onUploaded)=>{const attachment=await rpc("/html_editor/attachment/add_url",{url,res_model:resModel,res_id:resId,});await onUploaded(attachment);},uploadFiles:async(files,{resModel,resId,isImage},onUploaded,setAbortCallback)=>{const sortedFiles=Array.from(files).sort((a,b)=>a.size-b.size);const controller=new AbortController();const{signal}=controller;let currentXHR=null;let addAttachmentRpc=null;setAbortCallback?.(()=>{controller.abort();addAttachmentRpc?.abort?.();currentXHR?.abort?.();});for(const file of sortedFiles){if(signal.aborted){return;} 5703let fileSize=file.size;if(!checkFileSize(fileSize,notification)){return null;} 5704if(!fileSize){fileSize="";}else{fileSize=humanNumber(fileSize)+"B";} 5705const id=++fileId;file.progressToastId=id;addFile({id,name:file.name,size:fileSize,});} 5706for(const sortedFile of sortedFiles){if(signal.aborted){break;} 5707const file=progressToast.files[sortedFile.progressToastId];let dataURL;try{dataURL=await getDataURLFromFile(sortedFile);if(signal.aborted){break;}}catch{deleteFile(file.id);env.services.notification.add(_t('Could not load the file "%s".',sortedFile.name),{type:"danger"});continue;} 5708currentXHR=new XMLHttpRequest();addAttachmentRpc=null;const onProgress=(ev)=>{if(ev.lengthComputable){file.progress=(ev.loaded/ev.total)*100;}};const onLoad=()=>(file.progress=100);const onFileAbort=()=>{deleteFile(file.id);file.aborted=true;};currentXHR.upload.addEventListener("progress",onProgress);currentXHR.upload.addEventListener("load",onLoad);currentXHR.addEventListener("abort",onFileAbort);try{addAttachmentRpc=rpc("/html_editor/attachment/add_data",{name:file.name,data:dataURL.split(",")[1],res_id:resId,res_model:resModel,is_image:!!isImage,width:0,quality:0,},{xhr:currentXHR});const attachment=await addAttachmentRpc;if(signal.aborted||file.aborted){break;} 5709if(attachment.error){file.hasError=true;file.errorMessage=attachment.error;}else{if(attachment.mimetype==="image/webp"){try{await convertWebpToJpeg(dataURL,file.name,attachment.id);}catch(convErr){console.warn("[uploadService] webp conversion failed:",convErr);}} 5710file.uploaded=true;await onUploaded(attachment);}}catch(err){if(signal.aborted){break;} 5711file.hasError=true;console.error("Upload error:",err);throw err;}finally{currentXHR.upload.removeEventListener("progress",onProgress);currentXHR.upload.removeEventListener("load",onLoad);const message_autoclose_delay=file.hasError?AUTOCLOSE_DELAY_LONG:AUTOCLOSE_DELAY;setTimeout(()=>deleteFile(file.id),message_autoclose_delay);dataURL=null;}} 5712currentXHR=null;addAttachmentRpc=null;},};},};registry.category("services").add("upload",uploadService);return __exports;});; 5713 5714/* /html_editor/static/src/main/media/media_dialog/video_selector.js */ 5715odoo.define('@html_editor/main/media/media_dialog/video_selector',['@web/core/l10n/translation','@web/core/network/rpc','@web/core/utils/hooks','@web/core/utils/timing','@odoo/owl','@html_editor/components/switch/switch'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{rpc}=require("@web/core/network/rpc");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{debounce}=require("@web/core/utils/timing");const{Component,useState,useRef,onMounted,status}=require("@odoo/owl");const{Switch}=require("@html_editor/components/switch/switch");class VideoOption extends Component{static template="html_editor.VideoOption";static components={Switch,};static props={description:{type:String,optional:true},label:{type:String,optional:true},onChangeOption:Function,onChangeStartAt:Function,value:{type:[String,Boolean],optional:true},name:{type:String,optional:true},};get showStartAtInput(){return this.props.name==="start_from";}} 5716class VideoIframe extends Component{static template="html_editor.VideoIframe";static props={src:{type:String},};} 5717const VideoSelector=__exports.VideoSelector=class VideoSelector extends Component{static mediaSpecificClasse
5717s=["media_iframe_video"];static mediaSpecificStyles=[];static mediaExtraClasses=[];static tagNames=["IFRAME","DIV"];static template="html_editor.VideoSelector";static components={VideoIframe,VideoOption,};static props={selectMedia:Function,errorMessages:Function,vimeoPreviewIds:{type:Array,optional:true},isForBgVideo:{type:Boolean,optional:true},media:{validate:(p)=>p.nodeType===Node.ELEMENT_NODE,optional:true},"*":true,};static defaultProps={vimeoPreviewIds:[],isForBgVideo:false,};setup(){this.http=useService("http");this.state=useState({options:[],src:"",urlInput:"",platform:null,vimeoPreviews:[],errorMessage:"",});this.PLATFORMS={youtube:"youtube",dailymotion:"dailymotion",vimeo:"vimeo",};this.platformParams={youtube:"start",dailymotion:"startTime",vimeo:"#t=",};this.OPTIONS={autoplay:{label:_t("Autoplay"),description:_t("Videos are muted when autoplay is enabled"),platforms:[this.PLATFORMS.youtube,this.PLATFORMS.vimeo,],urlParameter:()=>"autoplay=1",},loop:{label:_t("Loop"),platforms:[this.PLATFORMS.youtube,this.PLATFORMS.vimeo],urlParameter:()=>"loop=1",},hide_controls:{label:_t("Hide player controls"),platforms:[this.PLATFORMS.youtube,this.PLATFORMS.vimeo,],urlParameter:()=>"controls=0",},hide_fullscreen:{label:_t("Hide fullscreen button"),platforms:[this.PLATFORMS.youtube],urlParameter:()=>"fs=0",isHidden:()=>this.state.options.filter((option)=>option.id==="hide_controls")[0].value,},start_from:{label:_t("Start at"),platforms:[this.PLATFORMS.youtube,this.PLATFORMS.vimeo,this.PLATFORMS.dailymotion,],urlParameter:()=>this.platformParams[this.state.platform],},};this.urlInputRef=useRef("url-input");onMounted(async()=>{if(this.props.media){const src=this.props.media.dataset.oeExpression||this.props.media.dataset.src||(this.props.media.tagName==="IFRAME"&&this.props.media.getAttribute("src"))||"";if(src){this.state.urlInput=src;if(!src.startsWith("https:")&&!src.startsWith("http:")){this.state.urlInput="https:"+this.state.urlInput;} 5718await this.syncOptionsWithUrl();if(status(this)==="destroyed"){return;}}} 5719await this.prepareVimeoPreviews();});useAutofocus();this.onChangeUrl=debounce(()=>this.syncOptionsWithUrl(),500);this.onChangeStartAt=debounce(async(ev,optionId)=>{const start_from=this.convertTimestampToSeconds(ev.target.value);this.state.options=this.state.options.map((option)=>{if(option.id===optionId){return{...option,value:start_from==="0"?"00:00":start_from};} 5720return option;});await this.updateVideo();this.state.urlInput="https:"+this.state.src;},1000);} 5721get shownOptions(){if(this.props.isForBgVideo){return[];} 5722return this.state.options.filter((option)=>!this.OPTIONS[option.id].isHidden||!this.OPTIONS[option.id].isHidden());} 5723get value(){if(this.option.id==="start_from"&&this.option.value!=="00:00"){return this.convertSecondsToTimestamp(this.option.value);} 5724return this.option.value;} 5725async onChangeOption(optionId){this.state.options=this.state.options.map((option)=>{if(option.id===optionId){return{...option,value:!option.value?"00:00":""};} 5726return option;});await this.updateVideo();this.state.urlInput="https:"+this.state.src;} 5727async onClickSuggestion(src){this.state.urlInput=src;await this.updateVideo();} 5728async updateVideo(){if(!this.state.urlInput){this.state.src="";this.state.urlInput="";this.state.options=[];this.state.platform=null;this.state.errorMessage="";this.props.selectMedia({});return;} 5729const embedMatch=this.state.urlInput.match(/(src|href)=["']?([^"']+)?/);if(embedMatch&&embedMatch[2].length>0&&embedMatch[2].indexOf("instagram")){embedMatch[1]=embedMatch[2];} 5730const url=embedMatch?embedMatch[1]:this.state.urlInput;const options={};if(this.props.isForBgVideo&&URL.canParse(url)){const parsedUrl=new URL(url);const urlParams=parsedUrl.searchParams;const startFrom=urlParams.get("start")||urlParams.get("startTime")||urlParams.get("t");Object.keys(this.OPTIONS).forEach((key)=>{options[key]=key==="start_from"?startFrom:true;});}else{for(const option of this.shownOptions){options[option.id]=option.value;}} 5731const{embed_url:src,video_id:videoId,params,platform,}=await this._getVideoURLData(url,options);if(!src){this.state.errorMessage=_t("The provided url is not val
5731id");}else if(!platform){this.state.errorMessage=_t("The provided url does not reference any supported video");}else{this.state.errorMessage="";} 5732this.props.errorMessages(this.state.errorMessage);const newOptions=[];if(platform&&platform!==this.state.platform){Object.keys(this.OPTIONS).forEach((key)=>{if(this.OPTIONS[key].platforms.includes(platform)){const{label,description}=this.OPTIONS[key];newOptions.push({id:key,label,description});}});} 5733this.state.src=src;this.props.selectMedia({id:src,src,platform,videoId,params,});if(platform!==this.state.platform){this.state.platform=platform;this.state.options=newOptions;}} 5734async _getVideoURLData(url,options){return await rpc("/html_editor/video_url/data",{video_url:url,...options,});} 5735static createElements(selectedMedia){return selectedMedia.map((video)=>{const div=document.createElement("div");div.dataset.oeExpression=video.src;div.innerHTML='<div class="css_editable_mode_display"></div>'+'<div class="media_iframe_video_size" contenteditable="false"></div>'+'<iframe frameborder="0" contenteditable="false" allowfullscreen="allowfullscreen"></iframe>';div.querySelector("iframe").src=video.src;return div;});} 5736async prepareVimeoPreviews(){await Promise.all(this.props.vimeoPreviewIds.map(async(videoId)=>{try{const{thumbnail_url:thumbnailSrc}=await this.http.get(`https://vimeo.com/api/oembed.json?url=http%3A//vimeo.com/${encodeURIComponent( 5737 videoId 5738 )}`);this.state.vimeoPreviews.push({id:videoId,thumbnailSrc,src:`https://player.vimeo.com/video/${encodeURIComponent(videoId)}`,});}catch(err){console.warn(`Could not get video #${videoId} from vimeo: ${err}`);}}));} 5739async syncOptionsWithUrl(){await this.updateVideo();if(!URL.canParse(this.state.urlInput)){return;} 5740const parsedUrl=new URL(this.state.urlInput);const urlParams=parsedUrl.searchParams;this.state.options=this.state.options.map((option)=>{const urlParameter=this.OPTIONS[option.id].urlParameter();let value="";switch(urlParameter){case"#t=":value=this.parseTimeToSeconds(this.state.urlInput.split("#t=")[1]);break;case"start":value=urlParams.get("start")||urlParams.get("t");break;case"startTime":value=urlParams.get("startTime")||urlParams.get("start");break;default:value=this.state.urlInput.includes(urlParameter)?"00:00":"";} 5741if(option.id==="start_from"&&value==="0"){return{...option,value:"00:00"};} 5742return{...option,value:value||""};});await this.updateVideo();} 5743convertTimestampToSeconds(timestamp){timestamp=timestamp.trim();const timeRegex=/^(?:(\d+):)?([0-5]?\d):([0-5]?\d)$/;if(timeRegex.test(timestamp)){return(timestamp=timestamp.split(":").reduce((acc,time)=>acc*60+ +time,0)+"");} 5744if(isNaN(timestamp)){return"0";} 5745return timestamp;} 5746convertSecondsToTimestamp(value){if(!value){return"";} 5747const match=value.match(/^\d+s?$/);if(!match){return"";} 5748const totalSeconds=parseInt(match[0],10);if(!Number.isFinite(totalSeconds)||totalSeconds<=0){return value;} 5749const hours=Math.floor(totalSeconds/3600);const minutes=Math.floor((totalSeconds%3600)/60);const seconds=totalSeconds%60;const pad=(n)=>String(n).padStart(2,"0");if(hours>0){return`${hours}:${pad(minutes)}:${pad(seconds)}`;} 5750return`${minutes}:${pad(seconds)}`;} 5751parseTimeToSeconds(value){const match=value?.match(/^(?:(\d+)m(\d+)s|(\d+)m|(\d+)s|(\d+))$/);if(!match){return value;} 5752let minutes=match[1]||match[3];minutes=parseInt(minutes||"0",10);let seconds=match[2]||match[4]||match[5];seconds=parseInt(seconds||"0",10);return String(minutes*60+seconds);}} 5753return __exports;});; 5754 5755/* /website/static/src/components/media_dialog/image_selector.js */ 5756odoo.define('@website/components/media_dialog/image_selector',['@web/core/utils/patch','@html_editor/main/media/media_dialog/image_selector'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{ImageSelector:HtmlImageSelector}=require("@html_editor/main/media/media_dialog/image_selector");patch(HtmlImageSelector.prototype,{get attachmentsDomain(){const domain=super.attachmentsDomain;domain.push("|",["url","=",false],"!",["url","=like","/web/image/website.%"]);domain.push(["key","=",false]);return domain;},});return __exports;});; 5757 5758/* /web_unsplash/static/src/media_dialog/image_selector_patch.js */ 5759odoo.define('@web_unsplash/media_dialog/image_selector_patch',['@web/core/l10n/translation','@web/core/utils/patch','@web/core/utils/concurrency','@web/core/network/rpc','@web/core/utils/hooks','@html_editor/main/media/media_dialog/image_selector','@web_unsplash/unsplash_error/unsplash_error','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web_unsplash",...args);const{patch}=require("@web/core/utils/patch");const{KeepLast}=require("@web/core/utils/concurrency");const{rpc}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const{ImageSelector}=require("@html_editor/main/media/media_dialog/image_selector");const{UnsplashError}=require("@web_unsplash/unsplash_error/unsplash_error");const{useState}=require("@odoo/owl");patch(ImageSelector.prototype,{setup(){super.setup();this.unsplash=useService("unsplash");this.keepLastUnsplash=new KeepLast();this.unsplashState=useState({unsplashRecords:[],isFetchingUnsplash:false,isMaxed:false,unsplashError:null,useUnsplash:true,});this.NUMBER_OF_RECORDS_TO_DISPLAY=30;this.errorMessages={key_not_found:{title:_t("Setup Unsplash to access royalty free photos."),subtitle:"",},401:{title:_t("Unauthorized Key"),subtitle:_t("Please check your Unsplash access key and application ID."),},403:{title:_t("Search is temporarily unavailable"),subtitle:_t("The max number of searches is exceeded. Please retry in an hour or extend to a better account."),},};},get canLoadMore(){if(this.state.searchService==="all"){return(super.canLoadMore||(this.state.needle&&!this.unsplashState.isMaxed&&!this.unsplashState.unsplashError));}else if(this.state.searchService==="unsplash"){return(this.state.needle&&!this.unsplashState.isMaxed&&!this.unsplashState.unsplashError);} 5760return super.canLoadMore;},get hasContent(){if(this.state.searchService==="all"){return super.hasContent||!!this.unsplashState.unsplashRecords.length;}else if(this.state.searchService==="unsplash"){return!!this.unsplashState.unsplashRecords.length;} 5761return super.hasContent;},get errorTitle(){if(this.errorMessages[this.unsplashState.unsplashError]){return this.errorMessages[this.unsplashState.unsplashError].title;} 5762return _t("Something went wrong");},get errorSubtitle(){if(this.errorMessages[this.unsplashState.unsplashError]){return this.errorMessages[this.unsplashState.unsplashError].subtitle;} 5763return _t("Please check your internet connection or contact administrator.");},get selectedRecordIds(){return this.props.selectedMedia[this.props.id].filter((media)=>media.mediaType==="unsplashRecord").map(({id})=>id);},get isFetching(){return super.isFetching||this.unsplashState.isFetchingUnsplash;}
5763,get combinedRecords(){function alternate(a,b){return[a.map((v,i)=>(i<b.length?[v,b[i]]:v)),b.slice(a.length)].flat(2);} 5764return alternate(this.unsplashState.unsplashRecords,this.state.libraryMedia);},get allAttachments(){return[...super.allAttachments,...this.unsplashState.unsplashRecords];},async fetchUnsplashRecords(offset){if(!this.state.needle){return{records:[],isMaxed:false};} 5765this.unsplashState.isFetchingUnsplash=true;try{const{isMaxed,images}=await this.unsplash.getImages(this.state.needle,offset,this.NUMBER_OF_RECORDS_TO_DISPLAY,this.props.orientation);this.unsplashState.isFetchingUnsplash=false;this.unsplashState.unsplashError=false;const existingIds=new Set(this.unsplashState.unsplashRecords.map(r=>r.id));const newImages=images.filter(record=>{if(existingIds.has(record.id)){return false;} 5766existingIds.add(record.id);return true;});const records=newImages.map((record)=>{const url=new URL(record.urls.regular);url.searchParams.set("h",2*this.MIN_ROW_HEIGHT);url.searchParams.delete("w");return Object.assign({},record,{url:url.toString(),mediaType:"unsplashRecord",});});return{isMaxed,records};}catch(e){this.unsplashState.isFetchingUnsplash=false;if(e==="no_access"){this.unsplashState.useUnsplash=false;}else{this.unsplashState.unsplashError=e;} 5767return{records:[],isMaxed:true};}},async loadMore(...args){await super.loadMore(...args);return this.keepLastUnsplash.add(this.fetchUnsplashRecords(this.unsplashState.unsplashRecords.length)).then(({records,isMaxed})=>{this.unsplashState.unsplashRecords.push(...records);this.unsplashState.isMaxed=isMaxed;});},async search(...args){await super.search(...args);await this.searchUnsplash();},async searchUnsplash(){if(!this.state.needle){this.unsplashState.unsplashError=false;this.unsplashState.unsplashRecords=[];this.unsplashState.isMaxed=false;} 5768return this.keepLastUnsplash.add(this.fetchUnsplashRecords(0)).then(({records,isMaxed})=>{this.unsplashState.unsplashRecords=records;this.unsplashState.isMaxed=isMaxed;});},async onClickRecord(media){this.props.selectMedia({...media,mediaType:"unsplashRecord",query:this.state.needle});if(!this.props.multiSelect){await this.props.save();}},async submitCredentials(key,appId){this.unsplashState.unsplashError=null;await rpc("/web_unsplash/save_unsplash",{key,appId});await this.searchUnsplash();},});ImageSelector.components={...ImageSelector.components,UnsplashError,};return __exports;});; 5769 5770/* /web_unsplash/static/src/media_dialog/media_dialog_patch.js */ 5771odoo.define('@web_unsplash/media_dialog/media_dialog_patch',['@html_editor/main/media/media_dialog/media_dialog','@web/core/utils/patch','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{MediaDialog,TABS}=require("@html_editor/main/media/media_dialog/media_dialog");const{patch}=require("@web/core/utils/patch");const{useService}=require("@web/core/utils/hooks");patch(MediaDialog.prototype,{setup(){super.setup();this.unsplashService=useService("unsplash");},async save(){const selectedImages=this.selectedMedia[TABS.IMAGES.id];if(selectedImages){const unsplashRecords=selectedImages.filter((media)=>media.mediaType==="unsplashRecord");if(unsplashRecords.length){await this.unsplashService.uploadUnsplashRecords(unsplashRecords,{resModel:this.props.resModel,resId:this.props.resId},(attachments)=>{this.selectedMedia[TABS.IMAGES.id]=this.selectedMedia[TABS.IMAGES.id].filter((media)=>media.mediaType!=="unsplashRecord");this.selectedMedia[TABS.IMAGES.id]=this.selectedMedia[TABS.IMAGES.id].concat(attachments.map((attachment)=>({...attachment,mediaType:"attachment",})));});}} 5772return super.save(...arguments);},});return __exports;});; 5773 5774/* /web_unsplash/static/src/unsplash_credentials/unsplash_credentials.js */ 5775odoo.define('@web_unsplash/unsplash_credentials/unsplash_credentials',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const UnsplashCredentials=__exports.UnsplashCredentials=class UnsplashCredentials extends Component{static template="web_unsplash.UnsplashCredentials";static props={submitCredentials:Function,hasCredentialsError:Boolean,};setup(){this.state=useState({key:"",appId:"",hasKeyError:this.props.hasCredentialsError,hasAppIdError:this.props.hasCredentialsError,});} 5776submitCredentials(){if(this.state.key===""){this.state.hasKeyError=true;}else if(this.state.appId===""){this.state.hasAppIdError=true;}else{this.props.submitCredentials(this.state.key,this.state.appId);}}} 5777return __exports;});; 5778 5779/* /web_unsplash/static/src/unsplash_error/unsplash_error.js */ 5780odoo.define('@web_unsplash/unsplash_error/unsplash_error',['@odoo/owl','@web_unsplash/unsplash_credentials/unsplash_credentials'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{UnsplashCredentials}=require("@web_unsplash/unsplash_credentials/unsplash_credentials");const UnsplashError=__exports.UnsplashError=class UnsplashError extends Component{static template="web_unsplash.UnsplashError";static components={UnsplashCredentials,};static props={title:String,subtitle:String,showCredentials:Boolean,submitCredentials:{type:Function,optional:true},hasCredentialsError:{type:Boolean,optional:true},};} 5781return __exports;});; 5782 5783/* /web_unsplash/static/src/unsplash_service.js */ 5784odoo.define('@web_unsplash/unsplash_service',['@web/core/network/rpc','@web/core/registry','@web/core/l10n/translation','@html_editor/main/media/media_dialog/upload_progress_toast/upload_service'],function(require){'use strict';let __exports={};const{rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"web_unsplash",...args);const{AUTOCLOSE_DELAY}=require("@html_editor/main/media/media_dialog/upload_progress_toast/upload_service");const unsplashService=__exports.unsplashService={dependencies:["upload"],async start(env,{upload}){const _cache={};return{async uploadUnsplashRecords(records,{resModel,resId},onUploaded){upload.incrementId();
5784const file=upload.addFile({id:upload.fileId,name:records.length>1?_t("Uploading %(count)s '%(query)s' images.",{count:records.length,query:records[0].query,}):_t("Uploading '%s' image.",records[0].query),});try{const urls={};for(const record of records){const _1920Url=new URL(record.urls.regular);_1920Url.searchParams.set("w","1920");urls[record.id]={url:_1920Url.href,download_url:record.links.download_location,description:record.alt_description,};} 5785const xhr=new XMLHttpRequest();xhr.upload.addEventListener("progress",(ev)=>{const rpcComplete=(ev.loaded/ev.total)*100;file.progress=rpcComplete;});xhr.upload.addEventListener("load",function(){file.progress=100;});const attachments=await rpc("/web_unsplash/attachment/add",{res_id:resId,res_model:resModel,unsplashurls:urls,query:records[0].query,},{xhr});if(attachments.error){file.hasError=true;file.errorMessage=attachments.error;}else{file.uploaded=true;await onUploaded(attachments);} 5786setTimeout(()=>upload.deleteFile(file.id),AUTOCLOSE_DELAY);}catch(error){file.hasError=true;setTimeout(()=>upload.deleteFile(file.id),AUTOCLOSE_DELAY);throw error;}},async getImages(query,offset=0,pageSize=30,orientation){const from=offset;const to=offset+pageSize;let cachedData=orientation?_cache[query+orientation]:_cache[query];if(cachedData&&(cachedData.images.length>=to||(cachedData.totalImages!==0&&cachedData.totalImages<to))){return{images:cachedData.images.slice(from,to),isMaxed:to>cachedData.totalImages,};} 5787cachedData=await this._fetchImages(query,orientation);return{images:cachedData.images.slice(from,to),isMaxed:to>cachedData.totalImages,};},async _fetchImages(query,orientation){const key=orientation?query+orientation:query;if(!_cache[key]){_cache[key]={images:[],maxPages:0,totalImages:0,pageCached:0,};} 5788const cachedData=_cache[key];const payload={query:query,page:cachedData.pageCached+1,per_page:30,};if(orientation){payload.orientation=orientation;} 5789const result=await rpc("/web_unsplash/fetch_images",payload);if(result.error){return Promise.reject(result.error);} 5790cachedData.pageCached++;cachedData.images.push(...result.results);cachedData.maxPages=result.total_pages;cachedData.totalImages=result.total;return cachedData;},};},};registry.category("services").add("unsplash",unsplashService);return __exports;});; 5791 5792/* /html_editor/static/src/components/html_viewer/html_viewer.js */ 5793odoo.define('@html_editor/components/html_viewer/html_viewer',['@odoo/owl','@web/core/assets','@web/core/utils/functions','@html_editor/utils/clipboard','@html_editor/utils/sanitize','@html_editor/html_migrations/html_upgrade_manager','@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager','@html_editor/utils/url','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{Component,markup,onMounted,onWillStart,onWillUnmount,onWillUpdateProps,useEffect,useRef,useState,}=require("@odoo/owl");const{getBundle}=require("@web/core/assets");const{memoize}=require("@web/core/utils/functions");const{fillHtmlTransferData}=require("@html_editor/utils/clipboard");const{fixInvalidHTML,instanceofMarkup}=require("@html_editor/utils/sanitize");const{HtmlUpgradeManager}=require("@html_editor/html_migrations/html_upgrade_manager");const{TableOfContentManager}=require("@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager");const{scrollAndHighlightHeading}=require("@html_editor/utils/url");const{browser}=require("@web/core/browser/browser");const HtmlViewer=__exports.HtmlViewer=class HtmlViewer extends Component{static template="html_editor.HtmlViewer";static props={config:{type:Object},migrateHTML:{type:Boolean,optional:true},};static defaultProps={migrateHTML:true,};setup(){this._cleanups=[];this.htmlUpgradeManager=new HtmlUpgradeManager();this.iframeRef=useRef("iframe");this.state=useState({iframeVisible:false,value:this.formatValue(this.props.config.value),});this.components=new Set();onWillUpdateProps((newProps)=>{const newValue=this.formatValue(newProps.config.value);if(newValue.toString()!==this.state.value.toString()){this.state.value=this.formatValue(newProps.config.value);if(this.props.config.embeddedComponents){this.destroyComponents();} 5794if(this.showIframe){this.updateIframeContent(this.state.value);}}});onWillUnmount(()=>{this.destroyComponents();});if(this.showIframe){onMounted(()=>{const onLoadIframe=()=>this.onLoadIframe(this.state.value);this.iframeRef.el.addEventListener("load",onLoadIframe,{once:true});this.iframeRef.el.after(this.iframeRef.el);});}else{this.readonlyElementRef=useRef("readonlyContent");useEffect(()=>{this.processReadonlyContent(this.readonlyElementRef.el);},()=>[this.props.config.value.toString(),this.readonlyElementRef?.el]);} 5795onMounted(()=>{scrollAndHighlightHeading(this.readonlyElementRef?.el||this.iframeRef?.el);});if(this.props.config.cssAssetId){onWillStart(async()=>{this.cssAsset=await getBundle(this.props.config.cssAssetId);});} 5796if(this.props.config.embeddedComponents){this.embeddedComponents=memoize((embeddedComponents=[])=>{const result={};for(const embedding of embeddedComponents){result[embedding.name]=embedding;} 5797return result;});useEffect(()=>{if(this.readonlyElementRef?.el){this.mountComponents();}},()=>[this.props.config.value.toString(),this.readonlyElementRef?.el]);this.tocManager=new TableOfContentManager(this.readonlyElementRef);}} 5798addDomListener(target,eventName,fn,capture=false){const handler=(ev)=>
5798{fn?.call(this,ev);};target.addEventListener(eventName,handler,capture);this._cleanups.push(()=>target.removeEventListener(eventName,handler,capture));} 5799get showIframe(){return this.props.config.hasFullHtml||this.props.config.cssAssetId;} 5800formatValue(value){let newVal=fixInvalidHTML(value);if(this.props.migrateHTML){newVal=this.htmlUpgradeManager.processForUpgrade(newVal,{containsComplexHTML:this.props.config.hasFullHtml,env:this.env,});} 5801if(instanceofMarkup(value)){return markup(newVal);} 5802return newVal;} 5803processReadonlyContent(container){this.retargetLinks(container);this.applyAccessibilityAttributes(container);this.addDomListener(container,"copy",this.onCopy);} 5804onCopy(ev){ev.preventDefault();const selection=ev.target.ownerDocument.defaultView.getSelection();const clonedContents=selection.getRangeAt(0).cloneContents();fillHtmlTransferData(ev,"clipboardData",clonedContents,{textContent:selection.toString(),});} 5805applyAccessibilityAttributes(container){for(const el of container.querySelectorAll("[data-oe-role]")){el.setAttribute("role",el.dataset.oeRole);} 5806for(const el of container.querySelectorAll("[data-oe-aria-label]")){el.setAttribute("aria-label",el.dataset.oeAriaLabel);}} 5807retargetLinks(container){const isInsideIframe=container.ownerDocument!==document;const retargetSelector=isInsideIframe?"a":`a:not([href^="${browser.location.origin}"]):not([href^="/"])`;for(const link of container.querySelectorAll(retargetSelector)){this.retargetLink(link);}} 5808retargetLink(link){link.setAttribute("target","_blank");link.setAttribute("rel","noreferrer");} 5809updateIframeContent(content){const contentWindow=this.iframeRef.el.contentWindow;const iframeTarget=this.props.config.hasFullHtml?contentWindow.document.documentElement:contentWindow.document.querySelector("#iframe_target");iframeTarget.innerHTML=content;this.processReadonlyContent(iframeTarget);} 5810onLoadIframe(value){const contentWindow=this.iframeRef.el.contentWindow;if(!this.props.config.hasFullHtml){contentWindow.document.open("text/html","replace").write(`<!DOCTYPE html><html> 5811 <head> 5812 <meta charset="utf-8"/> 5813 <meta http-equiv="X-UA-Compatible" content="IE=edge"/> 5814 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/> 5815 </head> 5816 <body class="o_in_iframe o_readonly" style="overflow: hidden;"> 5817 <div id="iframe_target"></div> 5818 </body> 5819 </html>`);} 5820if(this.cssAsset){for(const cssLib of this.cssAsset.cssLibs){const link=contentWindow.document.createElement("link");link.setAttribute("type","text/css");link.setAttribute("rel","stylesheet");link.setAttribute("href",cssLib);contentWindow.document.head.append(link);}} 5821this.updateIframeContent(this.state.value);this.state.iframeVisible=true;} 5822destroyComponent({root,host}){const{getEditableDescendants}=this.getEmbedding(host);const editableDescendants=getEditableDescendants?.(host)||{};root.destroy();this.components.delete(arguments[0]);host.append(...Object.values(editableDescendants));} 5823destroyComponents(){for(const cleanup of this._cleanups){cleanup();} 5824for(const info of[...this.components]){this.destroyComponent(info);}} 5825forEachEmbeddedComponentHost(elem,callback){const selector=`[data-embedded]`;const targets=[...elem.querySelectorAll(selector)];if(elem.matches(selector)){targets.unshift(elem);} 5826for(const host of targets){const embedding=this.getEmbedding(host);if(!embedding){continue;} 5827callback(host,embedding);}} 5828getEmbedding(host){return this.embeddedComponents(this.props.config.embeddedComponents)[host.dataset.embedded];} 5829setupNewComponent({name,env,props}){if(name==="tableOfContent"){Object.assign(props,{manager:this.tocManager,});}} 5830mountComponent(host,{Component,getEditableDescendants,getProps,name}){const props=getProps?.(host)||{};const env=Object.create(this.env);if(getEditableDescendants){env.getEditableDescendants=getEditableDescendants;} 5831this.setupNewComponent({name,env,props,});const root=this.__owl__.app.createRoot(Component,{props,env,});const promise=root.mount(host);promise.catch();const fiber=root.node.fiber;const fiberComplete=fiber.complete;fiber.complete=function(){host.replaceChildren();fiberComplete.call(this);};const info={root,host,};this.components.add(info);} 5832mountComponents(){this.forEachEmbeddedComponentHost(this.readonlyElementRef.el,(host,embedding)=>{this.mountComponent(host,embedding);});}} 5833return __exports;});; 5834 5835/* /html_editor/static/src/local_overlay_container.js */ 5836odoo.define('@html_editor/local_overlay_container',['@odoo/owl','@web/core/main_components_container','@web/core/utils/hooks','@web/core/registry','@web/core/registry_hook'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{MainComponentsContainer}=require("@web/core/main_components_container");const{useForwardRefToParent}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const{useRegistry}=require("@web/core/registry_hook");const LocalOverlayContainer=__exports.LocalOverlayContainer=class LocalOverlayContainer extends MainComponentsContainer{static template="html_editor.LocalOverlayContainer";static props={localOverlay:{type:Function,optional:true},identifier:{type:String,optional:true},};static defaultProps={identifier:"overlay_components",};setup(){const overlayComponents=registry.category(this.props.identifier);if(!overlayComponents.validationSchema){overlayComponents.addValidation({Component:{validate:(c)=>c.prototype instanceof Component},props:{type:Object,optional:true},});} 5837this.Components=useRegistry(overlayComponents);useForwardRefToParent("localOverlay");}} 5838return __exports;});; 5839 5840/* /html_editor/static/src/position_hook.js */ 5841odoo.define('@html_editor/position_hook',['@html_editor/utils/dom_traversal','@web/core/utils/timing','@web/core/utils/scrolling','@odoo/owl'],function(require){'use strict';let __exports={};const{ancestors}=require("@html_editor/utils/dom_traversal");const{throttleForAnimation}=require("@web/core/utils/timing");const{couldBeScrollableX,couldBeScrollableY}=require("@web/core/utils/scrolling");const{useComponent,useEffect}=require("@odoo/owl");__exports.usePositionHook=usePositionHook;function usePositionHook(containerRef,document,callback){const comp=useComponent();const onLayoutGeometryChange=throttleForAnimation(callback.bind(comp));const resizeObserver=new ResizeObserver(onLayoutGeometryChange);const cleanups=[];const addDomListener=(target,eventName,capture)=>{target.addEventListener(eventName,onLayoutGeometryChange,capture);cleanups.push(()=>target.removeEventListener(eventName,onLayoutGeometryChange,capture));};useEffect(()=>{if(containerRef.el){resizeObserver.observe(document.body);resizeObserver.observe(containerRef.el);addDomListener(window,"resize");if(document.defaultView!==window){addDomListener(document.defaultView,"resize");} 5842addDomListener(document,"scroll");const scrollableElements=[containerRef.el,...ancestors(containerRef.el)].filter((node)=>couldBeScrollableX(node)||couldBeScrollableY(node));for(const scrollableElement of scrollableElements){addDomListener(scrollableElement,"scroll");resizeObserver.observe(scrollableElement);}} 5843return()=>{resizeObserver.disconnect();for(const cleanup of cleanups.toReversed()){cleanup();cleanups.pop();}};},()=>[containerRef.el]);} 5844return __exports;});; 5845 5846/* /html_editor/static/src/html_migrations/html_migrations_utils.js */ 5847odoo.define('@html_editor/html_migrations/html_migrations_utils',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");__exports.htmlEditorVersions=htmlEditorVersions;function htmlEditorVersions(){return Object.keys(registry.category("html_editor_upgrade").subRegistries).sort(compareVersions);} 5848const VERSION_SELECTOR=__exports.VERSION_SELECTOR="[data-oe-version]";__exports.stripVersion=stripVersion;function stripVersion(element){element.querySelectorAll(VERSION_SELECTOR).forEac
5848h((el)=>{delete el.dataset.oeVersion;});} 5849__exports.compareVersions=compareVersions;function compareVersions(version1,version2){version1=version1.split(".").map((v)=>parseInt(v));version2=version2.split(".").map((v)=>parseInt(v));if(version1[0]<version2[0]||(version1[0]===version2[0]&&version1[1]<version2[1])){return-1;}else if(version1[0]===version2[0]&&version1[1]===version2[1]){return 0;}else{return 1;}} 5850return __exports;});; 5851 5852/* /html_editor/static/src/html_migrations/html_upgrade_manager.js */ 5853odoo.define('@html_editor/html_migrations/html_upgrade_manager',['@odoo/owl','@html_editor/html_migrations/html_migrations_utils','@web/core/registry','@html_editor/utils/sanitize'],function(require){'use strict';let __exports={};const{markup}=require("@odoo/owl");const{compareVersions,VERSION_SELECTOR,htmlEditorVersions,}=require("@html_editor/html_migrations/html_migrations_utils");const{registry}=require("@web/core/registry");const{fixInvalidHTML}=require("@html_editor/utils/sanitize");const HtmlUpgradeManager=__exports.HtmlUpgradeManager=class HtmlUpgradeManager{constructor(){this.upgradeRegistry=registry.category("html_editor_upgrade");this.parser=new DOMParser();this.originalValue=undefined;this.upgradedValue=undefined;this.element=undefined;this.env={};} 5854get value(){return this.upgradedValue;} 5855processForUpgrade(value,{containsComplexHTML,env}={}){this.env=env||{};this.containsComplexHTML=containsComplexHTML;const strValue=value.toString();if(strValue===this.originalValue?.toString()||strValue===this.upgradedValue?.toString()){return this.value;} 5856this.originalValue=value;this.upgradedValue=value;this.element=this.parser.parseFromString(fixInvalidHTML(value),"text/html")[this.containsComplexHTML?"documentElement":"body"];const versionNode=this.element.querySelector(VERSION_SELECTOR);const version=versionNode?.dataset.oeVersion||"0.0";const VERSIONS=htmlEditorVersions();const currentVersion=VERSIONS.at(-1);if(!currentVersion||version===currentVersion){return this.value;} 5857try{const upgradeSequence=VERSIONS.filter((subVersion)=>compareVersions(subVersion,version)>0);this.upgradedValue=this.upgrade(upgradeSequence);}catch{} 5858return this.value;} 5859upgrade(upgradeSequence){for(const version of upgradeSequence){const modules=this.upgradeRegistry.category(version);for(const[key,module]of modules.getEntries()){const migrate=odoo.loader.modules.get(module).migrate;if(!migrate){console.error(`A "${key}" migrate function could not be found at "${module}" or it did not load.`);} 5860migrate(this.element,this.env);}} 5861return markup(this.element[this.containsComplexHTML?"outerHTML":"innerHTML"]);}} 5862return __exports;});; 5863 5864/* /html_editor/static/src/html_migrations/manifest.js */ 5865odoo.define('@html_editor/html_migrations/manifest',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const html_upgrade=registry.category("html_editor_upgrade");html_upgrade.category("1.0");html_upgrade.category("1.1").add("html_editor","@html_editor/html_migrations/migration-1.1");html_upgrade.category("1.2").add("html_editor","@html_editor/html_migrations/migration-1.2");html_upgrade.category("2.0");return __exports;});; 5866 5867/* /html_editor/static/src/html_migrations/migration-1.1.js */ 5868odoo.define('@html_editor/html_migrations/migration-1.1',[],function(require){'use strict';let __exports={};__exports.migrate=migrate;function migrate(container){const excalidrawContainers=container.querySelectorAll("[data-embedded='draw']");for(const excalidrawContainer of excalidrawContainers){const source=JSON.parse(excalidrawContainer.dataset.embeddedProps).source;const newParagraph=document.createElement("P");const anchor=document.createElement("A");newParagraph.append(anchor);anchor.append(document.createTextNode(source));anchor.href=source;excalidrawContainer.after(newParagraph);excalidrawContainer.remove();}} 5869return __exports;});; 5870 5871/* /html_editor/static/src/html_migrations/migration-1.2.js */ 5872odoo.define('@html_editor/html_migrations/migration-1.2',['@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const ARIA_LABELS={".o_editor_banner.alert-danger":_t("Banner Danger"),".o_editor_banner.alert-info":_t("Banner Info"),".o_editor_banner.alert-success":_t("Banner Success"),".o_editor_banner.alert-warning":_t("Banner Warning"),};function getAriaLabel(element){for(const[selector,ariaLabel]of Object.entries(ARIA_LABELS)){if(element.matches(selector)){return ariaLabel;}}} 5873__exports.migrate=migrate;function migrate(container){const bannerContainers=container.querySelectorAll(".o_editor_banner");
5873for(const bannerContainer of bannerContainers){bannerContainer.classList.remove("o_not_editable");bannerContainer.classList.add("o-contenteditable-false");bannerContainer.dataset.oeRole="status";const icon=bannerContainer.querySelector(".o_editor_banner_icon");if(icon){const ariaLabel=getAriaLabel(bannerContainer);if(ariaLabel){icon.dataset.oeAriaLabel=ariaLabel;}} 5874const bannerContent=bannerContainer.querySelector(".o_editor_banner_icon ~ div");if(bannerContent){bannerContent.classList.remove("o_editable");bannerContent.classList.add("o_editor_banner_content");bannerContent.classList.add("o-contenteditable-true");}}} 5875return __exports;});; 5876 5877/* /html_editor/static/src/others/embedded_component_utils.js */ 5878odoo.define('@html_editor/others/embedded_component_utils',['@odoo/owl'],function(require){'use strict';let __exports={};const{onMounted,onRendered,onPatched,onWillDestroy,reactive,toRaw,useComponent,useRef,useState,}=require("@odoo/owl");__exports.getEditableDescendants=getEditableDescendants;function getEditableDescendants(host){const editableDescendants={};for(const candidate of host.querySelectorAll("[data-embedded-editable]")){if(candidate.closest("[data-embedded]")===host){editableDescendants[candidate.dataset.embeddedEditable]=candidate;}} 5879return editableDescendants;} 5880__exports.useEditableDescendants=useEditableDescendants;function useEditableDescendants(host){const component=useComponent();if(!component.env.getEditableDescendants){throw new Error("Missing `getEditableDescendants` function in the `embedding` provided to the `EmbeddedComponentPlugin`.");} 5881const editableDescendants=Object.freeze(component.env.getEditableDescendants(host));const refs={};const renders={};for(const name of Object.keys(editableDescendants)){refs[name]=useRef(name);renders[name]=()=>refs[name].el.replaceChildren(editableDescendants[name]);} 5882let _restoreSelection;const restoreSelection=()=>{if(_restoreSelection){_restoreSelection();_restoreSelection=undefined;}};if(component.env.editorShared?.selection){onRendered(()=>{_restoreSelection=component.env.editorShared.selection.preserveSelection().restore;});} 5883onMounted(()=>{for(const render of Object.values(renders)){render();} 5884restoreSelection();});onPatched(()=>{for(const[name,render]of Object.entries(renders)){if(!host.contains(editableDescendants[name])){render();}} 5885restoreSelection();});return editableDescendants;} 5886function embeddedStateProxyHandler(state,stateChangeManager){return{set(target,key,value,receiver){if(value!==Reflect.get(target,key,receiver)&&!stateChangeManager.previousEmbeddedState){stateChangeManager.previousEmbeddedState=JSON.parse(JSON.stringify(stateChangeManager.embeddedState));} 5887return Reflect.set(target,key,value,receiver);},deleteProperty(target,key){if(Reflect.has(target,key)&&!stateChangeManager.previousEmbeddedState){stateChangeManager.previousEmbeddedState=JSON.parse(JSON.stringify(stateChangeManager.embeddedState));} 5888return Reflect.deleteProperty(target,key);},get(target,key,receiver){Reflect.get(state,key,state);return Reflect.get(target,key,receiver);},ownKeys(target){Reflect.ownKeys(state);return Reflect.ownKeys(target);},has(target,key){Reflect.has(state,key);return Reflect.has(target,key);},};} 5889function observeAllKeys(reactive){for(const key in reactive){const prop=reactive[key];if(prop instanceof Object){observeAllKeys(prop);}}} 5890__exports.getEmbeddedProps=getEmbeddedProps;function getEmbeddedProps(host){return host.dataset.embeddedProps?JSON.parse(host.dataset.embeddedProps):{};} 5891function sortedCopy(obj){const result={};const propNames=Object.keys(obj).sort();for(const propName of propNames){result[propName]=obj[propName];} 5892return result;} 5893__exports.applyObjectPropertyDifference=applyObjectPropertyDifference;function applyObjectPropertyDifference(container,key,previous,next){if(!container[key]){container[key]={};} 5894const obj1={...(previous||{})};const obj2={...(next||{})};const dest=container[key];for(const key in obj2){if(JSON.stringify(obj1[key])!==JSON.stringify(obj2[key])){dest[key]=obj2[key];} 5895delete obj1[key];} 5896for(const key in obj1){delete dest[key];} 5897if(!Object.keys(dest).length&&!next){delete container[key];}} 5898__exports.replaceProperty=replaceProperty;function replaceProperty(container,key,value){if(value===undefined){delete container[key];}else{container[key]=value;}} 5899const StateChangeManager=__exports.StateChangeManager=class StateChangeManager{constructor(config){this.config=config;} 5900setup(){const defaultState=sortedCopy(this.getEmbeddedState());const defaultStateChange={stateChangeId:null,previous:defaultState,next:defaultState,};this.defaultStateChange=defaultStateChange;this.previousStateChange=defaultStateChange;this.batchId=0;this.setupUnmounted();} 5901setupUnmounted(){this.previousEmbeddedState=null;this.state=null;this.embeddedState=null;this.embeddedStateProxy=null;this.isLiveComponent=false;this.batchId+=1;} 5902constructEmbeddedState(state){this.state=state;this.embeddedState=reactive(this.assignDeepProxyCopy({},state),this.batchedChangeState());this.embeddedStateProxy=new Proxy(this.embeddedState,embeddedStateProxyHandler(state,this));observeAllKeys(this.embeddedStateProxy);this.isLiveComponent=true;return this.embeddedStateProxy;} 5903getState(){let state=this.state;if(!this.isLiveComponent){state=this.getEmbeddedState();} 5904return state;} 5905onStateChanged(attrState,{reverse=false,forNewStep=false}={}){const stateChange=attrState?JSON.parse(attrState):this.defaultStateChange;const state=this.getState();if(reverse){this.reverseStateChange(stateChange);} 5906if(!this.areStateChangesEqual(this.previousStateChange,stateChange)){const previous=JSON.stringify(sortedCopy(state));this.commitStateChange(state,stateChange.previous,stateChange.next);const sortedState=sortedCopy(state);this.config.host.dataset.embeddedProps=JSON.stringify(this.stateToEmbeddedProps(this.config.host,sortedState));if(this.isLiveComponent&&!this.previousEmbeddedState){this.assignDeepProxyCopy(toRaw(this.embeddedState),sortedState);} 5907if(!forNewStep){this.previousStateChange=stateChange;}else{const next=JSON.stringify(sortedState);if(previous!==next){this.previousStateChange={stateChangeId:this.generateId(),previous:JSON.parse(previous),next:JSON.parse(next),};return JSON.stringify(this.previousStateChange);}}}} 5908batchedChangeState(){let scheduled=false;const batchId=this.batchId;return async()=>
5908{if(this.isLiveComponent&&!scheduled){scheduled=true;await Promise.resolve();scheduled=false;if(batchId===this.batchId){this.changeState();}}};} 5909changeState(){if(!this.previousEmbeddedState){return;} 5910const previousEmbeddedState=this.previousEmbeddedState;this.previousEmbeddedState=null;const previous=JSON.stringify(sortedCopy(this.state));this.commitStateChange(this.state,previousEmbeddedState,JSON.parse(JSON.stringify(this.embeddedState)));const sortedState=sortedCopy(this.state);const next=JSON.stringify(sortedState);this.assignDeepProxyCopy(toRaw(this.embeddedState),sortedState);if(previous!==next){this.previousStateChange={stateChangeId:this.generateId(),previous:JSON.parse(previous),next:JSON.parse(next),};this.config.host.dataset.embeddedState=JSON.stringify(this.previousStateChange);this.config.host.dataset.embeddedProps=JSON.stringify(this.stateToEmbeddedProps(this.config.host,sortedState));this.config.commitStateChanges();} 5911observeAllKeys(this.embeddedStateProxy);} 5912areStateChangesEqual(sc1,sc2){return(sc1.stateChangeId===sc2.stateChangeId&&JSON.stringify(sc1.previous)===JSON.stringify(sc2.previous)&&JSON.stringify(sc1.next)===JSON.stringify(sc2.next));} 5913reverseStateChange(stateChange){const previous=stateChange.previous;stateChange.previous=stateChange.next;stateChange.next=previous;} 5914assignDeepProxyCopy(target,source){for(const key of Object.keys(target)){delete target[key];} 5915for(const key of Object.keys(source)){target[key]=this.deepProxyCopy(source[key]);} 5916return target;} 5917deepProxyCopy(value){if(value instanceof Object){const copy=value instanceof Array?[]:{};for(const prop in value){copy[prop]=this.deepProxyCopy(value[prop]);} 5918return new Proxy(copy,embeddedStateProxyHandler(value,this));} 5919return value;} 5920generateId(){return Math.floor(Math.random()*Math.pow(2,52));} 5921commitStateChange(state,previous,next){const currentKeys=new Set([...Object.keys(state),...Object.keys(previous),...Object.keys(next),]);for(const key of currentKeys){if(key in(this.config.propertyUpdater||{})){this.config.propertyUpdater[key](state,previous,next);}else if(JSON.stringify(previous[key])!==JSON.stringify(next[key])){replaceProperty(state,key,next[key]);}}} 5922getEmbeddedState(){const host=this.config.host;return this.config.getEmbeddedState?.(host)||getEmbeddedProps(host);} 5923stateToEmbeddedProps(host,state){const props=this.config.stateToEmbeddedProps?.(host,state)||state;for(const key of Object.keys(props)){if(props[key]===undefined){delete props[key];}} 5924return props;}} 5925__exports.useEmbeddedState=useEmbeddedState;function useEmbeddedState(host){const component=useComponent();if(!component.env.getStateChangeManager){throw new Error("Missing `getStateChangeManager` function in the `embedding` provided to the `EmbeddedComponentPlugin`.");} 5926const stateChangeManager=component.env.getStateChangeManager(host);onWillDestroy(()=>stateChangeManager.setupUnmounted());const state=useState(stateChangeManager.getEmbeddedState());return stateChangeManager.constructEmbeddedState(state);} 5927return __exports;});; 5928 5929/* /html_editor/static/src/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar.js */ 5930odoo.define('@html_editor/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useForwardRefToParent}=require("@web/core/utils/hooks");const EmbeddedComponentToolbar=__exports.EmbeddedComponentToolbar=class EmbeddedComponentToolbar extends Component{static props={buttonsGroupClass:{type:String,optional:true},slots:Object,};static template="html_editor.EmbeddedComponentToolbar";} 5931const EmbeddedComponentToolbarButton=__exports.EmbeddedComponentToolbarButton=class EmbeddedComponentToolbarButton extends Component{static props={buttonRef:{type:Function,optional:true},hidden:{type:Boolean,optional:true},icon:{type:String,optional:true},label:String,name:{type:String,optional:true},onClick:Function,title:{type:String,optional:true},};static template="html_editor.EmbeddedComponentToolbarButton";setup(){useForwardRefToParent("buttonRef");}} 5932return __exports;});; 5933 5934/* /html_editor/static/src/others/embedded_components/core/file/readonly_file.js */ 5935odoo.define('@html_editor/others/embedded_components/core/file/readonly_file',['@web/core/l10n/translation','@web/core/network/download','@web/core/file_viewer/file_viewer_hook','@web/core/utils/hooks','@web/core/confirmation_dialog/confirmation_dialog','@html_editor/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar','@html_editor/others/embedded_components/core/file/state_file_model','@html_editor/others/embedded_component_utils','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{downloadFile}=require("@web/core/network/download");const{useFileViewer}=require("@web/core/file_viewer/file_viewer_hook");const{useService}=require("@web/core/utils/hooks");const{AlertDialog}=require("@web/core/confirmation_dialog/confirmation_dialog");const{EmbeddedComponentToolbar,EmbeddedComponentToolbarButton,}=require("@html_editor/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar");const{StateFileModel}=require("@html_editor/others/embedded_components/core/file/state_file_model");const{getEmbeddedProps}=require("@html_editor/others/embedded_component_utils");const{Component,useState}=require("@odoo/owl");const ReadonlyEmbeddedFileComponent=__exports.ReadonlyEmbeddedFileComponent=class ReadonlyEmbeddedFileComponent extends Component{static components={EmbeddedComponentToolbar,EmbeddedComponentToolbarButton,};static props={fileData:{type:Object},host:{type:Object},};static template="html_editor.ReadonlyEmbeddedFile";setup(){this.dialogService=useService("dialog");this.state=useState({fileData:{...this.props.fileData},});this.fileModel=new StateFileModel(this.state);this.attachmentViewer=useFileViewer();} 5936async download(){try{await downloadFile(this.fileModel.downloadUrl);}catch{this.dialogService.add(AlertDialog,{body:_t("Oops, the file %s could not be found. Please replace this file box by a new one to re-upload the file.",this.fileModel.name),title:_t("Missing File"),confirm:()=>{},confirmLabel:_t("Close"),});}} 5937onClickFileImage(){if(this.fileModel.isViewable){this.attachmentViewer.open(this.fileModel);}else{this.download();}}} 5938const readonlyFileEmbedding=__exports.readonlyFileEmbedding={name:"file",Component:ReadonlyEmbeddedFileComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),};return __exports;});; 5939 5940/* /html_editor/static/src/others/embedded_components/core/file/state_file_model.js */ 5941odoo.define('@html_editor/others/embedded_components/core/file/state_file_model',['@web/core/file_viewer/file_model'],function(require){'use strict';let __exports={};const{FileModel}=require("@web/core/file_viewer/file_model");const StateFileModel=__exports.StateFileModel=class StateFileModel extends FileModel{constructor(state){super();this.state=state;for(const property of["access_token","checksum","extension","filename","
5941id","mimetype","name","type","tmpUrl","url","uploading",]){Object.defineProperty(this,property,{get(){return this.state.fileData[property];},set(value){this.state.fileData[property]=value;},configurable:true,enumerable:true,});}} 5942get urlRoute(){if(this.isUrl&&!this.id){return this.url;} 5943return super.urlRoute;}} 5944return __exports;});; 5945 5946/* /html_editor/static/src/others/embedded_components/core/syntax_highlighting/readonly_syntax_highlighting.js */ 5947odoo.define('@html_editor/others/embedded_components/core/syntax_highlighting/readonly_syntax_highlighting',['@odoo/owl','@web/core/assets','@web/core/browser/cookie','@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillStart,xml}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const{cookie}=require("@web/core/browser/cookie");const{DEFAULT_LANGUAGE_ID,getPreValue,highlightPre}=require("@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils");const ReadonlySyntaxHighlightingComponent=__exports.ReadonlySyntaxHighlightingComponent=class ReadonlySyntaxHighlightingComponent extends Component{static props={value:{type:String},languageId:{type:String},host:{type:Object},};static template=xml`<span/>`;setup(){onWillStart(()=>loadBundle(`html_editor.assets_prism${cookie.get("color_scheme") === "dark" ? "_dark" : ""}`,{targetDoc:this.props.host.ownerDocument}));onMounted(()=>{const owlRoot=[...(this.props.host.children||[])].find((child)=>child.nodeName==="OWL-ROOT");highlightPre(owlRoot||this.props.host,this.props.value,this.props.languageId);});}} 5948const readonlySyntaxHighlightingEmbedding=__exports.readonlySyntaxHighlightingEmbedding={name:"readonlySyntaxHighlighting",Component:ReadonlySyntaxHighlightingComponent,getProps:(host)=>({host,languageId:host.dataset.languageId||DEFAULT_LANGUAGE_ID,value:getPreValue(host),}),};return __exports;});; 5949 5950/* /html_editor/static/src/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils.js */ 5951odoo.define('@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils',['@html_editor/utils/dom','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{fillEmpty}=require("@html_editor/utils/dom");const{descendants,lastLeaf}=require("@html_editor/utils/dom_traversal");const DEFAULT_LANGUAGE_ID=__exports.DEFAULT_LANGUAGE_ID="plaintext";const newlinesToLineBreaks=__exports.newlinesToLineBreaks=(element,doc=element.ownerDocument||document)=>{for(const node of descendants(element).filter((node)=>node.nodeType===Node.TEXT_NODE)){let newline=node.textContent.indexOf("\n");while(newline!==-1){node.before(doc.createTextNode(node.textContent.slice(0,newline)));node.before(doc.createElement("BR"));node.textContent=node.textContent.slice(newline+1);newline=node.textContent.indexOf("\n");} 5952if(!node.textContent){node.remove();}} 5953const trailingBr=lastLeaf(element);if(trailingBr?.nodeName==="BR"){element.append(trailingBr);trailingBr.after(doc.createElement("BR"));} 5954fillEmpty(element);};const getPreValue=__exports.getPreValue=(pre)=>{const html=pre.innerHTML;const hasTrailingBr=/<br\s*\/?>$/i.test(html);let text=html.replace(/<br\s*\/?>/gi,"\n").replace(/<span\b[^>]*\bclass=["']oe-tabs["'][^>]*>.*?<\/span>/gi," ").replace(/<[^>]+>|[\u200B\uFEFF]/g,"").replace(/&(amp|lt|gt|#x27|quot|#x60|nbsp);/g,(_,entity)=>({amp:"&",lt:"<",gt:">","#x27":"'",quot:'"',"#x60":"`",nbsp:" "}[entity]));if(hasTrailingBr&&text.endsWith("\n")){text=text.slice(0,-1);} 5955return text;};const highlightPre=__exports.highlightPre=(pre,value,languageId)=>{const fakeElement=pre.ownerDocument.createElement("pre");if(window.Prism){fakeElement.innerHTML=Prism.highlight(value,Prism.languages[languageId],languageId);}else{fakeElement.innerHTML=value;} 5956newlinesToLineBreaks(fakeElement,pre.ownerDocument);[...pre.childNodes].forEach((child)=>child.remove());[...fakeElement.childNodes].forEach((child)=>pre.append(child));};return __exports;});; 5957 5958/* /html_editor/static/src/others/embedded_components/core/table_of_content/table_of_content.js */ 5959odoo.define('@html_editor/others/embedded_components/core/table_of_content/table_of_content',['@odoo/owl','@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager'],function(require){'use strict';let __exports={};const{Component,onWillStart,useState}=require("@odoo/owl");const{TableOfContentManager}=require("@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager");const EmbeddedTableOfContentComponent=__exports.EmbeddedTableOfContentComponent=class EmbeddedTableOfContentComponent extends Component{static template="html_editor.EmbeddedTableOfContent";static props={manager:{type:TableOfContentManager},readonly:{type:Boolean,optional:true},};setup(){this.state=useState({toc:this.props.manager.structure,folded:false});onWillStart(async()=>{await this.props.manager.batchedUpdateStructure();});} 5960displayTocHint(){return this.state.toc.headings.length<2&&!this.props.readonly;} 5961onTocLinkClick(heading){this.props.manager.scrollIntoView(heading);}} 5962const tableOfContentEmbedding=__exports.tableOfContentEmbedding={name:"tableOfContent",Component:EmbeddedTableOfContentComponent,};const readonlyTableOfContentEmbedding=__exports.readonlyTableOfContentEmbedding={name:"tableOfContent",Component:EmbeddedTableOfContentComponent,getProps:(host)=>({readonly:true,}),};return __exports;});; 5963 5964/* /html_editor/static/src/others/embedded_components/core/table_of_content/table_of_content_manager.js */ 5965odoo.define('@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager',['@odoo/owl','@web/core/utils/scrolling'],function(require){'use strict';let __exports={};const{batched,reactive}=require("@odoo/owl");const{closestScrollableY,scrollTo}=require("@web/core/utils/scrolling");const HEADINGS=__exports.HEADINGS=["H1","H2","H3","H4","H5","H6"];const TableOfContentManager=__exports.TableOfContentManager=class TableOfContentManager{constructor(containerRef){this.containerRef
5965=containerRef;this.structure=reactive({headings:[],});this.batchedUpdateStructure=batched(this.updateStructure.bind(this));} 5966getContainerEl(){return this.containerRef.el;} 5967fetchValidHeadings(element){const inEmbeddedHeadings=new Set(element.querySelectorAll(HEADINGS.map((heading)=>`[data-embedded] ${heading}`).join(",")));return Array.from(element.querySelectorAll(HEADINGS.join(","))).filter((heading)=>heading.innerText.trim().replaceAll("\u200B","").length>0).filter((heading)=>!inEmbeddedHeadings.has(heading));} 5968scrollIntoView(heading){if(!heading){return;} 5969const{target}=heading;let offset=0;const scrollable=closestScrollableY(target);if(scrollable){for(const el of scrollable.children){const{position,top,height}=getComputedStyle(el);if(position==="sticky"&&parseInt(top)===0){offset=Math.max(offset,parseInt(height));}} 5970const{top,bottom}=scrollable.getBoundingClientRect();const scrollableOffset=(bottom-top)/3;const{top:targetTop}=target.getBoundingClientRect();offset=top>targetTop?-scrollableOffset-offset:scrollableOffset*2;scrollTo(target,{behavior:"smooth",offset:offset}).then(()=>{scrollTo(target,{behavior:"smooth"});});} 5971target.classList.add("o_embedded_toc_header_highlight");window.setTimeout(()=>{target.classList.remove("o_embedded_toc_header_highlight");},2000);} 5972updateStructure(){const container=this.getContainerEl();if(!container){return;} 5973const tagDepthStack=[];this.structure.headings=this.fetchValidHeadings(container).map((heading)=>{while(tagDepthStack.at(-1)>=heading.tagName){tagDepthStack.pop();} 5974const depth=tagDepthStack.length;tagDepthStack.push(heading.tagName);return{depth,name:heading.innerText,target:heading,};});}} 5975return __exports;});; 5976 5977/* /html_editor/static/src/others/embedded_components/core/toggle_block/toggle_block.js */ 5978odoo.define('@html_editor/others/embedded_components/core/toggle_block/toggle_block',['@html_editor/others/embedded_component_utils','@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{getEditableDescendants,getEmbeddedProps,useEditableDescendants,}=require("@html_editor/others/embedded_component_utils");const{browser}=require("@web/core/browser/browser");const{Component,useEffect,useExternalListener,useState}=require("@odoo/owl");const sessionStorage=browser.sessionStorage;const EmbeddedToggleBlockComponent=__exports.EmbeddedToggleBlockComponent=class EmbeddedToggleBlockComponent extends Component{static template="html_editor.EmbeddedToggleBlock";static props={host:{type:Object},toggleBlockId:{type:String},};setup(){useEditableDescendants(this.props.host);this.state=useState({showContent:sessionStorage.getItem(this.toggleStorageKey)==="true",});this.neutralRestoreSelection=()=>{};this.restoreSelection=this.neutralRestoreSelection;useExternalListener(this.props.host,"forceToggle",this.onToggle);useEffect(()=>{this.restoreSelection();this.restoreSelection=this.neutralRestoreSelection;},()=>[this.restoreSelection]);} 5979get toggleStorageKey(){return`html_editor.ToggleBlock${this.props.toggleBlockId}.showContent`;} 5980onToggle(ev){let{showContent,restoreSelection}=ev.detail??{};showContent??=!this.state.showContent;restoreSelection??=this.neutralRestoreSelection;if(this.state.showContent!==showContent){this.restoreSelection=restoreSelection;this.state.showContent=showContent;sessionStorage.setItem(this.toggleStorageKey,this.state.showContent);}else{restoreSelection();}}} 5981const toggleBlockEmbedding=__exports.toggleBlockEmbedding={name:"toggleBlock",Component:EmbeddedToggleBlockComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),getEditableDescendants:getEditableDescendants,};return __exports;});; 5982 5983/* /html_editor/static/src/others/embedded_components/core/video/readonly_video.js */ 5984odoo.define('@html_editor/others/embedded_components/core/video/readonly_video',['@html_editor/others/embedded_component_utils','@html_editor/utils/url','@odoo/owl'],function(require){'use strict';let __exports={};const{getEmbeddedProps}=require("@html_editor/others/embedded_component_utils");const{getVideoUrl}=require("@html_editor/utils/url");const{Component}=require("@odoo/owl");const ReadonlyEmbeddedVideoComponent=__exports.ReadonlyEmbeddedVideoComponent=class ReadonlyEmbeddedVideoComponent extends Component{static template="html_editor.EmbeddedVideo";static props={platform:{type:String},videoId:{type:String},params:{type:Object,optional:true},};get url(){return getVideoUrl(this.props.platform,this.props.videoId,this.props.params).toString();}} 5985const readonlyVideoEmbedding=__exports.readonlyVideoEmbedding={name:"video",Component:ReadonlyEmbeddedVideoComponent,getProps:(host)=>({...getEmbeddedProps(host)}),};return __exports;});; 5986 5987/* /html_editor/static/src/utils/base_container.js */ 5988odoo.define('@html_editor/utils/base_container',[],function(require){'use strict';let __exports={};const BASE_CONTAINER_CLASS=__exports.BASE_CONTAINER_CLASS="o-paragraph";const SUPPORTED_BASE_CONTAINER_NAMES=__exports.SUPPORTED_BASE_CONTAINER_NAMES=["P","DIV"];__exports.getBaseContainerSelector=getBaseContainerSelector;
5988function getBaseContainerSelector(nodeName){if(!nodeName){return baseContainerGlobalSelector;} 5989nodeName=SUPPORTED_BASE_CONTAINER_NAMES.includes(nodeName)?nodeName:"P";let suffix="";if(nodeName!=="P"){suffix=`.${BASE_CONTAINER_CLASS}`;} 5990return`${nodeName}${suffix}`;} 5991const baseContainerGlobalSelector=__exports.baseContainerGlobalSelector=`:is(${SUPPORTED_BASE_CONTAINER_NAMES.map((name) => 5992 getBaseContainerSelector(name) 5993).join(",")})`;__exports.createBaseContainer=createBaseContainer;function createBaseContainer(nodeName,document){if(!document&&window){document=window.document;} 5994nodeName=nodeName&&SUPPORTED_BASE_CONTAINER_NAMES.includes(nodeName)?nodeName:"P";const el=document.createElement(nodeName);if(nodeName!=="P"){el.className=BASE_CONTAINER_CLASS;} 5995return el;} 5996return __exports;});; 5997 5998/* /html_editor/static/src/utils/blocks.js */ 5999odoo.define('@html_editor/utils/blocks',['@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{closestPath,findNode}=require("@html_editor/utils/dom_traversal");const blockTagNames=["ADDRESS","ARTICLE","ASIDE","BLOCKQUOTE","DETAILS","DIALOG","DD","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","LI","MAIN","NAV","OL","P","PRE","SECTION","TABLE","UL","SELECT","OPTION","TR","TD","TBODY","THEAD","TH",];const computedStyleDisplayCache=new WeakMap();__exports.isBlock=isBlock;function isBlock(node){if(!node||node.nodeType!==Node.ELEMENT_NODE){return false;} 6000const tagName=node.nodeName.toUpperCase();if(tagName==="BR"){return false;} 6001if(!node.isConnected){return blockTagNames.includes(tagName);} 6002let display=computedStyleDisplayCache.get(node);if(display===undefined){const style=node.ownerDocument.defaultView.getComputedStyle(node);display=style.display;computedStyleDisplayCache.set(node,display);} 6003if(display&&display!=="none"){return!display.includes("inline")&&display!=="contents";} 6004return blockTagNames.includes(tagName);} 6005__exports.closestBlock=closestBlock;function closestBlock(node){return findNode(closestPath(node),(node)=>isBlock(node));} 6006return __exports;});; 6007 6008/* /html_editor/static/src/utils/clipboard.js */ 6009odoo.define('@html_editor/utils/clipboard',[],function(require){'use strict';let __exports={};function prependOriginToImages(doc,origin){doc.querySelectorAll("img").forEach((img)=>{const src=img.getAttribute("src");if(src&&!/^(http|\/\/|data:)/.test(src)){img.src=origin+(src.startsWith("/")?src:"/"+src);}});} 6010__exports.fillHtmlTransferData=fillHtmlTransferData;function fillHtmlTransferData(ev,transferObjectProperty,clonedContents,{setEditorTransferData=true,textContent}={}){const doc=ev.target.ownerDocument;const dataHtmlElement=doc.createElement("data");dataHtmlElement.append(clonedContents);prependOriginToImages(dataHtmlElement,doc.defaultView.location.origin);const htmlContent=dataHtmlElement.innerHTML;if(textContent){ev[transferObjectProperty].setData("text/plain",textContent);} 6011ev[transferObjectProperty].setData("text/html",htmlContent);if(setEditorTransferData){ev[transferObjectProperty].setData("application/vnd.odoo.odoo-editor",htmlContent);}} 6012return __exports;});; 6013 6014/* /html_editor/static/src/utils/color.js */ 6015odoo.define('@html_editor/utils/color',['@html_editor/utils/dom_traversal','@web/core/utils/colors','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{closestElement}=require("@html_editor/utils/dom_traversal");const{isColorGradient}=require("@web/core/utils/colors");const{isElement}=require("@html_editor/utils/dom_info");const COLOR_PALETTE_COMPATIBILITY_COLOR_NAMES=__exports.COLOR_PALETTE_COMPATIBILITY_COLOR_NAMES=["primary","secondary","alpha","beta","gamma","delta","epsilon","success","info","warning","danger",];const DEFAULT_PALETTE=__exports.DEFAULT_PALETTE={1:"#3AADAA",2:"#7C6576",3:"#F6F6F6",4:"#FFFFFF",5:"#383E45",};const EDITOR_COLOR_CSS_VARIABLES=__exports.EDITOR_COLOR_CSS_VARIABLES=[...COLOR_PALETTE_COMPATIBILITY_COLOR_NAMES];for(let i=1;i<=5;i++){EDITOR_COLOR_CSS_VARIABLES.push(`o-color-${i}`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-bg`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-bg-gradient`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-headings`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-text`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-btn-primary`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-btn-primary-text`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-btn-secondary`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-btn-secondary-text`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-btn-primary-border`);EDITOR_COLOR_CSS_VARIABLES.push(`o-cc${i}-btn-secondary-border`);} 6016for(let i=100;i<=900;
6016i+=100){EDITOR_COLOR_CSS_VARIABLES.push(`${i}`);} 6017EDITOR_COLOR_CSS_VARIABLES.push("black","black-15","black-25","black-50","black-75","white","white-25","white-50","white-75","white-85");__exports.isColorCombinationName=isColorCombinationName;function isColorCombinationName(name){const number=parseInt(name);return!isNaN(number)&&number%100!==0;} 6018const TEXT_CLASSES_REGEX=__exports.TEXT_CLASSES_REGEX=/\btext-(primary|secondary|success|danger|warning|info|light|dark|body|muted|white|black|reset|gradient|opacity-\d{1,3}|o-[^\s]+|\d+)\b/;const BG_CLASSES_REGEX=__exports.BG_CLASSES_REGEX=/\bbg-[^\s]*\b/;const COLOR_COMBINATION_CLASSES_REGEX=__exports.COLOR_COMBINATION_CLASSES_REGEX=/\bo_cc[0-9]+\b/g;__exports.hasTextColorClass=hasTextColorClass;function hasTextColorClass(element,mode){if(!element||!isElement(element)){return false;} 6019const classRegex=mode==="color"?TEXT_CLASSES_REGEX:BG_CLASSES_REGEX;const parent=element.parentNode;return(classRegex.test(element.className)&&(!parent||getComputedStyle(element)[mode]!==getComputedStyle(parent)[mode]));} 6020__exports.hasColor=hasColor;function hasColor(element,mode){const style=element.style;const parent=element.parentNode;if(element.classList.contains("btn")||element.tagName==="A"){return false;} 6021if(isColorGradient(style["background-image"])){if(element.classList.contains("text-gradient")){if(mode==="color"){return true;}}else{if(mode!=="color"){return true;}}} 6022return((style[mode]&&style[mode]!=="inherit"&&(!parent||style[mode]!==parent.style[mode]))||hasTextColorClass(element,mode));} 6023__exports.hasAnyNodesColor=hasAnyNodesColor;function hasAnyNodesColor(nodes,mode){for(const node of nodes){if(hasColor(closestElement(node),mode)){return true;}} 6024return false;} 6025__exports.getTextColorOrClass=getTextColorOrClass;function getTextColorOrClass(node){if(!node){return null;} 6026if(node.style.color){return{type:"style",value:node.style.color};} 6027const textColorClass=[...node.classList].find((cls)=>TEXT_CLASSES_REGEX.test(cls));if(textColorClass){return{type:"class",value:textColorClass};} 6028return null;} 6029return __exports;});; 6030 6031/* /html_editor/static/src/utils/content_types.js */ 6032odoo.define('@html_editor/utils/content_types',[],function(require){'use strict';let __exports={};const CTYPES=__exports.CTYPES={CONTENT:1,SPACE:2,BLOCK_OUTSIDE:4,BLOCK_INSIDE:8,BR:16,};__exports.ctypeToString=ctypeToString;function ctypeToString(ctype){return Object.keys(CTYPES).find((key)=>CTYPES[key]===ctype);} 6033const CTGROUPS=__exports.CTGROUPS={INLINE:CTYPES.CONTENT|CTYPES.SPACE,BLOCK:CTYPES.BLOCK_OUTSIDE|CTYPES.BLOCK_INSIDE,BR:CTYPES.BR,};return __exports;});; 6034 6035/* /html_editor/static/src/utils/dom.js */ 6036odoo.define('@html_editor/utils/dom',['@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/selection','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/utils/base_container'],function(require){'use strict';let __exports={};const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{isElement,isEmptyTextNode,isParagraphRelatedElement,isShrunkBlock,isTextNode,isVisible,nextLeaf,previousLeaf,}=require("@html_editor/utils/dom_info");const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{isEmptyBlock,isPhrasingContent}=require("@html_editor/utils/dom_info");const{childNodes,descendants}=require("@html_editor/utils/dom_traversal");const{childNodeIndex,DIRECTIONS,nodeSize}=require("@html_editor/utils/position");const{baseContainerGlobalSelector,createBaseContainer,}=require("@html_editor/utils/base_container");__exports.makeContentsInline=makeContentsInline;function makeContentsInline(node){const document=node.ownerDocument;let currentNode=node.firstChild;while(currentNode){if(isBlock(currentNode)){if(currentNode.previousSibling&&isParagraphRelatedElement(currentNode)){currentNode.before(document.createElement("br"));} 6037currentNode=unwrapContents(currentNode)[0];}else{currentNode=currentNode.nextSibling;}}} 6038__exports.wrapInlinesInBlocks=wrapInlinesInBlocks;function wrapInlinesInBlocks(element,{baseContainerNodeName="P",cursors={update:()=>{}}}={}
6038){const wrapInBlock=(node,cursors)=>{const block=isPhrasingContent(node)?createBaseContainer(baseContainerNodeName,node.ownerDocument):node.ownerDocument.createElement("DIV");cursors.update(callbacksForCursorUpdate.append(block,node));cursors.update(callbacksForCursorUpdate.before(node,block));if(node.nextSibling){const sibling=node.nextSibling;node.remove();sibling.before(block);}else{const parent=node.parentElement;node.remove();parent.append(block);} 6039block.append(node);return block;};const appendToCurrentBlock=(currentBlock,node,cursors)=>{if(currentBlock.matches(baseContainerGlobalSelector)&&!isPhrasingContent(node)){const block=currentBlock.ownerDocument.createElement("DIV");cursors.update(callbacksForCursorUpdate.before(currentBlock,block));currentBlock.before(block);for(const child of childNodes(currentBlock)){cursors.update(callbacksForCursorUpdate.append(block,child));block.append(child);} 6040cursors.update(callbacksForCursorUpdate.remove(currentBlock));currentBlock.remove();currentBlock=block;} 6041cursors.update(callbacksForCursorUpdate.append(currentBlock,node));currentBlock.append(node);return currentBlock;};const removeNode=(node,cursors)=>{cursors.update(callbacksForCursorUpdate.remove(node));node.remove();};const children=childNodes(element);const visibleNodes=new Set(children.filter(isVisible));let currentBlock;let shouldBreakLine=true;for(const node of children){if(isBlock(node)){shouldBreakLine=true;}else if(!visibleNodes.has(node)){removeNode(node,cursors);}else if(node.nodeName==="BR"){if(shouldBreakLine){wrapInBlock(node,cursors);}else{removeNode(node,cursors);shouldBreakLine=true;}}else if(shouldBreakLine){currentBlock=wrapInBlock(node,cursors);shouldBreakLine=false;}else{currentBlock=appendToCurrentBlock(currentBlock,node,cursors);}}} 6042__exports.unwrapContents=unwrapContents;function unwrapContents(node){const contents=childNodes(node);for(const child of contents){node.parentNode.insertBefore(child,node);} 6043node.parentNode.removeChild(node);return contents;} 6044__exports.removeClass=removeClass;function removeClass(element,...classNames){const classNamesSet=new Set(classNames);if([...element.classList].every((className)=>classNamesSet.has(className))){element.removeAttribute("class");}else{element.classList.remove(...classNames);}} 6045__exports.removeStyle=removeStyle;function removeStyle(element,...styleProperties){styleProperties.forEach((prop)=>element.style.removeProperty(prop));if(element.getAttribute("style")===""){element.removeAttribute("style");}} 6046__exports.fillEmpty=fillEmpty;function fillEmpty(el){const document=el.ownerDocument;if(!isVisible(el)&&!el.hasAttribute("data-oe-zws-empty-inline")&&!isBlock(el)){const zws=document.createTextNode("\u200B");el.appendChild(zws);el.setAttribute("data-oe-zws-empty-inline","");const previousSibling=el.previousSibling;if(previousSibling&&previousSibling.nodeName==="BR"){previousSibling.remove();} 6047return{zws};}else{return fillShrunkPhrasingParent(el);}} 6048__exports.fillShrunkPhrasingParent=fillShrunkPhrasingParent;function fillShrunkPhrasingParent(el){const document=el.ownerDocument;const fillers={};const blockEl=closestBlock(el);if(isShrunkBlock(blockEl)){const br=document.createElement("br");blockEl.appendChild(br);fillers.br=br;} 6049return fillers;} 6050__exports.cleanTrailingBR=cleanTrailingBR;function cleanTrailingBR(el,predicates=[]){const candidate=el?.lastChild;if(candidate?.nodeName==="BR"&&candidate.previousSibling?.nodeName!=="BR"&&!isEmptyBlock(el)&&!predicates.some((predicate)=>predicate(candidate))){candidate.remove();return candidate;}} 6051__exports.toggleClass=toggleClass;function toggleClass(element,className,force){element.classList.toggle(className,force);if(!element.className){element.removeAttribute("class");}} 6052__exports.cleanEmptyAncestors=cleanEmptyAncestors;function cleanEmptyAncestors(node,cursors,exclude=()=>false){let currentNode=node;while(currentNode&&!nodeSize(currentNode)&&!exclude(currentNode)){cursors?.update(callbacksForCursorUpdate.remove(currentNode));const parent=currentNode.parentNode;currentNode.remove();currentNode=parent;}} 6053__exports.cleanTextNode=cleanTextNode;function cleanTextNode(node,char,cursors){const removedIndexes=[];node.textContent=node.textContent.replaceAll(char,(_,offset)=>{removedIndexes.push(offset);return"";});if(isEmptyTextNode(node)){cursors?.update(callbacksForCursorUpdate.remove(node));node.remove();}else{cursors?.update((cursor)=>{if(cursor.node===node){cursor.offset-=removedIndexes.filter((index)=>cursor.offset>index).length;}});}} 6054__exports.removeEmptyTextNodes=removeEmptyTextNodes;function removeEmptyTextNodes(root,cursors){for(const node of childNodes(root).filter((n)=>isEmptyTextNode(n))){cursors?.update(callbacksForCursorUpdate.remove(node));node.remove();}} 6055__exports.splitTextNode=splitTextNode;function splitTextNode(textNode,offset,originalNodeSide=DIRECTIONS.RIGHT){const document=textNode.ownerDocument;let parentOffset=childNodeIndex(textNode);
6055if(offset>0){parentOffset++;if(offset<textNode.length){const left=textNode.nodeValue.substring(0,offset);const right=textNode.nodeValue.substring(offset);if(originalNodeSide===DIRECTIONS.LEFT){const newTextNode=document.createTextNode(right);textNode.after(newTextNode);textNode.nodeValue=left;}else{const newTextNode=document.createTextNode(left);textNode.before(newTextNode);textNode.nodeValue=right;}}} 6056return parentOffset;} 6057__exports.removeInvisibleWhitespace=removeInvisibleWhitespace;function removeInvisibleWhitespace(el,cursors){const whitespaceRegex=/[^\S\u00A0\uFEFF]/;const[countLeadingWhitespace,countTrailingWhitespace]=[new RegExp(`^${whitespaceRegex.source}+`),new RegExp(`${whitespaceRegex.source}+$`),].map((regex)=>(node)=>node?.textContent.match(regex)?.[0]?.length||0);const isInlineElement=(node)=>node?.nodeType===Node.ELEMENT_NODE&&!isBlock(node);const textChildren=descendants(el).filter((child)=>child.nodeType===Node.TEXT_NODE);let removedTrailingSpaceBefore=false;let index=0;for(const child of textChildren){let leadingWhitespace=countLeadingWhitespace(child);let trailingWhitespace=countTrailingWhitespace(child);const previous=previousLeaf(child,el);if(leadingWhitespace&&previous&&(isInlineElement(child.previousSibling)||removedTrailingSpaceBefore)){leadingWhitespace-=1;}else if(trailingWhitespace&&index!==textChildren.length-1&&isInlineElement(child.nextSibling)&&!countTrailingWhitespace(nextLeaf(child,el))){trailingWhitespace-=1;} 6058removedTrailingSpaceBefore=!!trailingWhitespace;cursors?.shiftOffset(child,-leadingWhitespace);child.textContent=child.textContent.substring(leadingWhitespace,child.textContent.length-trailingWhitespace||leadingWhitespace).replace(new RegExp(`^${whitespaceRegex.source}+`)," ").replace(new RegExp(`${whitespaceRegex.source}+$`)," ");if(!child.textContent){child.remove();} 6059index+=1;}} 6060__exports.mergeAdjacentTextNodes=mergeAdjacentTextNodes;function mergeAdjacentTextNodes(node,cursor){let child=node.firstChild;while(child){if(isElement(child)){mergeAdjacentTextNodes(child,cursor);} 6061const next=child.nextSibling;if(isTextNode(child)&&next&&isTextNode(next)){if(cursor.anchor.node===next){cursor.anchor.node=child;cursor.anchor.offset=child.textContent.length+cursor.anchor.offset;} 6062if(cursor.focus.node===next){cursor.focus.node=child;cursor.focus.offset=child.textContent.length+cursor.focus.offset;} 6063child.textContent+=next.textContent;next.remove();}else{child=next;}}} 6064return __exports;});; 6065 6066/* /html_editor/static/src/utils/dom_info.js */ 6067odoo.define('@html_editor/utils/dom_info',['@html_editor/utils/base_container','@html_editor/utils/blocks','@html_editor/utils/dom_traversal','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{childNodes,closestElement,firstLeaf,lastLeaf}=require("@html_editor/utils/dom_traversal");const{childNodeIndex,DIRECTIONS,nodeSize}=require("@html_editor/utils/position");__exports.isEmpty=isEmpty;function isEmpty(el){if(isProtecting(el)||isProtected(el)){return false;} 6068const content=el.innerHTML.trim();if(content===""||content==="<br>"){return true;} 6069return false;} 6070__exports.isEmptyTextNode=isEmptyTextNode;function isEmptyTextNode(node){if(node.nodeType!==Node.TEXT_NODE){return false;} 6071if(!node.textContent){return true;} 6072const trimmedContent=node.textContent.trim();if(!trimmedContent){if(node.textContent.includes("\n")){return true;} 6073if(node.textContent){return false;}} 6074return!trimmedContent;} 6075__exports.isBold=isBold;function isBold(node){const fontWeight=+getComputedStyle(closestElement(node)).fontWeight;const referenceElement=closestElement(node,(el)=>isBlock(el)||+getComputedStyle(el).fontWeight!==fontWeight);return fontWeight>500||fontWeight>+getComputedStyle(referenceElement).fontWeight;} 6076__exports.isItalic=isItalic;function isItalic(node){return getComputedStyle(closestElement(node)).fontStyle==="italic";} 6077__exports.isUnderline=isUnderline;function isUnderline(node){let parent=closestElement(node);while(parent){if(getComputedStyle(parent).textDecorationLine.includes("underline")){return true;} 6078parent=parent.parentElement;} 6079return false;} 6080__exports.isStrikeThrough=isStrikeThrough;function isStrikeThrough(node){let parent=closestElement(node);while(parent){if(!parent.classList.contains("o_checked")&&getComputedStyle(parent).textDecorationLine.includes("line-through")){return true;} 6081parent=parent.parentElement;} 6082return false;} 6083__exports.isFontSize=isFontSize;function isFontSize(node,props){const element=closestElement(node);return getComputedStyle(element)["font-size"]===props.size;} 6084__exports.hasClass=hasClass;function hasClass(node,props){const element=closestElement(node);return element.classList.contains(props.className);} 6085__exports.isDirectionSwitched=isDirectionSwitched;function isDirectionSwitched(node,editable){const defaultDirection=editable.getAttribute("dir")||"ltr";return getComputedStyle(closestElement(node)).direction!==defaultDirection;} 6086__exports.isRow=isRow;function isRow(node){return["TH","TD"].includes(node.tagName);} 6087__exports.isZWS=isZWS;function isZWS(node){return node&&node.textContent==="\u200B";} 6088__exports.isInPre=isInPre;function isInPre(node){const element=node.nodeType===Node.TEXT_NODE?node.parentElement:node;return(!!element&&(!!element.closest("pre")||getComputedStyle(element).getPropertyValue("white-space")==="pre"));} 6089const ZERO_WIDTH_CHARS=__exports.ZERO_WIDTH_CHARS=["\u200b","\ufeff"];const whitespace=__exports.whitespace=`[^\\S\\u00A0\\u0009\\ufeff]`;const whitespaceRegex=new RegExp(`^${whitespace}*$`);__exports.isWhitespace=isWhitespace;function isWhitespace(value){const str=typeof value==="string"?value:value.nodeValue;return whitespaceRegex.test(str);} 6090const visibleCharRegex=/[^\s\u200b]|[\u00A0\u0009]$/;__exports.isVisibleTextNode=isVisibleTextNode;function isVisibleTextNode(testedNode){if(!testedNode||!testedNode.length||testedNode.nodeType!==Node.TEXT_NODE){return false;} 6091if(isProtected(testedNode)){return true;} 6092if(visibleCharRegex.test(testedNode.textContent)||(isInPre(testedNode)&&isWhitespace(testedNode))){return true;} 6093if(ZERO_WIDTH_CHARS.includes(testedNode.textContent)){return false;} 6094let preceding;let following;let foundTestedNode;const currentNodeParentBlock=closestBlock(testedNode);if(!currentNodeParentBlock){return false;} 6095const nodeIterator=document.createNodeIterator(currentNodeParentBlock);for(let node=nodeIterator.nextNode();node;node=nodeIterator.nextNode()){if(node.nodeType===Node.TEXT_NODE){if(foundTestedNode){following=node;break;}else if(testedNode===node){foundTestedNode=true;}else{preceding=node;}}else if(isBlock(node)){if(foundTestedNode){break;}else{preceding=null;}}else if(foundTestedNode&&!isWhitespace(node)){following=node;break;}} 6096while(following&&!visibleCharRegex.test(following.textContent)){following=following.nextSibling;}
6097if(!(preceding&&following)||currentNodeParentBlock!==closestBlock(preceding)||currentNodeParentBlock!==closestBlock(following)){return false;} 6098return!isWhitespace(preceding);} 6099const selfClosingElementTags=["BR","IMG","INPUT","HR"];__exports.isSelfClosingElement=isSelfClosingElement;function isSelfClosingElement(node){return node&&selfClosingElementTags.includes(node.nodeName);} 6100__exports.isVisible=isVisible;function isVisible(node){return(!!node&&((node.nodeType===Node.TEXT_NODE&&isVisibleTextNode(node))||isSelfClosingElement(node)||isMediaElement(node)||hasVisibleContent(node)||isProtecting(node)||isEmbeddedComponent(node)||(node.nodeName==="TD"&&!!closestElement(node,"table.o_table"))));} 6101__exports.hasVisibleContent=hasVisibleContent;function hasVisibleContent(node){return(node?childNodes(node):[]).some((n)=>isVisible(n));} 6102__exports.isButton=isButton;function isButton(node){if(!node||node.nodeType!==Node.ELEMENT_NODE){return false;} 6103return node.nodeName==="BUTTON"||node.classList.contains("btn");} 6104__exports.isZwnbsp=isZwnbsp;function isZwnbsp(node){return node?.nodeType===Node.TEXT_NODE&&node.textContent==="\ufeff";} 6105__exports.isTangible=isTangible;function isTangible(node){return isVisible(node)||isZwnbsp(node)||hasTangibleContent(node);} 6106__exports.hasTangibleContent=hasTangibleContent;function hasTangibleContent(node){return(node?childNodes(node):[]).some((n)=>isTangible(n));} 6107const isNotEditableNode=__exports.isNotEditableNode=(node)=>node.getAttribute&&node.getAttribute("contenteditable")&&node.getAttribute("contenteditable").toLowerCase()==="false";const iconTags=["I","SPAN"];const iconClasses=__exports.iconClasses=["fa","fab","fad","far","oi"];const ICON_SELECTOR=__exports.ICON_SELECTOR=iconTags.map((tag)=>iconClasses.map((cls)=>`${tag}.${cls}`).join(", ")).join(", ");const MEDIA_SELECTOR=__exports.MEDIA_SELECTOR=`${ICON_SELECTOR}, .media_iframe_video, .o_file_box`;const EDITABLE_MEDIA_CLASS=__exports.EDITABLE_MEDIA_CLASS="o_editable_media";__exports.isIconElement=isIconElement;function isIconElement(node){return!!(node&&iconTags.includes(node.nodeName)&&iconClasses.some((cls)=>node.classList.contains(cls)));} 6108__exports.isMediaElement=isMediaElement;function isMediaElement(node){return(isIconElement(node)||(node.classList&&(node.classList.contains("o_file_box")||node.classList.contains("media_iframe_video")))||node.nodeName==="CANVAS");} 6109__exports.hasMediaOnly=hasMediaOnly;function hasMediaOnly(mediaContainerEl,requiresSingleMedia=false){const nonEmptyContent=[...mediaContainerEl.childNodes].filter((node)=>node.tagName!=="BR"&&(node.nodeType!==Node.TEXT_NODE||node.textContent.replaceAll(/\s+/g,"")));if(requiresSingleMedia&&nonEmptyContent.length!==1){return false;} 6110return nonEmptyContent.every((el)=>{if(isMediaElement(el)||el.tagName==="IMG"){return true;} 6111if(el.tagName==="A"){return hasMediaOnly(el,requiresSingleMedia);}});} 6112const phrasingTagNames=new Set(["ABBR","AUDIO","B","BDI","BDO","BR","BUTTON","CANVAS","CITE","CODE","DATA","DATALIST","DFN","EM","EMBED","I","IFRAME","IMG","INPUT","KBD","LABEL","MARK","MATH","METER","NOSCRIPT","OBJECT","OUTPUT","PICTURE","PROGRESS","Q","RUBY","S","SAMP","SCRIPT","SELECT","SLOT","SMALL","SPAN","STRONG","SUB","SUP","SVG","TEMPLATE","TEXTAREA","TIME","U","VAR","VIDEO","WBR","FONT","A","AREA","DEL","INS","LINK","MAP","META",]);__exports.isPhrasingContent=isPhrasingContent;function isPhrasingContent(node){if(node&&(node.nodeType===Node.TEXT_NODE||(node.nodeType===Node.ELEMENT_NODE&&phrasingTagNames.has(node.tagName)))){return true;} 6113return false;} 6114__exports.containsAnyInline=containsAnyInline;function containsAnyInline(element){if(!element){return false;} 6115let child=element.firstChild;while(child){if((!isBlock(child)&&child.nodeType===Node.ELEMENT_NODE)||(child.nodeType===Node.TEXT_NODE&&child.textContent.trim()!=="")){return true;} 6116child=child.nextSibling;} 6117return false;} 6118__exports.containsAnyNonPhrasingContent=containsAnyNonPhrasingContent;function containsAnyNonPhrasingContent(element){if(!element){return false;} 6119let child=element.firstChild;while(child){if(!isPhrasingContent(child)){return true;} 6120child=child.nextSibling;} 6121return false;} 6122__exports.isEmbeddedComponent=isEmbeddedComponent;function isEmbeddedComponent(node){return node.nodeType===Node.ELEMENT_NODE&&node.matches("[data-embedded]");} 6123__exports.isProtected=isProtected;function isProtected(node){if(!node){return false;} 6124const candidate=node.parentElement?closestElement(node.parentElement,"[data-oe-protected]"):null;if(!candidate||candidate.dataset.oeProtected==="false"){return false;} 6125return true;} 6126__exports.isProtecting=isProtecting;function isProtecting(node){if(!node){return false;} 6127return(node.nodeType===Node.ELEMENT_NODE&&node.dataset.oeProtected!=="false"&&node.dataset.oeProtected!==undefined);} 6128__exports.isUnprotecting=isUnprotecting;function isUnprotecting(node){if(!node){return false;} 6129return node.nodeType===Node.ELEMENT_NODE&&node.dataset.oeProtected==="false";} 6130const paragraphRelatedElements=__exports.paragraphRelatedElements=["P","H1","H2","H3","H4","H5","H6","PRE"];__exports.allowsParagraphRelatedElements=allowsParagraphRelatedElements;function allowsParagraphRelatedElements(node){return!isParagraphRelatedElement(node)&&isBlock(node);} 6131const phrasingContent=__exports.phrasingContent=new Set(["#text",...phrasingTagNames]);const flowContent=new Set([...phrasingContent,...paragraphRelatedElements,"DIV","HR"]);const listItem=__exports.listItem=new Set(["LI"]);const listContainers=new Set(["UL","OL"]);const allowedContent={BLOCKQUOTE:flowContent,DIV:flowContent,H1:phrasingContent,H2:phrasingContent,H3:phrasingContent,H4:phrasingContent,H5:phrasingContent,H6:phrasingContent,HR:new Set(),LI:flowContent,OL:listItem,UL:listItem,P:phrasingContent,PRE:phrasingContent,TD:flowContent,TR:new Set(["TD"]),};__exports.isParagraphRelatedElement=isParagraphRelatedElement;function isParagraphRelatedElement(node){if(!node){return false;} 6132return(paragraphRelatedElements.includes(node.nodeName)||(node.nodeType===Node.ELEMENT_NODE&&node.matches(baseContainerGlobalSelector)));} 6133const paragraphRelatedElementsSelector=__exports.paragraphRelatedElementsSelector=[...paragraphRelatedElements,baseContainerGlobalSelector,].join(",");__exports.isListItemElement=isListItemElement;function isListItemElement(node){return[...listItem].includes(node.nodeName);} 6134const listItemElementSelector=__exports.listItemElementSelector=[...listItem].join(",");__exports.isListElement=isListElement;function isListElement(node){return[...listContainers].includes(node.nodeName);} 6135const listElementSelector=__exports.listElementSelector=[...listContainers].join(",");__exports.isTableCell=isTableCell;function isTableCell(node){return["TH","TD"].includes(node.nodeName);} 6136__exports.isAllowedContent=isAllowedContent;function isAllowedContent(parentBlock,nodes){let allowedContentSet=allowedContent[parentBlock.nodeName];if(!allowedContentSet){return true;} 6137if(parentBlock.matches(baseContainerGlobalSelector)){allowedContentSet=phrasingContent;} 6138return nodes.every((node)=>allowedContentSet.has(node.nodeName));} 6139__exports.isEmptyBlock=isEmptyBlock;function isEmptyBlock(blockEl){if(!blockEl||blockEl.nodeType!==Node.ELEMENT_NODE){return false;} 6140if(visibleCharRegex.test(blockEl.textContent)){return false;} 6141if(blockEl.querySelectorAll("br").length>=2){return false;} 6142if(isProtecting(blockEl)||isProtected(blockEl)){return false;} 6143const nodes=blockEl.querySelectorAll("*");for(const node of nodes){if(node.nodeName!="BR"&&(isSelfClosingElement(node)||isMediaElement(node)||isProtecting(node)||isButton(node))){return false;}} 6144return isBlock(blockEl);} 6145__exports.isShrunkBlock=isShrunkBlock;function isShrunkBlock(blockEl){return(isElement(blockEl)&&!blockEl.querySelector("br")&&!isSelfClosingElement(blockEl)&&isEmptyBlock(blockEl));} 6146__exports.isEditorTab=isEditorTab;function isEditorTab(node){return node&&node.nodeName==="SPAN"&&node.classList.contains("oe-tabs");} 6147__exports.getDeepestPosition=getDeepestPosition;function getDeepestPosition(node,offset){let direction=DIRECTIONS.RIGHT;let next=node;while(next){if(isTangible(next)||(isZWS(next)&&isContentEditable(next))){if(next!==node){[node,offset]=[next,direction?0:nodeSize(next)];} 6148const childrenNodes=childNodes(node);direction=offset<childrenNodes.length;next=childrenNodes[direction?offset:offset-1];}else if(direction&&next.nextSibling&&closestBlock(node).contains(next.nextSibling)){next=next.nextSibling;}else{direction=DIRECTIONS.LEFT;next=closestBlock(node).contains(next.previousSibling)&&next.previousSibling;} 6149next=!isSelfClosingElement(next)&&next;} 6150return[node,offset];} 6151__exports.getDeepestEditablePosition=getDeepestEditablePosition;function getDeepestEditablePosition(node,offset){const[deepNode,deepOffset]=getDeepestPosition(node,offset);if(isContentEditable(deepNode)){return[deepNode,deepOffset];} 6152const nodeLevelAncestor=isTextNode(deepNode)&&deepNode.parentElement===node?deepNode:closestElement(deepNode,(el)=>el.parentElement===node);const closestNonEditable=closestElement(deepNode,(el)=>!isContentEditable(el)&&isContentEditable(el.parentElement));const nodeLevelAncestorIndex=childNodeIndex(nodeLevelAncestor);const closestNonEditableIndex=childNodeIndex(closestNonEditable);const deepEditableNode=closestNonEditable.parentElement;const deepEditableOffset=nodeLevelAncestorIndex<offset?closestNonEditableIndex+1:closestNonEditableIndex;if(deepEditableOffset===closestNonEditableIndex){const previousSiblingOfNonEditable=closestNonEditable.previousSibling;if(previousSiblingOfNonEditable){if(isTextNode(previousSiblingOfNonEditable)){return[previousSiblingOfNonEditable,no
6152deSize(previousSiblingOfNonEditable)];}else if(isElement(previousSiblingOfNonEditable)&&previousSiblingOfNonEditable.childNodes.length){return getDeepestEditablePosition(previousSiblingOfNonEditable,nodeSize(previousSiblingOfNonEditable));}}} 6153return[deepEditableNode,deepEditableOffset];} 6154__exports.previousLeaf=previousLeaf;function previousLeaf(node,editable,skipInvisible=false){let ancestor=node;while(ancestor&&!ancestor.previousSibling&&ancestor!==editable){ancestor=ancestor.parentElement;} 6155if(ancestor&&ancestor!==editable){if(skipInvisible&&!isVisible(ancestor.previousSibling)){return previousLeaf(ancestor.previousSibling,editable,skipInvisible);}else{const last=lastLeaf(ancestor.previousSibling);if(skipInvisible&&!isVisible(last)){return previousLeaf(last,editable,skipInvisible);}else{return last;}}}} 6156__exports.nextLeaf=nextLeaf;function nextLeaf(node,editable,skipInvisible=false){let ancestor=node;while(ancestor&&!ancestor.nextSibling&&ancestor!==editable){ancestor=ancestor.parentElement;} 6157if(ancestor&&ancestor!==editable){if(skipInvisible&&ancestor.nextSibling&&!isVisible(ancestor.nextSibling)){return nextLeaf(ancestor.nextSibling,editable,skipInvisible);}else{const first=firstLeaf(ancestor.nextSibling);if(skipInvisible&&!isVisible(first)){return nextLeaf(first,editable,skipInvisible);}else{return first;}}}} 6158function hasPseudoElementContent(node,pseudoSelector){const content=getComputedStyle(node,pseudoSelector).getPropertyValue("content");return content&&content!=="none";} 6159const NOT_A_NUMBER=/[^\d]/g;__exports.areSimilarElements=areSimilarElements;function areSimilarElements(node,node2){if(![node,node2].every((n)=>n?.nodeType===Node.ELEMENT_NODE)){return false;} 6160if(node.nodeName!==node2.nodeName){return false;} 6161for(const name of new Set([...node.getAttributeNames(),...node2.getAttributeNames()])){if(name==="style"){if(!hasSameStyleAttributes(node,node2)){return false;}}else if(name==="class"){if(!hasSameClasses(node,node2)){return false;}}else if(node.getAttribute(name)!==node2.getAttribute(name)){return false;}} 6162if([node,node2].some((n)=>hasPseudoElementContent(n,":before")||hasPseudoElementContent(n,":after"))){return false;} 6163if(isBlock(node)){return false;} 6164const nodeStyle=getComputedStyle(node);const node2Style=getComputedStyle(node2);if(node.matches("code.o_inline_code")){if(nodeStyle.padding===node2Style.padding&&nodeStyle.margin===node2Style.margin){return true;}} 6165return(!+nodeStyle.padding.replace(NOT_A_NUMBER,"")&&!+node2Style.padding.replace(NOT_A_NUMBER,"")&&!+nodeStyle.margin.replace(NOT_A_NUMBER,"")&&!+node2Style.margin.replace(NOT_A_NUMBER,""));} 6166__exports.hasSameStyleAttributes=hasSameStyleAttributes;function hasSameStyleAttributes(node,node2){const getNodeStyles=(node)=>(node.getAttribute("style")||"").split(";").map((style)=>style.trim()).filter(Boolean);const[nodeStyles,node2Styles]=[node,node2].map(getNodeStyles);return(nodeStyles.length===node2Styles.length&&nodeStyles.every((style)=>node2Styles.includes(style)));} 6167__exports.hasSameClasses=hasSameClasses;function hasSameClasses(node,node2){const getNodeClasses=(node)=>(node.getAttribute("class")||"").split(/\s+/).map((c)=>c.trim()).filter(Boolean);const[nodeClasses,node2Classes]=[node,node2].map(getNodeClasses);return(nodeClasses.length===node2Classes.length&&nodeClasses.every((cls)=>node2Classes.includes(cls)));} 6168__exports.isTextNode=isTextNode;function isTextNode(node){return node.nodeType===Node.TEXT_NODE;} 6169__exports.isElement=isElement;function isElement(node){return node.nodeType===Node.ELEMENT_NODE;} 6170__exports.isContentEditable=isContentEditable;function isContentEditable(node){const element=isTextNode(node)?node.parentElement:node;return element&&element.isContentEditable;} 6171__exports.isContentEditableAncestor=isContentEditableAncestor;function isContentEditableAncestor(node){if(node.nodeType!==Node.ELEMENT_NODE){return false;} 6172return node.isContentEditable&&node.matches("[contenteditable]");} 6173function hasClassesSubset(node,node2){const getNodeClasses=(n)=>(n||"").trim().split(/\s+/).filter(Boolean);const[nodeClasses,node2Classes]=[node,node2].map(getNodeClasses);return nodeClasses.every((cls)=>node2Classes.includes(cls));} 6174function hasStylesSubset(node,node2){const getNodeStyles=(n)=>(n||"").split(";").map((s)=>
6174s.trim()).filter(Boolean);const[nodeStyles,node2Styles]=[node,node2].map(getNodeStyles);return nodeStyles.every((style)=>node2Styles.includes(style));} 6175__exports.isRedundantElement=isRedundantElement;function isRedundantElement(node){if(!node||node.nodeType!==Node.ELEMENT_NODE||!node.parentElement){return false;} 6176const closestEl=closestElement(node.parentElement,node.tagName);if(!closestEl){return false;} 6177for(const{name:attrName,value:nodeAttrVal}of node.attributes){const closestElAttrVal=closestEl.getAttribute(attrName);if(!closestElAttrVal){return false;} 6178if(attrName==="class"){if(!hasClassesSubset(nodeAttrVal,closestElAttrVal)){return false;}}else if(attrName==="style"){if(!hasStylesSubset(nodeAttrVal,closestElAttrVal)){return false;}}else{if(nodeAttrVal!==closestElAttrVal){return false;}}} 6179return true;} 6180const PROTECTED_QWEB_SELECTOR=__exports.PROTECTED_QWEB_SELECTOR="[t-esc], [t-raw], [t-out], [t-field]";return __exports;});; 6181 6182/* /html_editor/static/src/utils/dom_state.js */ 6183odoo.define('@html_editor/utils/dom_state',['@html_editor/utils/blocks','@html_editor/utils/content_types','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{isBlock}=require("@html_editor/utils/blocks");const{CTGROUPS,CTYPES,ctypeToString}=require("@html_editor/utils/content_types");const{isInPre,isVisible,isWhitespace,whitespace}=require("@html_editor/utils/dom_info");const{PATH_END_REASONS,ancestors,closestElement,closestPath,createDOMPathGenerator,}=require("@html_editor/utils/dom_traversal");const{DIRECTIONS,leftPos,rightPos}=require("@html_editor/utils/position");const prepareUpdateLockedEditables=new Set();__exports.prepareUpdate=prepareUpdate;function prepareUpdate(...args){const closestRoot=args.length&&ancestors(args[0]).find((ancestor)=>ancestor.classList.contains("odoo-editor-editable"));const isPrepareUpdateLocked=closestRoot&&prepareUpdateLockedEditables.has(closestRoot);const hash=(Math.random()+1).toString(36).substring(7);const options={allowReenter:true,label:hash,debug:false,...(args.length&&args[args.length-1]instanceof Object?args.pop():{}),};if(options.debug){console.log("%cPreparing%c update: "+ 6184options.label+ 6185(options.label===hash?"":` (${hash})`)+"%c"+ 6186(isPrepareUpdateLocked?" LOCKED":""),"color: cyan;","color: white;","color: red; font-weight: bold;");} 6187if(isPrepareUpdateLocked){return()=>{if(options.debug){console.log("%cRestoring%c update: "+ 6188options.label+ 6189(options.label===hash?"":` (${hash})`)+"%c LOCKED","color: lightgreen;","color: white;","color: red; font-weight: bold;");}};} 6190if(!options.allowReenter&&closestRoot){prepareUpdateLockedEditables.add(close
6190stRoot);} 6191const positions=[...args];const restoreData=[];let el,offset;while(positions.length){offset=positions.pop();el=positions.pop();const left=getState(el,offset,DIRECTIONS.LEFT);const right=getState(el,offset,DIRECTIONS.RIGHT,left.cType);if(options.debug){const editable=el&&closestElement(el,".odoo-editor-editable");const oldEditableHTML=(editable&&editable.innerHTML.replaceAll(" ","_").replaceAll("\u200B","ZWS"))||"";left.oldEditableHTML=oldEditableHTML;right.oldEditableHTML=oldEditableHTML;} 6192restoreData.push(left,right);} 6193return function restoreStates(){if(options.debug){console.log("%cRestoring%c update: "+ 6194options.label+ 6195(options.label===hash?"":` (${hash})`),"color: lightgreen;","color: white;");} 6196for(const data of restoreData){restoreState(data,options.debug);} 6197if(!options.allowReenter&&closestRoot){prepareUpdateLockedEditables.delete(closestRoot);}};} 6198const leftLeafOnlyNotBlockPath=__exports.leftLeafOnlyNotBlockPath=createDOMPathGenerator(DIRECTIONS.LEFT,{leafOnly:true,stopTraverseFunction:isBlock,stopFunction:isBlock,});const rightLeafOnlyNotBlockPath=createDOMPathGenerator(DIRECTIONS.RIGHT,{leafOnly:true,stopTraverseFunction:isBlock,stopFunction:isBlock,});__exports.getState=getState;function getState(el,offset,direction,leftCType){const leftDOMPath=leftLeafOnlyNotBlockPath;const rightDOMPath=rightLeafOnlyNotBlockPath;let domPath;let inverseDOMPath;const whitespaceAtStartRegex=new RegExp("^"+whitespace+"+");const whitespaceAtEndRegex=new RegExp(whitespace+"+$");const reasons=[];if(direction===DIRECTIONS.LEFT){domPath=leftDOMPath(el,offset,reasons);inverseDOMPath=rightDOMPath(el,offset);}else{domPath=rightDOMPath(el,offset,reasons);inverseDOMPath=leftDOMPath(el,offset);} 6199const boundaryNode=inverseDOMPath.next().value;let cType=undefined;let lastSpace=null;for(const node of domPath){if(node.nodeType===Node.TEXT_NODE){const value=node.nodeValue;if(direction===DIRECTIONS.LEFT){if(!isWhitespace(value)){if(lastSpace){cType=CTYPES.SPACE;}else{const rightLeaf=rightLeafOnlyNotBlockPath(node).next().value;const hasContentRight=rightLeaf&&!whitespaceAtStartRegex.test(rightLeaf.textContent);cType=!hasContentRight&&whitespaceAtEndRegex.test(node.textContent)?CTYPES.SPACE:CTYPES.CONTENT;} 6200break;} 6201if(value.length){lastSpace=node;}}else{leftCType=leftCType||getState(el,offset,DIRECTIONS.LEFT).cType;if(whitespaceAtStartRegex.test(value)){const leftLeaf=leftLeafOnlyNotBlockPath(node).next().value;const hasContentLeft=leftLeaf&&!whitespaceAtEndRegex.test(leftLeaf.textContent);const rct=!isWhitespace(value)?CTYPES.CONTENT:getState(...rightPos(node),DIRECTIONS.RIGHT).cType;cType=leftCType&CTYPES.CONTENT&&rct&(CTYPES.CONTENT|CTYPES.BR)&&!hasContentLeft?CTYPES.SPACE:rct;break;} 6202if(!isWhitespace(value)){cType=CTYPES.CONTENT;break;}}}else if(node.nodeName==="BR"){cType=CTYPES.BR;break;}else if(isVisible(node)){cType=CTYPES.CONTENT;break;}} 6203if(cType===undefined){cType=reasons.includes(PATH_END_REASONS.BLOCK_HIT)?CTYPES.BLOCK_OUTSIDE:CTYPES.BLOCK_INSIDE;} 6204return{node:boundaryNode,direction:direction,cType:cType,};} 6205const priorityRestoreStateRules=[[{cType1:CTYPES.CONTENT,cType2:CTYPES.SPACE|CTGROUPS.BLOCK},{spaceVisibility:true},],[{direction:DIRECTIONS.LEFT,cType1:CTGROUPS.INLINE,cType2:CTGROUPS.BR},{spaceVisibility:true},],[{direction:DIRECTIONS.RIGHT,cType1:CTGROUPS.CONTENT,cType2:CTGROUPS.BR},{spaceVisibility:true},],[{direction:DIRECTIONS.RIGHT,cType1:CTGROUPS.BR,cType2:CTYPES.SPACE},{spaceVisibility:true},],[{direction:DIRECTIONS.RIGHT,cType1:CTGROUPS.BR,cType2:CTGROUPS.BLOCK},{spaceVisibility:true,brVisibility:true},],[{cType1:CTYPES.SPACE},{spaceVisibility:false},],[{direction:DIRECTIONS.LEFT,cType1:CTGROUPS.BR},{spaceVisibility:false},],[{cType1:CTGROUPS.BLOCK,cType2:CTGROUPS.INLINE|CTGROUPS.BR},{spaceVisibility:false},],[{direction:DIRECTIONS.RIGHT,cType1:CTGROUPS.INLINE,cType2:CTGROUPS.BLOCK},{brVisibility:true},],[{direction:DIRECTIONS.RIGHT,cType1:CTGROUPS.BLOCK,cType2:CTGROUPS.INLINE|CTGROUPS.BR,},{brVisibility:false},],[{direction:DIRECTIONS.LEFT,cType1:CTGROUPS.BR|CTGROUPS.BLOCK,cType2:CTGROUPS.INLINE,},{brVisibility:false,extraBRRemovalCondition:(brNode)=>isFakeLineBreak(brNode)},],];function restoreStateRuleHashCode(direction,cType1,cType2){return`${direction}-${cType1}-${cType2}`;} 6206const allRestoreStateRules=(function(){const map=new Map();const keys=["direction","cType1","cType2"];
6206for(const direction of Object.values(DIRECTIONS)){for(const cType1 of Object.values(CTYPES)){for(const cType2 of Object.values(CTYPES)){const rule={direction:direction,cType1:cType1,cType2:cType2};const matchedRules=[];for(const entry of priorityRestoreStateRules){let priority=0;for(const key of keys){const entryKeyValue=entry[0][key];if(entryKeyValue!==undefined){if(typeof entryKeyValue==="boolean"?rule[key]===entryKeyValue:rule[key]&entryKeyValue){priority++;}else{priority=-1;break;}}} 6207if(priority>=0){matchedRules.push([priority,entry[1]]);}} 6208const finalRule={};for(let p=0;p<=keys.length;p++){for(const entry of matchedRules){if(entry[0]===p){Object.assign(finalRule,entry[1]);}}} 6209const hashCode=restoreStateRuleHashCode(direction,cType1,cType2);map.set(hashCode,finalRule);}}} 6210return map;})();__exports.restoreState=restoreState;function restoreState(prevStateData,debug=false){const{node,direction,cType:cType1,oldEditableHTML}=prevStateData;if(!node||!node.parentNode){return;} 6211const[el,offset]=direction===DIRECTIONS.LEFT?leftPos(node):rightPos(node);const{cType:cType2}=getState(el,offset,direction);const ruleHashCode=restoreStateRuleHashCode(direction,cType1,cType2);const rule=allRestoreStateRules.get(ruleHashCode);if(debug){const editable=closestElement(node,".odoo-editor-editable");console.log("%c"+ 6212node.textContent.replaceAll(" ","_").replaceAll("\u200B","ZWS")+"\n"+"%c"+ 6213(direction===DIRECTIONS.LEFT?"left":"right")+"\n"+"%c"+ 6214ctypeToString(cType1)+"\n"+"%c"+ 6215ctypeToString(cType2)+"\n"+"%c"+"BEFORE: "+ 6216(oldEditableHTML||"(unavailable)")+"\n"+"%c"+"AFTER: "+ 6217(editable?editable.innerHTML.replaceAll(" ","_").replaceAll("\u200B","ZWS"):"(unavailable)")+"\n","color: white; display: block; width: 100%;","color: "+ 6218(direction===DIRECTIONS.LEFT?"magenta":"lightgreen")+"; display: block; width: 100%;","color: pink; display: block; width: 100%;","color: lightblue; display: block; width: 100%;","color: white; display: block; width: 100%;","color: white; display: block; width: 100%;",rule);} 6219if(Object.values(rule).filter((x)=>x!==undefined).length){const inverseDirection=direction===DIRECTIONS.LEFT?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;enforceWhitespace(el,offset,inverseDirection,rule);} 6220return rule;} 6221__exports.isFakeLineBreak=isFakeLineBreak;function isFakeLineBreak(brEl){return!(getState(...rightPos(brEl),DIRECTIONS.RIGHT).cType&(CTYPES.CONTENT|CTGROUPS.BR));} 6222__exports.enforceWhitespace=enforceWhitespace;function enforceWhitespace(el,offset,direction,rule){const document=el.ownerDocument;let domPath,whitespaceAtEdgeRegex;if(direction===DIRECTIONS.LEFT){domPath=leftLeafOnlyNotBlockPath(el,offset);whitespaceAtEdgeRegex=new RegExp(whitespace+"+$");}else{domPath=rightLeafOnlyNotBlockPath(el,offset);whitespaceAtEdgeRegex=new RegExp("^"+whitespace+"+");} 6223const invisibleSpaceTextNodes=[];let foundVisibleSpaceTextNode=null;for(const node of domPath){if(node.nodeName==="BR"){if(rule.brVisibility===undefined){break;} 6224if(rule.brVisibility){node.before(document.createElement("br"));}else{if(!rule.extraBRRemovalCondition||rule.extraBRRemovalCondition(node)){node.remove();}} 6225break;}else if(node.nodeType===Node.TEXT_NODE&&!isInPre(node)){if(whitespaceAtEdgeRegex.test(node.nodeValue)){if(!isWhitespace(node)){foundVisibleSpaceTextNode=node;break;}else{invisibleSpaceTextNodes.push(node);}}else if(!isWhitespace(node)){break;}}else{break;}} 6226if(rule.spaceVisibility===undefined){return;} 6227if(!rule.spaceVisibility){for(const node of invisibleSpaceTextNodes){node.nodeValue="";const ancestorPath=closestPath(node.parentNode);let toRemove=null;for(const pNode of ancestorPath){if(toRemove){toRemove.remove();} 6228if(pNode.childNodes.length===1&&!isBlock(pNode)){pNode.after(node);toRemove=pNode;}else{break;}}}} 6229const spaceNode=foundVisibleSpaceTextNode||invisibleSpaceTextNodes[0];if(spaceNode){let spaceVisibility=rule.spaceVisibility;if(spaceVisibility&&!foundVisibleSpaceTextNode&&getState(...rightPos(spaceNode),DIRECTIONS.RIGHT).cType&CTGROUPS.BLOCK&&getState(...leftPos(spaceNode),DIRECTIONS.LEFT).cType!==CTYPES.CONTENT){spaceVisibility=false;} 6230spaceNode.nodeValue=spaceNode.nodeValue.replace(whitespaceAtEdgeRegex,spaceVisibility?"\u00A0":"");}} 6231__exports.observeMutations=observeMutations;function observeMutations(target,observerOptions){const records=[];const observerCallback=(mutations)=>records.push(...mutations);const observer=new MutationObserver(observerCallback);observer.observe(target,observerOptions);return()=>{observerCallback(observer.takeRecords());observer.disconnect();return records;};} 6232return __exports;});; 6233 6234/* /html_editor/static/src/utils/dom_traversal.js */ 6235odoo.define('@html_editor/utils/dom_traversal',['@html_editor/utils/position'],function(require){'use strict';let __exports={};const{DIRECTIONS}=require("@html_editor/utils/position");const closestPath=__exports.closestPath=function*(node){while(node){yield node;node=node.parentNode;}};__exports.findNode=findNode;function findNode(domPath,findCallback=()=>true,stopCallback=()=>false){for(const node of domPath){if(findCallback(node)){return node;} 6236if(stopCallback(node)){break;}} 6237return null;} 6238__exports.findUpTo=findUpTo;function findUpTo(node,limitAncestor,predicate){while(node!==limitAncestor){if(predicate(node)){return node;} 6239node=node.parentElement;} 6240return null;} 6241__exports.findFurthest=findFurthest;function findFurthest(node,limitAncestor,predicate){const nodes=[];while(node!==limitAncestor){nodes.push(node);node=node.parentNode;} 6242return nodes.findLast(predicate);} 6243__exports.closestElement=closestElement;function closestElement(node,predicate="*"){let element=node.nodeType===Node.ELEMENT_NODE?node:node.parentElement;const editable=element?.closest(".odoo-editor-editable");if(typeof predicate==="function"){while(element&&!predicate(element)){element=element===editable?null:element.parentElement;}}else{element=element?.closest(predicate);} 6244if(element&&((editable&&editable.contains(element))||!node.isConnected)){return element;} 6245return null;} 6246__exports.ancestors=ancestors;function ancestors(node,editable){const result=[];while(node&&node.parentElement&&node!==editable){result.push(node.parentElement);node=node.parentElement;} 6247return result;} 6248__exports.children=children;function children(elem){const children=[];let child=elem.firstElementChild;while(child){children.push(child);child=child.nextElementSibling;} 6249return children;} 6250__exports.childNodes=childNodes;function childNodes(node){const childNodes=[];let child=node.firstChild;while(child){childNodes.push(child);child=child.nextSibling;} 6251return childNodes;} 6252__exports.descendants=descendants;function descendants(node,posterity=[]){let child=node.firstChild;while(child){posterity.push(child);
6252descendants(child,posterity);child=child.nextSibling;} 6253return posterity;} 6254const PATH_END_REASONS=__exports.PATH_END_REASONS={NO_NODE:0,BLOCK_OUT:1,BLOCK_HIT:2,OUT_OF_SCOPE:3,};__exports.createDOMPathGenerator=createDOMPathGenerator;function createDOMPathGenerator(direction,{leafOnly=false,inScope=false,stopTraverseFunction,stopFunction}={}){const nextDeepest=direction===DIRECTIONS.LEFT?(node)=>lastLeaf(node.previousSibling,stopTraverseFunction):(node)=>firstLeaf(node.nextSibling,stopTraverseFunction);const firstNode=direction===DIRECTIONS.LEFT?(node,offset)=>lastLeaf(node.childNodes[offset-1],stopTraverseFunction):(node,offset)=>firstLeaf(node.childNodes[offset],stopTraverseFunction);return function*(node,offset,reasons=[]){let movedUp=false;let currentNode=firstNode(node,offset);if(!currentNode){movedUp=true;currentNode=node;} 6255while(currentNode){if(stopFunction&&stopFunction(currentNode)){reasons.push(movedUp?PATH_END_REASONS.BLOCK_OUT:PATH_END_REASONS.BLOCK_HIT);break;} 6256if(inScope&¤tNode===node){reasons.push(PATH_END_REASONS.OUT_OF_SCOPE);break;} 6257if(!(leafOnly&&movedUp)){yield currentNode;} 6258movedUp=false;let nextNode=nextDeepest(currentNode);if(!nextNode){movedUp=true;nextNode=currentNode.parentNode;} 6259currentNode=nextNode;} 6260reasons.push(PATH_END_REASONS.NO_NODE);};} 6261__exports.lastLeaf=lastLeaf;function lastLeaf(node,stopTraverseFunction){while(node&&node.lastChild&&!(stopTraverseFunction&&stopTraverseFunction(node))){node=node.lastChild;} 6262return node;} 6263__exports.firstLeaf=firstLeaf;function firstLeaf(node,stopTraverseFunction){while(node&&node.firstChild&&!(stopTraverseFunction&&stopTraverseFunction(node))){node=node.firstChild;} 6264return node;} 6265__exports.getAdjacentPreviousSiblings=getAdjacentPreviousSiblings;function getAdjacentPreviousSiblings(node,predicate=(n)=>!!n){let previous=node.previousSibling;const list=[];while(previous&&predicate(previous)){list.push(previous);previous=previous.previousSibling;} 6266return list;} 6267__exports.getAdjacentNextSiblings=getAdjacentNextSiblings;function getAdjacentNextSiblings(node,predicate=(n)=>!!n){let next=node.nextSibling;const list=[];while(next&&predicate(next)){list.push(next);next=next.nextSibling;} 6268return list;} 6269__exports.getAdjacents=getAdjacents;function getAdjacents(node,predicate=(n)=>!!n){const previous=getAdjacentPreviousSiblings(node,predicate);const next=getAdjacentNextSiblings(node,predicate);return predicate(node)?[...previous.reverse(),node,...next]:[];} 6270__exports.getCommonAncestor=getCommonAncestor;function getCommonAncestor(nodes,root=undefined){const pathsToRoot=nodes.map((node)=>[node,...ancestors(node,root)]);let candidate=pathsToRoot[0]?.at(-1);if(root&&candidate!==root){return null;} 6271let commonAncestor=null;while(candidate&&pathsToRoot.every((path)=>path.at(-1)===candidate)){commonAncestor=candidate;pathsToRoot.forEach((path)=>path.pop());candidate=pathsToRoot[0].at(-1);} 6272return commonAncestor;} 6273const selectElements=__exports.selectElements=function*(root,selector){if(root.matches(selector)){yield root;} 6274for(const elem of root.querySelectorAll(selector)){yield elem;}};return __exports;});; 6275 6276/* /html_editor/static/src/utils/drag_and_drop.js */ 6277odoo.define('@html_editor/utils/drag_and_drop',['@web/core/utils/draggable_hook_builder','@web/core/utils/objects','@odoo/owl','@web/core/utils/timing','@web/core/utils/ui'],function(require){'use strict';let __exports={};const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder");const{pick}=require("@web/core/utils/objects");const{reactive}=require("@odoo/owl");const{throttleForAnimation}=require("@web/core/utils/timing");const{closest,touching}=require("@web/core/utils/ui");__exports.useNativeDraggable=useNativeDraggable;function useNativeDraggable(hookParams,initialParams){const setupFunctions=new Map();const cleanupFunctions=[];const currentParams={...initialParams};const setupHooks={wrapState:reactive,throttle:throttleForAnimation,addListener:(el,type,callback,options)=>{el.addEventListener(type,callback,options);cleanupFunctions.push(()=>el.removeEventListener(type,callback));},setup:(setupFn,depsFn)=>setupFunctions.set(setupFn,depsFn),teardown:(cleanupFn)=>{cleanupFunctions.push(cleanupFn);},};const el=initialParams.ref.el;el.classList.add("o_draggable");cleanupFunctions.push(()=>el.classList.remove("o_draggable"));const draggableState=makeDraggableHook({setupHooks,...hookParams}
6277)(currentParams);draggableState.enable=true;const draggableComponent={state:draggableState,update:(newParams)=>{Object.assign(currentParams,newParams);setupFunctions.forEach((depsFn,setupFn)=>setupFn(...depsFn()));},destroy:()=>{cleanupFunctions.forEach((cleanupFn)=>cleanupFn());},};draggableComponent.update({});return draggableComponent;} 6278function updateElementPosition(el,{x,y},styleFn,offset={x:0,y:0}){return styleFn(el,{top:`${y - offset.y}px`,left:`${x - offset.x}px`});} 6279const dragAndDropHookParams={name:"useDragAndDrop",acceptedParams:{dropzones:[Function],scrollingElement:[Function],helper:[Function],extraWindow:[Object,Function],},edgeScrolling:{enabled:true},onComputeParams({ctx,params}){ctx.followCursor=false;ctx.getScrollingElement=params.scrollingElement;ctx.getHelper=params.helper;ctx.getDropZones=params.dropzones;},onWillStartDrag:({ctx})=>{ctx.current.container=ctx.getScrollingElement();ctx.current.helperOffset={x:0,y:0};},onDragStart:({ctx,addStyle,addCleanup})=>{ctx.current.helper=ctx.getHelper({...ctx.current,...ctx.pointer});ctx.current.helper.style.position="fixed";ctx.current.element.classList.remove("o_dragged");ctx.current.helper.style.cursor=ctx.cursor;ctx.current.helper.style.pointerEvents="auto";const frameElement=ctx.current.helper.ownerDocument.defaultView.frameElement;if(frameElement){addStyle(frameElement,{pointerEvents:"auto"});} 6280addCleanup(()=>ctx.current.helper.remove());updateElementPosition(ctx.current.helper,ctx.pointer,addStyle,ctx.current.helperOffset);return pick(ctx.current,"element","helper");},onDrag:({ctx,addStyle,callHandler})=>{ctx.current.helper.classList.add("o_draggable_dragging");updateElementPosition(ctx.current.helper,ctx.pointer,addStyle,ctx.current.helperOffset);let helperRect=ctx.current.helper.getBoundingClientRect();helperRect={x:helperRect.x,y:helperRect.y,width:helperRect.width,height:helperRect.height,};const dropzoneEl=closest(touching(ctx.getDropZones(),helperRect),helperRect);if(ctx.current.dropzone?.el&&ctx.current.dropzone.el.classList.contains("oe_grid_zone")){ctx.current.dropzone.rect=ctx.current.dropzone.el.getBoundingClientRect();} 6281if(ctx.current.dropzone&&(ctx.current.dropzone.el===dropzoneEl||(!dropzoneEl&&touching([ctx.current.helper],ctx.current.dropzone.rect).length>0))){return pick(ctx.current,"element","dropzone","helper");} 6282if(ctx.current.dropzone&&dropzoneEl!==ctx.current.dropzone.el){callHandler("dropzoneOut",{dropzone:ctx.current.dropzone,helper:ctx.current.helper,});delete ctx.current.dropzone;} 6283if(dropzoneEl){const rect=DOMRect.fromRect(dropzoneEl.getBoundingClientRect());ctx.current.dropzone={el:dropzoneEl,rect:{x:rect.x,y:rect.y,width:rect.width,height:rect.height,},};callHandler("dropzoneOver",{dropzone:ctx.current.dropzone,helper:ctx.current.helper,});} 6284return pick(ctx.current,"element","dropzone","helper");},onDragEnd({ctx}){return pick(ctx.current,"element","dropzone","helper");},};__exports.useDragAndDrop=useDragAndDrop;function useDragAndDrop(initialParams){return useNativeDraggable(dragAndDropHookParams,initialParams);} 6285return __exports;});; 6286 6287/* /html_editor/static/src/utils/fonts.js */ 6288odoo.define('@html_editor/utils/fonts',[],function(require){'use strict';let __exports={};const fonts=__exports.fonts={cacheCssSelectors:{},getCssSelectors:function(filter){if(this.cacheCssSelectors[filter]){return this.cacheCssSelectors[filter];} 6289this.cacheCssSelectors[filter]=[];var sheets=document.styleSheets;for(var i=0;i<sheets.length;i++){var rules;try{rules=sheets[i].rules||sheets[i].cssRules;}catch{continue;} 6290if(!rules){continue;} 6291for(var r=0;r<rules.length;r++){var selectorText=rules[r].selectorText;if(!selectorText){continue;} 6292var selectors=selectorText.split(/\s*,\s*/);var data=null;for(var s=0;s<selectors.length;s++){var match=selectors[s].trim().match(filter);if(!match){continue;} 6293if(!data){data={selector:match[0],css:rules[r].cssText.replace(/(^.*\{\s*)|(\s*\}\s*$)/g,""),names:[match[1]],};}else{data.selector+=", "+match[0];data.names.push(match[1]);}} 6294if(data){this.cacheCssSelectors[filter].push(data);}}} 6295return this.cacheCssSelectors[filter];},fontIcons:[{base:"fa",parser:/\.(fa-(?:\w|-)+)::?before/i}],computedFonts:false,computeFonts:function(){if(!this.computedFonts){var self=this;this.fontIcons.forEach((data)=>{data.cssData=self.getCssSelectors(data.parser);data.alias=data.cssData.map((x)=>x.names).flat();});this.computedFonts=true;}},};return __exports;});; 6296 6297/* /html_editor/static/src/utils/formatting.js */ 6298odoo.define('@html_editor/utils/formatting',['@web/core/utils/colors','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/blocks'],function(require){'use strict';let __exports={};const{normalizeCSSColor}=require("@web/core/utils/colors");const{removeClass}=require("@html_editor/utils/dom");const{isBold,isItalic,isStrikeThrough,isUnderline}=require("@html_editor/utils/dom_info");const{closestElement,closestPath,findNode,findUpTo}=require("@html_editor/utils/dom_traversal");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const FONT_SIZE_CLASSES=__exports.FONT_SIZE_CLASSES=["display-1-fs","display-2-fs","display-3-fs","display-4-fs","h1-fs","h2-fs","h3-fs","h4-fs","h5-fs","h6-fs","base-fs","small","o_small-fs",];const TEXT_STYLE_CLASSES=__exports.TEXT_STYLE_CLASSES=["display-1","display-2","display-3","display-4","lead"];const DEFAULT_FONT_SIZE_CLASSES=__exports.DEFAULT_FONT_SIZE_CLASSES=["h1","h2","h3","h4","h5","h6","o_default_font_size",];const FORMATTABLE_TAGS=__exports.FORMATTABLE_TAGS=["SPAN","FONT","B","STRONG","I","EM","U","S","CODE"];const formatsSpecs=__exports.formatsSpecs={italic:{tagName:"em",isFormatted:isItalic,isTag:(node)=>["EM","I"].includes(node.tagName),hasStyle:(node)=>Boolean(node.style&&node.style["font-style"]),addStyle:(node)=>(node.style["font-style"]="italic"),addNeutralStyle:(node)=>(node.style["font-style"]="normal"),removeStyle:(node)=>removeStyle(node,"font-style"),},bold:{tagName:"strong",isFormatted:isBold,isTag:(node)=>["STRONG","B"].includes(node.tagName),hasStyle:(node)=>Boolean(node.style&&node.style["font-weight"]),addStyle:(node)=>(node.style["font-weight"]="bolder"),addNeutralStyle:(node)=>{node.style["font-weight"]="normal";},removeStyle:(node)=>removeStyle(node,"font-weight"),},underline:{tagName:"u",isFormatted:isUnderline,isTag:(node)=>node.tagName==="U",hasStyle:(node)=>node.style&&(node.style["text-decoration"].includes("underline")||node.style["text-decoration-line"].includes("underline")),addStyle:(node)=>(node.style["text-decoration-line"]+=" underline"),removeStyle:(node)=>removeStyle(node,node.style["text-decoration"].includes("underline")?"text-decoration":"text-decoration-line","underline"),},strikeThrough:{tagName:"s",isFormatted:isStrikeThrough,isTag:(node)=>node.tagName==="S",hasStyle:(node)=>node.style&&(node.style["text-decoration"].includes("line-through")||node.style["text-decoration-line"].includes("line-through")),addStyle:(node)=>(node.style["text-decoration-line"]+=" line-through"),removeStyle:(node)=>removeStyle(node,node.style["text-decoration"].includes("line-through")?"text-decoration":"text-decoration-line","line-through"),},fontFamily:{isFormatted:(node)=>!!closestElement(node,(el)=>el.style["font-family"]),hasStyle:(node)=>node.style&&node.style["font-family"],addStyle:(node,props)=>{removeStyle(node,"font-family");if(props.fontFamily){node.style["font-family"]=props.fontFamily;}},removeStyle:(node)=>removeStyle(node,"font-family"),},fontSize:{isFormatted:(node,props)=>{const fontSize=(findNode(closestPath(node),(el)=>el.style?.["font-size"],isBlock)||closestElement(node,"li"))?.style["font-size"];return props?.size?fontSize===props.size:fontSize;},hasStyle:(node)=>node.style&&node.style["font-size"],addStyle:(node,props)=>{node.style["font-size"]=props.size;removeClass(node,...FONT_SIZE_CLASSES);},removeStyle:(node)=>removeStyle(node,"font-size"),},setFontSizeClassName:{isFormatted:(node,props)=>props?.className?FONT_SIZE_CLASSES.includes(props.className)&&!!(findNode(closestPath(node),(el)=>el.classList?.contains(props.className),(el)=>el===closestBlock(node).parentElement)||closestElement(node,"li")?.classList?.contains(props.className)):!!findNode(closestPath(node),(el)=>FONT_SIZE_CLASSES.find((cls)=>el.classList?.contains(cls)),(el)=>el===closestBlock(node).parentElement)||FONT_SIZE_CLASSES.find((cls)=>closestElement(node,"li")?.classList.contains(cls)),hasStyle:(node,props)=>[...FONT_SIZE_CLASSES,...TEXT_STYLE_CLASSES,...DEFAULT_FONT_SIZE_CLASSES].find((cls)=>node.classList.contains(cls)),addStyle:(node,props)=>{node.style.removeProperty("font-size");node.classList.add(props.className);},removeStyle:(node)=>{removeStyle(node,"font-size");removeClass(node,...FONT_SIZE_CLASSES);if(!isBlock(node)){removeClass(node,...TEXT_STYLE_CLASSES,...DEFAULT_FONT_SIZE_CLASSES);}},addNeutralStyle:function(node){const block=closestBlock(node);if(["H1","H2","H3","H4","H5","H6"].includes(block.nodeName)){node.classList.add(block.nodeName.toLowerCase());}else{node.classList.add("o_default_font_size");}},},};function removeStyle(node,styleName,item){if(item){const newStyle=node.style[styleName].split(" ").filter((x)=>x!==item).join(" ");node.style[styleName]=newStyle||null;}else{node.style[styleName]=null;} 6299if(node.getAttribute("style")===""){node.removeAttribute("style");}} 6300__exports.getCSSVariableValue=getCSSVariableValue;function getCSSVariableValue(key,htmlStyle){let value=htmlStyle.getPropertyValue(`--${key}`).trim();value=normalizeCSSColor(value);return value.replace(/"/g,"'");} 6301const CSS_UNITS_CONVERSION={"s-ms":()=>1000,"ms-s":()=>0.001,"rem-px":(htmlStyle)=>parseFloat(htmlStyle["font-size"]),"px-rem":(htmlStyle)=>1/parseFloat(htmlStyle["font-size"]),"%-px":()=>-1,"px-%":()=>-1,};__exports.convertNumericToUnit=convertNumericToUnit;function convertNumericToUnit(value,unitFrom,unitTo,htmlStyle){if(Math.abs(value)<Number.EPSILON||unitFrom===unitTo){return value;} 6302const converter=CSS_UNITS_CONVERSION[`${unitFrom}-${unitTo}`];if(converter===undefined){throw new Error(`Cannot convert '${unitFrom}' units into '${unitTo}' units !`);} 6303return value*converter(htmlStyle);} 6304__exports.getHtmlStyle=getHtmlStyle;function getHtmlStyle(document){return document.defaultView.getComputedStyle(document.documentElement);} 6305__exports.getFontSizeDisplayValue=getFontSizeDisplayValue;function getFontSizeDisplayValue(sel,document){const tagNameRelatedToFontSize=["h1","h2","h3","h4","h5","h6"];const closestStartContainerEl=closestElement(sel.startContainer);const closestFontSizedEl=findUpTo(closestStartContainerEl,closestStartContainerEl.closest(".o_default_font_size"),
6305(n)=>n.matches(` 6306 [style*='font-size'], 6307 ${FONT_SIZE_CLASSES.map((className) => `.${className}`)}, 6308 ${TEXT_STYLE_CLASSES.map((className) => `.${className}`)}, 6309 ${tagNameRelatedToFontSize} 6310 `));let remValue;const htmlStyle=getHtmlStyle(document);if(closestFontSizedEl){const useFontSizeInput=closestFontSizedEl.style.fontSize;if(useFontSizeInput){return parseFloat(getComputedStyle(closestStartContainerEl).fontSize);} 6311const fontSizeClass=FONT_SIZE_CLASSES.find((className)=>closestFontSizedEl.classList.contains(className));let fsName;if(fontSizeClass){fsName=fontSizeClass.substring(0,fontSizeClass.length-3);}else{fsName=TEXT_STYLE_CLASSES.find((className)=>closestFontSizedEl.classList.contains(className))||closestFontSizedEl.tagName.toLowerCase();} 6312remValue=parseFloat(getCSSVariableValue(`${fsName}-font-size`,htmlStyle));} 6313const pxValue=remValue&&convertNumericToUnit(remValue,"rem","px",htmlStyle);return pxValue||parseFloat(getComputedStyle(closestStartContainerEl).fontSize);} 6314__exports.getFontSizeOrClass=getFontSizeOrClass;function getFontSizeOrClass(node){if(!node){return null;} 6315if(node.style.fontSize){return{type:"font-size",value:node.style.fontSize};} 6316const fontSizeClass=FONT_SIZE_CLASSES.find((cls)=>node.classList.contains(cls));if(fontSizeClass){return{type:"class",value:fontSizeClass};} 6317return null;} 6318return __exports;});; 6319 6320/* /html_editor/static/src/utils/functions.js */ 6321odoo.define('@html_editor/utils/functions',[],function(require){'use strict';let __exports={};__exports.weakMemoize=weakMemoize;function weakMemoize(func){const cache=new WeakMap();const funcName=func.name?func.name+" (memoized)":"memoized";return{[funcName](firstArg,...args){if(!cache.has(firstArg)){cache.set(firstArg,func(firstArg,...args));} 6322return cache.get(firstArg);},}[funcName];} 6323return __exports;});; 6324 6325/* /html_editor/static/src/utils/html.js */ 6326odoo.define('@html_editor/utils/html',[],function(require){'use strict';let __exports={};__exports.parseHTML=parseHTML;function parseHTML(document,html){const fragment=document.createDocumentFragment();const parser=new document.defaultView.DOMParser();const parsedDocument=parser.parseFromString(html,"text/html");fragment.replaceChildren(...parsedDocument.body.childNodes);return fragment;} 6327__exports.normalizeHTML=normalizeHTML;function normalizeHTML(content,cleanup=()=>{}){const parser=new document.defaultView.DOMParser();const body=parser.parseFromString(content,"text/html").body;cleanup(body);return body.innerHTML;} 6328return __exports;});; 6329 6330/* /html_editor/static/src/utils/image.js */ 6331odoo.define('@html_editor/utils/image',['@web/core/utils/cache','@web/core/utils/colors'],function(require){'use strict';let __exports={};const{Cache}=require("@web/core/utils/cache");const{isColorGradient}=require("@web/core/utils/colors");const SUPPORTED_MIMETYPES=["image/gif","image/jpe","image/jpeg","image/jpg","image/png","image/svg+xml","image/webp",];const headResponseCache=new Cache(async(src)=>{if(!src){return new Response(null,{status:404,statusText:"Source is undefined"});} 6332return await fetch(src,{method:"HEAD"});},JSON.stringify);__exports.backgroundImageCssToParts=backgroundImageCssToParts;function backgroundImageCssToParts(css=""){const parts={};if(css.startsWith("url(")){const urlEnd=css.indexOf(")")+1;parts.url=css.substring(0,urlEnd).trim();const commaPos=css.indexOf(",",urlEnd);css=commaPos>0?css.substring(commaPos+1):"";} 6333if(isColorGradient(css)){parts.gradient=css.trim();} 6334return parts;} 6335__exports.backgroundImagePartsToCss=backgroundImagePartsToCss;function backgroundImagePartsToCss(parts){return[parts.url,parts.gradient].filter(Boolean).join(", ")||"";} 6336__exports.getMimetype=getMimetype;function getMimetype(image,data=image.dataset){const src=getImageSrc(image);return(data.mimetype||data.mimetypeBeforeConversion||(src&&((src.endsWith(".png")&&"image/png")||(src.endsWith(".webp")&&"image/webp")||(src.endsWith(".jpg")&&"image/jpeg")||(src.endsWith(".jpeg")&&"image/jpeg")))||null);} 6337__exports.getFetchedMimetype=getFetchedMimetype;async function getFetchedMimetype(image,data=image.dataset){const mimetypeOnData=data.mimetype||data.mimetypeBeforeConversion;if(mimetypeOnData){return mimetypeOnData;} 6338const src=getImageSrc(image);if(!src){return;}
6339try{const response=await headResponseCache.read(src);if(!response.ok){return null;} 6340const contentType=response.headers.get("content-type");if(!SUPPORTED_MIMETYPES.some((mimetype)=>contentType.startsWith(mimetype))){return null;} 6341if(contentType.startsWith("image/svg+xml")){return"image/svg+xml";} 6342return contentType;}catch{return null;}} 6343__exports.isImageCorsProtected=isImageCorsProtected;async function isImageCorsProtected(img){const src=img.getAttribute("src");if(!src){return false;} 6344let isCorsProtected=false;if(!src.startsWith("/")||/\/web\/image\/\d+-redirect\//.test(src)){isCorsProtected=await headResponseCache.read(src).then(()=>false).catch(()=>true);} 6345return isCorsProtected;} 6346__exports.isSrcCorsProtected=isSrcCorsProtected;async function isSrcCorsProtected(src){const dummyImg=document.createElement("img");dummyImg.src=src;return isImageCorsProtected(dummyImg);} 6347__exports.getImageSrc=getImageSrc;function getImageSrc(el){if(el.tagName==="IMG"){return el.getAttribute("src");} 6348if(el.querySelector(".s_parallax_bg")){el=el.querySelector(".s_parallax_bg");} 6349const url=backgroundImageCssToParts(el.style.backgroundImage).url;return url&&getBgImageURLFromURL(url);} 6350__exports.getBgImageURLFromURL=getBgImageURLFromURL;function getBgImageURLFromURL(url){const match=url.match(/^url\((['"])(.*?)\1\)$/);if(!match){return"";} 6351const matchedURL=match[2];const fullURL=new URL(matchedURL,window.location.origin);if(fullURL.origin===window.location.origin){return fullURL.href.slice(fullURL.origin.length);} 6352return matchedURL;} 6353return __exports;});; 6354 6355/* /html_editor/static/src/utils/image_processing.js */ 6356odoo.define('@html_editor/utils/image_processing',['@web/core/network/rpc','@web/core/utils/objects','@web/core/assets','@html_editor/utils/image'],function(require){'use strict';let __exports={};const{rpc}=require("@web/core/network/rpc");const{pick}=require("@web/core/utils/objects");const{loadBundle}=require("@web/core/assets");const{getImageSrc}=require("@html_editor/utils/image");const cropperDataFields=__exports.cropperDataFields=["x","y","width","height","rotate","scaleX","scaleY"];const cropperDataFieldsWithAspectRatio=__exports.cropperDataFieldsWithAspectRatio=[...cropperDataFields,"aspectRatio"];const isGif=__exports.isGif=(mimetype)=>mimetype==="image/gif";let _isWebGLEnabled;__exports.isWebGLEnabled=isWebGLEnabled;function isWebGLEnabled(){if(_isWebGLEnabled!==undefined){return _isWebGLEnabled;} 6357try{const canvas=document.createElement("canvas");_isWebGLEnabled=!!(window.WebGLRenderingContext&&(canvas.getContext("webgl")||canvas.getContext("experimental-webgl")));}catch{_isWebGLEnabled=false;} 6358return _isWebGLEnabled;} 6359const modifierFields=["filter","quality","mimetype","glFilter","originalId","originalSrc","resizeWidth","aspectRatio","mimetypeBeforeConversion",];const removeOnImageChangeAttrs=__exports.removeOnImageChangeAttrs=[...cropperDataFields,...modifierFields];const cache={};const placeholderHref="/web/image/__odoo__unknown__src__/";function _getValidSrc(src){if(src in cache){return cache[src];} 6360const prom=new Promise((resolve)=>{if(!src){resolve(placeholderHref);return;} 6361fetch(src).then((response)=>{resolve(response.ok?src:placeholderHref);}).catch(()=>{resolve(placeholderHref);});});cache[src]=prom;return prom;} 6362__exports.loadImage=loadImage;async function loadImage(src,img=new Image()){const source=await _getValidSrc(src);return new Promise((resolve,reject)=>{img.addEventListener("load",()=>resolve(img),{once:true});img.addEventListener("error",reject,{once:true});img.src=source;});} 6363const imageCache=new Map();function _loadImageObjectURL(src){return _updateImageData(src);} 6364__exports.loadImageDataURL=loadImageDataURL;function loadImageDataURL(src){return _updateImageData(src,"dataURL");} 6365async function _updateImageData(src,key="objectURL"){const currentImageData=imageCache.get(src);if(currentImageData&¤tImageData[key]){return currentImageData[key];} 6366let value="";const blob=await fetch(src).then((res)=>res.blob());if(key==="dataURL"){value=await createDataURL(blob);}else{value=URL.createObjectURL(blob);} 6367imageCache.set(src,Object.assign(currentImageData||{},{[key]:value,size:blob.size}));return value;} 6368__exports.getImageSizeFromCache=getImageSizeFromCache;function getImageSizeFromCache(src){return imageCache.get(src).size;} 6369__exports.activateCropper=activateCropper;async function activateCropper(image,aspectRatio,dataset,{onReady}={}){await loadBundle("html_editor.assets_image_cropper");const oldSrc=image.src;const newSrc=await _loadImageObjectURL(image.getAttribute("src"));image.src=newSrc;let readyResolve;const readyPromise=new Promise((resolve)=>(readyResolve=resolve));const cropper=new Cropper(image,{viewMode:2,dragMode:"move",autoCropArea:1.0,aspectRatio:aspectRatio,data:Object.fromEntries(Object.entries(pick(dataset,...cropperDataFields)).map(([key,value])=>[key,parseFloat(value),])),minContainerWidth:1,minContainerHeight:1,ready:()=>{readyResolve();if(onReady){onReady(cropper);}},});if(oldSrc===newSrc&&image.complete){return;} 6370await readyPromise;return cropper;} 6371__exports.loadImageInfo=loadImageInfo;async function loadImageInfo(el,attachmentSrc=""){const newDataset={};const elSrc=getImageSrc(el);const src=attachmentSrc||elSrc;if((el.dataset.originalSrc&&el.dataset.mimetypeBeforeConversion)||!src){return newDataset;} 6372let docHref=el.ownerDocument.defaultView.location.href;if(docHref.startsWith("about:")){docHref=window.location.href;} 6373const srcUrl=new URL(src,docHref);let relativeSrc=decodeURI(srcUrl.pathname);let match=relativeSrc.match(/\/(?:web_editor|html_editor)\/image_shape\/(\w+\.\w+)/);if(el.dataset.shape&&match){match=match[1];if(match.endsWith("_perspective")){match=match.slice(0,-12);} 6374relativeSrc=`/web/image/${encodeURIComponent(match)}`;} 6375const{original}=await rpc("/html_editor/get_image_info",{src:relativeSrc},{cache:true});if(original&&original.image_src&&!/\/web\/image\/\d+-redirect\//.test(original.image_src)){newDataset.originalId=original.id;newDataset.originalSrc=original.image_src;newDataset.mimetypeBeforeConversion=original.mimetype;}else if(/^\/web\/image\/[\w.]+\/\d+\/[\w-]+(\/|\?|$)/.test(src)){newDataset.originalSrc=src;} 6376return newDataset;} 6377__exports.createDataURL=createDataURL;function createDataURL(blob){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.addEventListener("load",()=>resolve(reader.result));reader.addEventListener("abort",reject);reader.addEventListener("error",reject);
6377reader.readAsDataURL(blob);});} 6378__exports.getDataURLBinarySize=getDataURLBinarySize;function getDataURLBinarySize(dataURL){return(dataURL.split(",")[1].length/4)*3;} 6379__exports.getAspectRatio=getAspectRatio;function getAspectRatio(ratio){if(typeof ratio==="number"){return ratio;} 6380const[a,b]=ratio.split(/[:/]/).map((n)=>parseFloat(n));if(!b){return a;} 6381return a/b;} 6382return __exports;});; 6383 6384/* /html_editor/static/src/utils/perspective_utils.js */ 6385odoo.define('@html_editor/utils/perspective_utils',[],function(require){'use strict';let __exports={};__exports.transform=transform;function transform([[a,b,c],[d,e,f],[g,h,i]],[x,y]){const z=g*x+h*y+i;return[(a*x+b*y+c)/z,(d*x+e*y+f)/z];} 6386function invert([[a,b,c],[d,e,f],[g,h,i]]){const determinant=a*e*i-a*f*h-b*d*i+b*f*g+c*d*h-c*e*g;return[[(e*i-h*f)/determinant,(h*c-b*i)/determinant,(b*f-e*c)/determinant,],[(g*f-d*i)/determinant,(a*i-g*c)/determinant,(d*c-a*f)/determinant,],[(d*h-g*e)/determinant,(g*b-a*h)/determinant,(a*e-d*b)/determinant,],];} 6387function multiply(a,b){const[[a0,a1,a2],[a3,a4,a5],[a6,a7,a8]]=a;const[[b0,b1,b2],[b3,b4,b5],[b6,b7,b8]]=b;return[[a0*b0+a1*b3+a2*b6,a0*b1+a1*b4+a2*b7,a0*b2+a1*b5+a2*b8],[a3*b0+a4*b3+a5*b6,a3*b1+a4*b4+a5*b7,a3*b2+a4*b5+a5*b8],[a6*b0+a7*b3+a8*b6,a6*b1+a7*b4+a8*b7,a6*b2+a7*b5+a8*b8],];} 6388__exports.getProjective=getProjective;function getProjective(width,height,[[x0,y0],[x1,y1],[x2,y2],[x3,y3]]){const denominator=x3*(y1-y2)+x1*(y2-y3)+x2*(y3-y1);const a=(x0*(y2-y3)+x2*(y3-y0)+x3*(y0-y2))/denominator;const b=(x0*(y3-y1)+x3*(y1-y0)+x1*(y0-y3))/denominator;const c=(x0*(y1-y2)+x1*(y2-y0)+x2*(y0-y1))/denominator;const reverse=invert([[width,-width,0],[0,-height,height],[1,-1,1],]);const forward=[[a*x1,b*x2,c*x3],[a*y1,b*y2,c*y3],[a,b,c],];return multiply(forward,reverse);} 6389__exports.getAffineApproximation=getAffineApproximation;function getAffineApproximation(projective,[[x0,y0],[x1,y1],[x2,y2]]){const a=transform(projective,[x0,y0]);const b=transform(projective,[x1,y1]);const c=transform(projective,[x2,y2]);return multiply([[a[0],b[0],c[0]],[a[1],b[1],c[1]],[1,1,1],],invert([[x0,x1,x2],[y0,y1,y2],[1,1,1],]));} 6390return __exports;});; 6391 6392/* /html_editor/static/src/utils/position.js */ 6393odoo.define('@html_editor/utils/position',[],function(require){'use strict';let __exports={};const DIRECTIONS=__exports.DIRECTIONS={LEFT:false,RIGHT:true,};__exports.leftPos=leftPos;function leftPos(node){return[node.parentElement,childNodeIndex(node)];} 6394__exports.rightPos=rightPos;function rightPos(node){return[node.parentElement,childNodeIndex(node)+1];} 6395__exports.boundariesOut=boundariesOut;function boundariesOut(node){const index=childNodeIndex(node);return[node.parentElement,index,node.parentElement,index+1];} 6396__exports.boundariesIn=boundariesIn;function boundariesIn(node){return[node,0,node,nodeSize(node)];} 6397__exports.startPos=startPos;function startPos(node){return[node,0];} 6398__exports.endPos=endPos;function endPos(node){return[node,nodeSize(node)];} 6399__exports.childNodeIndex=childNodeIndex;function childNodeIndex(node){let i=0;while(node.previousSibling){i++;node=node.previousSibling;} 6400return i;} 6401__exports.nodeSize=nodeSize;function nodeSize(node){const isTextNode=node.nodeType===Node.TEXT_NODE;if(isTextNode){return node.length;}else{const child=node.lastChild;return child?childNodeIndex(child)+1:0;}} 6402return __exports;});; 6403 6404/* /html_editor/static/src/utils/regex.js */ 6405odoo.define('@html_editor/utils/regex',[],function(require){'use strict';let __exports={};const tldWhitelist=['com','net','org','ac','ad','ae','af','ag','ai','al','am','an','ao','aq','ar','as','at','au','aw','ax','az','ba','bb','bd','be','bf','bg','bh','bi','bj','bl','bm','bn','bo','br','bq','bs','bt','bv','bw','by','bz','ca','cc','cd','cf','cg','ch','ci','ck','cl','cm','cn','co','cr','cs','cu','cv','cw','cx','cy','cz','dd','de','dj','dk','dm','do','dz','ec','ee','eg','eh','er','es','et','eu','fi','fj','fk','fm','fo','fr','ga','gb','gd','ge','gf','gg','gh','gi','gl','gm','gn','gp','gq','gr','gs','gt','gu','gw','gy','hk','hm','hn','hr','ht','hu','id','ie','il','im','in','io','iq','ir','is','it','je','jm','jo','jp','ke','kg','kh','ki','km','kn','kp','kr','kw','ky','kz','la','lb','lc','li','lk','lr','ls','lt','lu','lv','ly','ma','mc','md','me','mf','mg','mh','mk','ml','mm','mn','mo','mp','mq','mr','ms','mt','mu','mv','mw','mx','my','mz','na','nc','ne','nf','ng','ni','nl','no','np','nr','nu','nz','om','pa','pe','pf','pg','ph','pk','pl','pm','pn','pr','ps','pt','pw','py','qa','re','ro','rs','ru','rw','sa','sb','sc','sd','se','sg','sh','si','sj','sk','sl','sm','sn','so','sr','ss','st','su','sv','sx','sy','sz','tc','td','tf','tg','th','tj','tk','tl','tm','tn','to','tp','tr','tt','tv','tw','tz','ua','ug','uk','um','us','uy','uz','va','vc','ve','vg','vi','vn','vu','wf','ws','ye','yt','yu','za','zm','zr','zw','co\\.uk'];const urlRegexBase=`|(?:www.))[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-zA-Z][a-zA-Z0-9]{1,62}|(?:[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.(?:${tldWhitelist.join('|')})\\b))(?:(?:[/?#])[^\\s]*[^!.,})\\]'"\\s]|(?:[^!(){}.,[\\]'"\\s]+))?`;const httpCapturedRegex=`(https?:\\/\\/)`;const URL_REGEX=__exports.URL_REGEX=new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`,'i');return __exports;});; 6406 6407/* /html_editor/static/src/utils/resource.js */ 6408odoo.define('@html_editor/utils/resource',[],function(require){'use strict';let __exports={};const resourceSequenceSymbol=__exports.resourceSequenceSymbol=Symbol("resourceSequence");const READ=__exports.READ=0;__exports.withSequence=withSequence;function withSequence(sequenceNumber,object){if(typeof sequenceNumber!=="number"){throw new Error(`sequenceNumber must be a number. Got ${sequenceNumber} (${typeof sequenceNumber}).`);} 6409return{[resourceSequenceSymbol]:sequenceNumber,object,};} 6410return __exports;});; 6411 6412/* /html_editor/static/src/utils/sanitize.js */ 6413odoo.define('@html_editor/utils/sanitize',['@html_editor/utils/dom_info','@html_editor/utils/dom','@odoo/owl','@web/core/utils/html'],function(require){'use strict';let __exports={};const{containsAnyInline}=require("@html_editor/utils/dom_info");const{wrapInlinesInBlocks}=require("@html_editor/utils/dom");const{markup}=require("@odoo/owl");const{htmlReplace}=require("@web/core/utils/html");__exports.initElementForEdition=initElementForEdition;function initElementForEdition(element,options={}){if(element?.nodeType===Node.ELEMENT_NODE&&containsAnyInline(element)&&!options.allowInlineAtRoot){wrapInlinesInBlocks(element,{baseContainerNodeName:"DIV",});} 6414for(const img of element.querySelectorAll("img[width], img[height]")){const width=img.getAttribute("width");const height=img.getAttribute("height");img.removeAttribute("height");img.removeAttribute("width");
6414img.style.setProperty("width",isNaN(width)?width:`${width}px`);img.style.setProperty("height",isNaN(height)?height:`${height}px`);}} 6415__exports.fixInvalidHTML=fixInvalidHTML;function fixInvalidHTML(content){if(!content){return content;} 6416const regex=/<\s*(?!area\b|base\b|br\b|col\b|embed\b|hr\b|img\b|input\b|link\b|meta\b|param\b|v:image\b|v:fill\b|source\b|track\b|wbr\b)([a-zA-Z0-9:-]+)\s*((?:(?:\s+[\w:-]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*))\s*\/>/g;return htmlReplace(content,regex,(match,tag,attributes)=>{attributes=markup(attributes);return markup`<${tag}${attributes}></${tag}>`;});} 6417let Markup=null;__exports.instanceofMarkup=instanceofMarkup;function instanceofMarkup(value){if(!Markup){Markup=markup("").constructor;} 6418return value instanceof Markup;} 6419return __exports;});; 6420 6421/* /html_editor/static/src/utils/selection.js */ 6422odoo.define('@html_editor/utils/selection',['@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_state','@html_editor/utils/dom_traversal','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{getDeepestPosition,isContentEditable,isNotEditableNode,isSelfClosingElement,nextLeaf,previousLeaf,}=require("@html_editor/utils/dom_info");const{isFakeLineBreak}=require("@html_editor/utils/dom_state");const{closestElement,createDOMPathGenerator}=require("@html_editor/utils/dom_traversal");const{DIRECTIONS,childNodeIndex,endPos,leftPos,nodeSize,rightPos,startPos,}=require("@html_editor/utils/position");__exports.getCursorDirection=getCursorDirection;function getCursorDirection(anchorNode,anchorOffset,focusNode,focusOffset){if(anchorNode===focusNode){if(anchorOffset===focusOffset){return false;} 6423return anchorOffset<focusOffset?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;} 6424return anchorNode.compareDocumentPosition(focusNode)&Node.DOCUMENT_POSITION_FOLLOWING?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;} 6425__exports.findInSelection=findInSelection;function findInSelection(selection,selector){const selectorInStartAncestors=closestElement(selection.startContainer,selector);if(selectorInStartAncestors){return selectorInStartAncestors;}else{const commonElementAncestor=closestElement(selection.commonAncestorContainer);return(commonElementAncestor&&[...commonElementAncestor.querySelectorAll(selector)].find((node)=>selection.intersectsNode(node)));}} 6426const leftLeafOnlyInScopeNotBlockEditablePath=createDOMPathGenerator(DIRECTIONS.LEFT,{leafOnly:true,inScope:true,stopTraverseFunction:(node)=>isNotEditableNode(node)||isBlock(node),stopFunction:(node)=>isNotEditableNode(node)||isBlock(node),});const rightLeafOnlyInScopeNotBlockEditablePath=createDOMPathGenerator(DIRECTIONS.RIGHT,{leafOnly:true,inScope:true,stopTraverseFunction:(node)=>isNotEditableNode(node)||isBlock(node),stopFunction:(node)=>isNotEditableNode(node)||isBlock(node),});__exports.normalizeSelfClosingElement=normalizeSelfClosingElement;function normalizeSelfClosingElement(node,offset){if(isSelfClosingElement(node)){[node,offset]=rightPos(node);} 6427return[node,offset];} 6428__exports.normalizeNotEditableNode=normalizeNotEditableNode;function normalizeNotEditableNode(node,offset,position="right"){const editable=closestElement(node,".odoo-editor-editable");let closest=closestElement(node);while(closest&&closest!==editable&&!closest.isContentEditable){[node,offset]=position==="right"?rightPos(node):leftPos(node);closest=node;} 6429return[node,offset];} 6430__exports.normalizeCursorPosition=normalizeCursorPosition;function normalizeCursorPosition(node,offset,position="right"){[node,offset]=normalizeSelfClosingElement(node,offset);[node,offset]=normalizeNotEditableNode(node,offset,position);return[node,offset];} 6431__exports.normalizeFakeBR=normalizeFakeBR;function normalizeFakeBR(node,offset){const prevNode=node.nodeType===Node.ELEMENT_NODE&&node.childNodes[offset-1];if(prevNode&&prevNode.nodeName==="BR"&&isFakeLineBreak(prevNode)){offset--;} 6432return[node,offset];} 6433__exports.normalizeDeepCursorPosition=normalizeDeepCursorPosition;function normalizeDeepCursorPosition(node,offset){let el;let elOffset;if(node.nodeType===Node.ELEMENT_NODE){el=node;elOffset=offset;}else if(node.nodeType===Node.TEXT_NODE){if(offset===0){el=node.parentNode;elOffset=childNodeIndex(node);}else if(offset===node.length){el=node.parentNode;elOffset=childNodeIndex(node)+1;}} 6434if(el){const leftInlineNode=leftLeafOnlyInScopeNotBlockEditablePath(el,elOffset).next().value;let leftVisibleEmpty=false;if(leftInlineNode){leftVisibleEmpty=isSelfClosingElement(leftInlineNode)||!isContentEditable(leftInlineNode);[node,offset]=leftVisibleEmpty?rightPos(leftInlineNode):endPos(leftInlineNode);} 6435if(!leftInlineNode||leftVisibleEmpty){const rightInlineNode=rightLeafOnlyInScopeNotBlockEditablePath(el,elOffset).next().value;if(rightInlineNode){const closest=closestElement(rightInlineNode);const rightVisibleEmpty=isSelfClosingElement(rightInlineNode)||!closest||!closest.isContentEditable;if(!(leftVisibleEmpty&&rightVisibleEmpty)){[node,offset]=rightVisibleEmpty?leftPos(rightInlineNode):startPos(rightInlineNode);}}}} 6436return[node,offset];}
6437function updateCursorBeforeMove(destParent,destIndex,node,cursor){if(cursor.node===destParent&&cursor.offset>=destIndex){cursor.offset+=1;}else if(cursor.node===node.parentNode){const childIndex=childNodeIndex(node);if(cursor.offset===childIndex&&cursor.offset===0){[cursor.node,cursor.offset]=[destParent,destIndex];}else if(cursor.offset===childIndex+1&&cursor.offset===nodeSize(cursor.node)){[cursor.node,cursor.offset]=[destParent,destIndex+1];}else if(cursor.offset>childIndex){cursor.offset-=1;}}} 6438function updateCursorBeforeRemove(node,cursor){if(node.contains(cursor.node)){[cursor.node,cursor.offset]=[node.parentNode,childNodeIndex(node)];}else if(cursor.node===node.parentNode&&cursor.offset>childNodeIndex(node)){cursor.offset-=1;}} 6439function updateCursorBeforeUnwrap(node,cursor){if(cursor.node===node){[cursor.node,cursor.offset]=[node.parentNode,cursor.offset+childNodeIndex(node)];}else if(cursor.node===node.parentNode&&cursor.offset>childNodeIndex(node)){cursor.offset+=nodeSize(node)-1;}} 6440function updateCursorBeforeMergeIntoPreviousSibling(node,cursor){if(cursor.node===node){cursor.node=node.previousSibling;cursor.offset+=node.previousSibling.childNodes.length;}else if(cursor.node===node.parentNode){const childIndex=childNodeIndex(node);if(cursor.offset===childIndex){cursor.node=node.previousSibling;cursor.offset=node.previousSibling.childNodes.length;}else if(cursor.offset>childIndex){cursor.offset--;}}} 6441const callbacksForCursorUpdate=__exports.callbacksForCursorUpdate={remove:(node)=>(cursor)=>updateCursorBeforeRemove(node,cursor),before:(ref,node)=>(cursor)=>updateCursorBeforeMove(ref.parentNode,childNodeIndex(ref),node,cursor),after:(ref,node)=>(cursor)=>updateCursorBeforeMove(ref.parentNode,childNodeIndex(ref)+1,node,cursor),append:(to,node)=>(cursor)=>updateCursorBeforeMove(to,to.childNodes.length,node,cursor),prepend:(to,node)=>(cursor)=>updateCursorBeforeMove(to,0,node,cursor),unwrap:(node)=>(cursor)=>updateCursorBeforeUnwrap(node,cursor),merge:(node)=>(cursor)=>updateCursorBeforeMergeIntoPreviousSibling(node,cursor),};__exports.getAdjacentCharacter=getAdjacentCharacter;function getAdjacentCharacter(selection,side,editable){let{focusNode,focusOffset}=selection;[focusNode,focusOffset]=getDeepestPosition(focusNode,focusOffset);const originalBlock=closestBlock(focusNode);let adjacentCharacter;while(!adjacentCharacter&&focusNode){if(side==="previous"){adjacentCharacter=focusOffset>0&&focusNode.textContent[focusOffset-1];}else{adjacentCharacter=focusNode.textContent[focusOffset];} 6442if(!adjacentCharacter){if(side==="previous"){focusNode=previousLeaf(focusNode,editable);focusOffset=focusNode&&nodeSize(focusNode);}else{focusNode=nextLeaf(focusNode,editable);focusOffset=0;} 6443const characterIndex=side==="previous"?focusOffset-1:focusOffset;adjacentCharacter=focusNode&&focusNode.textContent[characterIndex];}} 6444if(!focusNode||!isContentEditable(focusNode)||closestBlock(focusNode)!==originalBlock){return undefined;} 6445return adjacentCharacter;} 6446return __exports;});; 6447 6448/* /html_editor/static/src/utils/table.js */ 6449odoo.define('@html_editor/utils/table',['@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{closestElement}=require("@html_editor/utils/dom_traversal");__exports.getRowIndex=getRowIndex;function getRowIndex(trOrTd){const tr=closestElement(trOrTd,"tr");return tr.rowIndex;} 6450__exports.getColumnIndex=getColumnIndex;function getColumnIndex(td){return td.cellIndex;} 6451__exports.getTableCells=getTableCells;function getTableCells(table){return[...table.querySelectorAll("td, th")].filter((cell)=>closestElement(cell,"table")===table);} 6452return __exports;});; 6453 6454/* /html_editor/static/src/utils/tracking.js */ 6455odoo.define('@html_editor/utils/tracking',[],function(require){'use strict';let __exports={};__exports.trackOccurrences=trackOccurrences;function trackOccurrences(){const visited=new Set();return function isFirstOccurrence(key){if(visited.has(key)){return false;} 6456visited.add(key);return true;};} 6457__exports.trackOccurrencesPair=trackOccurrencesPair;function trackOccurrencesPair(){const visited=new Map();return function isFirstOccurrence(a,b){if(!visited.has(a)){visited.set(a,trackOccurrences());} 6458return visited.get(a)(b);};} 6459return __exports;});; 6460 6461/* /html_editor/static/src/utils/url.js */ 6462odoo.define('@html_editor/utils/url',['@web/core/browser/browser','@web/session'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{session}=require("@web/session");const ODOO_DOMAIN_REGEX=new RegExp(`^https?://${session.db}\\.odoo\\.com(/.*)?$`);__exports.checkURL=checkURL;function checkURL(url,hostnameList){if(url){let potentialURL;try{potentialURL=new URL(url);}catch{return false;} 6463if(hostnameList.includes(potentialURL.hostname)){return`https://${potentialURL.hostname}${potentialURL.pathname}`;}} 6464return false;} 6465__exports.isImageUrl=isImageUrl;function isImageUrl(url){const urlFileExtention=url.split(".").pop();return["jpg","jpeg","png","gif","svg","webp"].includes(urlFileExtention.toLowerCase());} 6466__exports.getVideoUrl=getVideoUrl;function getVideoUrl(platform,videoId,params){let url;switch(platform){case"youtube":url=new URL(`https://www.youtube.com/embed/${videoId}`);break;case"vimeo":url=new URL(`https://player.vimeo.com/video/${videoId}`);break;case"dailymotion":url=new URL(`https://www.dailymotion.com/embed/video/${videoId}`);break;case"instagram":url=new URL(`https://www.instagram.com/p/${videoId}/embed`);break;default:throw new Error(`Unsupported platform: ${platform}`);} 6467url.search=new URLSearchParams(params);return url;} 6468__exports.isAbsoluteURLInCurrentDomain=isAbsoluteURLInCurrentDomain;function isAbsoluteURLInCurrentDomain(url,env=null){let hasProtocol;try{hasProtocol=!!new URL(url).protocol;}catch{hasProtocol=false;} 6469if(!hasProtocol){return false;} 6470const urlObj=new URL(url,window.location.origin);return(urlObj.origin===window.location.origin||ODOO_DOMAIN_REGEX.test(urlObj.origin));} 6471__exports.scrollAndHighlightHeading=scrollAndHighlightHeading;function scrollAndHighlightHeading(content,headingId=browser?.location?.hash?.replace?.(/^#/,"")){if(content&&headingId){setTimeout(()=>{const heading=content.querySelector(`[data-heading-link-id="${headingId}"]`);if(heading){heading.scrollIntoView({behavior:"smooth"});heading.classList.add("o-highlight-heading");setTimeout(()=>{heading.classList.remove("o-highlight-heading");},2000);}},500);}} 6472return __exports;});; 6473 6474/* /html_editor/static/src/dropdown_autovisibility_hook.js */ 6475odoo.define('@html_editor/dropdown_autovisibility_hook',['@odoo/owl'],function(require){'use strict';let __exports={};const{useEffect,useState}=require("@odoo/owl");__exports.useDropdownAutoVisibility=useDropdownAutoVisibility;function useDropdownAutoVisibility(overlayState,popoverRef){if(!overlayState){return;} 6476const state=useState(overlayState);useEffect(()=>{if(popoverRef.el){if(!state.isOverlayVisible){popoverRef.el.style.visibility="hidden";}else{popoverRef.el.style.visibility="visible";}}},()=>[state.isOverlayVisible]);} 6477return __exports;});; 6478 6479/* /html_editor/static/src/editor.js */ 6480odoo.define('@html_editor/editor',['@html_editor/plugin_sets','@html_editor/utils/base_container','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/resource','@html_editor/utils/sanitize','@web/core/utils/html'],function(require){'use strict';let __exports={};const{MAIN_PLUGINS}=require("@html_editor/plugin_sets");const{createBaseContainer,SUPPORTED_BASE_CONTAINER_NAMES}=require("@html_editor/utils/base_container");const{fillShrunkPhrasingParent,removeClass}=require("@html_editor/utils/dom");const{isEmpty}=require("@html_editor/utils/dom_info");const{resourceSequenceSymbol,withSequence}=require("@html_editor/utils/resource");const{fixInvalidHTML,initElementForEdition}=require("@html_editor/utils/sanitize");const{setElementContent}=require("@web/core/utils/html");function sortPlugins(plugins){const initialPlugins=new Set(plugins);const inResult=new Set();const result=[];let P;function findPlugin(){for(const P of initialPlugins){if(P.dependencies.every((dep)=>inResult.has(dep))){initialPlugins.delete(P);return P;}}}
6481while((P=findPlugin())){inResult.add(P.id);result.push(P);} 6482if(initialPlugins.size){const messages=[];for(const P of initialPlugins){messages.push(`"${P.id}" is missing (${P.dependencies 6483 .filter((d) => !inResult.has(d)) 6484 .join(", ")})`);} 6485throw new Error(`Missing dependencies: ${messages.join(", ")}`);} 6486return result;} 6487const Editor=__exports.Editor=class Editor{constructor(config,services){this.isReady=false;this.isDestroyed=false;this.config=config;this.services=services;this.resources=null;this.plugins=[];this.editable=null;this.document=null;this.shared={};} 6488attachTo(editable){if(this.isDestroyed||this.editable){throw new Error("Cannot re-attach an editor");} 6489this.editable=editable;this.document=editable.ownerDocument;this.preparePlugins();if("content"in this.config){setElementContent(editable,fixInvalidHTML(this.config.content));if(isEmpty(editable)){const baseContainer=createBaseContainer(this.config.baseContainers[0],this.document);fillShrunkPhrasingParent(baseContainer);editable.replaceChildren(baseContainer);}} 6490editable.setAttribute("contenteditable",true);editable.setAttribute("translate","no");initElementForEdition(editable,{allowInlineAtRoot:!!this.config.allowInlineAtRoot});editable.classList.add("odoo-editor-editable");if(this.config.classList){editable.classList.add(...this.config.classList);} 6491if(this.config.height){editable.style.height=this.config.height;} 6492if(!this.config.baseContainers.every((name)=>SUPPORTED_BASE_CONTAINER_NAMES.includes(name))){throw new Error(`Invalid baseContainers: ${this.config.baseContainers.join( 6493 ", " 6494 )}. Supported: ${SUPPORTED_BASE_CONTAINER_NAMES.join(", ")}`);} 6495this.startPlugins();this.isReady=true;this.config.onEditorReady?.();} 6496preparePlugins(){const Plugins=sortPlugins(this.config.Plugins||MAIN_PLUGINS);this.config=Object.assign({},...Plugins.map((P)=>P.defaultConfig),this.config);this.pluginsMap=new Map();for(const P of Plugins){if(P.id===""){throw new Error(`Missing plugin id (class ${P.name})`);} 6497if(this.pluginsMap.has(P.id)){throw new Error(`Duplicate plugin id: ${P.id}`);} 6498this.pluginsMap.set(P.id,P);const plugin=new P(this.getEditorContext(P.dependencies));plugin.__editor=this;this.plugins.push(plugin);const exports={};for(const h of P.shared){if(!(h in plugin)){throw new Error(`Missing helper implementation: ${h} in plugin ${P.id}`);} 6499exports[h]=plugin[h].bind(plugin);} 6500this.shared[P.id]=exports;} 6501const resources=this.createResources();for(const plugin of this.plugins){plugin._resources=resources;} 6502this.resources=resources;} 6503startPlugins(){for(const plugin of this.plugins){plugin.setup();} 6504this.resources["normalize_handlers"].forEach((cb)=>cb(this.editable));this.resources["start_edition_handlers"].forEach((cb)=>cb());} 6505getDependencies(dependencies){const deps={};for(const depName of dependencies){if(!(depName in this.shared)){throw new Error(`Missing dependency: ${depName}`);} 6506deps[depName]=this.shared[depName];} 6507return deps;} 6508createResources(){const resources={};function registerResources(obj){for(const key in obj){if(!(key in resources)){resources[key]=[];} 6509resources[key].push(obj[key]);}} 6510if(this.config.resources){registerResources(this.config.resources);} 6511for(const plugin of this.plugins){if(plugin.resources){registerResources(plugin.resources);}} 6512for(const key in resources){const resource=resources[key].flat().map((r)=>{const isObjectWithSequence=typeof r==="object"&&r!==null&&resourceSequenceSymbol in r;return isObjectWithSequence?r:withSequence(10,r);}).sort((a,b)=>a[resourceSequenceSymbol]-b[resourceSequenceSymbol]).map((r)=>r.object);resources[key]=resource;Object.freeze(resources[key]);} 6513return Object.freeze(resources);} 6514getEditorContext(dependencies=[]){return{document:this.document,editable:this.editable,dependencies:this.getDependencies(dependencies),config:this.config,services:this.services,getResource:this.getResource.bind(this),dispatchTo:this.dispatchTo.bind(this),delegateTo:this.delegateTo.bind(this),checkPredicates:this.checkPredicates.bind(this),};} 6515getResource(resourceId){return this.resources[resourceId]||[];} 6516dispatchTo(resourceId,...args){this.getResource(resourceId).forEac
6516h((handler)=>handler(...args));} 6517delegateTo(resourceId,...args){return this.getResource(resourceId).some((fn)=>fn(...args));} 6518checkPredicates(resourceId,...args){const results=this.getResource(resourceId).map((predicate)=>predicate(...args)).filter((result)=>result!==undefined);return results.length?results.every(Boolean):undefined;} 6519getContent(){return this.getElContent().innerHTML;} 6520getElContent(){const el=this.editable.cloneNode(true);this.resources["clean_for_save_handlers"].forEach((cb)=>cb({root:el}));return el;} 6521destroy(willBeRemoved){if(this.editable){let plugin;while((plugin=this.plugins.pop())){plugin.destroy();} 6522this.shared={};if(!willBeRemoved){this.editable.removeAttribute("contenteditable");removeClass(this.editable,"odoo-editor-editable");} 6523this.editable=null;} 6524this.isDestroyed=true;}} 6525return __exports;});; 6526 6527/* /html_editor/static/src/plugin.js */ 6528odoo.define('@html_editor/plugin',['@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{isProtected,isProtecting,isUnprotecting}=require("@html_editor/utils/dom_info");const isValidTargetForDomListener=__exports.isValidTargetForDomListener=(target)=>!isProtecting(target)&&(!isProtected(target)||isUnprotecting(target));const Plugin=__exports.Plugin=class Plugin{static id="";static dependencies=[];static shared=[];static defaultConfig={};resources;constructor(context){this.document=context.document;this.window=context.document.defaultView;this.editable=context.editable;this.config=context.config;this.services=context.services;this.dependencies=context.dependencies;this.getResource=context.getResource;this.dispatchTo=context.dispatchTo;this.delegateTo=context.delegateTo;this.checkPredicates=context.checkPredicates;this._cleanups=[];this.isDestroyed=false;} 6529setup(){} 6530isValidTargetForDomListener(ev){return isValidTargetForDomListener(ev.target);} 6531addDomListener(target,eventName,fn,capture=false,isGlobal=false){const handler=(ev)=>{if(isGlobal||this.isValidTargetForDomListener(ev)){fn?.call(this,ev);}};target.addEventListener(eventName,handler,capture);this._cleanups.push(()=>target.removeEventListener(eventName,handler,capture));} 6532addGlobalDomListener(eventName,fn,capture=false){this.addDomListener(this.document,eventName,fn,capture,true);} 6533destroy(){for(const cleanup of this._cleanups){cleanup();} 6534this.isDestroyed=true;}} 6535return __exports;});; 6536 6537/* /html_editor/static/src/plugin_sets.js */ 6538odoo.define('@html_editor/plugin_sets',['@html_editor/core/base_container_plugin','@html_editor/core/clipboard_plugin','@html_editor/core/comment_plugin','@html_editor/core/delete_plugin','@html_editor/core/dialog_plugin','@html_editor/core/dom_plugin','@html_editor/main/separator_plugin','@html_editor/core/format_plugin','@html_editor/core/history_plugin','@html_editor/core/input_plugin','@html_editor/core/line_break_plugin','@html_editor/core/no_inline_root_plugin','@html_editor/core/overlay_plugin','@html_editor/core/protected_node_plugin','@html_editor/core/sanitize_plugin','@html_editor/core/selection_plugin','@html_editor/core/shortcut_plugin','@html_editor/core/split_plugin','@html_editor/core/user_command_plugin','@html_editor/main/align/align_plugin','@html_editor/main/banner_plugin','@html_editor/main/chatgpt/chatgpt_translate_plugin','@html_editor/main/column_plugin','@html_editor/main/emoji_plugin','@html_editor/main/font/color_plugin','@html_editor/main/font/color_ui_plugin','@html_editor/main/feff_plugin','@html_editor/main/font/font_plugin','@html_editor/main/font/font_family_plugin','@html_editor/main/hint_plugin','@html_editor/main/inline_code','@html_editor/main/link/link_paste_plugin','@html_editor/main/link/link_plugin','@html_editor/main/link/link_selection_odoo_plugin','@html_editor/main/link/link_selection_plugin','@html_editor/main/list/list_plugin','@html_editor/main/local_overlay_plugin','@html_editor/main/media/file_plugin','@html_editor/main/media/icon_plugin','@html_editor/main/media/icon_color_plugin','@html_editor/main/media/image_crop_plugin','@html_editor/main/media/image_plugin','@html_editor/main/media/image_save_plugin','@html_editor/main/media/media_plugin','@html_editor/main/movenode_plugin','@html_editor/main/power_buttons_plugin','@html_editor/main/position_plugin','@html_editor/main/powerbox/powerbox_plugin','@html_editor/main/link/powerbox_url_paste_plugin','@html_editor/main/powerbox/search_powerbox_plugin','@html_editor/main/star_plugin','@html_editor/main/table/table_align_plugin','@html_editor/main/table/table_plugin','@html_editor/main/table/table_resize_plugin','@html_editor/main/table/table_ui_plugin','@html_editor/main/tabulation_plugin','@html_editor/main/text_direction_plugin','@html_editor/main/toolbar/toolbar_plugin','@html_editor/main/media/video_plugin','@html_editor/main/youtube_plugin','@html_editor/main/placeholder_plugin','@html_editor/others/collaboration/collaboration_odoo_plugin','@html_editor/others/collaboration/collaboration_plugin','@html_editor/others/collaboration/collaboration_selection_avatar_plugin','@html_editor/others/collaboration/collaboration_selection_plugin','@html_editor/others/embedded_component_plugin','@html_editor/others/embedded_components/plugins/table_of_content_plugin/table_of_content_plugin','@html_editor/others/embedded_components/plugins/toggle_block_plugin/toggle_block_plugin','@html_editor/others/embedded_components/plugins/video_plugin/embedded_video_plugin','@html_editor/others/embedded_components/plugins/video_plugin/embedded_youtube_plugin','@html_editor/others/embedded_components/plugins/caption_plugin/caption_plugin','@html_editor/others/embedded_components/plugins/syntax_highlighting_plugin/syntax_highlighting_plugin','@html_editor/others/qweb_plugin','@html_editor/core/editor_version_plugin','@html_editor/main/media/image_post_process_plugin','@html_editor/main/media/dblclick_image_preview_plugin','@html_editor/core/style_plugin','@html_editor/core/content_editable_plugin','@html_editor/main/selection_placeholder_plugin'],function(require){'use strict';let __exports={};const{BaseContainerPlugin}=require("@html_editor/core/base_container_plugin");const{ClipboardPlugin}=require("@html_editor/core/clipboard_plugin");const{CommentPlugin}=require("@html_editor/core/comment_plugin");const{DeletePlugin}=require("@html_editor/core/delete_plugin");const{DialogPlugin}=require("@html_editor/core/dialog_plugin");const{DomPlugin}=require("@html_editor/core/dom_plugin");const{SeparatorPlugin}=require("@html_editor/main/separator_plugin");const{FormatPlugin}=require("@html_editor/core/format_plugin");const{HistoryPlugin}=require("@html_editor/core/history_plugin");const{InputPlugin}=require("@html_editor/core/input_plugin");const{LineBreakPlugin}=require("@html_editor/core/line_break_plugin");const{NoInlineRootPlugin}=require("@html_editor/core/no_inline_root_plugin");const{OverlayPlugin}=require("@html_editor/core/overlay_plugin");const{ProtectedNodePlugin}=require("@html_editor/core/protected_node_plugin");const{SanitizePlugin}=require("@html_editor/core/sanitize_plugin");const{SelectionPlugin}=require("@html_editor/core/selection_plugin");const{ShortCutPlugin}=require("@html_editor/core/shortcut_plugin");const{SplitPlugin}=require("@html_editor/core/split_plugin");const{UserCommandPlugin}=require("@html_editor/core/user_command_plugin");const{AlignPlugin}=require("@html_editor/main/align/align_plugin");const{BannerPlugin}=require("@html_editor/main/banner_plugin");const{ChatGPTTranslatePlugin}=require("@html_editor/main/chatgpt/chatgpt_translate_plugin");const{ColumnPlugin}=require("@html_editor/main/column_plugin");const{EmojiPlugin}=require("@html_editor/main/emoji_plugin");const{ColorPlugin}=require("@html_editor/main/font/color_plugin");const{ColorUIPlugin}=require("@html_editor/main/font/color_ui_plugin");const{FeffPlugin}=require("@html_editor/main/feff_plugin");const{FontPlugin}=require("@html_editor/main/font/font_plugin");const{FontFamilyPlugin}=require("@html_editor/main/font/font_family_plugin");const{HintPlugin}=require("@html_editor/main/hint_plugin");const{InlineCodePlugin}=require("@html_editor/main/inline_code");const{LinkPastePlugin}=require("@html_editor/main/link/link_paste_plugin");const{LinkPlugin}=require("@html_editor/main/link/link_plugin");const{OdooLinkSelectionPlugin}=require("@html_editor/main/link/link_selection_odoo_plugin");const{LinkSelectionPlugin}=require("@html_editor/main/link/link_selection_plugin");const{ListPlugin}=require("@html_editor/main/list/list_plugin");const{LocalOverlayPlugin}=require("@html_editor/main/local_overlay_plugin");const{FilePlugin}=require("@html_editor/main/media/file_plugin");const{IconPlugin}=require("@html_editor/main/media/icon_plugin");const{IconColorPlugin}=require("@html_editor/main/media/icon_color_plugin");const{ImageCropPlugin}=require("@html_editor/main/media/image_crop_plugin");const{ImagePlugin}=require("@html_editor/main/media/image_plugin");const{ImageSavePlugin}=require("@html_editor/main/media/image_save_plugin");const{MediaPlugin}=require("@html_editor/main/media/media_plugin");const{MoveNodePlugin}=require("@html_editor/main/movenode_plugin");const{PowerButtonsPlugin}=require("@html_editor/main/power_buttons_plugin");const{PositionPlugin}=require("@html_editor/main/position_plugin");const{PowerboxPlugin}=require("@html_editor/main/powerbox/powerbox_plugin");const{MediaUrlPastePlugin}=require("@html_editor/main/link/powerbox_url_paste_plugin");const{SearchPowerboxPlugin}=require("@html_editor/main/powerbox/search_powerbox_plugin");const{StarPlugin}=require("@html_editor/main/star_plugin");const{TableAlignPlugin}=require("@html_editor/main/table/table_align_plugin");const{TablePlugin}=require("@html_editor/main/table/table_plugin");const{TableResizePlugin}=require("@html_editor/main/table/table_resize_plugin");const{TableUIPlugin}=require("@html_editor/main/table/table_ui_plugin");const{TabulationPlugin}=require("@html_editor/main/tabulation_plugin");const{TextDirectionPlugin}=require("@html_editor/main/text_direction_plugin");const{ToolbarPlugin}=require("@html_editor/main/toolbar/toolbar_plugin");const{VideoPlugin}=require("@html_editor/main/media/video_plugin");const{YoutubePlugin}=require("@html_editor/main/youtube_plugin");const{PlaceholderPlugin}=require("@html_editor/main/placeholder_plugin");const{CollaborationOdooPlugin}=require("@html_editor/others/collaboration/collaboration_odoo_plugin");const{CollaborationPlugin}=require("@html_editor/others/collaboration/collaboration_plugin");const{CollaborationSelectionAvatarPlugin}=require("@html_editor/others/collaboration/collaboration_selection_avatar_plugin");const{CollaborationSelectionPlugin}=require("@html_editor/others/collaboration/collaboration_selection_plugin");const{EmbeddedComponentPlugin}=require("@html_editor/others/embedded_component_plugin");const{TableOfContentPlugin}=require("@html_editor/others/embedded_components/plugins/table_of_content_plugin/table_of_content_plugin");const{ToggleBlockPlugin}=require("@html_editor/others/embedded_components/plugins/toggle_block_plugin/toggle_block_plugin");const{EmbeddedVideoPlugin}=require("@html_editor/others/embedded_components/plugins/video_plugin/embedded_video_plugin");const{EmbeddedYoutubePlugin}=require("@html_editor/others/embedded_components/plugins/video_plugin/embedded_youtube_plugin");const{CaptionPlugin}=require("@html_editor/others/embedded_components/plugins/caption_plugin/caption_plugin");const{SyntaxHighlightingPlugin}=require("@html_editor/others/embedded_components/plugins/syntax_highlighting_plugin/syntax_highlighting_plugin");const{QWebPlugin}=require("@html_editor/others/qweb_plugin");const{EditorVersionPlugin}=require("@html_editor/core/editor_version_plugin");const{ImagePostProcessPlugin}=require("@html_editor/main/media/image_post_process_plugin");const{DoubleClickImagePreviewPlugin}=require("@html_editor/main/media/dblclick_image_preview_plugin");const{StylePlugin}=require("@html_editor/core/style_plugin");const{ContentEditablePlugin}=require("@html_editor/core/content_editable_plugin");const{SelectionPlaceholderPlugin}=require("@html_editor/main/selection_placeholder_plugin");const CORE_PLUGINS=__exports.CORE_PLUGINS=[BaseContainerPlugin,ClipboardPlugin,CommentPlugin,DeletePlugin,DialogPlugin,DomPlugin,FormatPlugin,HistoryPlugin,InputPlugin,LineBreakPlugin,NoInlineRootPlugin,OverlayPlugin,ProtectedNodePlugin,SanitizePlugin,SelectionPlugin,SplitPlugin,UserCommandPlugin,StylePlugin,ContentEditablePlugin,];const MAIN_PLUGINS=__exports.MAIN_PLUGINS=[...CORE_PLUGINS,BannerPlugin,ChatGPTTranslatePlugin,ColorPlugin,ColorUIPlugin,SeparatorPlugin,ColumnPlugin,EmojiPlugin,HintPlugin,AlignPlugin,ListPlugin,MediaPlugin,ImageSavePlugin,ShortCutPlugin,PowerboxPlugin,SearchPowerboxPlugin,MediaUrlPastePlugin,StarPlugin,TablePlugin,TableAlignPlugin,TableUIPlugin,TabulationPlugin,ToolbarPlugin,FontPlugin,FontFamilyPlugin,IconPlugin,IconColorPlugin,ImagePlugin,ImagePostProcessPlugin,ImageCropPlugin,DoubleClickImagePreviewPlugin,LinkPlugin,LinkPastePlugin,FeffPlugin,LinkSelectionPlugin,OdooLinkSelectionPlugin,PowerButtonsPlugin,MoveNodePlugin,LocalOverlayPlugin,PositionPlugin,TextDirectionPlugin,InlineCodePlugin,TableResizePlugin,FilePlugin,PlaceholderPlugin,SelectionPlaceholderPlugin,];const COLLABORATION_PLUGINS=__exports.COLLABORATION_PLUGINS=[CollaborationPlugin,CollaborationOdooPlugin,CollaborationSelectionPlugin,CollaborationSelectionAvatarPlugin,];const EMBEDDED_COMPONENT_PLUGINS=__exports.EMBEDDED_COMPONENT_PLUGINS=[EmbeddedComponentPlugin,TableOfContentPlugin,ToggleBlockPlugin,EmbeddedVideoPlugin,EmbeddedYoutubePlugin,CaptionPlugin,SyntaxHighlightingPlugin,];const NO_EMBEDDED_COMPONENTS_FALLBACK_PLUGINS=__exports.NO_EMBEDDED_COMPONENTS_FALLBACK_PLUGINS=[VideoPlugin,YoutubePlugin];const EXTRA_PLUGINS=__exports.EXTRA_PLUGINS=[...COLLABORATION_PLUGINS,...MAIN_PLUGINS,...EMBEDDED_COMPONENT_PLUGINS,EditorVersionPlugin,QWebPlugin,];return __exports;});; 6539 6540/* /html_editor/static/src/wysiwyg.js */ 6541odoo.define('@html_editor/wysiwyg',['@odoo/owl','@html_editor/editor','@html_editor/main/toolbar/toolbar','@web/core/utils/hooks','@html_editor/local_overlay_container','@web/core/utils/functions'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillDestroy,useRef,useSubEnv}=require("@odoo/owl");const{Editor}=require("@html_editor/editor");const{Toolbar}=require("@html_editor/main/toolbar/toolbar");const{useChildRef,useSpellCheck}=require("@web/core/utils/hooks");const{LocalOverlayContainer}=require("@html_editor/local_overlay_container");const{uniqueId}=require("@web/core/utils/functions");function copyCssRules(sourceDoc,targetDoc){for(const sheet of sourceDoc.styleSheets){const rules=[];for(const r of sheet.cssRules){rules.push(r.cssText);} 6542const cssRules=rules.join(" ");
6542const styleTag=targetDoc.createElement("style");styleTag.appendChild(targetDoc.createTextNode(cssRules));targetDoc.head.appendChild(styleTag);}} 6543const Wysiwyg=__exports.Wysiwyg=class Wysiwyg extends Component{static template="html_editor.Wysiwyg";static components={Toolbar,LocalOverlayContainer};static props={config:{type:Object,optional:true},class:{type:String,optional:true},contentClass:{type:String,optional:true},style:{type:String,optional:true},iframe:{type:Boolean,optional:true},copyCss:{type:Boolean,optional:true},onLoad:{type:Function,optional:true},onBlur:{type:Function,optional:true},dynamicPlaceholder:{type:Boolean,optional:true},};static defaultProps={onLoad:()=>{},onBlur:()=>{},};setup(){this.overlayRef=useChildRef();useSubEnv({localOverlayContainerKey:uniqueId("wysiwyg"),});const contentRef=useRef("content");this.editor=this.props.editor;const config=this.getEditorConfig();this.editor=new Editor(config,this.env.services);this.props.onLoad(this.editor);useSpellCheck({refName:"content",});onMounted(()=>{const el=contentRef.el;if(el.tagName==="IFRAME"){const attachEditor=()=>{if(!this.editor.isDestroyed){if(this.props.copyCss){copyCssRules(document,el.contentDocument);} 6544const additionalClasses=el.dataset.class?.trim().split(" ");if(additionalClasses){for(const c of additionalClasses){el.contentDocument.body.classList.add(c);}} 6545this.editor.attachTo(el.contentDocument.body);}};if(el.contentDocument.readyState==="complete"){attachEditor();}else{el.addEventListener("load",()=>{attachEditor();this.render();},{once:true});}}else{this.editor.attachTo(el);}});onWillDestroy(()=>this.editor.destroy(true));} 6546getEditorConfig(){return{...this.props.config,localOverlayContainers:{key:this.env.localOverlayContainerKey,ref:this.overlayRef,},};}} 6547return __exports;});; 6548 6549/* /html_editor/static/src/components/history_dialog/history_dialog.js */ 6550odoo.define('@html_editor/components/history_dialog/history_dialog',['@web/core/dialog/dialog','@web/core/notebook/notebook','@web/core/l10n/dates','@web/core/utils/hooks','@web/core/utils/functions','@odoo/owl','@web/core/l10n/translation','@web/core/user','@html_editor/components/html_viewer/html_viewer','@html_editor/others/embedded_components/embedding_sets','@web/core/browser/browser','@web/core/browser/cookie','@web/core/assets','@web/core/utils/html'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{Notebook}=require("@web/core/notebook/notebook");const{formatDateTime}=require("@web/core/l10n/dates");const{useService}=require("@web/core/utils/hooks");const{memoize}=require("@web/core/utils/functions");const{Component,onMounted,useState,markup,onWillStart,onWillDestroy}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{user}=require("@web/core/user");const{HtmlViewer}=require("@html_editor/components/html_viewer/html_viewer");const{READONLY_MAIN_EMBEDDINGS}=require("@html_editor/others/embedded_components/embedding_sets");const{browser}=require("@web/core/browser/browser");const{cookie}=require("@web/core/browser/cookie");const{loadBundle}=require("@web/core/assets");const{htmlReplaceAll}=require("@web/core/utils/html");const{DateTime}=luxon;const HistoryDialog=__exports.HistoryDialog=class HistoryDialog extends Component{static template="html_editor.HistoryDialog";static components={Dialog,HtmlViewer,Notebook};static props={recordId:Number,recordModel:String,close:Function,restoreRequested:Function,historyMetadata:Array,versionedFieldName:String,title:{String,optional:true},noContentHelper:{String,optional:true},embeddedComponents:{Array,optional:true},};DEFAULT_AVATAR="/mail/static/src/img/smiley/avatar.jpg";static defaultProps={title:_t("History"),noContentHelper:markup(""),embeddedComponents:[...READONLY_MAIN_EMBEDDINGS],};state=useState({revisionsData:[],currentView:"content",isComparisonSplit:false,revisionContent:null,revisionComparison:null,revisionId:null,revisionLoading:true,cssMaxHeight:400,});setup(){this.size="fullscreen";this.title=this.props.title;this.orm=useService("orm");this.resizeObserver=null;onWillStart(async()=>{let revisionId=-1;const revisionData=[];for(const metadata of this.props.historyMetadata){revisionData.push({...metadata,revision_
6550id:revisionId});revisionId=metadata["revision_id"];} 6551const record=await this.orm.read(this.props.recordModel,[this.props.recordId],["create_date","create_uid"]);revisionData.push({revision_id:revisionId,create_date:DateTime.fromFormat(record[0]["create_date"],"yyyy-MM-dd HH:mm:ss",{zone:"utc"}).toISO(),create_uid:record[0]["create_uid"][0],create_user_name:record[0]["create_uid"][1],});this.state.revisionsData=revisionData;this.resizeObserver=new ResizeObserver(this.resize.bind(this));this.resizeObserver.observe(document.body);});onMounted(()=>this.init());onWillDestroy(()=>{this.resizeObserver?.disconnect();});} 6552resize(){const dialogContainer=document.querySelector(".html-history-dialog-container");const computedStyle=getComputedStyle(dialogContainer);this.state.cssMaxHeight=parseInt(computedStyle.height.replace("px",""))-160;} 6553getConfig(value){return{value:this.state[value],embeddedComponents:this.props.embeddedComponents,};} 6554async init(){if(this.env.debug){await loadBundle("html_editor.assets_history_diff");} 6555await this.updateCurrentRevision(this.state.revisionsData[0]["revision_id"]);this.resize();} 6556async updateCurrentRevision(revisionId){if(this.state.revisionId===revisionId){return;} 6557this.state.revisionLoading=true;this.state.revisionId=revisionId;this.state.revisionContent=await this.getRevisionContent(revisionId);this.state.revisionComparison=await this.getRevisionComparison(revisionId);this.state.revisionComparisonSplit=await this.getRevisionComparisonSplit(revisionId);this.state.revisionLoading=false;} 6558getRevisionComparison=memoize(async function getRevisionComparison(revisionId){if(revisionId===-1){return"";} 6559const comparison=await this.orm.call(this.props.recordModel,"html_field_history_get_comparison_at_revision",[this.props.recordId,this.props.versionedFieldName,revisionId]);return this._removeExternalBlockHtml(markup(comparison));}.bind(this));getRevisionComparisonSplit=memoize(async function getRevisionComparisonSplit(revisionId){if(!this.env.debug||revisionId===-1){return"";} 6560let unifiedDiffString=await this.orm.call(this.props.recordModel,"html_field_history_get_unified_diff_at_revision",[this.props.recordId,this.props.versionedFieldName,revisionId]);unifiedDiffString=unifiedDiffString.replace(/^\s*[\r\n]/gm,"");const colorScheme=cookie.get("color_scheme")==="dark"?"dark":"light";const diffHtml=Diff2Html.html(unifiedDiffString,{drawFileList:false,matching:"lines",outputFormat:"side-by-side",colorScheme:colorScheme,});return markup(diffHtml);}.bind(this));getRevisionContent=memoize(async function getRevisionContent(revisionId){if(revisionId===-1){const curentContent=await this.orm.read(this.props.recordModel,[this.props.recordId],[this.props.versionedFieldName]);if(!curentContent||!curentContent.length){return this.props.noContentHelper;} 6561return this._removeExternalBlockHtml(markup(curentContent[0][this.props.versionedFieldName]));} 6562const content=await this.orm.call(this.props.recordModel,"html_field_history_get_content_at_revision",[this.props.recordId,this.props.versionedFieldName,revisionId]);return this._removeExternalBlockHtml(markup(content));}.bind(this));async _onRestoreRevisionClick(){this.env.services.ui.block();const restoredContent=await this.getRevisionContent(this.state.revisionId);this.props.restoreRequested(restoredContent,this.props.close);this.env.services.ui.unblock();} 6563_removeExternalBlockHtml(baseHtml){const filteringRegex=/<[a-z ]+data-embedded="(?:(?!<).)+<\/[a-z]+>/gim;
6563const placeholderHtml=markup`<div class="embedded-history-dialog-placeholder">${_t( 6564 "Dynamic element" 6565 )}</div>`;return htmlReplaceAll(baseHtml,filteringRegex,()=>placeholderHtml);} 6566getRevisionDate(revision){if(!revision||!revision["create_date"]){return"--";} 6567const userTZ=user.tz||"local";return formatDateTime(DateTime.fromISO(revision["create_date"],{zone:"utc"}).setZone(userTZ),{showSeconds:false});} 6568getRevisionClasses(revision){let classesStr="btn";if(this.state.revisionId!==-1&&(this.state.revisionId<revision.revision_id||revision.revision_id===-1)){classesStr+=" targeted";}else if(this.state.revisionId===revision.revision_id){classesStr+=" selected";} 6569return classesStr;} 6570getRevisionAuthorAvatar(revision){if(!revision||!revision["create_uid"]){return this.DEFAULT_AVATAR;} 6571return`${browser.location.origin}/web/image?model=res.users&field=avatar_128&id=${revision["create_uid"]}`;} 6572get currentRevision(){const id=this.state?.revisionId||this.state.revisionsData[0]["revision_id"];return this.state.revisionsData.find((revision)=>
6572revision["revision_id"]===id);}} 6573return __exports;});; 6574 6575/* /html_editor/static/src/core/base_container_plugin.js */ 6576odoo.define('@html_editor/core/base_container_plugin',['@html_editor/utils/dom_info','@html_editor/plugin','@html_editor/utils/dom','@html_editor/utils/base_container','@html_editor/utils/resource','@html_editor/utils/dom_traversal','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{containsAnyNonPhrasingContent,getDeepestPosition,isContentEditable,isElement,isEmpty,isMediaElement,isProtected,isProtecting,}=require("@html_editor/utils/dom_info");const{Plugin}=require("@html_editor/plugin");const{fillEmpty}=require("@html_editor/utils/dom");const{BASE_CONTAINER_CLASS,baseContainerGlobalSelector,createBaseContainer,}=require("@html_editor/utils/base_container");const{withSequence}=require("@html_editor/utils/resource");const{selectElements}=require("@html_editor/utils/dom_traversal");const{childNodeIndex}=require("@html_editor/utils/position");const BaseContainerPlugin=__exports.BaseContainerPlugin=class BaseContainerPlugin extends Plugin{static id="baseContainer";static shared=["createBaseContainer","getDefaultNodeName","isCandidateForBaseContainer"];static defaultConfig={baseContainers:["P","DIV"],};static dependencies=["selection"];hasNonPhrasingContentPredicate=(element)=>element?.nodeType===Node.ELEMENT_NODE&&containsAnyNonPhrasingContent(element);isUnsplittablePredicate=(element)=>this.getResource("unsplittable_node_predicates").some((fn)=>fn(element));resources={clean_for_save_handlers:this.cleanForSave.bind(this),normalize_handlers:withSequence(Infinity,this.normalizeDivBaseContainers.bind(this)),delete_handlers:()=>{if(this.config.cleanEmptyStructuralContainers===false){return;} 6577this.cleanEmptyStructuralContainers();},unsplittable_node_predicates:(node)=>{if(node.nodeName!=="DIV"){return false;} 6578return!this.isCandidateForBaseContainerAllowUnsplittable(node);},invalid_for_base_container_predicates:[(node)=>!node||node.nodeType!==Node.ELEMENT_NODE||!this.config.baseContainers.includes(node.tagName)||isProtected(node)||isProtecting(node)||isMediaElement(node),this.isUnsplittablePredicate,this.hasNonPhrasingContentPredicate,],system_classes:[BASE_CONTAINER_CLASS],};createBaseContainer(nodeName=this.getDefaultNodeName()){return createBaseContainer(nodeName,this.document);} 6579getDefaultNodeName(){return this.config.baseContainers[0];} 6580cleanEmptyStructuralContainers(){const node=this.document.getSelection().anchorNode;if(!isElement(node)||!isEmpty(node)){return;} 6581const closestEditable=(n)=>isContentEditable(n.parentElement)?closestEditable(n.parentElement):n;const isUnsplittable=this.isUnsplittablePredicate(node);const isCandidateForBase=this.isCandidateForBaseContainerAllowUnsplittable(node);if(isUnsplittable||!isCandidateForBase){return;} 6582let anchorNode=node.parentElement;if(anchorNode===closestEditable(node)||!this.config.baseContainers.includes(anchorNode.nodeName)||this.getResource("unremovable_node_predicates").some((p)=>p(anchorNode))){return;} 6583if(isEmpty(anchorNode)){fillEmpty(anchorNode);} 6584let anchorOffset=childNodeIndex(node);node.remove();[anchorNode,anchorOffset]=getDeepestPosition(anchorNode,anchorOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset,});} 6585isCandidateForBaseContainer(element){return!this.getResource("invalid_for_base_container_predicates").some((fn)=>fn(element));} 6586isCandidateForBaseContainerAllowUnsplittable(element){for(const predicate of this.getResource("invalid_for_base_container_predicates")){if(predicate===this.isUnsplittablePredicate){continue;} 6587if(predicate(element)){return false;}} 6588return true;} 6589shallowIsCandidateForBaseContainer(element){const predicates=this.getResource("invalid_for_base_container_predicates");for(const predicate of predicates){if(predicate===this.hasNonPhrasingContentPredicate){continue;} 6590if(predicate(element)){return false;}} 6591return true;} 6592cleanForSave({root}){for(const baseContainer of selectElements(root,`.${BASE_CONTAINER_CLASS}`)){baseContainer.classList.remove(BASE_CONTAINER_CLASS);if(baseContainer.classList.length===0){baseContainer.removeAttribute("class");}}} 6593normalizeDivBaseContainers(element=this.editable){if(this.config.baseContainers&&!this.config.baseContainers.includes("DIV")){return;} 6594const newBaseContainers=[];const targets=selectElements(element,`div:not(.${BASE_CONTAINER_CLASS})`);for(const div of targets){if(!div.parentElement?.matches(baseContainerGlobalSelector)&&this.shallowIsCandidateForBaseContainer(div)&&!containsAnyNonPhrasingContent(div)){div.classList.add(BASE_CONTAINER_CLASS);newBaseContainers.push(div);if(!div.hasChildNodes()){const br=document.createElement("br");div.appendChild(br);}}}}} 6595return __exports;});; 6596 6597/* /html_editor/static/src/core/clipboard_plugin.js */ 6598odoo.define('@html_editor/core/clipboard_plugin',['@html_editor/utils/dom_info','@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/clipboard','@html_editor/utils/dom_traversal','@html_editor/utils/html','@html_editor/utils/base_container','@html_editor/utils/position','@html_editor/core/selection_plugin','@html_editor/utils/table'],function(require){'use strict';let __exports={};const{isTextNode,isParagraphRelatedElement,isEmptyBlock,isContentEditable,}=require("@html_editor/utils/dom_info");const{Plugin}=require("@html_editor/plugin");const{closestBlock}=require("@html_editor/utils/blocks");const{unwrapContents,wrapInlinesInBlocks,splitTextNode,fillEmpty}=require("@html_editor/utils/dom");const{fillHtmlTransferData}=require("@html_editor/utils/clipboard");const{childNodes,closestElement}=require("@html_editor/utils/dom_traversal");const{parseHTML}=require("@html_editor/utils/html");const{baseContainerGlobalSelector,getBaseContainerSelector,}=require("@html_editor/utils/base_container");const{DIRECTIONS}=require("@html_editor/utils/position");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{getRowIndex}=require("@html_editor/utils/table");const CLIPBOARD_BLACKLISTS={unwrap:[".Apple-interchange-newline","DIV",],remove:["META","STYLE","SCRIPT"],};const CLIPBOARD_WHITELISTS=__exports.CLIPBOARD_WHITELISTS={nodes:["P","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","PRE","UL","OL","LI","I","B","U","S","EM","FONT","STRONG","TABLE","THEAD","TH","TBODY","TR","TD","IMG","BR","A",".fa",],classes:[/^float-/,"d-block","mx-auto","img-fluid","img-thumbnail","rounded","rounded-circle","o_table","table","table-bordered",/^padding-/,/^shadow/,/^text-o-/,/^bg-o-/,"o_checked","o_checklist","oe-nested",/^btn/,/^fa/,],attributes:["class","href","src","target","colspan","rowspan"],styledTags:["SPAN","B","STRONG","I","S","U","FONT","TD"],};const ONLY_LINK_REGEX=/^(https?:\/\/)?([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/i;const ClipboardPlugin=__exports.ClipboardPlugin=class ClipboardPlugin extends Plugin{static id="clipboard";static dependencies=["baseContainer","dom","selection","sanitize","history","split","delete","lineBreak",];static shared=["pasteText"];setup(){this.addDomListener(this.editable,"copy",this.onCopy);this.addDomListener(this.editable,"cut",this.onCut);this.addDomListener(this.editable,"paste",this.onPaste);this.addDomListener(this.editable,"dragstart",this.onDragStart);this.addDomListener(this.editable,"drop",this.onDrop);} 6599onCut(ev){const selection=this.dependencies.selection.getEditableSelection();this.dispatchTo("before_cut_handlers",selection);this.onCopy(ev);this.dependencies.history.stageSelection();this.dependencies.delete.deleteSelection();this.dependencies.history.addStep();} 6600onCopy(ev){ev.preventDefault();this.setSelectionTransferData(ev,"clipboardData");} 6601setSelectionTransferData(ev,transferObjectProperty){const selection=this.dependencies.selection.getEditableSelection();let clonedContents=selection.cloneContents();if(!clonedContents.hasChildNodes()){return;} 6602let textContent=selection.textContent();for(const processor of this.getResource("clipboard_text_processors")){textContent=processor(textContent);} 6603for(const processor of this.getResource("clipboard_content_processors")){clonedContents=processor(clonedContents,selection)||clonedContents;} 6604this.dependencies.dom.removeSystemProperties(clonedContents);fillHtmlTransferData(ev,transferObjectProperty,clonedContents,{setEditorTransferData:isContentEditable(selection.commonAncestorContainer)||this.dependencies.selection.isNodeEditable(selection.commonAncestorContainer),textContent,});} 6605onPaste(ev){let selection=this.dependencies.selection.getEditableSelection();if(!selection.anchorNode.isConnected||!closestElement(selection.anchorNode).isContentEditable){return;} 6606ev.preventDefault();this.dependencies.history.stageSelection();this.dispatchTo("before_paste_handlers",selection,ev);selection=this.dependencies.selection.getEditableSelection();if(!this.delegateTo("paste_overrides",selection,ev.clipboardData)){this.handlePasteUnsupportedHtml(selection,ev.clipboardData)||this.handlePasteOdooEditorHtml(ev.clipboardData)||this.handlePasteHtml(selection,ev.clipboardData)||this.handlePasteText(selection,ev.clipboardData);} 6607this.dispatchTo("after_paste_handlers",selection);this.dependencies.history.addStep();} 6608handlePasteUnsupportedHtml(selection,clipboardData){if(!isHtmlContentSupported(selection)){const text=clipboardData.getData("text/plain");this.dependencies.dom.insert(text);return true;}} 6609handlePasteOdooEditorHtml(clipboardData){const odooEditorHtml=clipboardData.getData("application/vnd.odoo.odoo-editor");const textContent=clipboardData.getData("text/plain");if(ONLY_LINK_REGEX.test(textContent)){return false;} 6610if(odooEditorHtml){const fragment=parseHTML(this.document,odooEditorHtml);this.dependencies.sanitize.sanitize(fragment);if(this.delegateTo("handle_paste_html_override",fragment)){return true;} 6611if(fragment.hasChildNodes()){this.dependencies.dom.insert(fragment);} 6612return true;}} 6613handlePasteHtml(selection,clipboardData){const files=this.delegateTo("bypass_paste_image_files")?[]:getImageFiles(clipboardData);const clipboardHtml=clipboardData.getData("text/html");const textContent=clipboardData.getData("text/plain");if(ONLY_LINK_REGEX.test(textContent)){return false;} 6614const fragment=parseHTML(this.document,clipboardHtml);this.dependencies.sanitize.sanitize(fragment);if(this.delegateTo("handle_paste_html_override",fragment)){return true;} 6615if(files.length||clipboardHtml){const clipboardElem=this.prepareClipboardData(clipboardHtml);if(files.length&&!clipboardElem.querySelector("table")){return this.addImagesFiles(files).then((html)=>{this.dependencies.dom.insert(html);this.dependencies.history.addStep();});}else if(clipboardElem.hasChildNodes()){if(closestElement(selection.anchorNode,"a")){this.dependencies.dom.insert(clipboardElem.textContent);}else{this.dependencies.dom.insert(clipboardElem);}} 6616return true;}} 6617handlePasteText(selection,clipboardData){const text=clipboardData.getData("text/plain");if(this.delegateTo("paste_text_overrides",selection,text)){return;}else{this.pasteText(text);}} 6618pasteText(text){const textFragments=text.split(/\r?\n/);let selection=this.dependencies.selection.getEditableSelection();const preEl=closestElement(selection.anchorNode,"PRE");let textIndex=1;for(const textFragment of textFragments){let modifiedTextFragment=textFragment;
6618if(!preEl){modifiedTextFragment=textFragment.replace(/( {2,})/g,(match)=>{let alternateValue=false;return match.replace(/ /g,()=>{alternateValue=!alternateValue;const replaceContent=alternateValue?"\u00A0":" ";return replaceContent;});});} 6619this.dependencies.dom.insert(modifiedTextFragment);if(textIndex<textFragments.length){selection=this.dependencies.selection.getEditableSelection();const block=closestBlock(selection.anchorNode);if(this.dependencies.split.isUnsplittable(block)||closestElement(selection.anchorNode).tagName==="PRE"){this.dependencies.lineBreak.insertLineBreak();}else{const[blockBefore]=this.dependencies.split.splitBlock();if(block&&block.matches(baseContainerGlobalSelector)&&blockBefore&&!blockBefore.matches(getBaseContainerSelector("DIV"))){const div=this.dependencies.baseContainer.createBaseContainer("DIV");const cursors=this.dependencies.selection.preserveSelection();blockBefore.before(div);div.replaceChildren(...childNodes(blockBefore));blockBefore.remove();cursors.remapNode(blockBefore,div).restore(
6619);}}} 6620textIndex++;}} 6621prepareClipboardData(clipboardData){const fragment=parseHTML(this.document,clipboardData);this.dependencies.sanitize.sanitize(fragment);const container=this.document.createElement("fake-container");container.append(fragment);for(const tableElement of container.querySelectorAll("table")){tableElement.classList.add("table","table-bordered","o_table");} 6622if(this.delegateTo("bypass_paste_image_files")){for(const imgElement of container.querySelectorAll("img")){imgElement.remove();}} 6623const progId=container.querySelector('meta[name="ProgId"]');if(progId&&progId.content==="Excel.Sheet"){const xlStylesheet=container.querySelector("style");const xlNodes=container.querySelectorAll("[class*=xl],[class*=font]");for(const xlNode of xlNodes){for(const xlClass of xlNode.classList){const xlStyle=xlStylesheet.textContent.match(`.${xlClass}[^{]*{(?<xlStyle>[^}]*)}`).groups.xlStyle.replace("background:","background-color:");xlNode.setAttribute("style",xlNode.style.cssText+";"+xlStyle);}}} 6624const childContent=childNodes(container);for(const child of childContent){this.cleanForPaste(child);} 6625const selection=this.dependencies.selection.getEditableSelection();const closestBaseContainer=selection.anchorNode&&closestElement(selection.anchorNode,baseContainerGlobalSelector);wrapInlinesInBlocks(container,{baseContainerNodeName:closestBaseContainer?.nodeName||this.dependencies.baseContainer.getDefaultNodeName(),});const result=this.document.createDocumentFragment();result.replaceChildren(...childNodes(container));const brs=result.querySelectorAll("br");for(const br of brs){const block=closestBlock(br);if((isParagraphRelatedElement(block)||this.dependencies.baseContainer.isCandidateForBaseContainer(block))&&block.nodeName!=="PRE"){const isEmptyLine=block.firstChild.nodeName==="BR";const remainingBrContainer=this.dependencies.split.splitAroundUntil(br,block);if(!isEmptyLine){remainingBrContainer.remove();}}} 6626return result;} 6627cleanForPaste(node){if(!this.isWhitelisted(node)||this.isBlacklisted(node)||(node.id&&node.id.startsWith("docs-internal-guid"))){if(!node.matches||node.matches(CLIPBOARD_BLACKLISTS.remove.join(","))){node.remove();}else{let childrenNodes;if(node.nodeName==="DIV"){if(!node.hasChildNodes()){node.remove();return;}else if(this.dependencies.baseContainer.isCandidateForBaseContainer(node)){const whiteSpace=node.style?.whiteSpace;if(whiteSpace&&!["normal","nowrap"].includes(whiteSpace)){node.innerHTML=node.innerHTML.replace(/\n/g,"<br>");} 6628const baseContainer=this.dependencies.baseContainer.createBaseContainer();const dir=node.getAttribute("dir");if(dir){baseContainer.setAttribute("dir",dir);} 6629baseContainer.append(...node.childNodes);node.replaceWith(baseContainer);childrenNodes=childNodes(baseContainer);}else{childrenNodes=unwrapContents(node);}}else{childrenNodes=unwrapContents(node);} 6630for(const child of childrenNodes){this.cleanForPaste(child);}}}else if(node.nodeType!==Node.TEXT_NODE){if(["TD","TH"].includes(node.nodeName)){if(node.nodeName==="TH"&&getRowIndex(node)!==0){node=this.dependencies.dom.setTagName(node,"td");} 6631if(isEmptyBlock(node)){const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);node.replaceChildren(baseContainer);} 6632if(node.hasAttribute("bgcolor")&&!node.style["background-color"]){node.style["background-color"]=node.getAttribute("bgcolor");}}else if(node.nodeName==="FONT"){if(node.hasAttribute("color")&&!node.style["color"]){node.style["color"]=node.getAttribute("color");} 6633if(node.hasAttribute("size")&&!node.style["font-size"]){node.style["font-size"]=+node.getAttribute("size")+10+"pt";}}else if(["S","U"].includes(node.nodeName)&&childNodes(node).length===1&&node.firstChild.nodeName==="FONT"){const fontNode=node.firstChild;node.before(fontNode);node.replaceChildren(...childNodes(fontNode));fontNode.appendChild(node);}else if(node.nodeName==="IMG"&&node.getAttribute("aria-roledescription")==="checkbox"){const checklist=node.closest("ul");const closestLi=node.closest("li");if(checklist){checklist.classList.add("o_checklist");if(node.getAttribute("alt")==="checked"){closestLi.classList.add("o_checked");} 6634node.remove();node=checklist;}} 6635for(const attribute of[...node.attributes]){if(CLIPBOARD_WHITELISTS.styledTags.includes(node.nodeName)&&attribute.name==="style"){node.removeAttribute(attribute.name);if(["SPAN","FONT"].includes(node.tagName)){for(const unwrappedNode of unwrapContents(node)){this.cleanForPaste(unwrappedNode);}}}else if(!this.isWhitelisted(attribute)){node.removeAttribute(attribute.name);}} 6636for(const klass of[...node.classList]){if(!this.isWhitelisted(klass)){node.classList.remove(klass);}} 6637for(const child of childNodes(node)){this.cleanForPaste(child);}}} 6638isWhitelisted(item){if(item.nodeType===Node.ATTRIBUTE_NODE){return CLIPBOARD_WHITELISTS.attributes.includes(item.name);}else if(typeof item==="string"){return CLIPBOARD_WHITELISTS.classes.some((okClass)=>okClass instanceof RegExp?okClass.test(item):okClass===item);}else{return isTextNode(item)||item.matches?.(CLIPBOARD_WHITELISTS.nodes.join(","));}} 6639isBlacklisted(node){return(!isTextNode(node)&&node.matches([].concat(...Object.values(CLIPBOARD_BLACKLISTS)).join(",")));} 6640onDragStart(ev){const selection=this.dependencies.selection.getEditableSelection();this.dispatchTo("before_drag_handlers",selection);this.setSelectionTransferData(ev,"dataTransfer");} 6641async onDrop(ev){ev.preventDefault();const selection=this.dependencies.selection.getEditableSelection();if(!isHtmlContentSupported(selection)){return;} 6642const nodeToSplit=selection.direction===DIRECTIONS.RIGHT?selection.focusNode:selection.anchorNode;const offsetToSplit=selection.direction===DIRECTIONS.RIGHT?selection.focusOffset:selection.anchorOffset;if(nodeToSplit.nodeType===Node.TEXT_NODE&&!selection.isCollapsed){const selectionToRestore=this.dependencies.selection.preserveSelection();splitTextNode(nodeToSplit,offsetToSplit,DIRECTIONS.LEFT);
6642selectionToRestore.restore();} 6643const dataTransfer=(ev.originalEvent||ev).dataTransfer;const odooEditorHtml=ev.dataTransfer.getData("application/vnd.odoo.odoo-editor");const fileTransferItems=!odooEditorHtml&&getImageFiles(dataTransfer);const htmlTransferItem=[...dataTransfer.items].find((item)=>item.type==="text/html");if(fileTransferItems.length||htmlTransferItem){let dropRange;if(this.document.caretPositionFromPoint){const caretPosition=this.document.caretPositionFromPoint(ev.clientX,ev.clientY);if(caretPosition){dropRange=this.document.createRange();dropRange.setStart(caretPosition.offsetNode,caretPosition.offset);}}else if(this.document.caretRangeFromPoint){dropRange=this.document.caretRangeFromPoint(ev.clientX,ev.clientY);} 6644if(dropRange){this.dependencies.delete.deleteSelection();this.dependencies.selection.setSelection({anchorNode:dropRange.startContainer,anchorOffset:dropRange.startOffset,});}} 6645if(this.delegateTo("html_drop_overrides",this.dependencies.selection.getEditableSelection(),ev.dataTransfer)){this.dependencies.history.addStep();return;} 6646if(odooEditorHtml){const fragment=parseHTML(this.document,odooEditorHtml);this.dependencies.sanitize.sanitize(fragment);if(fragment.hasChildNodes()){this.dependencies.dom.insert(fragment);this.dependencies.history.addStep();}}else if(fileTransferItems.length){const html=await this.addImagesFiles(fileTransferItems);this.dependencies.dom.insert(html);this.dependencies.history.addStep();}else if(htmlTransferItem){htmlTransferItem.getAsString((pastedText)=>{this.dependencies.dom.insert(this.prepareClipboardData(pastedText));this.dependencies.history.addStep();});}} 6647async addImagesFiles(imageFiles){const promises=[];for(const imageFile of imageFiles){const imageNode=this.document.createElement("img");imageNode.classList.add("img-fluid");this.dispatchTo("added_image_handlers",imageNode);imageNode.dataset.fileName=imageFile.name;promises.push(getImageUrl(imageFile).then((url)=>{imageNode.src=url;return imageNode;}));} 6648const nodes=await Promise.all(promises);const fragment=this.document.createDocumentFragment();fragment.append(...nodes);return fragment;}} 6649function getImageFiles(dataTransfer){return[...dataTransfer.items].filter((item)=>item.kind==="file"&&item.type.includes("image/")).map((item)=>item.getAsFile());} 6650function getImageUrl(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.readAsDataURL(file);reader.onloadend=(e)=>{if(reader.error){return reject(reader.error);} 6651resolve(e.target.result);};});} 6652return __exports;});; 6653 6654/* /html_editor/static/src/core/comment_plugin.js */ 6655odoo.define('@html_editor/core/comment_plugin',['@html_editor/utils/dom_info','@html_editor/plugin','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{isProtected}=require("@html_editor/utils/dom_info");const{Plugin}=require("@html_editor/plugin");const{descendants}=require("@html_editor/utils/dom_traversal");const CommentPlugin=__exports.CommentPlugin=class CommentPlugin extends Plugin{static id="comment";resources={normalize_handlers:this.removeComment.bind(this),};removeComment(node){for(const el of[node,...descendants(node)]){if(el.nodeType===Node.COMMENT_NODE&&!isProtected(el)){el.remove();}}}} 6656return __exports;});; 6657 6658/* /html_editor/static/src/core/content_editable_plugin.js */ 6659odoo.define('@html_editor/core/content_editable_plugin',['@html_editor/core/selection_plugin','@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{isArtificialVoidElement}=require("@html_editor/core/selection_plugin");const{Plugin}=require("@html_editor/plugin");const{selectElements}=require("@html_editor/utils/dom_traversal");const{withSequence}=require("@html_editor/utils/resource");const ContentEditablePlugin=__exports.ContentEditablePlugin=class ContentEditablePlugin extends Plugin{static id="contentEditablePlugin";resources={normalize_handlers:withSequence(5,this.normalize.bind(this)),clean_for_save_handlers:withSequence(Infinity,this.cleanForSave.bind(this)),};normalize(root){const contentNotEditableEls=[];for(const fn of this.getResource("content_not_editable_providers")){contentNotEditableEls.push(...fn(root));} 6660for(const contentNotEditableEl of contentNotEditableEls){contentNotEditableEl.setAttribute("contenteditable","false");} 6661const contentEditableEls=[];for(const fn of this.getResource("content_editable_providers")){contentEditableEls.push(...fn(root));} 6662const filteredContentEditableEls=contentEditableEls.filter((contentEditableEl)=>this.getResource("valid_contenteditable_predicates").every((p)=>p(contentEditableEl)));for(const contentEditableEl of filteredContentEditableEls){if(!contentEditableEl.isContentEditable){if(isArtificialVoidElement(contentEditableEl)||contentEditableEl.nodeName==="IMG"){contentEditableEl.classList.add("o_editable_media");continue;} 6663if(!contentNotEditableEls.includes(contentEditableEl)){contentEditableEl.setAttribute("contenteditable",true);}}}} 6664cleanForSave({root}){const toRemoveSelector=this.getResource("contenteditable_to_remove_selector").join(",");const contenteditableEls=toRemoveSelector?[...selectElements(root,toRemoveSelector)]:[];for(const contenteditableEl of contenteditableEls){contenteditableEl.removeAttribute("contenteditable");}}} 6665return __exports;});; 6666 6667/* /html_editor/static/src/core/delete_plugin.js */ 6668odoo.define('@html_editor/core/delete_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_state','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/utils/content_types','@html_editor/utils/resource','@html_editor/main/list/utils','@web/core/browser/feature_detection','@html_editor/utils/selection'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{isAllowedContent,isButton,isContentEditable,isEmpty,isInPre,isProtected,isShrunkBlock,isTangible,isTextNode,isVisibleTextNode,isWhitespace,isZwnbsp,isZWS,nextLeaf,previousLeaf,isEmptyBlock,isSelfClosingElement,}=require("@html_editor/utils/dom_info");const{getState,isFakeLineBreak,observeMutations,prepareUpdate}=require("@html_editor/utils/dom_state");const{childNodes,closestElement,findUpTo,descendants,firstLeaf,getCommonAncestor,lastLeaf,findFurthest,}=require("@html_editor/utils/dom_traversal");const{DIRECTIONS,childNodeIndex,endPos,leftPos,nodeSize,rightPos,startPos,}=require("@html_editor/utils/position");const{CTYPES}=require("@html_editor/utils/content_types");const{withSequence}=require("@html_editor/utils/resource");const{compareListTypes}=require("@html_editor/main/list/utils");const{hasTouch,isBrowserChrome,isBrowserSafari,isMacOS,}=require("@web/core/browser/feature_detection");const{normalizeDeepCursorPosition,normalizeFakeBR}=require("@html_editor/utils/selection");const unremovableNodePredicates=__exports.unremovableNodePredicates=[(node)=>node.classList?.contains("oe_unremovable"),(node)=>node.matches?.("[data-oe-type='monetary'] > span"),];const DeletePlugin=__exports.DeletePlugin=class DeletePlugin extends Plugin{static dependencies=["baseContainer","selection","history","input","userCommand"];static id="delete";static shared=["deleteBackward","deleteForward","deleteRange","deleteSelection","delete"];resources={user_commands:[{id:"deleteBackward",run:()=>this.delete("backward","character")},{id:"deleteForward",run:()=>this.delete("forward","character")},{id:"deleteBackwardWord",run:()=>this.delete("backward","word")},{id:"deleteForwardWord",run:()=>this.delete("forward","word")},{id:"deleteBackwardLine",run:()=>this.delete("backward","line")},{id:"deleteForwardLine",run:()=>this.delete("forward","line")},],shortcuts:[{hotkey:"backspace",commandId:"deleteBackward"},{hotkey:"delete",commandId:"deleteForward"},{hotkey:"control+backspace",commandId:"deleteBackwardWord"},{hotkey:"control+delete",commandId:"deleteForwardWord"},{hotkey:"control+shift+backspace",commandId:"deleteBackwardLine"},{hotkey:"control+shift+delete",commandId:"deleteForwardLine"},],beforeinput_handlers:[withSequence(5,this.onBeforeInputInsertText.bind(this)),this.onBeforeInputDelete.bind(this),],input_handlers:(ev)=>this.onAndroidChromeInput?.(ev),selectionchange_handlers:withSequence(5,()=>this.onAndroidChromeSelectionChange?.()),delete_backward_overrides:withSequence(30,this.deleteBackwardUnmergeable.bind(this)),delete_backward_word_overrides:withSequence(20,this.deleteBackwardUnmergeable.bind(this)),delete_backward_line_overrides:this.deleteBackwardUnmergeable.bind(this),delete_forward_overrides:withSequence(20,this.deleteForwardUnmergeable.bind(this)),delete_forward_word_overrides:this.deleteForwardUnmergeable.bind(this),delete_forward_line_overrides:this.deleteForwardUnmergeable.bind(this),unremovable_node_predicates:unremovableNodePredicates,invalid_for_base_container_predicates:(node)=>this.isUnremovable(node,this.editable),};setup(){this.findPreviousPosition=this.makeFindPositionFn("backward");this.findNextPosition=this.makeFindPositionFn("forward");if(isMacOS()){this.addDomListener(this.editable,"keydown",(event)=>{const runCommand=(commandId)=>{this.dependencies.userCommand.getCommand(commandId).run();event.stopImmediatePropagation();event.preventDefault();};if(event.altKey&&event.key==="Backspace"){return runCommand("deleteBackwardWord");} 6669if(event.altKey&&event.key==="Delete"){return runCommand("deleteForwardWord");} 6670if(event.metaKey&&event.key==="Backspace"){return runCommand("deleteBackwardLine");} 6671if(event.metaKey&&event.key==="Delete"){return runCommand("deleteForwardLine");}});}} 6672getNormalizedRange(selection){let{startContainer,startOffset,endContainer,endOffset,isCollapsed}=selection;for(const normalizer of[normalizeDeepCursorPosition,normalizeFakeBR]){[startContainer,startOffset]=normalizer(startContainer,startOffset);[endContainer,endOffset]=isCollapsed?[startContainer,startOffset]:normalizer(endContainer,endOffset);} 6673const range=this.document.createRange();range.setStart(startContainer,startOffset);range.setEnd(endContainer,endOffset);return range;} 6674deleteSelection(selection=this.dependencies.selection.getEditableSelection()){let range=this.getNormalizedRange(selection);if(range.collapsed){return;} 6675const selectedNodes=this.dependencies.selection.getTargetedNodes();const canBeDeleted=(node)=>{const isEditableOrFullySelected=(a)=>this.dependencies.selection.isNodeEditable(a)||(this.dependencies.selection.areNodeContentsFullySelected(a)&&isContentEditable(a.parentElement));return(isEditableOrFullySelected(node)||selectedNodes.includes(close
6675stElement(node,(node)=>isEditableOrFullySelected(node))));};if(selectedNodes.some((node)=>!canBeDeleted(node))){return;} 6676range=this.adjustRange(range,[this.expandRangeToIncludeNonEditables,this.includeEndOrStartBlock,this.fullyIncludeLinks,]);if(this.delegateTo("delete_range_overrides",range)){return;} 6677range=this.deleteRange(range);this.setCursorFromRange(range);} 6678delete(direction,granularity){const selection=this.dependencies.selection.getEditableSelection();this.dependencies.history.stageSelection();this.dispatchTo("before_delete_handlers");if(!selection.isCollapsed){this.deleteSelection(selection);}else if(direction==="backward"){this.deleteBackward(selection,granularity);}else if(direction==="forward"){this.deleteForward(selection,granularity);}else{throw new Error("Invalid direction");} 6679this.dispatchTo("delete_handlers");this.dependencies.history.addStep();} 6680deleteBackward(selection,granularity){const{endContainer,endOffset}=this.getNormalizedRange(selection);if(!closestElement(endContainer).isContentEditable){return;} 6681let range=this.getRangeForDelete(endContainer,endOffset,"backward",granularity);const resourceIds={character:"delete_backward_overrides",word:"delete_backward_word_overrides",line:"delete_backward_line_overrides",};if(this.delegateTo(resourceIds[granularity],range)){return;} 6682range=this.adjustRange(range,[this.includeEmptyInlineEnd,this.includePreviousZWS,this.includeEndOrStartBlock,]);range=this.deleteRange(range);this.document.getSelection()?.removeAllRanges();this.setCursorFromRange(range,{collapseToEnd:true});} 6683deleteForward(selection,granularity){const{startContainer,startOffset}=this.getNormalizedRange(selection);if(!closestElement(startContainer).isContentEditable){return;} 6684let range=this.getRangeForDelete(startContainer,startOffset,"forward",granularity);const resourceIds={character:"delete_forward_overrides",word:"delete_forward_word_overrides",line:"delete_forward_line_overrides",};if(this.delegateTo(resourceIds[granularity],range)){return;} 6685range=this.adjustRange(range,[this.includeEmptyInlineStart,this.includeNextZWS,this.includeEndOrStartBlock,]);range=this.deleteRange(range);this.setCursorFromRange(range);} 6686getRangeForDelete(node,offset,direction,granularity){let destContainer,destOffset;if(granularity==="word"){const blockEl=closestBlock(node);if((direction==="backward"&&this.isCursorAtStartOfElement(blockEl,node,offset))||(direction==="forward"&&this.isCursorAtEndOfElement(blockEl,node,offset))){granularity="character";}} 6687switch(granularity){case"character":[destContainer,destOffset]=this.findAdjacentPosition(node,offset,direction);break;case"word":({focusNode:destContainer,focusOffset:destOffset}=this.dependencies.selection.modifySelection("extend",direction,"w
6687ord"));break;case"line":[destContainer,destOffset]=this.findLineBoundary(node,offset,direction);break;default:throw new Error("Invalid granularity");} 6688if(!destContainer){[destContainer,destOffset]=[node,offset];} 6689const[startContainer,startOffset,endContainer,endOffset]=direction==="forward"?[node,offset,destContainer,destOffset]:[destContainer,destOffset,node,offset];return{startContainer,startOffset,endContainer,endOffset};} 6690deleteRange(range){if(range.startContainer===range.endContainer&&range.startOffset===range.endOffset){return range;} 6691range=this.splitTextNodes(range);const{startContainer,startOffset,endContainer,endOffset}=range;const restoreSpaces=prepareUpdate(startContainer,startOffset,endContainer,endOffset);let restoreFakeBRs;({restoreFakeBRs,range}=this.removeFakeBRs(range));let allNodesRemoved;({allNodesRemoved,range}=this.removeNodes(range));this.fillEmptyInlines(range);const originalCommonAncestor=range.commonAncestorContainer;if(allNodesRemoved){range=this.joinFragments(range);} 6692restoreFakeBRs();this.fillShrunkBlocks(originalCommonAncestor);restoreSpaces();return range;} 6693splitTextNodes({startContainer,startOffset,endContainer,endOffset}){const split=(textNode,offset)=>{let didSplit=false;if(offset===0){offset=childNodeIndex(textNode);}else if(offset===nodeSize(textNode)){offset=childNodeIndex(textNode)+1;}else{textNode.splitText(offset);didSplit=true;offset=childNodeIndex(textNode)+1;} 6694return[textNode.parentElement,offset,didSplit];};if(endContainer.nodeType===Node.TEXT_NODE){[endContainer,endOffset]=split(endContainer,endOffset);} 6695if(startContainer.nodeType===Node.TEXT_NODE){let didSplit;[startContainer,startOffset,didSplit]=split(startContainer,startOffset);if(startContainer===endContainer&&didSplit){endOffset+=1;}} 6696return{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer:getCommonAncestor([startContainer,endContainer],this.editable),};} 6697removeFakeBRs(range){let{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer}=range;const visitedNodes=new Set();const removeBRs=(container,offset)=>{let node=container;while(node!==commonAncestorContainer){const lastBR=childNodes(node).findLast((child)=>child.nodeName==="BR");if(lastBR&&isFakeLineBreak(lastBR)){if(lastBR===container){[container,offset]=leftPos(lastBR);}else if(node===container&&offset>childNodeIndex(lastBR)){offset-=1;} 6698lastBR.remove();} 6699visitedNodes.add(node);node=node.parentNode;} 6700return[container,offset];};[startContainer,startOffset]=removeBRs(startContainer,startOffset);[endContainer,endOffset]=removeBRs(endContainer,endOffset);range={startContainer,startOffset,endContainer,endOffset,commonAncestorContainer};const restoreFakeBRs=()=>{for(const node of visitedNodes){if(!node.isConnected){continue;} 6701const lastBR=childNodes(node).findLast((child)=>child.nodeName==="BR");if(lastBR&&isFakeLineBreak(lastBR)){lastBR.after(this.document.createElement("br"));}}};return{restoreFakeBRs,range};} 6702fillEmptyInlines(range){const nodes=[range.startContainer];if(range.endContainer!==range.startContainer){nodes.push(range.endContainer);} 6703for(const node of nodes){if(!isBlock(node)&&!isTangible(node)&&!isZWS(node)&&!isZwnbsp(node)){node.appendChild(this.document.createTextNode("\u200B"));node.setAttribute("data-oe-zws-empty-inline","");}}} 6704fillShrunkBlocks(commonAncestor){const fillBlock=(block)=>{if(block.matches("div[contenteditable='true']")&&!block.parentElement.isContentEditable){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));block.appendChild(baseContainer);}else{block.appendChild(this.document.createElement("br"));}};for(const node of descendants(commonAncestor).reverse()){if(isBlock(node)&&isShrunkBlock(node)){fillBlock(node);}} 6705const containingBlock=closestBlock(commonAncestor);if(isShrunkBlock(containingBlock)){fillBlock(containingBlock);}} 6706removeNodes(range){const{startContainer,startOffset,endContainer,commonAncestorContainer}=range;let{endOffset}=range;const nodesToRemove=[];let node=startContainer;let startRemoveIndex=startOffset;while(node!==commonAncestorContainer){for(let i=startRemoveIndex;i<node.childNodes.length;i++){nodesToRemove.push(node.childNodes[i]);} 6707startRemoveIndex=childNodeIndex(node)+1;node=node.parentElement;} 6708node=endContainer;let endRemoveIndex=endOffset;while(node!==commonAncestorContainer){for(let i=0;i<endRemoveIndex;i++){nodesToRemove.push(node.childNodes[i]);} 6709endRemoveIndex=childNodeIndex(node);node=node.parentElement;} 6710for(let i=startRemoveIndex;i<endRemoveIndex;i++){nodesToRemove.push(commonAncestorContainer.childNodes[i]);} 6711let allNodesRemoved=true;for(const node of nodesToRemove){const parent=node.parentNode;const didRemove=this.removeNode(node);allNodesRemoved&&=didRemove;if(didRemove&&endContainer===parent){endOffset-=1;}} 6712const endContainerList=closestElement(endContainer,"UL, OL");if(["OL","UL"].includes(startContainer.nodeName)&&endContainerList&&!compareListTypes(startContainer,endContainerList)){const newRange=this.document.createRange();newRange.setStart(range.endContainer,endOffset);return{allNodesRemoved,range:newRange};} 6713return{allNodesRemoved,range:{...range,endOffset}};} 6714isUnremovable(node,root=undefined){return this.getResource("unremovable_node_predicates").some((p)=>p(node,root));} 6715removeNode(node){const root=node;const remove=(node)=>{let customHandling=false;let customIsUnremovable;for(const cb of this.getResource("removable_descendants_providers")){const descendantsToRemove=cb(node);if(descendantsToRemove){for(const descendant of descendantsToRemove){remove(descendant);} 6716customHandling=true;customIsUnremovable=this.isUnremovable(node,root);if(!customIsUnremovable){node.remove();}}} 6717if(customHandling){return!customIsUnremovable;} 6718for(const child of[...node.childNodes]){remove(child);} 6719if(this.isUnremovable(node,root)||(!this.dependencies.selection.isNodeEditable(node)&&!node.parentElement?.isContentEditable)){return false;} 6720if(node.hasChildNodes()&&node.isContentEditable){node.before(...node.childNodes);node.remove();return false;} 6721node.remove();return true;};return remove(node);} 6722joinFragments(range){const joinableLeft=this.getJoinableFragment(range,"start");const joinableRight=this.getJoinableFragment(range,"end");const join=this.getJoinOperation(joinableLeft.type,joinableRight.type);const didJoin=join(joinableLeft.node,joinableRight.node,range.commonAncestorContainer);return didJoin?this.collapseRange(range):range;} 6723getJoinableFragment(range,side){const commonAncestor=range.commonAncestorContainer;const container=side==="start"?range.startContainer:range.endContainer;const offset=side==="start"?range.startOffset:range.endOffset;if(container===range.commonAncestorContainer){const sibling=childNodes(commonAncestor)[side==="start"?offset-1:offset];if(sibling&&!isBlock(sibling)&&!(sibling.nodeType===Node.TEXT_NODE&&!isVisibleTextNode(sibling))){return{node:sibling,type:"inline"};} 6724return{node:null,type:"null"};} 6725let last;let element=container;while(element!==commonAncestor){if(isBlock(element)){return{node:element,type:"block"};} 6726last=element;element=element.parentElement;} 6727return{node:last,type:"inline"};} 6728getJoinOperation(leftType,rightType){return({"block + block":this.joinBlocks,"block + inline":this.joinInlineIntoBlock,"inline + block":this.joinBlockIntoInline,}[leftType+" + "+rightType]||(()=>true)).bind(this);} 6729isUnmergeable(node){return this.getResource("unsplittable_node_predicates").some((p)=>p(node));} 6730joinBlocks(left,right,commonAncestor){const canMerge=(n)=>!findUpTo(n,commonAncestor,this.isUnmergeable.bind(this));if(!canMerge(left)||!canMerge(right)){return false;} 6731const rightChildNodes=childNodes(right);if(!isAllowedContent(left,rightChildNodes)){return false;} 6732left.append(...rightChildNodes);let toRemove=right;let parent=right.parentElement;while(parent!==commonAncestor&&parent.childNodes.length===1){toRemove=parent;parent=parent.parentElement;} 6733toRemove.remove();return true;} 6734joinInlineIntoBlock(leftBlock,rightInline,commonAncestor){if(findUpTo(leftBlock,commonAncestor,(node)=>this.isUnmergeable(node))){return false;} 6735while(rightInline&&!isBlock(rightInline)){const toAppend=rightInline;rightInline=rightInline.nextSibling;leftBlock.append(toAppend);} 6736return true;} 6737joinBlockIntoInline(leftInline,rightBlock,commonAncestor){if(findUpTo(rightBlock,commonAncestor,(node)=>this.isUnmergeable(node))){return false;} 6738leftInline.after(...childNodes(rightBlock));let toRemove=rightBlock;let parent=rightBlock.parentElement;while(parent!==commonAncestor&&parent.childNodes.length===1){toRemove=parent;parent=parent.parentElement;} 6739if(parent===commonAncestor){const rightSibling=toRemove.nextSibling;if(rightSibling&&!isBlock(rightSibling)){rightSibling.before(this.document.createElement("br"));}} 6740toRemove.remove();return true;} 6741adjustRange({startContainer,startOffset,endContainer,endOffset},callbacks){let range=this.document.createRange();range.setStart(startContainer,startOffset);range.setEnd(endContainer,endOffset);for(const callback of callbacks){range=callback.call(this,range);} 6742({startContainer,startOffset,endOffset,endContainer}=range);return{startContainer,startOffset,endOffset,endContainer};} 6743includeBlockStart(block,range){const{startContainer,startOffset,commonAncestorContainer}=range;if(block===commonAncestorContainer||!this.isCursorAtStartOfElement(block,startContainer,startOffset)){return range;} 6744range.setStartBefore(block);return this.includeBlockStart(block.parentNode,range);} 6745includeBlockEnd(block,range){const{startContainer,endContainer,endOffset,commonAncestorContainer}=range;const startList=closestElement(startContainer,"UL, OL");const endList=closestElement(endContainer,"UL, OL");if(block===commonAncestorContainer||!this.isCursorAtEndOfElement(block,endContainer,endOffset)||(startList&&endList&&!compareListTypes(startList,endList)&&!startList.contains(endList))){return range;} 6746range.setEndAfter(block);return this.includeBlockEnd(block.parentNode,range);} 6747includeEndOrStartBlock(range){const{startContainer,endContainer,commonAncestorContainer}=range;const startBlock=findUpTo(startContainer,commonAncestorContainer,isBlock);const endBlock=findUpTo(endContainer,commonAncestorContainer,isBlock);if(!startBlock||!endBlock){return range;} 6748range=this.includeBlockEnd(endBlock,range);if(range.endContainer===endContainer){range=this.includeBlockStart(startBlock,range);} 6749return range;} 6750fullyIncludeLinks(range){const{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer}=range;const[startLink,endLink]=[startContainer,endContainer].map((container)=>findUpTo(container,commonAncestorContainer,(node)=>node.nodeName==="A"));if(startLink&&this.isCursorAtStartOfElement(startLink,startContainer,startOffset)){range.setStartBefore(startLink);} 6751if(endLink&&this.isCursorAtEndOfElement(endLink,endContainer,endOffset)){range.setEndAfter(endLink);} 6752return range;} 6753includeEmptyInlineStart(range){const element=closestElement(range.startContainer);if(this.isEmptyInline(element)){range.setStartBefore(element);} 6754return range;}
6755includeEmptyInlineEnd(range){const element=closestElement(range.endContainer);if(this.isEmptyInline(element)){range.setEndAfter(element);} 6756return range;} 6757includeNextZWS(range){const{endContainer,endOffset}=range;if(isTextNode(endContainer)&&endContainer.textContent[endOffset]==="\u200B"){range.setEnd(endContainer,endOffset+1);} 6758return range;} 6759includePreviousZWS(range){const{startContainer,startOffset}=range;if(isTextNode(startContainer)&&startContainer.textContent[startOffset-1]==="\u200B"){range.setStart(startContainer,startOffset-1);} 6760return range;} 6761expandRangeToIncludeNonEditables(range){const{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer:commonAncestor,}=range;const isNonEditable=(node)=>!isContentEditable(node);const startUneditable=startOffset===0&&!previousLeaf(startContainer,closestBlock(startContainer))&&findFurthest(startContainer,commonAncestor,isNonEditable);if(startUneditable){range.setStartBefore(startUneditable);} 6762const endUneditable=endOffset===nodeSize(endContainer)&&!nextLeaf(endContainer,closestBlock(endContainer))&&findFurthest(endContainer,commonAncestor,isNonEditable);if(endUneditable){range.setEndAfter(endUneditable);} 6763return range;} 6764findAdjacentPosition(node,offset,direction){return direction==="forward"?this.findNextPosition(node,offset):this.findPreviousPosition(node,offset);} 6765makeFindPositionFn(direction){const isDirectionForward=direction==="forward";const findVisibleChar=(isDirectionForward?this.findNextVisibleChar:this.findPreviousVisibleChar).bind(this);const charLeftPos=(index,char)=>index;const charRightPos=(index,char)=>index+char.length;const indexBeforeChar=isDirectionForward?charLeftPos:charRightPos;const indexAfterChar=isDirectionForward?charRightPos:charLeftPos;const textEdgePos=isDirectionForward?startPos:endPos;const adjacentLeaf=(isDirectionForward?this.nextLeaf:this.previousLeaf).bind(this);const adjacentLeafFromPos=(isDirectionForward?this.nextLeafFromPos:this.previousLeafFromPos).bind(this);const beforePos=isDirectionForward?leftPos:rightPos;const afterPos=isDirectionForward?rightPos:leftPos;return function findPosition(node,offset){if(node.nodeType===Node.TEXT_NODE){const[char,index]=findVisibleChar(node,offset);if(char){return[node,indexAfterChar(index,char)];}} 6766const isEditableRoot=(n)=>n.isContentEditable&&!n.parentNode.isContentEditable;const editableRoot=findUpTo(node,this.editable.parentNode,isEditableRoot);let blockSwitch;const nodeClosestBlock=closestBlock(node);let leaf=adjacentLeafFromPos(node,offset,editableRoot);while(leaf){const leafClosestBlock=closestBlock(leaf);blockSwitch||=leafClosestBlock!==nodeClosestBlock;if(this.shouldSkip(leaf,blockSwitch)){leaf=adjacentLeaf(leaf,editableRoot);continue;} 6767if(leaf.nodeType===Node.TEXT_NODE&&!(blockSwitch&&isEmptyBlock(leafClosestBlock))){const[char,index]=findVisibleChar(...textEdgePos(leaf));if(char){const idx=(blockSwitch?indexBeforeChar:indexAfterChar)(index,char);return[leaf,idx];}}else if(!leaf.isContentEditable&&isBlock(leaf)){return afterPos(leaf);}else{return blockSwitch?beforePos(leaf):afterPos(leaf);} 6768leaf=adjacentLeaf(leaf,editableRoot);} 6769return[null,null];};} 6770findLineBoundary(container,offset,direction){const adjacentLeaf=direction==="forward"?nextLeaf:previousLeaf;const edgeIndex=(node)=>(direction==="forward"?nodeSize(node):0);const block=closestBlock(container);let last=container;let node=adjacentLeaf(container,this.editable);while(node&&node.nodeName!=="BR"&&closestBlock(node)===block){last=node;node=adjacentLeaf(node,this.editable);} 6771if(last===container&&offset===edgeIndex(container)){return this.findAdjacentPosition(container,offset,direction);} 6772return direction==="forward"?rightPos(last):leftPos(last);} 6773isVisibleChar(char,textNode,offset){if(isProtected(textNode)){return true;} 6774const isEmptyButton=(node)=>isButton(node)&&/^\ufeff*$/.test(node.textContent);if(isZwnbsp(textNode)&&(isButton(textNode.previousSibling)||isEmptyButton(textNode.nextSibling))){return true;} 6775if(["\u200B","\uFEFF"].includes(char)){return false;} 6776if(!isWhitespace(char)||isInPre(textNode)){return true;} 6777if(offset){return!isWhitespace(textNode.textContent[offset-char.length]);}else if(!(getState(...leftPos(textNode),DIRECTIONS.LEFT).cType&CTYPES.CONTENT)){return false;} 6778const charsToTheRight=textNode.textContent.slice(offset+char.length);for(char of charsToTheRight){if(!isWhitespace(char)){return true;}} 6779if(getState(...rightPos(textNode),DIRECTIONS.RIGHT).cType&CTYPES.CONTENT){return true;} 6780return false;} 6781shouldSkip(leaf,blockSwitch){const systemNodeSelectors=this.getResource("system_node_selectors").join(",");if(systemNodeSelectors&&closestElement(leaf,systemNodeSelectors)){return true;} 6782if(leaf.nodeType===Node.TEXT_NODE){return false;} 6783if(blockSwitch){return false;} 6784if(leaf.nodeName==="BR"&&isFakeLineBreak(leaf)){return true;} 6785if(this.getResource("functional_empty_node_predicates").some((predicate)=>predicate(leaf))){return false;} 6786if(isEmpty(leaf)||isZWS(leaf)){return true;} 6787return false;} 6788findPreviousVisibleChar(textNode,index){const chars=[...textNode.textContent.slice(0,index)];let char=chars.pop();while(char){index-=char.length;if(this.isVisibleChar(char,textNode,index)){return[char,index];} 6789char=chars.pop();}
6790return[null,null];} 6791findNextVisibleChar(textNode,index){for(const char of textNode.textContent.slice(index)){if(this.isVisibleChar(char,textNode,index)){return[char,index];} 6792index+=char.length;} 6793return[null,null];} 6794adjustedLeaf(leaf,refEditableRoot){const isNonEditable=(node)=>!isContentEditable(node);const nonEditableRoot=leaf&&findFurthest(leaf,refEditableRoot,isNonEditable);return nonEditableRoot||leaf;} 6795previousLeaf(node,editableRoot){return this.adjustedLeaf(previousLeaf(node,editableRoot),editableRoot);} 6796nextLeaf(node,editableRoot){return this.adjustedLeaf(nextLeaf(node,editableRoot),editableRoot);} 6797previousLeafFromPos(node,offset,editableRoot){const leaf=node.hasChildNodes()&&offset>0?lastLeaf(node.childNodes[offset-1]):previousLeaf(node,editableRoot);return this.adjustedLeaf(leaf,editableRoot);} 6798nextLeafFromPos(node,offset,editableRoot){const leaf=node.hasChildNodes()&&offset<nodeSize(node)?firstLeaf(node.childNodes[offset]):nextLeaf(node,editableRoot);return this.adjustedLeaf(leaf,editableRoot);} 6799onBeforeInputDelete(ev){const handledInputTypes={deleteContentBackward:["backward","character"],deleteContentForward:["forward","character"],deleteWordBackward:["backward","word"],deleteWordForward:["forward","word"],deleteHardLineBackward:["backward","line"],deleteHardLineForward:["forward","line"],};const argsForDelete=handledInputTypes[ev.inputType];if(argsForDelete){this.delete(...argsForDelete);ev.preventDefault();if(isBrowserChrome()&&hasTouch()){this.preventDefaultDeleteAndroidChrome(ev);}}} 6800onBeforeInputInsertText(ev){if(ev.inputType==="insertText"){const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!selection.isCollapsed){this.dispatchTo("before_delete_handlers");this.deleteSelection(selection);this.dispatchTo("delete_handlers");if(isBrowserSafari()){ev.preventDefault();this.document.execCommand(ev.inputType,false,ev.data);}}}} 6801preventDefaultDeleteAndroidChrome(beforeInputEvent){const restoreDOM=this.dependencies.history.makeSavePoint();this.onAndroidChromeInput=(ev)=>{if(ev.inputType!==beforeInputEvent.inputType){return;} 6802restoreDOM();const{restore:restoreSelection}=this.dependencies.selection.preserveSelection();const observerOptions={childList:true,subtree:true,characterData:true};const getMutationRecords=observeMutations(this.editable,observerOptions);this.onAndroidChromeSelectionChange=()=>{const shouldRevertSelectionChanges=!getMutationRecords().length;if(shouldRevertSelectionChanges){restoreSelection();}};setTimeout(()=>delete this.onAndroidChromeSelectionChange);};} 6803deleteBackwardUnmergeable(range){const{startContainer,startOffset,endContainer,endOffset}=range;return this.deleteCharUnmergeable(endContainer,endOffset,startContainer,startOffset);} 6804deleteForwardUnmergeable(range){const{startContainer,startOffset,endContainer,endOffset}=range;return this.deleteCharUnmergeable(startContainer,startOffset,endContainer,endOffset);} 6805deleteCharUnmergeable(sourceContainer,sourceOffset,destContainer,destOffset){if(!destContainer){return;} 6806const commonAncestor=getCommonAncestor([sourceContainer,destContainer],this.editable);const closestUnmergeable=findUpTo(sourceContainer,commonAncestor,(node)=>this.isUnmergeable(node));if(!closestUnmergeable){return;} 6807if((isEmpty(closestUnmergeable)||this.getResource("is_empty_predicates").some((p)=>p(closestUnmergeable)))&&!this.isUnremovable(closestUnmergeable)){closestUnmergeable.remove();this.fillShrunkBlocks(commonAncestor);this.dependencies.selection.setSelection({anchorNode:destContainer,anchorOffset:destOffset,});}else{this.dependencies.selection.setSelection({anchorNode:sourceContainer,anchorOffset:sourceOffset,});} 6808return true;} 6809isEmptyInline(element){if(isBlock(element)){return false;} 6810if(isZWS(element)){return true;} 6811return element.innerHTML.trim()==="";} 6812isCursorAtStartOfElement(element,cursorNode,cursorOffset){const[node]=this.findPreviousPosition(cursorNode,cursorOffset);return!element.contains(node);} 6813isCursorAtEndOfElement(element,cursorNode,cursorOffset){const[node]=this.findNextPosition(cursorNode,cursorOffset);return!element.contains(node);}
6814setCursorFromRange(range,{collapseToEnd=false}={}){range=this.collapseRange(range,{toEnd:collapseToEnd});const[anchorNode,anchorOffset]=this.normalizeEnterBlock(range.startContainer,range.startOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset});} 6815normalizeEnterBlock(node,offset){while(isBlock(node.childNodes[offset])&&!isSelfClosingElement(node.childNodes[offset])){[node,offset]=[node.childNodes[offset],0];} 6816return[node,offset];} 6817collapseRange(range,{toEnd=false}={}){let{startContainer,startOffset,endContainer,endOffset}=range;if(toEnd){[startContainer,startOffset]=[endContainer,endOffset];}else{[endContainer,endOffset]=[startContainer,startOffset];} 6818const commonAncestorContainer=startContainer;return{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer};}} 6819return __exports;});; 6820 6821/* /html_editor/static/src/core/dialog_plugin.js */ 6822odoo.define('@html_editor/core/dialog_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const DialogPlugin=__exports.DialogPlugin=class DialogPlugin extends Plugin{static id="dialog";static dependencies=["selection"];static shared=["addDialog"];addDialog(DialogClass,props,options={}){return new Promise((resolve)=>{this.services.dialog.add(DialogClass,props,{onClose:()=>{this.dependencies.selection.focusEditable();resolve();},...options,});});}} 6823return __exports;});; 6824 6825/* /html_editor/static/src/core/dom_plugin.js */ 6826odoo.define('@html_editor/core/dom_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/formatting','@html_editor/utils/position','@html_editor/utils/selection','@html_editor/utils/base_container','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{cleanTrailingBR,fillEmpty,fillShrunkPhrasingParent,makeContentsInline,removeClass,removeStyle,unwrapContents,wrapInlinesInBlocks,}=require("@html_editor/utils/dom");const{allowsParagraphRelatedElements,isContentEditable,isContentEditableAncestor,isEmptyBlock,isListElement,isListItemElement,isParagraphRelatedElement,isProtecting,isProtected,isSelfClosingElement,isShrunkBlock,isTangible,isUnprotecting,isEditorTab,isPhrasingContent,getDeepestEditablePosition,isVisible,}=require("@html_editor/utils/dom_info");const{childNodes,children,closestElement,descendants,firstLeaf,lastLeaf,}=require("@html_editor/utils/dom_traversal");const{FONT_SIZE_CLASSES,TEXT_STYLE_CLASSES}=require("@html_editor/utils/formatting");const{childNodeIndex,nodeSize,rightPos}=require("@html_editor/utils/position");const{normalizeCursorPosition}=require("@html_editor/utils/selection");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");function getConnectedParents(nodes){const parents=new Set();for(const node of nodes){if(node.isConnected&&node.parentElement){parents.add(node.parentElement);}} 6827return parents;} 6828const DomPlugin=__exports.DomPlugin=class DomPlugin extends Plugin{static id="dom";static dependencies=["baseContainer","selection","history","split","delete","lineBreak"];static shared=["insert","copyAttributes","canSetBlock","setBlock","setTagName","removeSystemProperties",];resources={user_commands:[{id:"insertFontAwesome",run:this.insertFontAwesome.bind(this),isAvailable:isHtmlContentSupported,},{id:"setTag",run:this.setBlock.bind(this),isAvailable:isHtmlContentSupported,},],clean_for_save_handlers:({root})=>{this.removeEmptyClassAndStyleAttributes(root);},clipboard_content_processors:this.removeEmptyClassAndStyleAttributes.bind(this),functional_empty_node_predicates:[isSelfClosingElement,isEditorTab],};setup(){this.systemClasses=this.getResource("system_classes");this.systemAttributes=this.getResource("system_attributes");this.systemStyleProperties=this.getResource("system_style_properties");this.systemPropertiesSelector=[...this.systemClasses.map((className)=>`.${className}`),...this.systemAttributes.map((attr)=>`[${attr}]`),...this.systemStyleProperties.map((prop)=>`[style*="${prop}"]`),].join(",");} 6829insert(content){if(!content){return;} 6830let selection=this.dependencies.selection.getEditableSelection();if(!selection.isCollapsed){this.dependencies.delete.deleteSelection();selection=this.dependencies.selection.getEditableSelection();} 6831let container=this.document.createElement("fake-element");const containerFirstChild=this.document.createElement("fake-element-fc");const containerLastChild=this.document.createElement("fake-element-lc");if(typeof content==="string"){container.textContent=content;}else{if(content.nodeType===Node.ELEMENT_NODE){this.dispatchTo("normalize_handlers",content);}else{for(const child of children(content)){this.dispatchTo("normalize_handlers",child);}} 6832container.replaceChildren(content);} 6833const block=closestBlock(selection.anchorNode);for(const cb of this.getResource("before_insert_processors")){container=cb(container,block);} 6834if(!container.hasChildNodes()){return[];} 6835selection=this.dependencies.selection.getEditableSelection();let startNode;let insertBefore=false;if(selection.startContainer.nodeType===Node.TEXT_NODE){insertBefore=!selection.startOffset;if(selection.startOffset!==0&&selection.startOffset!==selection.startContainer.length){selection.startContainer.splitText(selection.startOffset);} 6836startNode=selection.startContainer;} 6837const allInsertedNodes=[];const hasSingleChild=nodeSize(container)===1;const closestList=(node)=>{if(isBlock(node)){return node&&isListItemElement(node);} 6838return closestList(node.parentElement);};
6838if(closestList(selection.anchorNode)&&isListElement(container.firstChild)){unwrapContents(container.firstChild);} 6839if(closestList(selection.focusNode)&&isListElement(container.lastChild)&&!hasSingleChild){unwrapContents(container.lastChild);} 6840startNode=startNode||this.dependencies.selection.getEditableSelection().anchorNode;const shouldUnwrap=(node)=>(isParagraphRelatedElement(node)||isListItemElement(node))&&!isEmptyBlock(block)&&!isEmptyBlock(node)&&isContentEditable(block)&&(isContentEditable(node)||(!node.isConnected&&!closestElement(node,"[contenteditable]")))&&!this.dependencies.split.isUnsplittable(node)&&(node.nodeName===block.nodeName||(this.dependencies.baseContainer.isCandidateForBaseContainer(node)&&this.dependencies.baseContainer.isCandidateForBaseContainer(block))||block.nodeName==="PRE"||(block.nodeName==="DIV"&&this.dependencies.split.isUnsplittable(block)))&&!this.isEditionBoundary(selection.anchorNode);const firstLeafNode=firstLeaf(container);if(isBlock(firstLeafNode)&&!(closestElement(firstLeafNode,"[contenteditable]")?.contentEditable==="false")){fillEmpty(firstLeafNode);} 6841const lastLeafNode=lastLeaf(container);if(isBlock(lastLeafNode)&&!(closestElement(lastLeafNode,"[contenteditable]")?.contentEditable==="false")){fillEmpty(lastLeafNode);} 6842if(container.childElementCount===1&&(this.dependencies.baseContainer.isCandidateForBaseContainer(container.firstChild)||shouldUnwrap(container.firstChild))){const nodeToUnwrap=container.firstElementChild;container.replaceChildren(...childNodes(nodeToUnwrap));}else if(container.childElementCount>1){const isSelectionAtStart=firstLeaf(block)===selection.anchorNode&&selection.anchorOffset===0;const isSelectionAtEnd=lastLeaf(block)===selection.focusNode&&selection.focusOffset===nodeSize(selection.focusNode);if(shouldUnwrap(container.firstChild)&&!isSelectionAtStart){if(isListItemElement(container.firstChild)){const deepestBlock=closestBlock(firstLeaf(container.firstChild));this.dependencies.split.splitAroundUntil(deepestBlock,container.firstChild);container.firstElementChild.replaceChildren(...childNodes(deepestBlock));} 6843containerFirstChild.replaceChildren(...childNodes(container.firstElementChild));container.firstElementChild.remove();} 6844if(shouldUnwrap(container.lastChild)&&!isSelectionAtEnd){if(isListItemElement(container.lastChild)){const deepestBlock=closestBlock(lastLeaf(container.lastChild));this.dependencies.split.splitAroundUntil(deepestBlock,container.lastChild);container.lastElementChild.replaceChildren(...childNodes(deepestBlock));} 6845containerLastChild.replaceChildren(...childNodes(container.lastElementChild));container.lastElementChild.remove();}} 6846const textNode=this.document.createTextNode("");if(startNode.nodeType===Node.ELEMENT_NODE){if(selection.anchorOffset===0){if(isSelfClosingElement(startNode)){startNode.parentNode.insertBefore(textNode,startNode);}else{startNode.prepend(textNode);} 6847startNode=textNode;allInsertedNodes.push(textNode);}else{startNode=childNodes(startNode).at(selection.anchorOffset-1);}} 6848let currentNode=startNode;const _insertAt=(reference,nodes,insertBefore)=>{for(const child of insertBefore?nodes.reverse():nodes){reference[insertBefore?"before":"after"](child);reference=child;}};const lastInsertedNodes=childNodes(containerLastChild);if(containerLastChild.hasChildNodes()){const toInsert=childNodes(containerLastChild);_insertAt(currentNode,[...toInsert],insertBefore);currentNode=insertBefore?toInsert[0]:currentNode;toInsert[toInsert.length-1];} 6849const firstInsertedNodes=childNodes(containerFirstChild);if(containerFirstChild.hasChildNodes()){const toInsert=childNodes(containerFirstChild);_insertAt(currentNode,[...toInsert],insertBefore);currentNode=toInsert[toInsert.length-1];insertBefore=false;} 6850allInsertedNodes.push(...firstInsertedNodes);if(!container.hasChildNodes()){if(this.dependencies.split.isUnsplittable(closestBlock(currentNode.nextSibling))){this.dependencies.lineBreak.insertLineBreakNode({targetNode:currentNode.nextSibling,targetOffset:0,});}else{const parent=currentNode.nextSibling.parentElement;const index=childNodes(parent).indexOf(currentNode.nextSibling);this.dependencies.split.splitBlockNode({targetNode:parent,targetOffset:index,});}} 6851let nodeToInsert;let doesCurrentNodeAllowsP=allowsParagraphRelatedElements(currentNode);const candidatesForRemoval=[];const insertedNodes=childNodes(container);while((nodeToInsert=container.firstChild)){if(isBlock(nodeToInsert)&&!
6851doesCurrentNodeAllowsP){while(!this.isEditionBoundary(currentNode)&&(!allowsParagraphRelatedElements(currentNode.parentElement)||(isListItemElement(currentNode.parentElement)&&!this.dependencies.split.isUnsplittable(nodeToInsert)))){if(this.dependencies.split.isUnsplittable(currentNode.parentElement)){if(this.dependencies.split.isUnsplittable(nodeToInsert)){if(this.isEditionBoundary(currentNode.parentElement)){break;} 6852currentNode=currentNode.parentElement;doesCurrentNodeAllowsP=allowsParagraphRelatedElements(currentNode);continue;}else{makeContentsInline(container);nodeToInsert=container.firstChild;break;}} 6853let offset=childNodeIndex(currentNode);if(!insertBefore){offset+=1;} 6854if((offset===1&&!insertBefore)||(offset&&isVisible(currentNode?.previousSibling))){const[left,right]=this.dependencies.split.splitElement(currentNode.parentElement,offset);currentNode=insertBefore?right:left;const otherNode=insertBefore?left:right;if(isBlock(otherNode)){fillShrunkPhrasingParent(otherNode);} 6855candidatesForRemoval.push(right);}else{if(isBlock(currentNode)){fillShrunkPhrasingParent(currentNode);} 6856currentNode=currentNode.parentElement;} 6857doesCurrentNodeAllowsP=allowsParagraphRelatedElements(currentNode);} 6858if(isListItemElement(currentNode.parentElement)&&isBlock(nodeToInsert)&&this.dependencies.split.isUnsplittable(nodeToInsert)){const br=document.createElement("br");currentNode[isEmptyBlock(currentNode)||!isTangible(currentNode)?"before":"after"](br);}} 6859const block=closestBlock(currentNode);for(const processor of this.getResource("node_to_insert_processors")){nodeToInsert=processor({nodeToInsert,container:block});} 6860if(insertBefore){currentNode.before(nodeToInsert);insertBefore=false;}else{currentNode.after(nodeToInsert);} 6861allInsertedNodes.push(nodeToInsert);if(currentNode.tagName!=="BR"&&isShrunkBlock(currentNode)){currentNode.remove();} 6862currentNode=nodeToInsert;} 6863textNode.remove();allInsertedNodes.push(...lastInsertedNodes);this.getResource("after_insert_handlers").forEach((handler)=>handler(allInsertedNodes));let insertedNodesParents=getConnectedParents(allInsertedNodes);for(const parent of insertedNodesParents){if(!this.areInlinesAllowedAtRoot(parent)&&this.isEditionBoundary(parent)&&allowsParagraphRelatedElements(parent)&&!isPhrasingContent(parent)){wrapInlinesInBlocks(parent,{baseContainerNodeName:this.dependencies.baseContainer.getDefaultNodeName(),});}} 6864insertedNodesParents=getConnectedParents(allInsertedNodes);for(const parent of insertedNodesParents){if(!isProtecting(parent)&&!(isProtected(parent)&&!isUnprotecting(parent))&&parent.isContentEditable){cleanTrailingBR(parent);}} 6865for(const candidateForRemoval of candidatesForRemoval){if(candidateForRemoval.isConnected&&(isParagraphRelatedElement(candidateForRemoval)||isListItemElement(candidateForRemoval))&&candidateForRemoval.parentElement.isContentEditable&&isEmptyBlock(candidateForRemoval)){candidateForRemoval.remove();}} 6866const lastInsertedNode=allInsertedNodes.findLast((node)=>node.isConnected);if(!lastInsertedNode){return;} 6867let lastPosition=isParagraphRelatedElement(lastInsertedNode)||isListItemElement(lastInsertedNode)||isListElement(lastInsertedNode)?rightPos(lastLeaf(lastInsertedNode)):rightPos(lastInsertedNode);lastPosition=normalizeCursorPosition(lastPosition[0],lastPosition[1],"right");if(!this.config.allowInlineAtRoot&&this.isEditionBoundary(lastPosition[0])){lastPosition=getDeepestEditablePosition(...lastPosition);} 6868this.dependencies.selection.setSelection({anchorNode:lastPosition[0],anchorOffset:lastPosition[1]},{normalize:false});return firstInsertedNodes.concat(insertedNodes).concat(lastInsertedNodes);} 6869isEditionBoundary(node){if(!node){return false;} 6870if(node===this.editable){return true;} 6871return isContentEditableAncestor(node);} 6872areInlinesAllowedAtRoot(node){const results=this.getResource("are_inlines_allowed_at_root_predicates").map((p)=>p(node)).filter((r)=>r!==undefined);if(!results.length){return this.config.allowInlineAtRoot;} 6873return results.every((r)=>r);} 6874copyAttributes(source,target){if(source?.nodeType!==Node.ELEMENT_NODE||target?.nodeType!==Node.ELEMENT_NODE){return;} 6875const ignoredAttrs=new Set(this.getResource("system_attributes"));const ignoredClasses=new Set(this.getResource("system_classes"));
6875for(const attr of source.attributes){if(ignoredAttrs.has(attr.name)){continue;} 6876if(attr.name!=="class"||ignoredClasses.size===0){target.setAttribute(attr.name,attr.value);}else{const classes=[...source.classList];for(const className of classes){if(!ignoredClasses.has(className)){target.classList.add(className);}}}}} 6877setTagName(el,newTagName){const document=el.ownerDocument;if(el.tagName===newTagName){return el;} 6878const newEl=document.createElement(newTagName);const content=childNodes(el);if(isListItemElement(el)){el.append(newEl);newEl.replaceChildren(...content);}else{if(el.parentElement){el.before(newEl);} 6879this.copyAttributes(el,newEl);newEl.replaceChildren(...content);el.remove();} 6880return newEl;} 6881removeSystemProperties(root){const clean=(element)=>{removeClass(element,...this.systemClasses);this.systemAttributes.forEach((attr)=>element.removeAttribute(attr));removeStyle(element,...this.systemStyleProperties);};if(root.matches?.(this.systemPropertiesSelector)){clean(root);} 6882for(const element of root.querySelectorAll(this.systemPropertiesSelector)){clean(element);}} 6883insertFontAwesome({faClass="fa fa-star"}={}){const fontAwesomeNode=document.createElement("i");fontAwesomeNode.className=faClass;this.insert(fontAwesomeNode);this.dependencies.history.addStep();const[anchorNode,anchorOffset]=rightPos(fontAwesomeNode);this.dependencies.selection.setSelection({anchorNode,anchorOffset});} 6884isRetaggingSafe(block){return!((isParagraphRelatedElement(block)||isListItemElement(block)||isPhrasingContent(block))&&this.getResource("unremovable_node_predicates").some((predicate)=>predicate(block)));} 6885getBlocksToSet(){const targetedBlocks=[...this.dependencies.selection.getTargetedBlocks()];return targetedBlocks.filter((block)=>this.isRetaggingSafe(block)&&!descendants(block).some((descendant)=>targetedBlocks.includes(descendant))&&block.isContentEditable);} 6886canSetBlock(){return this.getBlocksToSet().length>0;} 6887setBlock({tagName,extraClass=""}){let newCandidate=this.document.createElement(tagName.toUpperCase());if(extraClass){newCandidate.classList.add(extraClass);} 6888if(this.dependencies.baseContainer.isCandidateForBaseContainer(newCandidate)){const baseContainer=this.dependencies.baseContainer.createBaseContainer(newCandidate.nodeName);this.copyAttributes(newCandidate,baseContainer);newCandidate=baseContainer;} 6889const cursors=this.dependencies.selection.preserveSelection();const newEls=[];for(const block of this.getBlocksToSet()){if(isParagraphRelatedElement(block)||isListItemElement(block)||isPhrasingContent(block)||block.nodeName==="BLOCKQUOTE"){if(newCandidate.matches(baseContainerGlobalSelector)&&isListItemElement(block)){continue;} 6890this.dispatchTo("before_set_tag_handlers",block,tagName,cursors);const newEl=this.setTagName(block,tagName);cursors.remapNode(block,newEl);const headingClasses=["h1","h2","h3","h4","h5","h6"];removeClass(newEl,...FONT_SIZE_CLASSES,...TEXT_STYLE_CLASSES,...headingClasses);delete newEl.style.fontSize;if(extraClass){newEl.classList.add(extraClass);} 6891newEls.push(newEl);}else{newCandidate.append(...childNodes(block));block.append(newCandidate);cursors.remapNode(block,newCandidate);}} 6892cursors.restore();this.dependencies.history.addStep();} 6893removeEmptyClassAndStyleAttributes(root){for(const node of[root,...descendants(root)]){if(node.classList&&!node.classList.length){node.removeAttribute("class");} 6894if(node.style&&!node.style.length){node.removeAttribute("style");}}}} 6895return __exports;});; 6896 6897/* /html_editor/static/src/core/editor_version_plugin.js */ 6898odoo.define('@html_editor/core/editor_version_plugin',['@html_editor/html_migrations/html_migrations_utils','@html_editor/plugin'],function(require){'use strict';let __exports={};const{htmlEditorVersions,stripVersion,VERSION_SELECTOR,}=require("@html_editor/html_migrations/html_migrations_utils");const{Plugin}=require("@html_editor/plugin");const EditorVersionPlugin=__exports.EditorVersionPlugin=class EditorVersionPlugin extends Plugin{static id="editorVersion";resources={clean_for_save_handlers:this.cleanForSave.bind(this),normalize_handlers:this.normalize.bind(this),};normalize(element){if(element.matches(VERSION_SELECTOR)&&element!==this.editable){delete element.dataset.oeVersion;} 6899stripVersion(element);} 6900cleanForSave({root}){const VERSIONS=htmlEditorVersions();const firstChild=root.firstElementChild;const version=VERSIONS.at(-1);if(firstChild&&version){firstChild.dataset.oeVersion=version;}}} 6901return __exports;});; 6902 6903/* /html_editor/static/src/core/format_plugin.js */ 6904odoo.define('@html_editor/core/format_plugin',['@html_editor/utils/dom_state','@html_editor/utils/resource','@html_editor/utils/selection','@web/core/l10n/translation','@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/formatting','@html_editor/utils/position','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{prepareUpdate}=require("@html_editor/utils/dom_state");const{withSequence}=require("@html_editor/utils/resource");const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{cleanTextNode,fillEmpty,removeClass,splitTextNode,unwrapContents}=require("@html_editor/utils/dom");const{areSimilarElements,isContentEditable,isContentEditableAncestor,isElement,isEmptyBlock,isEmptyTextNode,isSelfClosingElement,isTextNode,isVisibleTextNode,isZwnbsp,isZWS,previousLeaf,PROTECTED_QWEB_SELECTOR,}=require("@html_editor/utils/dom_info");const{isFakeLineBreak}=require("@html_editor/utils/dom_state");const{childNodes,closestElement,descendants,findFurthest,selectElements,}=require("@html_editor/utils/dom_traversal");const{formatsSpecs,FORMATTABLE_TAGS}=require("@html_editor/utils/formatting");const{boundariesIn,leftPos,rightPos}=require("@html_editor/utils/position");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const allWhitespaceRegex=/^[\s\u200b]*$/;function isFormatted(formatPlugin,format){return(sel,nodes)=>
6904formatPlugin.isSelectionFormat(format,nodes);} 6905const FormatPlugin=__exports.FormatPlugin=class FormatPlugin extends Plugin{static id="format";static dependencies=["selection","history","input","split"];static shared=["isSelectionFormat","insertAndSelectZws","mergeAdjacentInlines","formatSelection",];resources={user_commands:[{id:"formatBold",description:_t("Toggle bold"),icon:"fa-bold",run:this.formatSelection.bind(this,"bold"),isAvailable:isHtmlContentSupported,},{id:"formatItalic",description:_t("Toggle italic"),icon:"fa-italic",run:this.formatSelection.bind(this,"italic"),isAvailable:isHtmlContentSupported,},{id:"formatUnderline",description:_t("Toggle underline"),icon:"fa-underline",run:this.formatSelection.bind(this,"underline"),isAvailable:isHtmlContentSupported,},{id:"formatStrikethrough",description:_t("Toggle strikethrough"),icon:"fa-strikethrough",run:this.formatSelection.bind(this,"strikeThrough"),isAvailable:isHtmlContentSupported,},{id:"formatFontSize",run:({size})=>this.formatSelection("fontSize",{applyStyle:true,formatProps:{size},}),isAvailable:isHtmlContentSupported,},{id:"formatFontSizeClassName",run:({className})=>this.formatSelection("setFontSizeClassName",{applyStyle:true,formatProps:{className},}),isAvailable:isHtmlContentSupported,},{id:"removeFormat",description:(sel,nodes)=>nodes&&this.hasAnyFormat(nodes)?_t("Remove Format (Ctrl + Space)"):_t("Selection has no format"),icon:"fa-eraser",run:this.removeAllFormats.bind(this),isAvailable:isHtmlContentSupported,},],shortcuts:[{hotkey:"control+b",commandId:"formatBold"},{hotkey:"control+i",commandId:"formatItalic"},{hotkey:"control+u",commandId:"formatUnderline"},{hotkey:"control+5",commandId:"formatStrikethrough"},{hotkey:"control+space",commandId:"removeFormat"},],toolbar_groups:withSequence(20,{id:"decoration"}),toolbar_items:[{id:"bold",groupId:"decoration",namespaces:["compact","expanded"],commandId:"formatBold",isActive:isFormatted(this,"bold"),},{id:"italic",groupId:"decoration",namespaces:["compact","expanded"],commandId:"formatItalic",isActive:isFormatted(this,"italic"),},{id:"underline",groupId:"decoration",namespaces:["compact","expanded"],commandId:"formatUnderline",isActive:isFormatted(this,"underline"),},{id:"strikethrough",groupId:"decoration",commandId:"formatStrikethrough",isActive:isFormatted(this,"strikeThrough"),},withSequence(20,{id:"remove_format",groupId:"decoration",commandId:"removeFormat",isDisabled:(sel,nodes)=>!this.hasAnyFormat(nodes),}),],beforeinput_handlers:withSequence(20,this.onBeforeInput.bind(this)),clean_for_save_handlers:this.cleanForSave.bind(this),normalize_handlers:this.normalize.bind(this),selectionchange_handlers:this.removeEmptyInlineElement.bind(this),before_set_tag_handlers:this.removeFontSizeFormat.bind(this),before_insert_processors:this.unwrapEmptyFormat.bind(this),intangible_char_for_keyboard_navigation_predicates:(_,char)=>char==="\u200b",};removeFormats(formats,targetedNodes){const editableTargetedNodes=targetedNodes.filter(this.dependencies.selection.isNodeEditable);for(const format of formats){if(!formatsSpecs[format].removeStyle||!this.hasSelectionFormat(format,editableTargetedNodes)){continue;} 6906this.formatSelection(format,{applyStyle:false,removeFormat:true});}} 6907unwrapEmptyFormat(insertedNode){const anchorNode=this.dependencies.selection.getEditableSelection().anchorNode;if(!allWhitespaceRegex.test(insertedNode.textContent)){return insertedNode;} 6908const emptyZWS=closestElement(anchorNode,"[data-oe-zws-empty-inline]");if(!emptyZWS||!emptyZWS.parentElement.isContentEditable||this.getResource("unremovable_node_predicates").some((p)=>p(emptyZWS))){return insertedNode;} 6909const cursors=this.dependencies.selection.preserveSelection();cursors.update(callbacksForCursorUpdate.remove(emptyZWS));emptyZWS.remove();cursors.restore();return insertedNode;} 6910removeAllFormats(){const targetedNodes=this.dependencies.selection.getTargetedNodes();this.removeFormats(Object.keys(formatsSpecs),targetedNodes);this.dispatchTo("remove_all_formats_handlers");this.dependencies.history.addStep();} 6911removeFontSizeFormat(el){for(const node of[el,...descendants(el)]){removeFormat(node,formatsSpecs.fontSize);removeFormat(node,formatsSpecs.setFontSizeClassName);}} 6912hasSelectionFormat(format,targetedNodes=this.dependencies.selection.getTargetedNodes()){const targetedTextNodes=targetedNodes.filter((node)=>node.matches?.(PROTECTED_QWEB_SELECTOR)||(isTextNode(node)&&(isVisibleTextNode(node)||isZWS(node))));const isFormatted=formatsSpecs[format].isFormatted;return targetedTextNodes.some((n)=>isFormatted(n,{editable:this.editable}));} 6913isSelectionFormat(format,targetedNodes=this.dependencies.selection.getTargetedNodes()){const isFormatted=formatsSpecs[format].isFormatted;const isNonFormattedWhiteSpaces=(node)=>/^(\s|\n)+$/.test(node.nodeValue)&&!isFormatted(node,{editable:this.editable});const targetedTextNodes=targetedNodes.filter((node)=>isTextNode(node)&&!isNonFormattedWhiteSpaces(node)&&this.dependencies.selection.isNodeEditable(node)&&(this.checkPredicates("is_formattable_node_predicates",node)??true));return(targetedTextNodes.length&&targetedTextNodes.every((node)=>isZwnbsp(node)||isEmptyTextNode(node)||isFormatted(node,{editable:this.editable})));}
6914hasAnyFormat(targetedNodes){const editableTargetedNodes=targetedNodes.filter(this.dependencies.selection.isNodeEditable);for(const format of Object.keys(formatsSpecs)){if(formatsSpecs[format].removeStyle&&this.hasSelectionFormat(format,editableTargetedNodes)){return true;}} 6915return editableTargetedNodes.some((node)=>this.getResource("has_format_predicates").some((predicate)=>predicate(node)));} 6916formatSelection(formatName,options){this.dispatchTo("format_selection_handlers",formatName,options);if(this._formatSelection(formatName,options)&&!options?.removeFormat){this.dependencies.history.addStep();}} 6917_formatSelection(formatName,{applyStyle,formatProps}={}){const deepSelection=this.dependencies.selection.getSelectionData().deepEditableSelection;const anchorElement=deepSelection.anchorNode;const focusElement=deepSelection.focusNode;if(anchorElement===focusElement&&!isContentEditable(anchorElement)&&!closestElement(anchorElement,PROTECTED_QWEB_SELECTOR)){return;} 6918this.dependencies.selection.selectAroundNonEditable();const selection=this.dependencies.split.splitSelection();if(typeof applyStyle==="undefined"){applyStyle=!this.isSelectionFormat(formatName);} 6919let zws;if(selection.isCollapsed){if(isTextNode(selection.anchorNode)&&selection.anchorNode.textContent==="\u200b"){zws=selection.anchorNode;this.dependencies.selection.setSelection({anchorNode:zws,anchorOffset:0,focusNode:zws,focusOffset:1,});}else{zws=this.insertAndSelectZws();}} 6920const cursor=this.dependencies.selection.preserveSelection();const systemNodesSelector=this.getResource("system_node_selectors").join(", ");const selectedTextNodes=(this.dependencies.selection.getTargetedNodes().filter((n)=>(!systemNodesSelector||!closestElement(n,systemNodesSelector))&&this.dependencies.selection.areNodeContentsFullySelected(n)&&((isTextNode(n)&&(isVisibleTextNode(n)||isZWS(n)))||(n.nodeName==="BR"&&(isFakeLineBreak(n)||previousLeaf(n,closestBlock(n))?.nodeName==="BR")))&&isContentEditable(n)));const unformattedTextNodes=selectedTextNodes.filter((n)=>{if(!(this.checkPredicates("is_formattable_node_predicates",n)??true)){return false;} 6921const listItem=closestElement(n,"li");if(listItem&&this.dependencies.selection.areNodeContentsFullySelected(listItem)){if(formatName==="setFontSizeClassName"){return!listItem.classList.contains(formatProps?.className);}else if(formatName==="fontSize"){return!listItem.style.fontSize;}} 6922return true;});const tagetedFieldNodes=new Set(this.dependencies.selection.getTargetedNodes().map((node)=>closestElement(node,PROTECTED_QWEB_SELECTOR)).filter((node)=>node&&this.dependencies.selection.isNodeEditable(node)));const formatSpec=formatsSpecs[formatName];for(const node of unformattedTextNodes){const inlineAncestors=[];let currentNode=node;let parentNode=node.parentElement;const isClassListSplittable=(classList)=>[...classList].every((className)=>this.getResource("format_class_predicates").some((cb)=>cb(className)));if(parentNode&&!isBlock(parentNode)&&this.dependencies.split.isUnsplittable(parentNode)&&this.dependencies.selection.areNodeContentsFullySelected(parentNode)&&!isContentEditableAncestor(parentNode)){inlineAncestors.push(parentNode);} 6923while(parentNode&&!isBlock(parentNode)){const isNodeUnsplittable=this.dependencies.split.isUnsplittable(parentNode);const isClassSplittable=parentNode.classList.length===0||isClassListSplittable(parentNode.classList);if(!isNodeUnsplittable&&isClassSplittable){const isUselessZws=parentNode.tagName==="SPAN"&&parentNode.hasAttribute("data-oe-zws-empty-inline")&&parentNode.getAttributeNames().length===1;if(isUselessZws){cursor.update(callbacksForCursorUpdate.unwrap(parentNode));unwrapContents(parentNode);}else{const newLastAncestorInlineFormat=this.dependencies.split.splitAroundUntil(currentNode,parentNode);removeFormat(newLastAncestorInlineFormat,formatSpec,cursor);if(newLastAncestorInlineFormat.isConnected){inlineAncestors.push(newLastAncestorInlineFormat);currentNode=newLastAncestorInlineFormat;}}}else{if(["setFontSizeClassName","fontSize"].includes(formatName)&&applyStyle){removeClass(parentNode,"o_default_font_size");} 6924if(!applyStyle&&isNodeUnsplittable&&this.dependencies.selection.areNodeContentsFullySelected(parentNode)){currentNode=currentNode.parentElement;}else{break;}} 6925parentNode=currentNode.parentElement;} 6926const firstBlockOrClassHasFormat=formatSpec.isFormatted(parentNode,formatProps);
6926if(firstBlockOrClassHasFormat&&!applyStyle){const isParentNodeBlockAndCompletelySelected=isBlock(parentNode)&&this.dependencies.selection.areNodeContentsFullySelected(parentNode);if(isParentNodeBlockAndCompletelySelected&&formatName==="setFontSizeClassName"){for(const node of[parentNode,...descendants(parentNode).filter(isElement)]){removeFormat(node,formatSpec,cursor);}}else{formatSpec.addNeutralStyle&&formatSpec.addNeutralStyle(getOrCreateSpan(node,inlineAncestors,cursor));}}else if((!firstBlockOrClassHasFormat||parentNode.nodeName==="LI")&&applyStyle){const tag=formatSpec.tagName&&this.document.createElement(formatSpec.tagName);if(tag){cursor.update(callbacksForCursorUpdate.after(node,tag));node.after(tag);cursor.update(callbacksForCursorUpdate.append(tag,node));tag.append(node);if(!formatSpec.isFormatted(tag,formatProps)){cursor.remapNode(tag,node);tag.after(node);tag.remove();formatSpec.addStyle(getOrCreateSpan(node,inlineAncestors,cursor),formatProps);}}else if(formatName!=="fontSize"||formatProps.size!==undefined){formatSpec.addStyle(getOrCreateSpan(node,inlineAncestors,cursor),formatProps);}}} 6927for(const targetedFieldNode of tagetedFieldNodes){if(applyStyle){formatSpec.addStyle(targetedFieldNode,formatProps);}else{formatSpec.removeStyle(targetedFieldNode);}} 6928if(zws){const siblings=[...zws.parentElement.childNodes];if(!isBlock(zws.parentElement)&&unformattedTextNodes.includes(siblings[0])&&unformattedTextNodes.includes(siblings[siblings.length-1])){zws.parentElement.setAttribute("data-oe-zws-empty-inline","");}else{const span=this.document.createElement("span");span.setAttribute("data-oe-zws-empty-inline","");cursor.update(callbacksForCursorUpdate.before(zws,span));zws.before(span);cursor.update(callbacksForCursorUpdate.append(span,zws));span.append(zws);}} 6929cursor.restore();if(unformattedTextNodes.length===1&&unformattedTextNodes[0]&&unformattedTextNodes[0].textContent==="\u200B"){this.dependencies.selection.setCursorEnd(unformattedTextNodes[0]);return!!tagetedFieldNodes.size;} 6930return true;} 6931normalize(root){for(const el of selectElements(root,"[data-oe-zws-empty-inline]")){if(!allWhitespaceRegex.test(el.textContent)){delete el.dataset.oeZwsEmptyInline;this.cleanZWS(el);if(el.tagName==="SPAN"&&el.getAttributeNames().length===0&&el.classList.length===0){unwrapContents(el);}}} 6932this.mergeAdjacentInlines(root);} 6933cleanForSave({root,preserveSelection=false}={}){for(const element of root.querySelectorAll("[data-oe-zws-empty-inline]")){let currentElement=element.parentElement;this.cleanElement(element,{preserveSelection});while(currentElement&&!isBlock(currentElement)&&!currentElement.childNodes.length){const parentElement=currentElement.parentElement;currentElement.remove();currentElement=parentElement;} 6934if(currentElement&&isBlock(currentElement)){fillEmpty(currentElement);}} 6935this.mergeAdjacentInlines(root,{preserveSelection});} 6936removeEmptyInlineElement(selectionData){const{anchorNode}=selectionData.editableSelection;const blockEl=closestBlock(anchorNode);if(!blockEl){return;} 6937const inlineElement=findFurthest(closestElement(anchorNode),blockEl,(e)=>!isBlock(e)&&e.textContent==="\u200b");if(this.lastEmptyInlineElement?.isConnected&&this.lastEmptyInlineElement!==inlineElement){this.cleanElement(this.lastEmptyInlineElement,{preserveSelection:true});} 6938if(inlineElement&&!isEmptyBlock(blockEl)){this.lastEmptyInlineElement=inlineElement;}else{this.lastEmptyInlineElement=null;}} 6939cleanElement(element,{preserveSelection}){if(!allWhitespaceRegex.test(element.textContent)){delete element.dataset.oeZwsEmptyInline;this.cleanZWS(element,{preserveSelection});return;} 6940if(this.getResource("unremovable_node_predicates").some((p)=>p(element))){return;} 6941if(![...element.classList].every((c)=>this.getResource("format_class_predicates").some((p)=>p(c)))){return;} 6942delete element.dataset.oeZwsEmptyInline;const restore=prepareUpdate(...leftPos(element),...rightPos(element));element.remove();restore();} 6943cleanZWS(element,{preserveSelection=true}={}){const textNodes=descendants(element).filter(isTextNode);const cursors=preserveSelection?this.dependencies.selection.preserveSelection():null;for(const node of textNodes){cleanTextNode(node,"\u200B",cursors);}
6944cursors?.restore();} 6945insertText(selection,content){if(selection.anchorNode.nodeType===Node.TEXT_NODE){selection=this.dependencies.selection.setSelection({anchorNode:selection.anchorNode.parentElement,anchorOffset:splitTextNode(selection.anchorNode,selection.anchorOffset),},{normalize:false});} 6946const txt=this.document.createTextNode(content||"#");const restore=prepareUpdate(selection.anchorNode,selection.anchorOffset);selection.anchorNode.insertBefore(txt,selection.anchorNode.childNodes[selection.anchorOffset]);restore();const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesIn(txt);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset},{normalize:false});return txt;} 6947insertAndSelectZws(){const selection=this.dependencies.selection.getEditableSelection();const zws=this.insertText(selection,"\u200B");splitTextNode(zws,selection.anchorOffset);return zws;} 6948onBeforeInput(ev){if(ev.inputType.startsWith("format")&&!isHtmlContentSupported(this.dependencies.selection.getEditableSelection())){ev.preventDefault();} 6949if(ev.inputType==="insertText"){const selection=this.dependencies.selection.getEditableSelection();if(!selection.isCollapsed){return;} 6950const element=closestElement(selection.anchorNode);if(element.hasAttribute("data-oe-zws-empty-inline")){const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesIn(element);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});}}} 6951mergeAdjacentInlines(root,{preserveSelection=true}={}){let selectionToRestore=null;for(const node of[root,...descendants(root)].filter(isElement)){if(this.shouldBeMergedWithPreviousSibling(node)){if(preserveSelection){selectionToRestore??=this.dependencies.selection.preserveSelection();selectionToRestore.update(callbacksForCursorUpdate.merge(node));} 6952if(node.matches("code.o_inline_code")){while(node.previousSibling?.nodeType===Node.TEXT_NODE&&/^\uFEFF*$/.test(node.previousSibling.nodeValue)){node.previousSibling.remove();}} 6953node.previousSibling.append(...childNodes(node));node.remove();}} 6954selectionToRestore?.restore();} 6955shouldBeMergedWithPreviousSibling(node){const isMergeable=(node)=>FORMATTABLE_TAGS.includes(node.nodeName)&&!this.getResource("unsplittable_node_predicates").some((predicate)=>predicate(node));let previousSibling=node.previousSibling;if(node.matches("code.o_inline_code")){while(previousSibling?.nodeType===Node.TEXT_NODE&&/^\uFEFF*$/.test(previousSibling.nodeValue)){previousSibling=previousSibling.previousSibling;}} 6956return(!isSelfClosingElement(node)&&isMergeable(node)&&areSimilarElements(node,previousSibling));}} 6957function getOrCreateSpan(node,ancestors,cursor){const document=node.ownerDocument;const span=ancestors.find((element)=>element.tagName==="SPAN"&&element.isConnected);const lastInlineAncestor=ancestors.findLast((element)=>!isBlock(element)&&element.isConnected);if(span){return span;}else{const span=document.createElement("span");if(lastInlineAncestor){cursor?.update(callbacksForCursorUpdate.after(lastInlineAncestor,span));lastInlineAncestor.after(span);cursor?.update(callbacksForCursorUpdate.append(span,lastInlineAncestor));span.append(lastInlineAncestor);}else{cursor?.update(callbacksForCursorUpdate.after(node,span));node.after(span);cursor?.update(callbacksForCursorUpdate.append(span,node));span.append(node);} 6958return span;}} 6959function removeFormat(node,formatSpec,cursor){const document=node.ownerDocument;node=closestElement(node);if(formatSpec.hasStyle(node)){formatSpec.removeStyle(node);if(["SPAN","FONT"].includes(node.tagName)&&!node.getAttributeNames().length){cursor?.update(callbacksForCursorUpdate.unwrap(node));return unwrapContents(node);}} 6960if(formatSpec.isTag&&formatSpec.isTag(node)){const attributesNames=node.getAttributeNames().filter((name)=>name!=="data-oe-zws-empty-inline");if(attributesNames.length){const newNode=document.createElement("span");while(node.firstChild){cursor?.update(callbacksForCursorUpdate.append(newNode,node.firstChild));newNode.appendChild(node.firstChild);} 6961for(let index=node.attributes.length-1;index>=0;--index){newNode.attributes.setNamedItem(node.attributes[index].cloneNode());} 6962cursor?.remapNode(node,newNode);node.parentNode.replaceChild(newNode,node);}else{cursor?.update(callbacksForCursorUpdate.unwrap(node));unwrapContents(node);}}} 6963return __exports;});; 6964 6965/* /html_editor/static/src/core/history_plugin.js */ 6966odoo.define('@html_editor/core/history_plugin',['@web/core/l10n/translation','@html_editor/plugin','@html_editor/utils/dom_traversal','@web/core/browser/feature_detection','@html_editor/utils/resource','@web/core/utils/concurrency','@html_editor/utils/dom','@web/core/utils/objects','@html_editor/utils/tracking'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Plugin}=require("@html_editor/plugin");const{childNodes,descendants,getCommonAncestor}=require("@html_editor/utils/dom_traversal");const{hasTouch}=require("@web/core/browser/feature_detection");const{withSequence}=require("@html_editor/utils/resource");const{Deferred}=require("@web/core/utils/concurrency");const{toggleClass}=require("@html_editor/utils/dom");const{omit,pick}=require("@web/core/utils/objects");const{trackOccurrences,trackOccurrencesPair}=require("@html_editor/utils/tracking");const HistoryPlugin=__exports.HistoryPlugin=class HistoryPlugin extends Plugin{static id="history";static dependencies=["selection","sanitize"];static shared=["addCustomMutation","applyCustomMutation","addExternalStep","addStep","canRedo","canUndo","ignoreDOMMutations","getHistorySteps","getNodeById","makePreviewableOperation","makePreviewableAsyncOperation","makeSavePoint","makeSnapshotStep","redo","reset","resetFromSteps","serializeSelection","stageSelection","stageFocus","undo","getIsPreviewing","setStepExtra","getIsCurrentStepModified",];resources={user_commands:[{id:"historyUndo",description:_t("Undo"),icon:"fa-undo",run:this.undo.bind(this),},{id:"historyRedo",description:_t("Redo"),icon:"fa-repeat",run:this.redo.bind(this),},],...(hasTouch()&&{toolbar_groups:withSequence(5,{id:"historyMobile"}),toolbar_items:[{id:"undo",groupId:"historyMobile",commandId:"historyUndo",isDisabled:()=>!this.canUndo(),namespaces:["compact","expanded"],},{id:"redo",groupId:"historyMobile",commandId:"historyRedo",isDisabled:()=>!this.canRedo(),namespaces:["compact","expanded"],},],}),shortcuts:[{hotkey:"control+z",commandId:"historyUndo",global:true},{hotkey:"control+y",commandId:"historyRedo",global:true},{hotkey:"control+shift+z",commandId:"historyRedo",global:true},],start_edition_handlers:()=>{this.enableObserver();this.reset(this.config.content);},on_prepare_drag_handlers:this.disableIsCurrentStepModifiedWarning.bind(this),};setup(){this.mutationFilteredClasses=new Set(this.getResource("system_classes"));this.mutationFilteredAttributes=new Set(this.getResource("system_attributes"));this._onKeyupResetContenteditableNodes=[];this.addDomListener(this.document,"beforeinput",this._onDocumentBeforeInput.bind(this));this.addDomListener(this.document,"input",this._onDocumentInput.bind(this));this.addGlobalDomListener("pointerup",(ev)=>{if(this.editable.contains(ev.target)){this.stageSelection();}});
6966this.observer=new MutationObserver((records)=>this.handleNewRecords(records));this.enableObserverCallbacks=new Set();this._cleanups.push(()=>this.observer.disconnect());this.clean();} 6967getIsPreviewing(){return this.isPreviewing;} 6968clean(){this.handleObserverRecords();this.steps=[];this.currentStep=this.processHistoryStep({selection:{},mutations:[],id:this.generateId(),previousStepId:undefined,extraStepInfos:{},});this.revertedSteps=new Set();this.discardedSteps=new Set();this.nodeMap=new NodeMap();this.lastObservedState=new WeakMap();this.setNodeId(this.editable);this.dispatchTo("history_cleaned_handlers");} 6969getNodeById(id){return this.nodeMap.getNode(id);} 6970reset(content){this.clean();this.stageSelection();this.steps.push(this.makeSnapshotStep());this.dispatchTo("history_reset_handlers",content);} 6971resetFromSteps(steps){this.withObserverOff(()=>{this.editable.replaceChildren();this.clean();this.stageSelection();for(const step of steps){this.applyMutations(step.mutations);} 6972this.steps=steps;this.dispatchTo("history_reset_from_steps_handlers");});this.dispatchTo("history_reset_from_steps_handlers");} 6973makeSnapshotStep(){return{selection:{anchorNode:undefined,anchorOffset:undefined,focusNode:undefined,focusOffset:undefined,},mutations:childNodes(this.editable).filter((node)=>this.nodeMap.hasNode(node)).map((node)=>({type:"add",parentNodeId:"root",nodeId:this.nodeMap.getId(node),serializedNode:this.serializeNode(node),nextNodeId:null,})),id:this.steps[this.steps.length-1]?.id||this.generateId(),previousStepId:undefined,};} 6974getHistorySteps(){return this.steps;} 6975processHistoryStep(step){for(const fn of this.getResource("history_step_processors")){step=fn(step);} 6976return step;} 6977enableObserver(){this.observer.observe(this.editable,{childList:true,subtree:true,attributes:true,attributeOldValue:true,characterData:true,characterDataOldValue:true,});} 6978disableObserver(){const enableObserver=()=>{this.enableObserverCallbacks.delete(enableObserver);if(this.enableObserverCallbacks.size>0){return;} 6979this.handleObserverRecords();this.isObserverDisabled=false;};this.enableObserverCallbacks.add(enableObserver);this.handleObserverRecords();this.isObserverDisabled=true;return enableObserver;} 6980ignoreDOMMutations(callback){const enableObserver=this.disableObserver();try{return callback();}finally{enableObserver();}} 6981withObserverOff(callback){this.handleObserverRecords();this.observer.disconnect();callback();this.enableObserver();} 6982handleObserverRecords(dispatch=true){this.handleNewRecords(this.observer.takeRecords(),dispatch);} 6983processNewRecords(mutationRecords){if(this.observer.takeRecords().length){throw new Error("MutationObserver has pending records");} 6984mutationRecords=this.filterMutationRecords(mutationRecords);let records=this.transformToHistoryMutationRecords(mutationRecords);records=records.filter((record)=>!this.isSystemMutationRecord(record));records=this.filterAndAdjustHistoryMutationRecords(records);this.stageRecords(records);records.filter(({type})=>type==="attributes").forEach((record)=>this.dispatchTo("attribute_change_handlers",record));return records;} 6985isValidRecord(record){switch(record.type){case"attributes":case"classList":case"characterData":return record.value!==record.oldValue;case"childList":return((record.addedTrees.length||record.removedTrees.length)&&(record.previousSibling!==undefined||record.nextSibling!==undefined));}} 6986dispatchContentUpdated(){if(!this.currentStep?.mutations?.length){return;} 6987const root=this.getMutationsRoot(this.currentStep.mutations);if(!root){return;} 6988this.dispatchTo("content_updated_handlers",root);} 6989handleNewRecords(records,dispatch=true){const processedRecords=this.processNewRecords(records);if(processedRecords.length){if(dispatch){const stepType=this.currentStep.type;this.dispatchTo("handleNewRecords",processedRecords,stepType);} 6990this.processNewRecords(this.observer.takeRecords());this.dispatchContentUpdated();}} 6991setIdOnAddedNodes(record){if(record.type!=="childList"){return;} 6992record.addedTrees.flatMap(treeToNodes).filter((node)=>
6992!this.nodeMap.hasNode(node)).forEach((node)=>this.nodeMap.set(this.generateId(),node));} 6993filterMutationRecords(records){records=this.filterAttributeMutationRecords(records);records=this.filterSameTextContentMutationRecords(records);records=this.filterOutIntermediateStateMutationRecords(records);return records;} 6994filterAttributeMutationRecords(records){return records.filter((record)=>{if(record.type!=="attributes"){return true;} 6995if(record.target===this.editable){return false;} 6996if(record.attributeName==="contenteditable"){return false;} 6997return true;});} 6998filterSameTextContentMutationRecords(records){const filteredRecords=[];for(const record of records){if(record.type==="childList"&&this.isSameTextContentMutation(record)){const{addedNodes,removedNodes}=record;const oldId=this.nodeMap.getId(removedNodes[0]);if(oldId){this.nodeMap.set(oldId,addedNodes[0]);continue;}} 6999filteredRecords.push(record);} 7000return filteredRecords;} 7001filterOutIntermediateStateMutationRecords(records){const isFirstAttributeOccurrence=trackOccurrencesPair();const isFirstCharDataOccurence=trackOccurrences();const filteredRecords=[];for(const record of records){if(record.type==="attributes"){if(isFirstAttributeOccurrence(record.target,record.attributeName)){filteredRecords.push(record);}}else if(record.type==="characterData"){if(isFirstCharDataOccurence(record.target)){filteredRecords.push(record);}}else{filteredRecords.push(record);}} 7002return filteredRecords;} 7003transformToHistoryMutationRecords(records){records=this.transformChildListRecords(records);return records.flatMap((record)=>{if(record.type==="attributes"){if(record.attributeName==="class"){return this.splitClassMutationRecord(record);} 7004const oldValue=record.oldValue===undefined?null:record.oldValue;const value=record.target.getAttribute(record.attributeName);return{...pick(record,"type","target","attributeName"),oldValue,value};} 7005if(record.type==="characterData"){const value=record.target.textContent;return{...pick(record,"type","target","oldValue"),value};} 7006return record;});} 7007transformChildListRecords(records){const childListSnapshot=new WeakMap();const getChildListSnapshot=(node)=>childListSnapshot.get(node)||childNodes(node);const makeSnapshotTree=(node)=>({node,children:getChildListSnapshot(node).map(makeSnapshotTree),});const reconstructChildList=(childListAfter,record)=>{const{removedNodes,previousSibling,nextSibling}=record;const previousSiblingNodes=previousSibling?childListAfter.slice(0,childListAfter.indexOf(previousSibling)+1):[];const nextSiblingNodes=nextSibling?childListAfter.slice(childListAfter.indexOf(nextSibling)):[];return[...previousSiblingNodes,...removedNodes,...nextSiblingNodes];};return records.toReversed().map((record)=>{if(record.type!=="childList"){return record;} 7008const transformedRecord={...pick(record,"type","previousSibling","nextSibling","target"),addedTrees:[...record.addedNodes].map(makeSnapshotTree),removedTrees:[...record.removedNodes].map(makeSnapshotTree),};const childListAfterMutation=getChildListSnapshot(record.target);const childListBefore=reconstructChildList(childListAfterMutation,record);childListSnapshot.set(record.target,childListBefore);return transformedRecord;}).toReversed();} 7009splitClassMutationRecord(record){const oldValue=record.oldValue?.split(" ").filter(Boolean);const classesBefore=new Set(oldValue);const classesAfter=new Set(record.target.classList);const setDifference=(setA,setB)=>{const diff=new Set(setA);setB.forEach((item)=>diff.delete(item));return diff;};const addedClasses=setDifference(classesAfter,classesBefore);const removedClasses=setDifference(classesBefore,classesAfter);const createClassRecord=(className,isAdded)=>({type:"classList",target:record.target,className,value:isAdded,oldValue:!isAdded,});return[...[...addedClasses].map((cls)=>createClassRecord(cls,true)),...[...removedClasses].map((cls)=>createClassRecord(cls,false)),];} 7010isSystemMutationRecord(record){if(record.type==="attributes"){return this.mutationFilteredAttributes.has(record.attributeName);} 7011if(record.type==="classList"){return this.mutationFilteredClasses.has(record.className);} 7012return false;} 7013filterAndAdjustHistoryMutationRecords(records){this.dispatchTo("before_filter_mutation_record_handlers",records);const savableRecordPredicates=this.getResource("savable_mutation_record_predicates");
7013const isRecordSavable=(record)=>savableRecordPredicates.every((p)=>p(record));const result=[];for(const record of records){if(!this.isObservedNode(record.target)){continue;} 7014if(this.isObserverDisabled||!isRecordSavable(record)){if(record.type!=="childList"){this.storeOldValue(record);} 7015continue;} 7016const updatedRecord=record.type==="childList"?this.updateChildListRecord(record):this.updateOldValue(record);if(this.isValidRecord(updatedRecord)){this.setIdOnAddedNodes(record);result.push(updatedRecord);}} 7017return result;} 7018isObservedNode(node){return this.nodeMap.hasNode(node);} 7019storeOldValue(record){const{stateMap,key}=this.getObservedStateStorage(record);if(!stateMap.has(key)){stateMap.set(key,record.oldValue);}} 7020updateOldValue(record){const{stateMap,key}=this.getObservedStateStorage(record);if(!stateMap.has(key)){return record;} 7021const lastObservedValue=stateMap.get(key);stateMap.delete(key);return{...record,oldValue:lastObservedValue};} 7022getObservedStateStorage(record){if(!this.lastObservedState.has(record.target)){this.lastObservedState.set(record.target,{attributes:new Map(),classList:new Map(),characterData:new Map(),});} 7023const stateMap=this.lastObservedState.get(record.target)[record.type];switch(record.type){case"attributes":return{stateMap,key:record.attributeName};case"classList":return{stateMap,key:record.className};case"characterData":return{stateMap,key:"textContent"};default:throw new Error(`Unsupported mutation type: ${record.type}`);}} 7024updateChildListRecord(record){const isValidReference=(node)=>node===null||this.isObservedNode(node);const updateSibling=(sibling)=>(isValidReference(sibling)?sibling:undefined);const previousSibling=updateSibling(record.previousSibling);const nextSibling=updateSibling(record.nextSibling);const removeUnobservedNodes=(tree)=>{if(!this.isObservedNode(tree.node)){return null;} 7025return{node:tree.node,children:tree.children.map(removeUnobservedNodes).filter(Boolean),};};const removedTrees=record.removedTrees.map(removeUnobservedNodes).filter(Boolean);return{...record,previousSibling,nextSibling,removedTrees,};} 7026isSameTextContentMutation(record){const{addedNodes,removedNodes}=record;return(record.type==="childList"&&addedNodes.length===1&&removedNodes.length===1&&addedNodes[0].nodeType===Node.TEXT_NODE&&removedNodes[0].nodeType===Node.TEXT_NODE&&addedNodes[0].textContent===removedNodes[0].textContent);} 7027stageSelection(){this.stageFocus();const selection=this.dependencies.selection.getEditableSelection();if(this.getIsCurrentStepModified()){console.warn(`should not have any "characterData", "remove" or "add" mutations in current step when you update the selection`);return;} 7028this.currentStep.selection=this.serializeSelection(selection);} 7029stageFocus(){let activeElement=this.document.activeElement;if(activeElement.contains(this.editable)){activeElement=this.editable;} 7030if(this.editable.contains(activeElement)){this.currentStep.activeElementId=this.setNodeId(activeElement);}} 7031stageRecords(records){for(const record of records){switch(record.type){case"characterData":case"classList":case"attributes":{const nodeId=this.nodeMap.getId(record.target);this.currentStep.mutations.push({...omit(record,"target"),nodeId});break;} 7032case"childList":{this.currentStep.mutations.push(...this.splitChildListRecord(record));break;}}}} 7033splitChildListRecord(record){const parentNodeId=this.nodeMap.getId(record.target);if(!parentNodeId){throw new Error("Unknown parent node");} 7034const makeSingleNodeRecords=(trees,type)=>trees.map((tree,index,treeList)=>{const node=tree.node;const nodeList=treeList.map((t)=>t.node);const[previousSibling,nextSibling]=type==="add"?[nodeList[index-1]||record.previousSibling,record.nextSibling]:[record.previousSibling,nodeList[index+1]||record.nextSibling];const[nextNodeId,previousNodeId]=[nextSibling,previousSibling].map((sibling)=>sibling?this.nodeMap.getId(sibling):sibling);const nodeId=this.nodeMap.getId(node);const serializedNode=this.serializeTree(tree);return{type,nodeId,parentNodeId,serializedNode,nextNodeId,previousNodeId};});return[...makeSingleNodeRecords(record.removedTrees,"remove"),...makeSingleNodeRecords(record.addedTrees,"add"),];} 7035applyCustomMutation({apply,revert}){apply();this.addCustomMutation({apply,revert});} 7036addCustomMutation({apply,revert}){const customMutation={type:"custom",apply:()=>{apply();this.addCustomMutation({apply,revert});},revert:()=>{revert();this.addCustomMutation({apply:revert,revert:apply});},};this.currentStep.mutations.push(customMutation);} 7037setNodeId(node){let id=this.nodeMap.getId(node);if(!id){id=node===this.editable?"root":this.generateId();this.nodeMap.set(id,node);node=node.firstChild;while(node){this.setNodeId(node);node=node.nextSibling;}} 7038return id;} 7039generateId(){return Math.floor(Math.random()*Math.pow(2,52)).toString();} 7040addStep({type="original",extraStepInfos}={}){const currentStep=this.currentStep;currentStep.type=type;this.handleObserverRecords();const currentMutationsCount=currentStep.mutations.length;if(currentMutationsCount===0){return false;} 7041const stepCommonAncestor=this.getMutationsRoot(currentStep.mutations)||this.editable;this.dispatchTo("normalize_handlers",stepCommonAncestor,type);this.handleObserverRecords(false);
7041if(currentMutationsCount===currentStep.mutations.length){this.dispatchContentUpdated();} 7042currentStep.previousStepId=this.steps.at(-1)?.id;currentStep.selectionAfter=this.serializeSelection(this.dependencies.selection.getEditableSelection());this.steps.push(currentStep);this.dispatchTo("before_add_step_handlers");if(extraStepInfos){currentStep.extraStepInfos=extraStepInfos;} 7043this.currentStep=this.processHistoryStep({id:this.generateId(),type:undefined,selection:{},mutations:[],previousStepId:undefined,extraStepInfos:{},});this.stageSelection();this.dispatchTo("step_added_handlers",{step:currentStep,stepCommonAncestor,isPreviewing:this.isPreviewing,});this.config.onChange?.({isPreviewing:this.isPreviewing});return currentStep;} 7044canUndo(){return this.getNextUndoIndex()>0;} 7045canRedo(){return this.getNextRedoIndex()>0;} 7046undo(){if(this.steps.length===1){return;} 7047this.handleObserverRecords();const lastStep=this.currentStep;this.revertMutations(lastStep.mutations);this.observer.takeRecords();lastStep.mutations=[];const pos=this.getNextUndoIndex();let revertedStep;if(pos>0){revertedStep=this.steps[pos];this.revertedSteps.add(revertedStep.id);this.revertMutations(revertedStep.mutations,{forNewStep:true});this.setSerializedFocus(revertedStep.activeElementId);this.stageFocus();this.setSerializedSelection(revertedStep.selection);this.currentStep.selection=revertedStep.selectionAfter;this.addStep({type:"undo",extraStepInfos:revertedStep.extraStepInfos});} 7048this.dispatchTo("post_undo_handlers",revertedStep);} 7049redo(){this.handleObserverRecords();this.revertMutations(this.currentStep.mutations);this.observer.takeRecords();this.currentStep.mutations=[];const pos=this.getNextRedoIndex();let revertedStep;if(pos>0){revertedStep=this.steps[pos];this.revertedSteps.add(revertedStep.id);this.revertMutations(revertedStep.mutations,{forNewStep:true});this.setSerializedFocus(revertedStep.activeElementId);this.stageFocus();this.setSerializedSelection(revertedStep.selection);this.currentStep.selection=revertedStep.selectionAfter;this.addStep({type:"redo",extraStepInfos:revertedStep.extraStepInfos});} 7050this.dispatchTo("post_redo_handlers",revertedStep);} 7051setSerializedSelection(selection){if(!selection.anchorNodeId){return;} 7052const anchorNode=this.nodeMap.getNode(selection.anchorNodeId);if(!anchorNode){return;} 7053const newSelection={anchorNode,anchorOffset:selection.anchorOffset,};const focusNode=this.nodeMap.getNode(selection.focusNodeId);if(focusNode){newSelection.focusNode=focusNode;newSelection.focusOffset=selection.focusOffset;} 7054this.dependencies.selection.setSelection(newSelection,{normalize:false});} 7055setSerializedFocus(activeElementId){const elementToFocus=activeElementId==="root"?this.editable:activeElementId&&this.nodeMap.getNode(activeElementId);if(elementToFocus?.isConnected&&elementToFocus!==this.document.activeElement){elementToFocus.focus();}} 7056getNextUndoIndex(){for(let index=this.steps.length-1;index>=0;index--){const step=this.steps[index];if(!this.isReversibleStep(index)||this.discardedSteps.has(step.id)){continue;} 7057if(["original","redo"].includes(step.type)&&!this.revertedSteps.has(step.id)){return index;}} 7058return-1;} 7059isReversibleStep(index){const step=this.steps[index];if(!step){return false;} 7060return!this.getResource("unreversible_step_predicates").some((predicate)=>predicate(step));} 7061getNextRedoIndex(){for(let index=this.steps.length-1;index>=0;index--){const step=this.steps[index];if(!this.isReversibleStep(index)||this.discardedSteps.has(step.id)){continue;} 7062if(step.type==="original"){return-1;} 7063if(step.type==="undo"&&!this.revertedSteps.has(step.id)){return index;}} 7064return-1;} 7065addExternalStep(newStep,index){this.withObserverOff(()=>{this.revertMutations(this.currentStep.mutations);const stepsAfterNewStep=this.steps.slice(index);for(const stepToRevert of stepsAfterNewStep.slice().reverse()){this.revertMutations(stepToRevert.mutations);} 7066this.applyMutations(newStep.mutations);this.dispatchTo("normalize_handlers",this.getMutationsRoot(newStep.mutations)||this.editable);this.steps.splice(index,0,newStep);for(const stepToApply of stepsAfterNewStep){this.applyMutations(stepToApply.mutations);} 7067this.applyMutations(this.currentStep.mutations);this.dispatchTo("external_step_added_handlers");});} 7068applyMutations(mutations,{forNewStep=false,reverse}={}){if(forNewStep){this.fixClassListMutationsForNewStep(mutations);} 7069for(const mutation of mutations){switch(mutation.type){case"custom"
7069:{mutation.apply();break;} 7070case"characterData":{const node=this.nodeMap.getNode(mutation.nodeId);if(node){node.textContent=mutation.value;} 7071break;} 7072case"classList":{const node=this.nodeMap.getNode(mutation.nodeId);if(node){toggleClass(node,mutation.className,mutation.value);} 7073break;} 7074case"attributes":{const node=this.nodeMap.getNode(mutation.nodeId);if(node){let value=mutation.value;for(const cb of this.getResource("attribute_change_processors")){value=cb({target:node,attributeName:mutation.attributeName,oldValue:mutation.oldValue,value,reverse,},{forNewStep});} 7075this.setAttribute(node,mutation.attributeName,value);} 7076break;} 7077case"remove":{this.applyRemoveMutation(mutation);break;} 7078case"add":{this.applyAddMutation(mutation);break;}}}} 7079fixClassListMutationsForNewStep(mutations){const isFirstOcurrence=trackOccurrencesPair();const nonObservableClassMutations=mutations.filter((mutation)=>mutation.type==="classList").filter(({nodeId,className})=>isFirstOcurrence(nodeId,className)).map((mutation)=>({...mutation,node:this.nodeMap.getNode(mutation.nodeId)})).filter(({node,className,value})=>value===node?.classList.contains(className));if(nonObservableClassMutations.length){const setToOldValue=({node,className,oldValue})=>toggleClass(node,className,oldValue);this.withObserverOff(()=>nonObservableClassMutations.forEach(setToOldValue));}} 7080applyRemoveMutation(mutation){const parent=this.nodeMap.getNode(mutation.parentNodeId);const toRemove=this.nodeMap.getNode(mutation.nodeId);if(!toRemove){console.warn("Mutation could not be applied, node to remove is unknown.",mutation);return;} 7081if(toRemove.parentElement!==parent){console.warn("Mutation could not be applied, parent node does not match.",mutation);return;} 7082toRemove.remove();} 7083applyAddMutation(mutation){const{nodeId,serializedNode,parentNodeId,nextNodeId,previousNodeId}=mutation;const toAdd=this.nodeMap.getNode(nodeId)||this.unserializeNode(serializedNode);if(!toAdd){return;} 7084const parent=this.nodeMap.getNode(parentNodeId);if(!parent){console.warn("Mutation could not be applied, parent node is missing.",mutation);return;} 7085if(previousNodeId===null){parent.prepend(toAdd);return;} 7086if(nextNodeId===null){parent.append(toAdd);return;} 7087const isValid=(node)=>node?.parentNode===parent;const previousNode=this.nodeMap.getNode(previousNodeId);if(isValid(previousNode)){previousNode.after(toAdd);return;} 7088const nextNode=this.nodeMap.getNode(nextNodeId);if(isValid(nextNode)){nextNode.before(toAdd);return;} 7089console.warn("Mutation could not be applied, reference nodes are invalid.",mutation);} 7090revertMutations(mutations,{forNewStep=false}={}){const revertedMutations=mutations.map((mutation)=>{switch(mutation.type){case"characterData":case"classList":case"attributes":return{...mutation,value:mutation.oldValue,oldValue:mutation.value};case"remove":return{...mutation,type:"add"};case"add":return{...mutation,type:"remove"};case"custom":return{...mutation,apply:mutation.revert,revert:mutation.apply};default:throw new Error(`Unknown mutation type: ${mutation.type}`);}});this.applyMutations(revertedMutations.toReversed(),{forNewStep,reverse:true});} 7091serializeSelection(selection){return{anchorNodeId:this.nodeMap.getId(selection.anchorNode),anchorOffset:selection.anchorOffset,focusNodeId:this.nodeMap.getId(selection.focusNode),focusOffset:selection.focusOffset,};} 7092getMutationsRoot(mutations){const nodes=mutations.map((m)=>this.nodeMap.getNode(m.parentNodeId||m.nodeId)).filter((node)=>this.editable.contains(node));let commonAncestor=getCommonAncestor(nodes,this.editable);if(commonAncestor?.nodeType===Node.TEXT_NODE){commonAncestor=commonAncestor.parentElement;} 7093return commonAncestor;} 7094makeSavePoint(){this.handleObserverRecords();const draftMutations=this.currentStep.mutations.slice();const step=this.steps.at(-1);let applied=false;const selectionToRestore=this.dependencies.selection.preserveSelection();const extraToRestore={...this.currentStep.extraStepInfos};return()=>{if(applied){return;} 7095applied=true;const stepIndex=this.steps.findLastIndex((item)=>item===step);const lastRevertedStep=this.restoreToStep(stepIndex);if(lastRevertedStep?.selection&&!draftMutations.length){selectionToRestore.setCursor((cursor)=>{const anchorNode=this.nodeMap.getNode(lastRevertedStep.selection.anchorNodeId);const focusNode=this.nodeMap.getNode(lastRevertedStep.selection.focusNodeId);cursor.anchor.node=anchorNode;cursor.anchor.offset=lastRevertedStep.selection.anchorOffset;cursor.focus.node=focusNode;cursor.focus.offset=lastRevertedStep.selection.focusOffset;});} 7096this.applyMutations(draftMutations,{forNewStep:true});this.handleObserverRecords();
7096selectionToRestore.restore();this.currentStep.extraStepInfos=extraToRestore;this.dispatchTo("restore_savepoint_handlers");};} 7097makePreviewableOperation(operation){let revertOperation=()=>{};return{preview:(...args)=>{revertOperation();revertOperation=this.makeSavePoint();this.isPreviewing=true;this.stageSelection();operation(...args);this.addStep();},commit:(...args)=>{revertOperation();this.isPreviewing=false;operation(...args);this.addStep();},revert:()=>{revertOperation();revertOperation=()=>{};this.isPreviewing=false;},};} 7098makePreviewableAsyncOperation(operation){let revertOperation=()=>{};return{preview:async(...args)=>{await revertOperation();const def=new Deferred();const revertSavePoint=this.makeSavePoint();revertOperation=async()=>{await def;revertSavePoint();};this.isPreviewing=true;try{await operation(...args);}catch(error){revertSavePoint();throw error;}finally{def.resolve();} 7099if(this.isDestroyed){return;} 7100this.addStep();},commit:async(...args)=>{await revertOperation();this.isPreviewing=false;const revertSavePoint=this.makeSavePoint();try{await operation(...args);}catch(error){revertSavePoint();throw error;} 7101if(this.isDestroyed){return;} 7102this.addStep();},revert:async()=>{await revertOperation();revertOperation=()=>{};this.isPreviewing=false;},};} 7103restoreToStep(stepIndex){this.handleObserverRecords();this.revertMutations(this.currentStep.mutations);this.observer.takeRecords();this.currentStep.mutations=[];let lastRevertedStep=this.currentStep;if(stepIndex===this.steps.length-1){return;} 7104for(let i=this.steps.length-1;i>stepIndex;i--){const currentStep=this.steps[i];this.revertMutations(currentStep.mutations,{forNewStep:true});this.processNewRecords(this.observer.takeRecords());if(this.isReversibleStep(i)){this.discardedSteps.add(currentStep.id);lastRevertedStep=currentStep;}} 7105for(let i=stepIndex+1;i<this.steps.length;i++){const currentStep=this.steps[i];if(!this.isReversibleStep(i)){this.applyMutations(currentStep.mutations,{forNewStep:true});this.processNewRecords(this.observer.takeRecords());}} 7106this.setSerializedSelection(lastRevertedStep.selection);this.dispatchContentUpdated();this.addStep({type:"restore"});return lastRevertedStep;} 7107setStepExtra(key,value){this.currentStep.extraStepInfos[key]=value;} 7108disableIsCurrentStepModifiedWarning(){this.ignoreIsCurrentStepModified=true;return()=>{this.ignoreIsCurrentStepModified=false;};} 7109getIsCurrentStepModified(){if(this.ignoreIsCurrentStepModified){return false;} 7110return this.currentStep.mutations.find((m)=>["characterData","remove","add"].includes(m.type));} 7111setAttribute(node,attributeName,attributeValue){if(this.delegateTo("set_attribute_overrides",node,attributeName,attributeValue)){return;} 7112if(attributeValue!==null){node.setAttribute(attributeName,attributeValue);}else{node.removeAttribute(attributeName);}} 7113serializeNode(node){return this.serializeTree(nodeToTree(node));} 7114unserializeNode(node){let[unserializedNode,newNodesMap]=this._unserializeNode(node,this.nodeMap);if(!unserializedNode){return null;} 7115const fakeNode=this.document.createElement("fake-el");fakeNode.appendChild(unserializedNode);this.dependencies.sanitize.sanitize(fakeNode,{IN_PLACE:true});unserializedNode=fakeNode.firstChild;if(!unserializedNode){return null;} 7116for(const node of[unserializedNode,...descendants(unserializedNode)]){if(this.nodeMap.hasNode(node)){continue;} 7117const id=newNodesMap.get(node);if(id){this.nodeMap.set(id,node);}} 7118return unserializedNode;} 7119serializeTree(tree){const node=tree.node;const nodeId=this.nodeMap.getId(node);if(!nodeId){return null;} 7120const result={nodeType:node.nodeType,nodeId:nodeId,};if(node.nodeType===Node.TEXT_NODE){result.textValue=node.nodeValue;}else if(node.nodeType===Node.ELEMENT_NODE){let childTreesToSerialize=tree.children;for(const cb of this.getResource("serializable_descendants_processors")){childTreesToSerialize=cb(node,childTreesToSerialize);} 7121result.tagName=node.tagName;result.attributes=Object.fromEntries([...node.attributes].map((attr)=>[attr.name,attr.value]));result.children=childTreesToSerialize.map((tree)=>this.serializeTree(tree)).filter(Boolean);} 7122return result;} 7123_unserializeNode(serializedNode,nodeMap=new NodeMap(),_map=new Map()){let node=nodeMap.getNode(serializedNode.nodeId);if(node){return[node,_map];} 7124if(serializedNode.nodeType===Node.TEXT_NODE){node=this.document.createTextNode(serializedNode.textValue);}else if(serializedNode.nodeType===Node.ELEMENT_NODE){node=this.document.createElement(serializedNode.tagName);for(const key in serializedNode.attributes){node.setAttribute(key,serializedNode.attributes[key]);} 7125node.append(...serializedNode.children.map((child)=>
7125this._unserializeNode(child,nodeMap,_map)[0]).filter(Boolean));}else{console.warn("unknown node type");return[null,_map];} 7126_map.set(node,serializedNode.nodeId);return[node,_map];} 7127_onDocumentBeforeInput(ev){if(this.editable.contains(ev.target)){return;} 7128if(["historyUndo","historyRedo"].includes(ev.inputType)){this._onKeyupResetContenteditableNodes.push(...this.editable.querySelectorAll("[contenteditable=true]"));if(this.editable.getAttribute("contenteditable")==="true"){this._onKeyupResetContenteditableNodes.push(this.editable);} 7129for(const node of this._onKeyupResetContenteditableNodes){node.setAttribute("contenteditable",false);}}} 7130_onDocumentInput(ev){if(["historyUndo","historyRedo"].includes(ev.inputType)&&this._onKeyupResetContenteditableNodes.length){for(const node of this._onKeyupResetContenteditableNodes){node.setAttribute("contenteditable",true);} 7131this._onKeyupResetContenteditableNodes=[];}}} 7132__exports.nodeToTree=nodeToTree;function nodeToTree(node){return{node,children:childNodes(node).map(nodeToTree),};} 7133function treeToNodes(tree){return[tree.node,...tree.children.flatMap(treeToNodes)];} 7134class NodeMap{constructor(){const idToNodeMap=new Map();const nodeToIdMap=new Map();this.set=(id,node)=>{if(!id||!node){throw new Error("Id and Node cannot be nullish");} 7135const oldNode=idToNodeMap.get(id);nodeToIdMap.delete(oldNode);const oldId=nodeToIdMap.get(node);idToNodeMap.delete(oldId);idToNodeMap.set(id,node);nodeToIdMap.set(node,id);};this.getNode=(id)=>idToNodeMap.get(id);this.getId=(node)=>nodeToIdMap.get(node);this.hasNode=(node)=>nodeToIdMap.has(node);}} 7136return __exports;});; 7137 7138/* /html_editor/static/src/core/input_plugin.js */ 7139odoo.define('@html_editor/core/input_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const InputPlugin=__exports.InputPlugin=class InputPlugin extends Plugin{static id="input";static dependencies=["history","selection"];setup(){this.addDomListener(this.editable,"beforeinput",this.onBeforeInput);this.addDomListener(this.editable,"keydown",this.onKeyDown);this.addDomListener(this.editable,"input",this.onInput);} 7140onKeyDown(ev){const selection=this.document.getSelection();if(selection?.rangeCount&&selection.isCollapsed&&ev.key==="Unidentified"&&selection.focusOffset===0){const range=selection.getRangeAt(0);this.dependencies.selection.setCachedSelection({anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:selection.focusNode,focusOffset:selection.focusOffset,rangeCount:1,isCollapsed:selection.isCollapsed,getRangeAt:()=>range.cloneRange(),});}} 7141onBeforeInput(ev){this.dependencies.history.stageSelection();this.dispatchTo("beforeinput_handlers",ev);this.dependencies.selection.setCachedSelection(null);} 7142onInput(ev){this.dependencies.history.addStep();this.dispatchTo("input_handlers",ev);}} 7143return __exports;});; 7144 7145/* /html_editor/static/src/core/line_break_plugin.js */ 7146odoo.define('@html_editor/core/line_break_plugin',['@html_editor/utils/dom','@html_editor/plugin','@html_editor/utils/content_types','@html_editor/utils/dom_state','@html_editor/utils/position','@html_editor/utils/dom_traversal','@html_editor/utils/blocks','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{splitTextNode}=require("@html_editor/utils/dom");const{Plugin}=require("@html_editor/plugin");const{CTGROUPS,CTYPES}=require("@html_editor/utils/content_types");const{getState,isFakeLineBreak,prepareUpdate}=require("@html_editor/utils/dom_state");const{DIRECTIONS,leftPos,rightPos}=require("@html_editor/utils/position");const{closestElement}=require("@html_editor/utils/dom_traversal");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{nextLeaf}=require("@html_editor/utils/dom_info");const LineBreakPlugin=__exports.LineBreakPlugin=class LineBreakPlugin extends Plugin{static dependencies=["selection","history","input","delete"];static id="lineBreak";static shared=["insertLineBreak","insertLineBreakNode","insertLineBreakElement"];resources={beforeinput_handlers:this.onBeforeInput.bind(this),legit_feff_predicates:[(node)=>!node.nextSibling&&!isBlock(closestElement(node))&&nextLeaf(node,closestBlock(node))&&node.previousSibling,],};insertLineBreak(){this.dispatchTo("before_line_break_handlers");let selection=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!selection.isCollapsed){this.dependencies.delete.deleteSelection();selection=this.dependencies.selection.getEditableSelection();}
7146else if(!closestElement(selection.anchorNode).isContentEditable){selection=this.dependencies.selection.getEditableSelection();} 7147const targetNode=selection.anchorNode;const targetOffset=selection.anchorOffset;this.insertLineBreakNode({targetNode,targetOffset});this.dependencies.history.addStep();} 7148insertLineBreakNode({targetNode,targetOffset}){const closestEl=closestElement(targetNode);if(closestEl&&!closestEl.isContentEditable){return;} 7149if(targetNode.nodeType===Node.TEXT_NODE){targetOffset=splitTextNode(targetNode,targetOffset);targetNode=targetNode.parentElement;} 7150if(this.delegateTo("insert_line_break_element_overrides",{targetNode,targetOffset})){return;} 7151this.insertLineBreakElement({targetNode,targetOffset});} 7152insertLineBreakElement({targetNode,targetOffset}){const closestEl=closestElement(targetNode);if(closestEl&&!closestEl.isContentEditable){return;} 7153const restore=prepareUpdate(targetNode,targetOffset);const brEl=this.document.createElement("br");const brEls=[brEl];if(targetOffset>=targetNode.childNodes.length){targetNode.appendChild(brEl);if(!isBlock(closestElement(targetNode))&&nextLeaf(targetNode,closestBlock(targetNode))){targetNode.appendChild(this.document.createTextNode("\uFEFF"));}}else{targetNode.insertBefore(brEl,targetNode.childNodes[targetOffset]);} 7154if(isFakeLineBreak(brEl)&&!(getState(...leftPos(brEl),DIRECTIONS.LEFT).cType&(CTGROUPS.BLOCK|CTYPES.BR))){const brEl2=this.document.createElement("br");brEl.before(brEl2);brEls.unshift(brEl2);} 7155restore();for(const el of brEls){if(el.parentNode){const pos=rightPos(el);this.dependencies.selection.setSelection({anchorNode:pos[0],anchorOffset:pos[1],});break;}}} 7156onBeforeInput(e){if(e.inputType==="insertLineBreak"){e.preventDefault();this.insertLineBreak();}}} 7157return __exports;});; 7158 7159/* /html_editor/static/src/core/no_inline_root_plugin.js */ 7160odoo.define('@html_editor/core/no_inline_root_plugin',['@html_editor/utils/dom_info','@html_editor/plugin','@html_editor/core/selection_plugin','@html_editor/utils/position','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{getDeepestPosition,isParagraphRelatedElement}=require("@html_editor/utils/dom_info");const{Plugin}=require("@html_editor/plugin");const{isNotAllowedContent}=require("@html_editor/core/selection_plugin");const{endPos,startPos}=require("@html_editor/utils/position");const{childNodes}=require("@html_editor/utils/dom_traversal");const NoInlineRootPlugin=__exports.NoInlineRootPlugin=class NoInlineRootPlugin extends Plugin{static id="noInlineRoot";static dependencies=["baseContainer","selection","history"];resources={fix_selection_on_editable_root_overrides:this.fixSelectionOnEditableRoot.bind(this),};setup(){this.addDomListener(this.editable,"keydown",(ev)=>{this.currentKeyDown=ev.key;});this.addDomListener(this.editable,"pointerdown",()=>{this.isPointerDown=true;});this.addDomListener(this.editable,"pointerup",()=>{this.isPointerDown=false;});} 7161fixSelectionOnEditableRoot(selection){if(!selection.isCollapsed||selection.anchorNode!==this.editable){return false;} 7162const children=childNodes(this.editable);const nodeAfterCursor=children[selection.anchorOffset];const nodeBeforeCursor=children[selection.anchorOffset-1];const key=this.currentKeyDown;delete this.currentKeyDown;if(key?.startsWith("Arrow")){return this.fixSelectionOnEditableRootArrowKeys(nodeAfterCursor,
7162nodeBeforeCursor,key);} 7163return this.fixSelectionOnEditableRootGeneric(nodeAfterCursor,nodeBeforeCursor);} 7164fixSelectionOnEditableRootArrowKeys(nodeAfterCursor,nodeBeforeCursor,key){if(!["ArrowRight","ArrowLeft","ArrowUp","ArrowDown"].includes(key)){return false;} 7165const directionForward=["ArrowRight","ArrowDown"].includes(key);let node=directionForward?nodeAfterCursor:nodeBeforeCursor;while(node&&isNotAllowedContent(node)){node=directionForward?node.nextElementSibling:node.previousElementSibling;} 7166if(!node){return false;} 7167let[anchorNode,anchorOffset]=directionForward?startPos(node):endPos(node);[anchorNode,anchorOffset]=getDeepestPosition(anchorNode,anchorOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset});return true;} 7168fixSelectionOnEditableRootGeneric(nodeAfterCursor,nodeBeforeCursor){if(isParagraphRelatedElement(nodeAfterCursor)){this.dependencies.selection.setCursorStart(nodeAfterCursor);return true;} 7169if(isParagraphRelatedElement(nodeBeforeCursor)){this.dependencies.selection.setCursorEnd(nodeBeforeCursor);return true;} 7170return false;}} 7171return __exports;});; 7172 7173/* /html_editor/static/src/core/overlay.js */ 7174odoo.define('@html_editor/core/overlay',['@odoo/owl','@web/core/overlay/overlay_container','@web/core/position/position_hook','@web/core/ui/ui_service'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,useEffect,useExternalListener,useRef,useState,useSubEnv,xml,}=require("@odoo/owl");const{OVERLAY_SYMBOL}=require("@web/core/overlay/overlay_container");const{usePosition}=require("@web/core/position/position_hook");const{useActiveElement}=require("@web/core/ui/ui_service");const EditorOverlay=__exports.EditorOverlay=class EditorOverlay extends Component{static template=xml` 7175 <div t-ref="root" class="overlay" t-att-class="props.className" t-on-pointerdown.stop="() => {}"> 7176 <t t-component="props.Component" t-props="props.props"/> 7177 </div>`;static props={target:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE,optional:true},initialSelection:{type:Object,optional:true},Component:Function,props:{type:Object,optional:true},editable:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE},bus:Object,shared:Object,close:Function,isOverlayOpen:Function,getCustomRect:{type:Function,optional:true},positionOptions:{type:Object,optional:true},className:{type:String,optional:true},closeOnPointerdown:{type:Boolean,optional:true},hasAutofocus:{type:Boolean,optional:true},};static defaultProps={className:"",closeOnPointerdown:true,hasAutofocus:false,};setup(){this.lastSelection=this.props.initialSelection;const editable=this.props.editable;let getTarget,position;if(this.props.target){getTarget=()=>this.props.target;}else{this.rangeElement=editable.ownerDocument.createElement("range-el");editable.after(this.rangeElement);onWillDestroy(()=>{this.rangeElement.remove();});getTarget=this.getSelectionTarget.bind(this);} 7178useExternalListener(this.props.bus,"updatePosition",()=>{position.unlock();});const rootRef=useRef("root");if(this.props.positionOptions?.updatePositionOnResize??true){const resizeObserver=new ResizeObserver(()=>{position.unlock();});useEffect((root)=>{resizeObserver.observe(root);return()=>{resizeObserver.unobserve(root);};},()=>[rootRef.el]);} 7179if(this.props.closeOnPointerdown){const clickAway=(ev)=>{if(!this.env[OVERLAY_SYMBOL]?.contains(ev.composedPath()[0])){this.props.close();}};const editableDocument=this.props.editable.ownerDocument;useExternalListener(editableDocument,"pointerdown",clickAway);if(editableDocument!==document){useExternalListener(document,"pointerdown",clickAway);}} 7180if(this.props.hasAutofocus){useActiveElement("root");} 7181const topDocument=editable.ownerDocument.defaultView.top.document;const scrollContainer=getScrollContainer(editable);const container=scrollContainer||topDocument.documentElement;const resizeObserver=new ResizeObserver(()=>position.unlock());resizeObserver.observe(container);onWillDestroy(()=>resizeObserver.disconnect());const positionOptions={position:"bottom-start",container:container,...this.props.positionOptions,onPositioned:(el,solution)=>{this.props.positionOptions?.onPositioned?.(el,solution);this.updateVisibility(el,solution,scrollContainer);},};position=usePosition("root",getTarget,positionOptions);this.overlayState=useState({isOverlayVisible:true});useSubEnv({overlayState:this.overlayState});} 7182getSelectionTarget(){const doc=this.props.editable.ownerDocument;const selection=doc.getSelection();const selectionData=this.props.shared.getSelectionData();if(!selection||!selection.rangeCount||!this.props.isOverlayOpen()){return null;} 7183const inEditable=selectionData.currentSelectionIsInEditable;let range;if(inEditable){range=selection.getRangeAt(0);this.lastSelection={range};}else{if(!this.lastSelection){return null;} 7184range=this.lastSelection.range;} 7185let rect=this.props.getCustomRect?.()||this.lastSelection.rect||range.getBoundingClientRect();if(rect.x===0&&rect.width===0&&rect.height===0){this.props.shared.ignoreDOMMutations(()=>{const clonedRange=range.cloneRange();const shadowCaret=doc.createTextNode("|");
7185clonedRange.insertNode(shadowCaret);clonedRange.selectNode(shadowCaret);rect=clonedRange.getBoundingClientRect();shadowCaret.remove();clonedRange.detach();});} 7186this.rangeElement.getBoundingClientRect=()=>rect;return this.rangeElement;} 7187updateVisibility(overlayElement,solution,scrollContainer){if(this.env.isSmall){return;} 7188const shouldBeVisible=this.shouldOverlayBeVisible(overlayElement,solution,scrollContainer);overlayElement.style.visibility=shouldBeVisible?"visible":"hidden";this.overlayState.isOverlayVisible=shouldBeVisible;} 7189shouldOverlayBeVisible(overlayElement,solution,scrollContainer){if(!scrollContainer){return true;} 7190const scrollContainerRect=scrollContainer.getBoundingClientRect();let scrollContainerTop=scrollContainerRect.top;if(scrollContainer.ownerDocument!==overlayElement.ownerDocument){const frameElement=scrollContainer.ownerDocument.defaultView?.frameElement;if(frameElement){scrollContainerTop+=frameElement.getBoundingClientRect().top;}} 7191const top=Math.max(scrollContainerTop,0);const bottom=top+scrollContainerRect.height;const overflowsTop=solution.top<top;const overflowsBottom=solution.top+overlayElement.offsetHeight>bottom;const canFlip=this.props.positionOptions?.flip??true;if(overflowsTop){if(overflowsBottom){return true;} 7192if(solution.direction==="top"&&canFlip){return true;} 7193return false;} 7194if(overflowsBottom){if(solution.direction==="bottom"&&canFlip){return true;} 7195return false;} 7196return true;}} 7197__exports.getScrollContainer=getScrollContainer;function getScrollContainer(el){const isScrollable=(el)=>{if(el.tagName==="HTML"){return el.scrollHeight>el.ownerDocument.defaultView.visualViewport.height;} 7198return(el.scrollHeight>el.clientHeight&&/\bauto\b|\bscroll\b/.test(getComputedStyle(el)["overflow-y"]));};const isFixed=(el)=>getComputedStyle(el).position==="fixed";while(el){if(isScrollable(el)){return el;} 7199if(isFixed(el)){el=el.ownerDocument.defaultView.frameElement;continue;} 7200el=el.parentElement||el.ownerDocument.defaultView.frameElement;} 7201return null;} 7202return __exports;});; 7203 7204/* /html_editor/static/src/core/overlay_plugin.js */ 7205odoo.define('@html_editor/core/overlay_plugin',['@odoo/owl','@html_editor/plugin','@html_editor/core/overlay'],function(require){'use strict';let __exports={};const{markRaw,EventBus}=require("@odoo/owl");const{Plugin}=require("@html_editor/plugin");const{EditorOverlay}=require("@html_editor/core/overlay");const OverlayPlugin=__exports.OverlayPlugin=class OverlayPlugin extends Plugin{static id="overlay";static dependencies=["history","selection"];static shared=["createOverlay"];overlays=[];setup(){this.targetRectProviders=this.getResource("overlay_selection_target_rect_providers");} 7206destroy(){super.destroy();for(const overlay of this.overlays){overlay.close();}} 7207createOverlay(Component,props={},options){const overlay=new Overlay(this,Component,props,options);this.overlays.push(overlay);return overlay;} 7208getCustomRect(){for(const cb of this.targetRectProviders){const rect=cb();if(rect){return rect;}}}} 7209const Overlay=__exports.Overlay=class Overlay{constructor(plugin,C,props,options){this.plugin=plugin;this.C=C;this.editorOverlayProps=props;this.options=options;this.isOpen=false;this._remove=null;this.component=null;this.bus=new EventBus();} 7210open({target,props}){if(this.isOpen){this.updatePosition();}else{this.isOpen=true;const selection=this.plugin.editable.ownerDocument.getSelection();let initialSelection;if(selection&&selection.type!=="None"){const rect=this.plugin.getCustomRect();initialSelection={range:selection.getRangeAt(0),rect,};} 7211this._remove=this.plugin.services.overlay.add(EditorOverlay,markRaw({...this.editorOverlayProps,Component:this.C,editable:this.plugin.editable,props,target,initialSelection,getCustomRect:this.plugin.getCustomRect.bind(this.plugin),bus:this.bus,close:this.close.bind(this),isOverlayOpen:this.isOverlayOpen.bind(this),shared:{ignoreDOMMutations:this.plugin.dependencies.history.ignoreDOMMutations,getSelectionData:this.plugin.dependencies.selection.getSelectionData,},}),{...this.options,});}} 7212close(){this.isOpen=false;if(this._remove){this._remove();}} 7213isOverlayOpen(){return this.isOpen;} 7214updatePosition(){this.bus.trigger("updatePosition");}} 7215return __exports;});; 7216 7217/* /html_editor/static/src/core/protected_node_plugin.js */ 7218odoo.define('@html_editor/core/protected_node_plugin',['@html_editor/plugin','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{isProtecting,isUnprotecting}=require("@html_editor/utils/dom_info");const{childNodes}=require("@html_editor/utils/dom_traversal");const{withSequence}=require("@html_editor/utils/resource");const PROTECTED_SELECTOR=`[data-oe-protected="true"],[data-oe-protected=""]`;
7218const UNPROTECTED_SELECTOR=`[data-oe-protected="false"]`;const ProtectedNodePlugin=__exports.ProtectedNodePlugin=class ProtectedNodePlugin extends Plugin{static id="protectedNode";static shared=["setProtectingNode"];resources={clean_for_save_handlers:({root})=>this.cleanForSave(root),normalize_handlers:withSequence(0,this.normalize.bind(this)),before_filter_mutation_record_handlers:this.beforeFilteringMutationRecords.bind(this),unsplittable_node_predicates:[isProtecting,isUnprotecting,],savable_mutation_record_predicates:this.isMutationRecordSavable.bind(this),removable_descendants_providers:this.filterDescendantsToRemove.bind(this),};setup(){this.protectedNodes=new WeakSet();} 7219filterDescendantsToRemove(elem){if(isProtecting(elem)){const descendantsToRemove=[];for(const candidate of elem.querySelectorAll(UNPROTECTED_SELECTOR)){if(candidate.closest(PROTECTED_SELECTOR)===elem){descendantsToRemove.push(...childNodes(candidate));}} 7220return descendantsToRemove;}} 7221protectNode(node){if(node.nodeType===Node.ELEMENT_NODE){if(node.matches(UNPROTECTED_SELECTOR)){this.unProtectDescendants(node);}else if(!this.protectedNodes.has(node)){this.protectDescendants(node);}} 7222this.protectedNodes.add(node);} 7223unProtectNode(node){if(node.nodeType===Node.ELEMENT_NODE){if(node.matches(PROTECTED_SELECTOR)){this.protectDescendants(node);}else if(this.protectedNodes.has(node)){this.unProtectDescendants(node);}} 7224this.protectedNodes.delete(node);} 7225protectDescendants(node){let child=node.firstChild;while(child){this.protectNode(child);child=child.nextSibling;}} 7226unProtectDescendants(node){let child=node.firstChild;while(child){this.unProtectNode(child);child=child.nextSibling;}} 7227beforeFilteringMutationRecords(records){for(const record of records){if(record.type==="childList"){if(record.target.nodeType!==Node.ELEMENT_NODE){return;} 7228const addedNodes=record.addedTrees.map((tree)=>tree.node);if((this.protectedNodes.has(record.target)&&!record.target.matches(UNPROTECTED_SELECTOR))||record.target.matches(PROTECTED_SELECTOR)){for(const addedNode of addedNodes){this.protectNode(addedNode);}}else if(!this.protectedNodes.has(record.target)||record.target.matches(UNPROTECTED_SELECTOR)){for(const addedNode of addedNodes){this.unProtectNode(addedNode);}}}}} 7229isMutationRecordSavable(record){if(record.type==="childList"){return!((this.protectedNodes.has(record.target)&&!record.target.matches(UNPROTECTED_SELECTOR))||record.target.matches(PROTECTED_SELECTOR));} 7230return!this.protectedNodes.has(record.target);} 7231forEachProtectingElem(elem,callback){const selector=`[data-oe-protected]`;
7231const protectingNodes=[...elem.querySelectorAll(selector)].reverse();if(elem.matches(selector)){protectingNodes.push(elem);} 7232for(const protectingNode of protectingNodes){if(protectingNode.dataset.oeProtected==="false"){callback(protectingNode,false);}else{callback(protectingNode,true);}}} 7233normalize(elem){this.forEachProtectingElem(elem,this.setProtectingNode.bind(this));} 7234setProtectingNode(elem,protecting){elem.dataset.oeProtected=protecting;if(protecting){elem.setAttribute("contenteditable","false");this.protectDescendants(elem);}else{elem.setAttribute("contenteditable","true");this.unProtectDescendants(elem);}} 7235cleanForSave(clone){this.forEachProtectingElem(clone,(protectingNode)=>{protectingNode.removeAttribute("contenteditable");});}} 7236return __exports;});; 7237 7238/* /html_editor/static/src/core/sanitize_plugin.js */ 7239odoo.define('@html_editor/core/sanitize_plugin',['@html_editor/utils/dom_traversal','@html_editor/plugin'],function(require){'use strict';let __exports={};const{selectElements}=require("@html_editor/utils/dom_traversal");const{Plugin}=require("@html_editor/plugin");const SanitizePlugin=__exports.SanitizePlugin=class SanitizePlugin extends Plugin{static id="sanitize";static shared=["sanitize"];resources={clean_for_save_handlers:this.cleanForSave.bind(this),normalize_handlers:this.normalize.bind(this),};setup(){if(!window.DOMPurify){throw new Error("DOMPurify is not available");} 7240this.DOMPurify=DOMPurify(this.window);} 7241sanitize(elem){for(const cb of this.getResource("before_sanitize_processors")){elem=cb(elem);} 7242elem=this.DOMPurify.sanitize(elem,{IN_PLACE:true,ADD_TAGS:["#document-fragment","fake-el"],ADD_ATTR:["contenteditable","t-field","t-out","t-esc"],});for(const cb of this.getResource("after_sanitize_processors")){elem=cb(elem);} 7243return elem;} 7244normalize(element){for(const el of selectElements(element,".o-contenteditable-false, .o-contenteditable-true")){el.contentEditable=el.matches(".o-contenteditable-true");} 7245for(const el of selectElements(element,"[data-oe-role]")){el.setAttribute("role",el.dataset.oeRole);} 7246for(const el of selectElements(element,"[data-oe-aria-label]")){el.setAttribute("aria-label",el.dataset.oeAriaLabel);}} 7247cleanForSave({root}){for(const el of selectElements(root,".o-contenteditable-false, .o-contenteditable-true")){el.removeAttribute("contenteditable");} 7248for(const el of selectElements(root,"[data-oe-role]")){el.removeAttribute("role");} 7249for(const el of selectElements(root,"[data-oe-aria-label]")){el.removeAttribute("aria-label");}}} 7250return __exports;});; 7251 7252/* /html_editor/static/src/core/selection_plugin.js */ 7253odoo.define('@html_editor/core/selection_plugin',['@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@web/core/h
7253otkeys/hotkey_service','@html_editor/plugin','@html_editor/utils/position','@html_editor/utils/selection','@web/core/utils/scrolling','@html_editor/utils/functions'],function(require){'use strict';let __exports={};const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{getDeepestEditablePosition,getDeepestPosition,isMediaElement,isProtected,isProtecting,isSelfClosingElement,isUnprotecting,}=require("@html_editor/utils/dom_info");const{childNodes,closestElement,closestPath,descendants,findNode,firstLeaf,lastLeaf,}=require("@html_editor/utils/dom_traversal");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{Plugin}=require("@html_editor/plugin");const{DIRECTIONS,leftPos,nodeSize,rightPos}=require("@html_editor/utils/position");const{getAdjacentCharacter,normalizeDeepCursorPosition,normalizeFakeBR,normalizeNotEditableNode,normalizeSelfClosingElement,}=require("@html_editor/utils/selection");const{closestScrollableY}=require("@web/core/utils/scrolling");const{weakMemoize}=require("@html_editor/utils/functions");const VOID_ELEMENT_NAMES=["AREA","BASE","BR","COL","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR",];__exports.isArtificialVoidElement=isArtificialVoidElement;function isArtificialVoidElement(node){return isMediaElement(node)||node.nodeName==="HR";} 7254__exports.isNotAllowedContent=isNotAllowedContent;function isNotAllowedContent(node){return isArtificialVoidElement(node)||VOID_ELEMENT_NAMES.includes(node.nodeName);} 7255const isHtmlContentSupported=__exports.isHtmlContentSupported=weakMemoize((selection)=>
7255!closestElement(selection.focusNode,'[data-oe-model]:not([data-oe-type="html"]):not([data-oe-field="arch"]):not([data-oe-translation-source-sha])'));function getUnselectedEdgeTextNodes(selection){const startEdgeNodes=(node,offset)=>node===selection.commonAncestorContainer||offset<nodeSize(node)?[]:[node,...startEdgeNodes(...rightPos(node))];const endEdgeNodes=(node,offset)=>node===selection.commonAncestorContainer||offset>0?[]:[node,...endEdgeNodes(...leftPos(node))];return new Set([...startEdgeNodes(selection.startContainer,selection.startOffset),...endEdgeNodes(selection.endContainer,selection.endOffset),].filter((node)=>node.nodeType===Node.TEXT_NODE));} 7256function scrollToSelection(selection){const range=selection.getRangeAt(0);const container=closestScrollableY(range.startContainer.parentElement);if(!container){return;} 7257let rect=range.getBoundingClientRect();if(rect.width===0&&rect.height===0&&selection.isCollapsed){rect=closestElement(selection.anchorNode).getBoundingClientRect();} 7258const containerRect=container.getBoundingClientRect();const offsetTop=rect.top-containerRect.top+container.scrollTop;const offsetBottom=rect.bottom-containerRect.top+container.scrollTop;if(rect.bottom>containerRect.top&&rect.top<containerRect.bottom){return;} 7259if(rect.top<containerRect.top){container.scrollTo({top:offsetTop,behavior:"instant"});}else if(rect.bottom>containerRect.bottom){container.scrollTo({top:offsetBottom-container.clientHeight,behavior:"instant"});}} 7260const SelectionPlugin=__exports.SelectionPlugin=class SelectionPlugin extends Plugin{static id="selection";static shared=["getSelectionData","getEditableSelection","setSelection","setCursorStart","setCursorEnd","extractContent","preserveSelection","resetSelection","getTargetedNodes","getTargetedBlocks","modifySelection","rectifySelection","areNodeContentsFullySelected","focusEditable","isSelectionInEditable","isNodeEditable","selectAroundNonEditable","getCachedSelection","setCachedSelection",];resources={user_commands:{id:"selectAll",run:this.selectAll.bind(this)},shortcuts:[{hotkey:"control+a",commandId:"selectAll"}],};setup(){this.resetSelection();this.addGlobalDomListener("selectionchange",()=>{this.updateActiveSelection();const selection=this.document.getSelection();if(this.isSelectionInEditable(selection)){scrollToSelection(selection);}});this.addDomListener(this.editable,"mousedown",(ev)=>{if(ev.detail&&ev.detail%3===2){this.onDoubleClick(ev);} 7261if(ev.detail&&ev.detail%3===0){this.onTripleClick(ev);}});this.addDomListener(this.editable,"keydown",(ev)=>{const handled=["arrowright","shift+arrowright","arrowleft","shift+arrowleft","shift+arrowup","shift+arrowdown",];if(handled.includes(getActiveHotkey(ev))){this.onKeyDownArrows(ev);}});this.focusEditableDocument=true;if(this.document!==document){const focusEditable=()=>{this.focusEditableDocument=true;this.dispatchTo("selection_enter_handlers");};const unFocusEditable=(ev)=>{if(this.focusEditableDocument){if(ev.target.tagName==="IFRAME"){return;} 7262const preventClosing=ev.target?.closest?.("[data-prevent-closing-overlay]");if(preventClosing?.dataset?.preventClosingOverlay==="true"){return;} 7263this.focusEditableDocument=false;this.dispatchTo("selection_leave_handlers");}};this.addDomListener(this.document,"focusin",focusEditable,{capture:true});this.addDomListener(document,"focusin",unFocusEditable,{capture:true});this.addDomListener(this.document,"pointerdown",focusEditable,{capture:true});this.addDomListener(document,"pointerdown",unFocusEditable,{capture:true});} 7264this.preservedCursors=[];this.editableOriginalFocus=this.editable.focus;this.editable.focus=()=>this.focusEditable();} 7265destroy(){if(this.editableOriginalFocus){this.editable.focus=this.editableOriginalFocus;} 7266super.destroy();} 7267getCachedSelection(){return this._cachedSelection;} 7268setCachedSelection(value){this._cachedSelection=value;} 7269selectAll(){const selection=this.getEditableSelection();const containerSelector='#wrap > *, .oe_structure > *, [contenteditable="true"]';const container=selection&&closestElement(selection.anchorNode,containerSelector);const[anchorNode,anchorOffset]=getDeepestEditablePosition(container,0);const[focusNode,focusOffset]=getDeepestEditablePosition(container,nodeSize(container));if(this.delegateTo("select_all_overrides",{anchorNode,anchorOffset,focu
7269sNode,focusOffset,})){return;} 7270this.setSelection({anchorNode,anchorOffset,focusNode,focusOffset});} 7271resetSelection(){this.activeSelection=this.makeActiveSelection();} 7272onDoubleClick(ev){const selectionData=this.getSelectionData();if(selectionData.documentSelectionIsInEditable){if(this.delegateTo("double_click_overrides",ev)){return;}}} 7273onTripleClick(ev){const selectionData=this.getSelectionData();if(selectionData.documentSelectionIsInEditable){if(this.delegateTo("triple_click_overrides",ev)){return;} 7274const{documentSelection}=selectionData;const block=findNode(closestPath(documentSelection.anchorNode),(node)=>isBlock(node)||node?.matches?.(`[contenteditable="true"]`));const[anchorNode,anchorOffset]=getDeepestPosition(block,0);const[focusNode,focusOffset]=getDeepestPosition(block,nodeSize(block));this.setSelection({anchorNode,anchorOffset,focusNode,focusOffset});ev.preventDefault();return;}} 7275updateActiveSelection(){if(this.getCachedSelection()){this.setCachedSelection(this.document.getSelection());} 7276this.previousActiveSelection=this.activeSelection;const selectionData=this.getSelectionData();if(this.fixSelectionOnEditableRoot(selectionData)){return;} 7277this.dispatchTo("selectionchange_handlers",selectionData);} 7278makeActiveSelection(selection){let range;let activeSelection;if(!selection||!selection.rangeCount){const[targetNode,targetOffset]=this.config.allowInlineAtRoot?[this.editable,0]:getDeepestPosition(this.editable,0);activeSelection={anchorNode:targetNode,anchorOffset:targetOffset,focusNode:targetNode,focusOffset:targetOffset,startContainer:targetNode,startOffset:targetOffset,endContainer:targetNode,endOffset:targetOffset,commonAncestorContainer:targetNode,isCollapsed:true,direction:DIRECTIONS.RIGHT,textContent:()=>"",intersectsNode:()=>false,};}else{range=selection.getRangeAt(0);let{anchorNode,anchorOffset,focusNode,focusOffset}=selection;let direction=anchorNode===range.startContainer?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;if(anchorNode===focusNode&&focusOffset<anchorOffset){direction=!direction;} 7279const isSelectionUncorrectable=direction?anchorNode!==range.startContainer:anchorNode!==range.endContainer;if(this.activeSelection&&(isSelectionUncorrectable||isProtecting(anchorNode)||(isProtected(anchorNode)&&!isUnprotecting(anchorNode)))){return this.activeSelection;} 7280anchorOffset=direction?range.startOffset:range.endOffset;focusOffset=direction?range.endOffset:range.startOffset;[anchorNode,anchorOffset]=normalizeSelfClosingElement(anchorNode,anchorOffset);[focusNode,focusOffset]=normalizeSelfClosingElement(focusNode,focusOffset);const[startContainer,startOffset,endContainer,endOffset]=direction===DIRECTIONS.RIGHT?[anchorNode,anchorOffset,focusNode,focusOffset]:[focusNode,focusOffset,anchorNode,anchorOffset];range=this.document.createRange();range.setStart(startContainer,startOffset);range.setEnd(endContainer,endOffset);activeSelection={anchorNode,anchorOffset,focusNode,focusOffset,startContainer,startOffset,endContainer,endOffset,commonAncestorContainer:range.commonAncestorContainer,isCollapsed:range.collapsed,direction,textContent:()=>(range.collapsed?"":selection.toString()),intersectsNode:(node)=>range.intersectsNode(node),};} 7281Object.freeze(activeSelection);return activeSelection;} 7282extractContent(selection){const range=new Range();range.setStart(selection.startContainer,selection.startOffset);range.setEnd(selection.endContainer,selection.endOffset);this.setSelection({anchorNode:selection.startContainer,anchorOffset:selection.startOffset,});return range.extractContents();} 7283createEditorSelection(anchorNode,anchorOffset,focusNode,focusOffset,direction){let startContainer,startOffset,endContainer,endOffset;const range=new Range();if(direction){[startContainer,startOffset]=[anchorNode,anchorOffset];[endContainer,endOffset]=[focusNode,focusOffset];}else{[startContainer,startOffset]=[focusNode,focusOffset];[endContainer,endOffset]=[anchorNode,anchorOffset];} 7284range.setStart(startContainer,startOffset);range.setEnd(endContainer,endOffset);return Object.freeze({...this.activeSelection,anchorNode,anchorOffset,focusNode,focusOffset,startContainer,startOffset,endContainer,endOffset,commonAncestorContainer:range.commonAncestorContainer,cloneContents:()=>range.cloneContents(),});}
7285getEditableSelection(){return this.getSelectionData().editableSelection;} 7286getSelectionData(){const selection=this.getCachedSelection()||this.document.getSelection();const documentSelectionIsInEditable=selection&&this.isSelectionInEditable(selection);let collapsed;const documentSelection=selection?.anchorNode&&selection?.focusNode?Object.freeze({get isCollapsed(){if(collapsed===undefined){collapsed=selection.isCollapsed;} 7287return collapsed;},anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:selection.focusNode,focusOffset:selection.focusOffset,commonAncestorContainer:selection.rangeCount?selection.getRangeAt(0).commonAncestorContainer:null,}):null;const isSelectionConnected=this.activeSelection.anchorNode.isConnected&&nodeSize(this.activeSelection.anchorNode)>=this.activeSelection.anchorOffset&&nodeSize(this.activeSelection.focusNode)>=this.activeSelection.focusOffset;if(documentSelectionIsInEditable){this.activeSelection=this.makeActiveSelection(selection);}else if(!isSelectionConnected){this.activeSelection=this.makeActiveSelection();} 7288let{anchorNode,anchorOffset,focusNode,focusOffset,isCollapsed,direction}=this.activeSelection;const editableSelection=this.createEditorSelection(anchorNode,anchorOffset,focusNode,focusOffset,direction);const selectionData={documentSelection:documentSelection,editableSelection:editableSelection,documentSelectionIsInEditable:documentSelectionIsInEditable,currentSelectionIsInEditable:documentSelectionIsInEditable&&this.focusEditableDocument,};Object.defineProperty(selectionData,"deepEditableSelection",{get:function(){[anchorNode,anchorOffset]=getDeepestPosition(anchorNode,anchorOffset);[focusNode,focusOffset]=isCollapsed?[anchorNode,anchorOffset]:getDeepestPosition(focusNode,focusOffset);return this.createEditorSelection(anchorNode,anchorOffset,focusNode,focusOffset,direction);}.bind(this),});Object.defineProperty(selectionData,"documentSelectionIsProtecting",{get:function(){return documentSelection?.anchorNode?isProtecting(documentSelection.anchorNode):false;}.bind(this),});Object.defineProperty(selectionData,"documentSelectionIsProtected",{get:function(){return documentSelection?.anchorNode?isProtected(documentSelection.anchorNode):false;}.bind(this),});return Object.freeze(selectionData);} 7289validateSelection({anchorNode,anchorOffset,focusNode,focusOffset}){const validateNode=(node)=>{if(!this.editable.contains(node)){console.warn("Invalid selection. Node is not part of the editable:",node);return false;} 7290return true;};const validateOffset=(node,offset)=>{if(offset<0||offset>nodeSize(node)){console.warn("Invalid selection. Offset is out of bounds:",offset,node);return false;} 7291return true;};const isCollapsed=anchorNode===focusNode&&anchorOffset===focusOffset;return(validateNode(anchorNode)&&(focusNode===anchorNode||validateNode(focusNode))&&validateOffset(anchorNode,anchorOffset)&&(isCollapsed||validateOffset(focusNode,focusOffset)));} 7292setSelection({anchorNode,anchorOffset,focusNode=anchorNode,focusOffset=anchorOffset},{normalize=true}={}){if(!this.validateSelection({anchorNode,anchorOffset,focusNode,focusOffset})){return null;} 7293const restore=this.preserveTextareaSelections();const isCollapsed=anchorNode===focusNode&&anchorOffset===focusOffset;[focusNode,focusOffset]=normalizeSelfClosingElement(focusNode,focusOffset,"right");[anchorNode,anchorOffset]=isCollapsed?[focusNode,focusOffset]:normalizeSelfClosingElement(anchorNode,anchorOffset,"left");if(normalize){[anchorNode,anchorOffset]=normalizeDeepCursorPosition(anchorNode,anchorOffset);[focusNode,focusOffset]=isCollapsed?[anchorNode,anchorOffset]:normalizeDeepCursorPosition(focusNode,focusOffset);} 7294[anchorNode,anchorOffset]=normalizeFakeBR(anchorNode,anchorOffset);[focusNode,focusOffset]=normalizeFakeBR(focusNode,focusOffset);const selection=this.document.getSelection();const documentSelectionIsInEditable=selection&&this.isSelectionInEditable(selection);if(selection){if(documentSelectionIsInEditable||selection.anchorNode===null){selection.setBaseAndExtent(anchorNode,anchorOffset,focusNode,focusOffset);this.activeSelection=this.makeActiveSelection(selection,true);}else{let range=new Range();range.setStart(anchorNode,anchorOffset);range.setEnd(focusNode,focusOffset);if(anchorNode!==focusNode||anchorOffset!==focusOffset){if(range.collapsed){range=new Range();range.setEnd(anchorNode,anchorOffset);range.setStart(focusNode,focusOffset);}} 7295this.activeSelection=this.makeActiveSelection({anchorNode,anchorOffset,focu
7295sNode,focusOffset,getRangeAt:()=>range,rangeCount:1,});}} 7296restore();return this.activeSelection;} 7297preserveTextareaSelections(){const focusedTextarea=this.document.activeElement?.nodeName==="TEXTAREA"&&this.document.activeElement;const selections=[...this.editable.querySelectorAll("textarea")].map((textarea)=>({textarea,start:textarea.selectionStart,end:textarea.selectionEnd,direction:textarea.selectionDirection,}));return()=>{if(focusedTextarea){focusedTextarea.focus();} 7298for(const{textarea,start,end,direction}of selections){textarea.setSelectionRange(start,end,direction);}};} 7299setCursorStart(node){return this.setSelection({anchorNode:node,anchorOffset:0});} 7300setCursorEnd(node){return this.setSelection({anchorNode:node,anchorOffset:nodeSize(node)});} 7301preserveSelection(){const hadSelection=this.document.getSelection()&&this.document.getSelection().anchorNode!==null;const selectionData=this.getSelectionData();const selection=selectionData.editableSelection;const anchor={node:selection.anchorNode,offset:selection.anchorOffset};const focus={node:selection.focusNode,offset:selection.focusOffset};const cursor={anchor,focus,restore:()=>{const index=this.preservedCursors.findIndex((ref)=>ref.deref()===cursor);if(index!==-1){this.preservedCursors.splice(index,1);} 7302if(!hadSelection){return;} 7303this.setSelection({anchorNode:cursor.anchor.node,anchorOffset:cursor.anchor.offset,focusNode:cursor.focus.node,focusOffset:cursor.focus.offset,},{normalize:false});},update:(callback)=>{this.preservedCursors.forEach((ref)=>{const liveCursor=ref.deref();if(liveCursor){callback(liveCursor.anchor);callback(liveCursor.focus);}});return cursor;},remapNode(node,newNode){return cursor.update((cursor)=>{if(cursor.node===node){cursor.node=newNode;}});},setOffset(node,newOffset){return cursor.update((cursor)=>{if(cursor.node===node){cursor.offset=newOffset;}});},shiftOffset(node,shiftOffset){return cursor.update((cursor)=>{if(cursor.node===node){cursor.offset+=shiftOffset;}});},setCursor:(callback)=>{this.preservedCursors.forEach((ref)=>{const liveCursor=ref.deref();if(liveCursor){callback(liveCursor);}});return cursor;},};this.preservedCursors=this.preservedCursors.filter((c)=>c.deref());this.preservedCursors.push(new WeakRef(cursor));return cursor;} 7304areNodeContentsFullySelected(node){const selection=this.getEditableSelection();if(selection.isCollapsed){return false;} 7305const range=new Range();range.setStart(selection.startContainer,selection.startOffset);const{endContainer,endOffset}=this.getEditableSelection();if(endContainer.childNodes?.[endOffset]?.nodeName==="BR"){range.setEnd(endContainer,endOffset+1);}else{range.setEnd(endContainer,endOffset);} 7306if(this.getResource("fully_selected_node_predicates")?.some((cb)=>cb(node,selection,range))){return true;} 7307const firstLeafNode=firstLeaf(node);const lastLeafNode=lastLeaf(node);return(range.isPointInRange(firstLeafNode,0)&&range.isPointInRange(lastLeafNode,nodeSize(lastLeafNode)));} 7308getTargetedNodes(){const selectionData=this.getSelectionData();const selection=selectionData.deepEditableSelection;const{commonAncestorContainer:root}=selectionData.editableSelection;let targetedNodes=[];if(selection.isCollapsed&&selection.anchorNode.nodeType!==Node.TEXT_NODE){targetedNodes=[root];} 7309for(const node of descendants(root)){targetedNodes.push(node);} 7310if(!targetedNodes.length){targetedNodes=[root];} 7311targetedNodes=targetedNodes.filter((node)=>selectionData.editableSelection.intersectsNode(node)||(node.nodeType===Node.TEXT_NODE&&(node===selection.anchorNode||node===selection.focusNode)));const modifiers=[(nodes)=>(nodes[0]===this.editable?nodes.slice(1):nodes),(nodes)=>{if(selection.isCollapsed){return nodes;}else{const edgeTextNodes=getUnselectedEdgeTextNodes(selection);return nodes.filter((node)=>!edgeTextNodes.has(node));}},...this.getResource("targeted_nodes_processors"),];for(const modifier of modifiers){targetedNodes=modifier(targetedNodes);} 7312return targetedNodes;} 7313getTargetedBlocks(){return new Set(this.getTargetedNodes().map(closestBlock).filter(Boolean));} 7314fixSelectionOnEditableRoot(selectionData){const{editableSelection,documentSelectionIsInEditable}=selectionData;if(this.config.allowInlineAtRoot||!documentSelectionIsInEditable){return false;} 7315const isSelectionOnEditableRoot=(s)=>s.isCollapsed&&s.anchorNode===this.editable;if(!isSelectionOnEditableRoot(editableSelection)){return false;} 7316if(this.delegateTo("fix_selection_on_editable_root_overrides",editableSelection)){return true;} 7317if(isSelectionOnEditableRoot(this.previousActiveSelection)){return false;} 7318const selection=this.document.getSelection();if(!selection){return false;}
7319const{anchorNode,anchorOffset,focusNode,focusOffset}=this.previousActiveSelection;selection.setBaseAndExtent(anchorNode,anchorOffset,focusNode,focusOffset);return true;} 7320rectifySelection(selection){if(!this.isSelectionInEditable(selection)){return null;} 7321const anchorNode=selection.anchorNode;let anchorOffset=selection.anchorOffset;const focusNode=selection.focusNode;let focusOffset=selection.focusOffset;const anchorSize=nodeSize(anchorNode);const focusSize=nodeSize(focusNode);if(anchorSize<anchorOffset){anchorOffset=anchorSize;} 7322if(focusSize<focusOffset){focusOffset=focusSize;} 7323const anchorTarget=childNodes(anchorNode).at(anchorOffset);const focusTarget=childNodes(focusNode).at(focusOffset);const protectionCheck=(node)=>isProtecting(node)||(isProtected(node)&&!isUnprotecting(node));if(focusTarget!==anchorTarget&&focusTarget?.previousSibling===anchorTarget&&protectionCheck(anchorTarget)){return;} 7324if(protectionCheck(anchorNode)||protectionCheck(focusNode)){return;} 7325return this.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});} 7326modifySelection(alter,direction,granularity){const selectionData=this.getSelectionData();if(!selectionData.documentSelectionIsInEditable){return selectionData.editableSelection;} 7327const selection=this.document.getSelection();if(!selection){return selectionData.editableSelection;} 7328selection.modify(alter,direction,granularity);if(!this.isSelectionInEditable(selection)){return this.setSelection(selectionData.editableSelection);} 7329this.activeSelection=this.makeActiveSelection(selection);return this.activeSelection;} 7330onKeyDownArrows(ev){const selection=this.document.getSelection();if(!selection||!this.isSelectionInEditable(selection)){return;} 7331const mode=ev.shiftKey?"extend":"move";if(["ArrowLeft","ArrowRight"].includes(ev.key)){const screenDirection=ev.key==="ArrowLeft"?"left":"right";const isRtl=closestElement(selection.focusNode,"[dir]")?.dir==="rtl";const domDirection=(screenDirection==="left")^isRtl?"previous":"next";const shouldSkipCallbacks=this.getResource("intangible_char_for_keyboard_navigation_predicates");let adjacentCharacter=getAdjacentCharacter(selection,domDirection,this.editable);let shouldSkip=shouldSkipCallbacks.some((cb)=>cb(ev,adjacentCharacter));while(shouldSkip){const{focusNode:nodeBefore,focusOffset:offsetBefore}=selection;selection.modify(mode,screenDirection,"character");const hasSelectionChanged=nodeBefore!==selection.focusNode||offsetBefore!==selection.focusOffset;const lastSkippedChar=adjacentCharacter;adjacentCharacter=getAdjacentCharacter(selection,domDirection,this.editable);shouldSkip=hasSelectionChanged&&shouldSkipCallbacks.some((cb)=>cb(ev,adjacentCharacter,lastSkippedChar));}} 7332const{focusNode,focusOffset}=selection;if(mode==="extend"){const selectingBackward=["ArrowLeft","ArrowUp"].includes(ev.key);const currentBlock=closestBlock(focusNode);const isAtBoundary=selectingBackward?[firstLeaf(currentBlock),currentBlock].includes(focusNode)&&focusOffset===0:[lastLeaf(currentBlock),currentBlock].includes(focusNode)&&focusOffset===nodeSize(focusNode);const adjacentBlock=selectingBackward?currentBlock.previousElementSibling:currentBlock.nextElementSibling;const targetBlock=selectingBackward?adjacentBlock?.previousElementSibling:adjacentBlock?.nextElementSibling;if(!adjacentBlock?.isContentEditable&&targetBlock&&isAtBoundary){let leafNode=selectingBackward?lastLeaf(targetBlock):firstLeaf(targetBlock);let offset=selectingBackward?nodeSize(leafNode):0;if(isSelfClosingElement(leafNode)){[leafNode,offset]=selectingBackward?leftPos(leafNode):rightPos(leafNode);} 7333selection.extend(leafNode,offset);ev.preventDefault();}}} 7334isSelectionInEditable({anchorNode,focusNode}={}){return(!!anchorNode&&!!focusNode&&this.editable.contains(anchorNode)&&(focusNode===anchorNode||this.editable.contains(focusNode)));} 7335isNodeEditable(node){const results=this.getResource("is_node_editable_predicates").map((p)=>p(node)).filter((r)=>r!==undefined);if(!results.length){return node.parentElement?.isContentEditable;} 7336return results.every((r)=>r);} 7337focusEditable(){const selection=this.document.getSelection();const documentSelectionIsInEditable=selection&&this.isSelectionInEditable(selection);if(this.editable.contains(this.document.activeElement)&&documentSelectionIsInEditable){if(this.document.activeElement.tagName==="TEXTAREA"){this.editableOriginalFocus.call(this.editable);} 7338return;} 7339const{editableSelection,currentSelectionIsInEditable}=this.getSelectionData();const closestEditable=closestElement(editableSelection.commonAncestorContainer,(el)=>el.getAttribute("contenteditable")==="true");if(closestEditable===this.editable){this.editableOriginalFocus.call(this.editable,{preventScroll:true});}else{closestEditable?.focus({preventScroll:true});} 7340const closestNonEditable=closestElement(editableSelection.commonAncestorContainer,(el)=>!el.isContentEditable);if(closestNonEditable){this.setSelection(editableSelection,{normalize:false});} 7341if(!currentSelectionIsInEditable){const{anchorNode,anchorOffset,focu
7341sNode,focusOffset}=editableSelection;const selection=this.document.getSelection();if(selection){selection.setBaseAndExtent(anchorNode,anchorOffset,focusNode,focusOffset);}}} 7342selectAroundNonEditable(){const{editableSelection}=this.getSelectionData();const isInUneditable=(node)=>!!closestElement(node,(elem)=>!elem.isContentEditable);let{startContainer:start,endContainer:end}=editableSelection;if(!(isInUneditable(start)||(end!==start&&isInUneditable(end)))){return editableSelection;} 7343let{startOffset,endOffset,direction}=editableSelection;[start,startOffset]=normalizeNotEditableNode(start,startOffset,"left");[end,endOffset]=normalizeNotEditableNode(end,endOffset,"right");const[anchorNode,anchorOffset,focusNode,focusOffset]=direction?[start,startOffset,end,endOffset]:[end,endOffset,start,startOffset];return this.setSelection({anchorNode,anchorOffset,focusNode,focusOffset});}} 7344return __exports;});; 7345 7346/* /html_editor/static/src/core/shortcut_plugin.js */ 7347odoo.define('@html_editor/core/shortcut_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_state'],function(require){'use strict';let __exports={};const{Plugin,isValidTargetForDomListener}=require("@html_editor/plugin");const{closestBlock}=require("@html_editor/utils/blocks");const{leftLeafOnlyNotBlockPath}=require("@html_editor/utils/dom_state");const ShortCutPlugin=__exports.ShortCutPlugin=class ShortCutPlugin extends Plugin{static id="shortcut";static dependencies=["userCommand","selection","delete"];resources={input_handlers:this.onInput.bind(this),};setup(){const hotkeyService=this.services.hotkey;if(!hotkeyService){throw new Error("ShorcutPlugin needs hotkey service to properly work");} 7348this.removeEditorCommandPalette=this.services.hotkey.add("control+k",()=>{this.services.command.openMainPalette({},()=>{this.dependencies.selection.focusEditable();});},{bypassEditableProtection:true,global:true,area:()=>this.editable,});if(document!==this.document){hotkeyService.registerIframe({contentWindow:this.window});} 7349for(const shortcut of this.getResource("shortcuts")){const command=this.dependencies.userCommand.getCommand(shortcut.commandId);this.addShortcut(shortcut.hotkey,()=>{command.run(shortcut.commandParams);},{isAvailable:command.isAvailable,global:!!shortcut.global,});} 7350this.shorthands=this.getResource("shorthands");} 7351destroy(){super.destroy();this.removeEditorCommandPalette();} 7352addShortcut(hotkey,action,{isAvailable,global}){this._cleanups.push(this.services.hotkey.add(hotkey,action,{area:()=>this.editable,bypassEditableProtection:true,allowRepeat:true,isAvailable:(target)=>(!isAvailable||isAvailable(this.dependencies.selection.getEditableSelection()))&&(global||isValidTargetForDomListener(target)),}));} 7353onInput(ev){if(ev.data!==" "){return;} 7354const selection=this.dependencies.selection.getEditableSelection();if(!(this.checkPredicates("are_shorthands_available_predicates",selection.anchorNode)??true)){return;} 7355const blockEl=closestBlock(selection.anchorNode);const leftDOMPath=leftLeafOnlyNotBlockPath(selection.anchorNode);let spaceOffset=selection.anchorOffset;let leftLeaf=leftDOMPath.next().value;while(leftLeaf){spaceOffset+=leftLeaf.length;leftLeaf=leftDOMPath.next().value;} 7356const precedingText=blockEl.textContent.substring(0,spaceOffset-1);const matchedShortcut=this.shorthands.find(({pattern})=>pattern.test(precedingText));if(matchedShortcut){const command=this.dependencies.userCommand.getCommand(matchedShortcut.commandId);if(command&&command.isAvailable(selection)){this.dependencies.selection.setSelection({anchorNode:blockEl.firstChild,anchorOffset:0,focusNode:selection.focusNode,focusOffset:selection.focusOffset,});this.dependencies.delete.deleteSelection();command.run(matchedShortcut.commandParams);}}}} 7357return __exports;});; 7358 7359/* /html_editor/static/src/core/split_plugin.js */ 7360odoo.define('@html_editor/core/split_plugin',['@html_editor/utils/selection','@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_state','@html_editor/utils/dom_traversal','@html_editor/utils/position','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{Plugin}=require("@html_editor/plugin");const{isBlock}=require("@html_editor/utils/blocks");const{fillEmpty,splitTextNode}=require("@html_editor/utils/dom");const{isContentEditable,isContentEditableAncestor,isTextNode,isVisible,}=require("@html_editor/utils/dom_info");const{prepareUpdate}=require("@html_editor/utils/dom_state");const{childNodes,closestElement,firstLeaf,lastLeaf,findUpTo}=require("@html_editor/utils/dom_traversal");const{DIRECTIONS,childNodeIndex,nodeSize}=require("@html_editor/utils/position");const{isProtected,isProtecting}=require("@html_editor/utils/dom_info");const{isBrowserSafari}=require("@web/core/browser/feature_detection");const SplitPlugin=__exports.SplitPlugin=class SplitPlugin extends Plugin{static dependencies=["baseContainer","selection","history","input","delete","lineBreak"];static id="split";static shared=["splitBlock","splitBlockNode","splitElementBlock","splitElement","splitAroundUntil","splitSelection","isUnsplittable",];resources={beforeinput_handlers:this.onBeforeInput.bind(this),unsplittable_node_predicates:[(node)=>this.getResource("unremovable_node_predicates").some((predicate)=>predicate(node)),(node)=>
7360node.classList?.contains("oe_unbreakable"),(node)=>{const isExplicitlyNotContentEditable=(node)=>!isContentEditable(node)&&(node.isConnected||closestElement(node,"[contenteditable]"));return(isExplicitlyNotContentEditable(node)||(node.parentElement&&isContentEditableAncestor(node)&&isExplicitlyNotContentEditable(node.parentElement)));},(node)=>node.nodeName==="SECTION",],selection_blocker_predicates:(blocker)=>{if(this.isUnsplittable(blocker)){return true;}},};setup(){super.setup();if(isBrowserSafari()){this.addDomListener(this.editable,"keydown",this.onKeyDown);}} 7361splitBlock(){this.dispatchTo("before_split_block_handlers");let selection=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!selection.isCollapsed){this.dependencies.delete.deleteSelection();selection=this.dependencies.selection.getEditableSelection();}else if(!closestElement(selection.anchorNode).isContentEditable){selection=this.dependencies.selection.getEditableSelection();} 7362return this.splitBlockNode({targetNode:selection.anchorNode,targetOffset:selection.anchorOffset,});} 7363splitBlockNode({targetNode,targetOffset}){if(targetNode.nodeType===Node.TEXT_NODE){targetOffset=splitTextNode(targetNode,targetOffset);targetNode=targetNode.parentElement;} 7364const blockToSplit=closestElement(targetNode,isBlock);const params={targetNode,targetOffset,blockToSplit};if(this.delegateTo("split_element_block_overrides",params)){return[undefined,undefined];} 7365return this.splitElementBlock(params);} 7366splitElementBlock({targetNode,targetOffset,blockToSplit}){if(this.isUnsplittable(blockToSplit)||findUpTo(targetNode,blockToSplit,(el)=>this.isUnsplittable(el))){this.dependencies.lineBreak.insertLineBreakElement({targetNode,targetOffset});return[undefined,undefined];} 7367const restore=prepareUpdate(targetNode,targetOffset);const[beforeElement,afterElement]=this.splitElementUntil(targetNode,targetOffset,blockToSplit.parentElement);restore();const fillEmptyElement=(node)=>{if(isProtecting(node)||isProtected(node)){return;}else if(node.nodeType===Node.TEXT_NODE&&!isVisible(node)){const parent=node.parentElement;node.remove();fillEmptyElement(parent);}else if(node.nodeType===Node.ELEMENT_NODE){if(node.hasAttribute("data-oe-zws-empty-inline")){delete node.dataset.oeZwsEmptyInline;} 7368fillEmpty(node);}};fillEmptyElement(lastLeaf(beforeElement));fillEmptyElement(firstLeaf(afterElement));this.dependencies.selection.setCursorStart(afterElement);return[beforeElement,afterElement];} 7369isUnsplittable(node){return this.getResource("unsplittable_node_predicates").some((p)=>p(node));} 7370splitElement(element,offset){const cursor=this.dependencies.selection.preserveSelection();const firstPart=element.cloneNode();const secondPart=element.cloneNode();cursor.update(callbacksForCursorUpdate.before(element,firstPart));element.before(firstPart);cursor.update(callbacksForCursorUpdate.after(element,secondPart));element.after(secondPart);const children=childNodes(element);for(const node of children.slice(0,offset)){cursor.update(callbacksForCursorUpdate.append(firstPart,node));firstPart.appendChild(node);} 7371for(const node of children.slice(offset)){cursor.update(callbacksForCursorUpdate.append(secondPart,node));secondPart.appendChild(node);} 7372cursor.update(callbacksForCursorUpdate.remove(element));element.remove();this.dispatchTo("after_split_element_handlers",{firstPart,secondPart});cursor.restore();return[firstPart,secondPart];} 7373splitElementUntil(element,offset,limitAncestor){if(element===limitAncestor){return[element,element];} 7374let[before,after]=this.splitElement(element,offset);if(after.parentElement!==limitAncestor){const afterIndex=childNodeIndex(after);[before,after]=this.splitElementUntil(after.parentElement,afterIndex,limitAncestor);} 7375return[before,after];} 7376splitAroundUntil(elements,limitAncestor){elements=Array.isArray(elements)?elements:[elements];const firstNode=elements[0];const lastNode=elements[elements.length-1];if([firstNode,lastNode].includes(limitAncestor)){return limitAncestor;} 7377let before=firstNode.previousSibling;let after=lastNode.nextSibling;let beforeSplit,afterSplit;if(!before&&!after&&firstNode.parentElement!==limitAncestor&&lastNode.parentElement!==limitAncestor){return this.splitAroundUntil([firstNode.parentElement,lastNode.parentElement],limitAncestor);}else if(!after&&lastNode.parentElement!==limitAncestor){return this.splitAroundUntil([firstNode,lastNode.parentElement],limitAncestor);}else if(!before&&firstNode.parentElement!==limitAncestor){return this.splitAroundUntil([firstNode.parentElement,lastNode],limitAncestor);} 7378while(after&&after.parentElement!==limitAncestor){afterSplit=this.splitElement(after.parentElement,childNodeIndex(after))[0];after=afterSplit.nextSibling;} 7379if(after){afterSplit=this.splitElement(limitAncestor,childNodeIndex(after))[0];limitAncestor=afterSplit;} 7380while(before&&before.parentElement!==limitAncestor){beforeSplit=this.splitElement(before.parentElement,childNodeIndex(before)+1)[1];before=beforeSplit.previousSibling;} 7381if(before){beforeSplit=this.splitElement(limitAncestor,childNodeIndex(before)+1)[1];} 7382return beforeSplit||afterSplit||limitAncestor;} 7383splitSelection(){let{startContainer,startOffset,endContainer,endOffset,direction}=this.dependencies.selection.getEditableSelection();const isInSingleContainer=startContainer===endContainer;if(isTextNode(endContainer)&&endOffset>0&&endOffset<nodeSize(endContainer)){const endParent=endContainer.parentNode;const splitOffset=splitTextNode(endContainer,endOffset);endContainer=endParent.childNodes[splitOffset-1]||endParent.firstChild;if(isInSingleContainer){startContainer=endContainer;} 7384endOffset=endContainer.textContent.length;} 7385if(isTextNode(startContainer)&&startOffset>0&&startOffset<nodeSize(startContainer)){splitTextNode(startContainer,startOffset);startOffset=0;if(isInSingleContainer){endOffset=startContainer.textContent.length;}} 7386const selection=direction===DIRECTIONS.RIGHT?{anchorNode:startContainer,anchorOffset:startOffset,focu
7386sNode:endContainer,focusOffset:endOffset,}:{anchorNode:endContainer,anchorOffset:endOffset,focusNode:startContainer,focusOffset:startOffset,};return this.dependencies.selection.setSelection(selection,{normalize:false});} 7387onBeforeInput(e){if(e.inputType==="insertParagraph"){e.preventDefault();if(this.forceLineBreak){this.forceLineBreak=false;this.dependencies.lineBreak.insertLineBreak();return;} 7388this.splitBlock();this.dependencies.history.addStep();}} 7389onKeyDown(e){this.forceLineBreak=e.key==="Enter"&&e.shiftKey;}} 7390return __exports;});; 7391 7392/* /html_editor/static/src/core/style_plugin.js */ 7393odoo.define('@html_editor/core/style_plugin',['@html_editor/plugin','@html_editor/utils/image'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{backgroundImageCssToParts,backgroundImagePartsToCss}=require("@html_editor/utils/image");const StylePlugin=__exports.StylePlugin=class StylePlugin extends Plugin{static id="style";static shared=["setBackgroundImageUrl"];setBackgroundImageUrl(el,value){const parts=backgroundImageCssToParts(el.style["background-image"]);if(value){parts.url=`url('${value}')`;}else{delete parts.url;} 7394el.style["background-image"]=backgroundImagePartsToCss(parts);}} 7395return __exports;});; 7396 7397/* /html_editor/static/src/core/user_command_plugin.js */ 7398odoo.define('@html_editor/core/user_command_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const UserCommandPlugin=__exports.UserCommandPlugin=class UserCommandPlugin extends Plugin{static id="userCommand";static shared=["getCommand"];setup(){this.commands={};for(const command of this.getResource("user_commands")){if(command.id in this.commands){throw new Error(`Duplicate user command id: ${command.id}`);} 7399this.commands[command.id]=command;} 7400Object.freeze(this.commands);} 7401getCommand(commandId){const command=this.commands[commandId];if(!command){throw new Error(`Unknown user command id: ${commandId}`);} 7402return command;}} 7403return __exports;});; 7404 7405/* /html_editor/static/src/main/align/align_plugin.js */ 7406odoo.define('@html_editor/main/align/align_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_info','@web/core/l10n/translation','@html_editor/main/align/align_selector','@odoo/owl','@html_editor/core/selection_plugin','@html_editor/utils/functions','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock}=require("@html_editor/utils/blocks");const{isVisibleTextNode}=require("@html_editor/utils/dom_info");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{AlignSelector}=require("@html_editor/main/align/align_selector");const{reactive}=require("@odoo/owl");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{weakMemoize}=require("@html_editor/utils/functions");const{READ,withSequence}=require("@html_editor/utils/resource");const alignmentItems=[{mode:"left"},{mode:"center"},{mode:"right"},{mode:"justify"},];const AlignPlugin=__exports.AlignPlugin=class AlignPlugin extends Plugin{static id="align";static dependencies=["history","selection"];resources={user_commands:[{id:"alignLeft",run:()=>this.setAlignment("left"),isAvailable:this.canSetAlignment.bind(this),},{id:"alignCenter",run:()=>this.setAlignment("center"),isAvailable:this.canSetAlignment.bind(this),},{id:"alignRight",run:()=>this.setAlignment("right"),isAvailable:this.canSetAlignment.bind(this),},{id:"justify",run:()=>this.setAlignment("justify"),isAvailable:this.canSetAlignment.bind(this),},],toolbar_items:[{id:"alignment",groupId:"layout",description:_t("Align text"),Component:AlignSelector,props:{getItems:()=>alignmentItems,getDisplay:()=>this.alignment,onSelected:(item)=>{this.setAlignment(item.mode);},},isAvailable:this.canSetAlignment.bind(this),},],selectionchange_handlers:withSequence(READ,this.updateAlignmentParams.bind(this)),post_undo_handlers:this.updateAlignmentParam
7406s.bind(this),post_redo_handlers:this.updateAlignmentParams.bind(this),remove_all_formats_handlers:this.setAlignment.bind(this),has_format_predicates:(node)=>closestBlock(node)?.style.textAlign,};setup(){this.alignment=reactive({displayName:""});this.canSetAlignmentMemoized=weakMemoize((selection)=>isHtmlContentSupported(selection)&&this.getBlocksToAlign().length>0);} 7407get alignmentMode(){const sel=this.dependencies.selection.getSelectionData().deepEditableSelection;const block=closestBlock(sel?.anchorNode);const textAlign=this.getTextAlignment(block);return["center","right","justify"].includes(textAlign)?textAlign:"left";} 7408getTextAlignment(block){const{direction,textAlign}=getComputedStyle(block);if(textAlign==="start"){return direction==="rtl"?"right":"left";}else if(textAlign==="end"){return direction==="rtl"?"left":"right";} 7409return textAlign;} 7410getBlocksToAlign(){return this.dependencies.selection.getTargetedNodes().filter((node)=>isVisibleTextNode(node)||node.nodeName==="BR").map((node)=>closestBlock(node)).filter((block)=>block.isContentEditable);} 7411setAlignment(mode=""){const visitedBlocks=new Set();let isAlignmentUpdated=false;for(const block of this.getBlocksToAlign()){if(!visitedBlocks.has(block)){const currentTextAlign=this.getTextAlignment(block);if(currentTextAlign!==mode){block.style.textAlign=mode;isAlignmentUpdated=true;if(mode&&getComputedStyle(block).textAlign!==mode){block.style.setProperty("text-align",mode,"important");}} 7412visitedBlocks.add(block);}} 7413if(mode&&isAlignmentUpdated){this.dependencies.history.addStep();} 7414this.updateAlignmentParams();} 7415canSetAlignment(selection){return this.canSetAlignmentMemoized(selection);} 7416updateAlignmentParams(){this.alignment.displayName=this.alignmentMode;}} 7417return __exports;});; 7418 7419/* /html_editor/static/src/main/align/align_selector.js */ 7420odoo.define('@html_editor/main/align/align_selector',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@html_editor/main/toolbar/toolbar','@html_editor/dropdown_autovisibility_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const{useChildRef}=require("@web/core/utils/hooks");const AlignSelector=__exports.AlignSelector=class AlignSelector extends Component{static template="html_editor.AlignSelector";static props={getItems:Function,getDisplay:Function,onSelected:Function,...toolbarButtonProps,};static components={Dropdown,DropdownItem};setup(){this.items=this.props.getItems();this.state=useState(this.props.getDisplay());this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);} 7421onSelected(item){this.props.onSelected(item);}} 7422return __exports;});; 7423 7424/* /html_editor/static/src/main/banner_plugin.js */ 7425odoo.define('@html_editor/main/banner_plugin',['@html_editor/plugin','@html_editor/utils/dom','@html_editor/utils/dom_traversal','@html_editor/utils/html','@html_editor/utils/resource','@odoo/owl','@web/core/l10n/translation','@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{fillEmpty,fillShrunkPhrasingParent}=require("@html_editor/utils/dom");const{closestElement,descendants,selectElements}=require("@html_editor/utils/dom_traversal");const{parseHTML}=require("@html_editor/utils/html");const{withSequence}=require("@html_editor/utils/resource");const{htmlEscape}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{closestBlock}=require("@html_editor/utils/blocks");const{isEmptyBlock,isParagraphRelatedElement}=require("@html_editor/utils/dom_info");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");function checkCommandAvailablePredicates(selection){return this.getResource("banner_command_available_predicates").every((predicateFn)=>predicateFn(selection));} 7426const BannerPlugin=__exports.BannerPlugin=class BannerPlugin extends Plugin{static id="banner";static dependencies=["baseContainer","history","dom","emoji","selection","sanitize"];static shared=["insertBanner"];resources={user_commands:[{id:"banner_info",title:_t("Banner Info"),description:_t("Insert an info banner"),icon:"fa-info-circle",isAvailable:checkCommandAvailablePredicates.bind(this),run:()=>{this.insertBanner(_t("Banner Info"),"ð¡","info");},},{id:"banner_success",title:_t("Banner Success"),description:_t("Insert a success banner"),icon:"fa-check-circle",isAvailable:checkCommandAvailablePredicates.bind(this),run:()=>{this.insertBanner(_t("Banner Success"),"â ","success");},},{id:"banner_warning",title:_t("Banner Warning"),description:_t("Insert a warning banner"),icon:"fa-exclamation-triangle",isAvailable:checkCommandAvailablePredicates.bind(this),run:()=>{this.insertBanner(_t("Banner Warning"),"â ï¸","warning");},},{id:"banner_danger",title:_t("Banner Danger"),description:_t("Insert a danger banner"),icon:"fa-exclamation-circle",isAvailable:checkCommandAvailablePredicates.bind(this),run:()=>{this.insertBanner(_t("Banner Danger"),"â","danger");},},{id:"banner_monospace",title:_t("Monospace"),description:_t("Insert a monospace banner"),icon:"fa-laptop",isAvailable:checkCommandAvailablePredicates.bind(this),run:()=>{this.insertBanner(_t("Monospace Banner"),undefined,"secondary","font-monospace");},},],banner_command_available_predicates:(selection)=>isHtmlContentSupported(selection)&&!closestElement(selection.anchorNode,".o_editor_banner"),powerbox_categories:withSequence(20,{id:"banner",name:_t("Banner")}),powerbox_items:[{commandId:"banner_info",categoryId:"banner",},{commandId:"banner_success",categoryId:"banner",},{commandId:"banner_warning",categoryId:"banner",},{commandId:"banner_danger",categoryId:"banner",},{commandId:"banner_monospace",categoryId:"banner",},],normalize_handlers:withSequence(5,this.handle_monospace_tab_to_spaces.bind(this)),power_buttons_visibility_predicates:({anchorNode})=>
7426!closestElement(anchorNode,".o_editor_banner"),move_node_blacklist_selectors:".o_editor_banner *",move_node_whitelist_selectors:".o_editor_banner",delete_backward_overrides:this.handleDeleteBackward.bind(this),delete_backward_word_overrides:this.handleDeleteBackward.bind(this),shift_tab_overrides:this.handleShiftTab.bind(this),};setup(){this.addDomListener(this.editable,"click",(e)=>{if(e.target.classList.contains("o_editor_banner_icon")){this.onBannerEmojiChange(e.target);}});} 7427insertBanner(title,emoji,alertClass,containerClass="",contentClass=""){containerClass=containerClass?`${containerClass} `:"";contentClass=contentClass?`${contentClass} `:"";const selection=this.dependencies.selection.getEditableSelection();const blockEl=closestBlock(selection.anchorNode);let baseContainer;if(isParagraphRelatedElement(blockEl)){baseContainer=this.document.createElement(blockEl.nodeName);baseContainer.append(...blockEl.childNodes);}else if(blockEl.nodeName==="LI"){baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(...blockEl.childNodes);fillShrunkPhrasingParent(blockEl);}else{baseContainer=this.dependencies.baseContainer.createBaseContainer();fillShrunkPhrasingParent(baseContainer);} 7428const baseContainerHtml=baseContainer.outerHTML;const emojiHtml=emoji?`<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="${htmlEscape( 7429 title 7430 )}">${emoji}</i>`:"";const bannerElement=parseHTML(this.document,`<div class="${containerClass}o_editor_banner user-select-none o-contenteditable-false ${ 7431 emoji ? "lh-1 " : "" 7432 }d-flex align-items-center alert alert-${alertClass} pb-0 pt-3 ps-3 pe-3" data-oe-role="status"> 7433 ${emojiHtml} 7434 <div class="${contentClass}o_editor_banner_content o-contenteditable-true w-100 px-3"> 7435 ${baseContainerHtml} 7436 </div> 7437 </div>`).childNodes[0];this.dependencies.dom.insert(bannerElement);this.dependencies.selection.setCursorEnd(bannerElement.querySelector(`.o_editor_banner_content > ${baseContainer.tagName}`));this.dependencies.history.addStep();} 7438onBannerEmojiChange(iconElement){this.dependencies.emoji.showEmojiPicker({target:iconElement,onSelect:(emoji)=>{iconElement.textContent=emoji;this.dependencies.history.addStep();},});} 7439handleDeleteBackward(range){const editorBannerContent=closestElement(range.endContainer,".o_editor_banner_content");if(!isEmptyBlock(editorBannerContent)){return;} 7440const bannerElement=closestElement(editorBannerContent,".o_editor_banner");const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);bannerElement.replaceWith(baseContainer);this.dependencies.selection.setCursorStart(baseContainer);return true;} 7441handle_monospace_tab_to_spaces(root){for(const el of selectElements(root,".font-monospace.o_editor_banner .oe-tabs")){const spacesElement=document.createTextNode("\u00A0\u00A0\u00A0\u00A0");el.replaceWith(spacesElement);}} 7442handleShiftTab(){const selection=this.dependencies.selection.getEditableSelection();const monospaceBannerElement=closestElement(selection.anchorNode,".font-monospace.o_editor_banner");if(!monospaceBannerElement){return;} 7443const fourSpacesRe=/^(?:\u200B*\s\u200B*){4}/;for(const block of[...this.dependencies.selection.getTargetedBlocks()]){const text=block.textContent;if(text.match(fourSpacesRe)){const textNode=descendants(block).find((n)=>n.nodeType===Node.TEXT_NODE&&n.textContent.length&&n.textContent!=="\u200b");if(textNode){textNode.textContent=textNode.textContent.replace(fourSpacesRe,"");}}}}} 7444return __exports;});; 7445 7446/* /html_editor/static/src/main/chatgpt/chatgpt_dialog.js */ 7447odoo.define('@html_editor/main/chatgpt/chatgpt_dialog',['@web/core/l10n/translation','@web/core/dialog/dialog','@web/core/network/rpc','@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Dialog}=require("@web/core/dialog/dialog");const{rpc}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const{Component,useState,onWillDestroy,status,markup}=require("@odoo/owl");const POSTPROCESS_GENERATED_CONTENT=(content,baseContainer)=>{let lines=content.split("\n");if(baseContainer.toUpperCase()==="P"){lines=lines.filter((line)=>line.trim().length);} 7448const fragment=document.createDocumentFragment();let parentUl,parentOl;let lineIndex=0;for(const line of lines){if(line.trim().startsWith("- ")){parentUl=parentUl||document.createElement("ul");const li=document.createElement("li");li.innerText=line.trim().slice(2);parentUl.appendChild(li);}else if((parentOl&&line.startsWith(`${parentOl.children.length + 1}. `))||(!parentOl&&line.startsWith("1. ")&&lines[lineIndex+1]?.startsWith("2. "))){parentOl=parentOl||document.createElement("ol");const li=document.createElement("li");li.innerText=line.slice(line.indexOf(".")+2);parentOl.appendChild(li);}else if(line.trim().length===0){const emptyLine=document.createElement("DIV");emptyLine.append(document.createElement("BR"));fragment.appendChild(emptyLine);}else{[parentUl,parentOl].forEach((list)=>list&&fragment.appendChild(list));parentUl=parentOl=undefined;const block=document.createElement(line.startsWith("Title: ")?"h2":baseContainer);block.innerText=line;fragment.appendChild(block);} 7449lineIndex+=1;} 7450[parentUl,parentOl].forEach((list)=>list&&fragment.appendChild(list));return fragment;};const ChatGPTDialog=__exports.ChatGPTDialog=class ChatGPTDialog extends Component{static template="";static components={Dialog};static props={insert:{type:Function},close:{type:Function},sanitize:{type:Function},baseContainer:{type:String,optional:true},};static defaultProps={baseContainer:"DIV",};setup(){this.notificationService=useService("notification");this.state=useState({selectedMessageId:null});onWillDestroy(()=>this.pendingRpcPromise?.abort());} 7451selectMessage(ev){this.state.selectedMessageId=+ev.currentTarget.getAttribute("data-message-id");} 7452insertMessage(ev){this.selectMessage(ev);this._confirm();} 7453formatContent(content){const fragment=POSTPROCESS_GENERATED_CONTENT(content,this.props.baseContainer);let result="";for(const child of fragment.children){this.props.sanitize(child,{IN_PLACE:true});result+=child.outerHTML;} 7454return markup(result);} 7455generate(prompt,callback){const protectedCallback=(...args)=>{if(status(this)!=="destroyed"){delete this.pendingRpcPromise;return callback(...args);}};this.pendingRpcPromise=rpc("/html_editor/generate_text",{prompt,conversation_history:this.state.conversationHistory,},{silent:true});return this.pendingRpcPromise.then((content)=>protectedCallback(content)).catch((error)=>protectedCallback(_t(error.data?.message||error.message),true));} 7456_cancel(){this.props.close();} 7457_confirm(){try{this.props.close();const text=this.state.messages.find((message)=>message.id===this.state.selectedMessageId)?.text;this.notificationService.add(_t("Your content was successfully generated."),{title:_t("Content generated"),type:"success",});const fragment=POSTPROCESS_GENERATED_CONTENT(text||"",this.props.baseContainer);this.props.sanitize(fragment,{IN_PLACE:true});this.props.insert(fragment);}catch(e){this.props.close();throw e;}}} 7458return __exports;});; 7459 7460/* /html_editor/static/src/main/chatgpt/chatgpt_translate_dialog.js */ 7461odoo.define('@html_editor/main/chatgpt/chatgpt_translate_dialog',['@odoo/owl','@html_editor/main/chatgpt/chatgpt_dialog'],function(require){'use strict';let __exports={};const{useState}=require("@odoo/owl");const{ChatGPTDialog}=require("@html_editor/main/chatgpt/chatgpt_dialog");const ChatGPTTranslateDialog=__exports.ChatGPTTranslateDialog=class ChatGPTTranslateDialog extends ChatGPTDialog{static template="html_editor.ChatGPTTranslateDialog";static props={...super.props,originalText:String,language:String,};setup(){super.setup();this.state=useState({...this.state,conversationHistory:[{role:"system",content:"You are a translation assistant. You goal is to translate text while maintaining the original format and"+"respecting specific instructions. \
7461n"+"Instructions: \n"+"- You must respect the format (wrapping the translated text between <generated_text> and </generated_text>)\n"+"- Do not write HTML.",},],messages:[],translationInProgress:true,});this.translate();} 7462async translate(){const query=`Translate <generated_text>${this.props.originalText}</generated_text> to ${this.props.language}`;const messageId=new Date().getTime();await this.generate(query,(content,isError)=>{let translatedText=content.replace(/^[\s\S]*<generated_text>/,"").replace(/<\/generated_text>[\s\S]*$/,"");if(!this.formatContent(translatedText).length){isError=true;translatedText="You didn't select any text.";} 7463this.state.translationInProgress=false;if(!isError){this.state.conversationHistory.push({role:"user",content:query,},{role:"assistant",content,});} 7464this.state.messages.push({author:"assistant",text:translatedText,id:messageId,isError,});this.state.selectedMessageId=messageId;});}} 7465return __exports;});; 7466 7467/* /html_editor/static/src/main/chatgpt/chatgpt_translate_plugin.js */ 7468odoo.define('@html_editor/main/chatgpt/chatgpt_translate_plugin',['@web/core/l10n/translation','@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/main/chatgpt/chatgpt_translate_dialog','@html_editor/main/chatgpt/language_selector','@html_editor/utils/resource','@web/core/user','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Plugin}=require("@html_editor/plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const{ChatGPTTranslateDialog}=require("@html_editor/main/chatgpt/chatgpt_translate_dialog");const{LanguageSelector}=require("@html_editor/main/chatgpt/language_selector");const{withSequence}=require("@html_editor/utils/resource");const{user}=require("@web/core/user");const{isContentEditable}=require("@html_editor/utils/dom_info");const ChatGPTTranslatePlugin=__exports.ChatGPTTranslatePlugin=class ChatGPTTranslatePlugin extends Plugin{static id="chatgpt_translate";static dependencies=["baseContainer","selection","history","dom","sanitize","dialog","split",];resources={toolbar_groups:withSequence(50,{id:"ai",}),toolbar_items:[{id:"translate",groupId:"ai",description:_t("Translate with AI"),isAvailable:(selection)=>!selection.isCollapsed&&user.userId,isDisabled:this.isNotReplaceableByAI.bind(this),Component:LanguageSelector,props:{onSelected:(language)=>this.openDialog({language}),},},],};isNotReplaceableByAI(selection=this.dependencies.selection.getEditableSelection()){const isEmpty=!selection.textContent().replace(/\s+/g,"");const cannotReplace=this.dependencies.selection.getTargetedNodes().find((el)=>this.dependencies.split.isUnsplittable(el)||!isContentEditable(el));return cannotReplace||isEmpty;} 7469openDialog(params={}){const selection=this.dependencies.selection.getEditableSelection();const dialogParams={insert:(content)=>{const insertedNodes=this.dependencies.dom.insert(content);this.dependencies.history.addStep();const start=insertedNodes?.length&&closestElement(insertedNodes[0]);const end=insertedNodes?.length&&closestElement(insertedNodes[insertedNodes.length-1]);if(start&&end){const divContainer=this.editable.parentElement;let[parent,left,top]=[start.offsetParent,start.offsetLeft,start.offsetTop-start.scrollTop,];while(parent&&!parent.contains(divContainer)){left+=parent.offsetLeft;top+=parent.offsetTop-parent.scrollTop;parent=parent.offsetParent;} 7470let[endParent,endTop]=[end.offsetParent,end.offsetTop-end.scrollTop];while(endParent&&!endParent.contains(divContainer)){endTop+=endParent.offsetTop-endParent.scrollTop;endParent=endParent.offsetParent;} 7471const div=document.createElement("div");div.classList.add("o-chatgpt-content");const FRAME_PADDING=3;div.style.left=`${left - FRAME_PADDING}px`;div.style.top=`${top - FRAME_PADDING}px`;div.style.width=`${ 7472 Math.max(start.offsetWidth, end.offsetWidth) + FRAME_PADDING * 2 7473 }px`;div.style.height=`${endTop + end.offsetHeight - top + FRAME_PADDING * 2}px`;divContainer.prepend(div);setTimeout(()=>div.remove(),2000);}},...params,};dialogParams.baseContainer=this.dependencies.baseContainer.getDefaultNodeName();const sanitize=this.dependencies.sanitize.sanitize;const originalText=selection.textContent()||"";this.dependencies.dialog.addDialog(ChatGPTTranslateDialog,{...dialogParams,originalText,sanitize,});if(this.services.ui.isSmall){Promise.resolve().then(()=>{this.document.getSelection()?.removeAllRanges();});}}} 7474return __exports;});; 7475 7476/* /html_editor/static/src/main/chatgpt/language_selector.js */ 7477odoo.define('@html_editor/main/chatgpt/language_selector',['@odoo/owl','@web/core/utils/hooks','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/l10n/translation','@web/core/l10n/utils','@html_editor/main/toolbar/toolbar','@web/core/user','@html_editor/dropdown_autovisibility_hook'],function(require){'use strict';let __exports={};const{Component,onWillStart,useState}=require("@odoo/owl");const{useChildRef,useService}=require("@web/core/utils/hooks");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{loadLanguages}=require("@web/core/l10n/translation");const{jsToPyLocale}=require("@web/core/l10n/utils");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{user}=require("@web/core/user");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const LanguageSelector=__exports.LanguageSelector=class LanguageSelector extends Component{static template="html_editor.LanguageSelector";static props={...toolbarButtonProps,onSelected:{type:Function},};static components={Dropdown,DropdownItem};setup(){this.orm=useService("orm");this.state=useState({languages:[],});this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);onWillStart(()=>{if(user.userId){const userLang=jsToPyLocale(user.lang);loadLanguages(this.orm).then((res)=>{const userLangIndex=res.findIndex((lang)=>lang[0]===userLang);if(userLangIndex!==-1){const[userLangItem]=res.splice(userLangIndex,1);res.unshift(userLangItem);} 7478this.state.languages=res;});}});} 7479onSelected(language){this.props.onSelected(language);}} 7480return __exports;});; 7481 7482/* /html_editor/static/src/main/column_plugin.js */ 7483odoo.define('@html_editor/main/column_plugin',['@web/core/l10n/translation','@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_traversal','@html_editor/utils/base_container','@html_editor/utils/dom_info','@html_editor/core/selection_plugin','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Plugin}=require("@html_editor/plugin");const{closestBlock}=require("@html_editor/utils/blocks");const{closestElement,firstLeaf}=require("@html_editor/utils/dom_traversal");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{isEmptyBlock}=require("@html_editor/utils/dom_info");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{nodeSize}=require("@html_editor/utils/position");const REGEX_BOOTSTRAP_COLUMN=/(^| )col(-[a-zA-Z]+)?(-\d+)?(?= |$)/;function isUnremovableColumn(node,root){const isColumnInnerStructure=node.nodeName==="DIV"&&[...node.classList].some((cls)=>/^row$|^col$|^col-/.test(cls));if(!isColumnInnerStructure){return false;} 7484if(!root){return true;} 7485const closestColumnContainer=closestElement(node,"div.o_text_columns");return!root.contains(closestColumnContainer);} 7486function columnIsAvailable(numberOfColumns){return(selection)=>
7486{const row=closestElement(selection.anchorNode,".o_text_columns .row");return row?row.childElementCount!==numberOfColumns:closestBlock(selection.anchorNode)?.parentNode?.isContentEditable;};} 7487const ColumnPlugin=__exports.ColumnPlugin=class ColumnPlugin extends Plugin{static id="column";static dependencies=["baseContainer","selection","history","dom"];resources={user_commands:[{id:"columnize",title:_t("Columnize"),description:_t("Convert into columns"),icon:"fa-columns",run:this.columnize.bind(this),isAvailable:isHtmlContentSupported,},],powerbox_items:[{title:_t("2 columns"),description:_t("Convert into 2 columns"),categoryId:"structure",isAvailable:columnIsAvailable(2),commandId:"columnize",commandParams:2,},{title:_t("3 columns"),description:_t("Convert into 3 columns"),categoryId:"structure",isAvailable:columnIsAvailable(3),commandId:"columnize",commandParams:3,},{title:_t("4 columns"),description:_t("Convert into 4 columns"),categoryId:"structure",isAvailable:columnIsAvailable(4),commandId:"columnize",commandParams:4,},{title:_t("Remove column layout"),description:_t("Convert columns to regular content"),categoryId:"structure",isAvailable:(selection)=>!!closestElement(selection.anchorNode,".o_text_columns .row"),commandId:"columnize",commandParams:0,},],hints:[{selector:`.odoo-editor-editable .o_text_columns div[class*='col-'], 7488 .odoo-editor-editable .o_text_columns div[class*='col-']>${baseContainerGlobalSelector}:first-child`,text:_t("Empty column"),},],unremovable_node_predicates:isUnremovableColumn,power_buttons_visibility_predicates:({anchorNode})=>
7488!closestElement(anchorNode,".o_text_columns"),move_node_whitelist_selectors:".o_text_columns",move_node_blacklist_selectors:".o_text_columns *",hint_targets_providers:(selectionData)=>{if(!selectionData.documentSelection){return[];} 7489const anchorNode=selectionData.documentSelection.anchorNode;const columnContainer=closestElement(anchorNode,"div.o_text_columns");if(!columnContainer){return[];} 7490const closestColumn=closestElement(anchorNode,"div[class*='col-']");const closestBlockEl=closestBlock(anchorNode);return[...columnContainer.querySelectorAll("div[class*='col-']")].map((column)=>{const block=closestBlock(firstLeaf(column));return column===closestColumn&&block!==closestBlockEl?null:block;}).filter(Boolean);},};hasValidContent(column){return![...column.children].every((node)=>isEmptyBlock(node));} 7491columnize(numberOfColumns){const cursors=this.dependencies.selection.preserveSelection();const anchor=cursors.anchor.node;const hasColumns=!!closestElement(anchor,".o_text_columns");let cursorFallbackNode;if(hasColumns){if(numberOfColumns){const column=this.changeColumnsNumber(anchor,numberOfColumns);cursorFallbackNode=column?.lastChild;}else{const remainingContent=this.removeColumns(anchor);cursorFallbackNode=remainingContent.at(-1);}}else if(numberOfColumns){const li=closestElement(anchor,"li");if(li){this.createColumnsFromList(anchor,li,numberOfColumns);return;} 7492this.createColumns(anchor,numberOfColumns);} 7493if(!anchor.isConnected){cursors.remapNode(anchor,cursorFallbackNode);cursors.setOffset(cursorFallbackNode,nodeSize(cursorFallbackNode));} 7494cursors.restore();this.dependencies.history.addStep();} 7495createColumnsFromList(anchor,li,numberOfColumns){const currentList=li.closest("ol, ul");let listBeforeBlock=currentList;if(li.nextElementSibling){const nextLi=li.nextElementSibling;const newList=currentList.cloneNode(false);nextLi.parentNode.after(newList);while(nextLi.nextSibling){newList.append(nextLi.nextSibling);} 7496newList.prepend(nextLi);listBeforeBlock=newList.previousElementSibling;} 7497const{container,columns}=this.buildColumnsContainer(anchor,numberOfColumns);for(const column of columns){column.append(this.createEmptyParagraph());} 7498listBeforeBlock.after(this.createEmptyParagraph());this.dependencies.selection.setSelection({anchorNode:listBeforeBlock.nextElementSibling,anchorOffset:0,});this.dependencies.dom.insert(container);this.dependencies.selection.setSelection({anchorNode:columns[0].firstElementChild,anchorOffset:0,});this.dependencies.history.addStep();} 7499removeColumns(anchor){const container=closestElement(anchor,".o_text_columns");const contents=[];for(const row of[...container.childNodes]){for(const column of[...row.childNodes]){if(this.hasValidContent(column)){contents.push(...column.children);}}} 7500if(!contents.length){contents.push(this.createEmptyParagraph());} 7501container.replaceWith(...contents);return contents;} 7502createColumns(anchor,numberOfColumns,addParagraphAfter){const{container,columns}=this.buildColumnsContainer(anchor,numberOfColumns);const block=closestBlock(anchor);columns.shift().append(block);for(const column of columns){column.append(this.createEmptyParagraph());} 7503this.dependencies.dom.insert(container);} 7504buildColumnsContainer(anchor,numberOfColumns){const container=this.document.createElement("div");if(!closestElement(anchor,".container")){container.classList.add("container");} 7505container.classList.add("o_text_columns","o-contenteditable-false");const row=this.document.createElement("div");row.classList.add("row");container.append(row);const columnSize=Math.floor(12/numberOfColumns);const columns=[];for(let i=0;i<numberOfColumns;i++){const column=this.document.createElement("div");column.classList.add(`col-${columnSize}`,"o-contenteditable-true");row.append(column);columns.push(column);} 7506return{container,columns};} 7507createEmptyParagraph(){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(this.document.createElement("br"));return baseContainer;} 7508changeColumnsNumber(anchor,numberOfColumns){const row=closestElement(anchor,".row");const columns=[...row.children];const columnSize=Math.floor(12/numberOfColumns);const diff=numberOfColumns-columns.length;if(!diff){return;} 7509for(const column of columns){column.className=column.className.replace(REGEX_BOOTSTRAP_COLUMN,`$1col$2-${columnSize}`);} 7510if(diff>0){let lastColumn=columns[columns.length-1];for(let i=0;i<diff;i++){const column=this.document.createElement("div");column.classList.add(`col-${columnSize}`,"o-contenteditable-true");column.append(this.createEmptyParagraph());lastColumn.after(column);lastColumn=column;}}else if(diff<0){const contents=[];for(let i=diff;i<0;i++){const column=columns.pop();if(this.hasValidContent(column)){contents.unshift(...column.children);} 7511column.remove();} 7512const targetColumn=columns[columns.length-1];targetColumn.append(...contents);return targetColumn;}}} 7513return __exports;});; 7514 7515/* /html_editor/static/src/main/emoji_plugin.js */ 7516odoo.define('@html_editor/main/emoji_plugin',['@html_editor/plugin','@web/core/emoji_picker/emoji_picker','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{EmojiPicker}=require("@web/core/emoji_picker/emoji_picker");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const EmojiPlugin=__exports.EmojiPlugin=class EmojiPlugin extends Plugin{static id="emoji";static dependencies=["history","overlay","dom","selection"];static shared=["showEmojiPicker"];resources={user_commands:[{id:"addEmoji",title:_t("Emoji"),description:_t("Add an emoji"),icon:"fa-smile-o",run:this.showEmojiPicker.bind(this),},],powerbox_items:[{categoryId:"widget",commandId:"addEmoji",},],};setup(){this.overlay=this.dependencies.overlay.createOverlay(EmojiPicker,{hasAutofocus:true,className:"popover",});} 7517showEmojiPicker({target,onSelect}={}){this.overlay.open({props:{close:()=>{this.overlay.close();this.dependencies.selection.focusEditable();},onSelect:(str)=>{if(onSelect){onSelect(str);return;} 7518this.dependencies.dom.insert(str);this.dependencies.history.addStep();},},target,});}} 7519return __exports;});; 7520 7521/* /html_editor/static/src/main/feff_plugin.js */ 7522odoo.define('@html_editor/main/feff_plugin',['@html_editor/plugin','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_state','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/utils/selection','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");
7522const{cleanEmptyAncestors,cleanTextNode}=require("@html_editor/utils/dom");const{isTextNode,isZwnbsp}=require("@html_editor/utils/dom_info");const{prepareUpdate}=require("@html_editor/utils/dom_state");const{descendants,selectElements}=require("@html_editor/utils/dom_traversal");const{leftPos,rightPos}=require("@html_editor/utils/position");const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{withSequence}=require("@html_editor/utils/resource");const FeffPlugin=__exports.FeffPlugin=class FeffPlugin extends Plugin{static id="feff";static dependencies=["selection"];static shared=["addFeff","removeFeffs","surroundWithFeffs"];resources={normalize_handlers:withSequence(Infinity,this.updateFeffs.bind(this)),clean_for_save_handlers:this.cleanForSave.bind(this),intangible_char_for_keyboard_navigation_predicates:(ev,char,lastSkipped)=>char==="\uFEFF"&&(ev.shiftKey||lastSkipped!=="\uFEFF"),clipboard_content_processors:this.processContentForClipboard.bind(this),clipboard_text_processors:(text)=>text.replace(/\ufeff/g,""),};cleanForSave({root,preserveSelection=false}){if(preserveSelection){const cursors=this.getCursors();this.removeFeffs(root,cursors);cursors.restore();}else{this.removeFeffs(root,null);}} 7523removeFeffs(root,cursors,{exclude=()=>false}={}){const hasFeff=(node)=>isTextNode(node)&&node.textContent.includes("\ufeff");const isEditable=(node)=>node.parentElement.isContentEditable;const composedFilter=(node)=>hasFeff(node)&&isEditable(node)&&!exclude(node);for(const node of descendants(root).filter(composedFilter)){const restoreSpaces=prepareUpdate(...leftPos(node),...rightPos(node));const parent=node.parentNode;cleanTextNode(node,"\ufeff",cursors);cleanEmptyAncestors(parent,cursors,(node)=>node.hasAttribute("data-oe-zws-empty-inline")||this.getResource("unremovable_node_predicates").some((predicate)=>predicate(node)));restoreSpaces();}} 7524addFeff(element,position,cursors){const feff=this.document.createTextNode("\ufeff");cursors?.update(callbacksForCursorUpdate[position](element,feff));element[position](feff);return feff;} 7525surroundWithFeffs(node,cursors){const addFeff=(position)=>{const c=position==="append"?null:cursors;return this.addFeff(node,position,c);};const zwnbspNodes=[];for(const[position,relation]of[["before","previousSibling"],["after","nextSibling"],["prepend","firstChild"],["append","lastChild"],]){const candidate=node[relation];const feff=isZwnbsp(candidate)&&!zwnbspNodes.includes(candidate)?candidate:addFeff(position);zwnbspNodes.push(feff);} 7526return zwnbspNodes;} 7527padWithFeffs(root,cursors){const combinedSelector=this.getResource("selectors_for_feff_providers").map((provider)=>provider()).join(", ");if(!combinedSelector){return[];} 7528const elements=[...selectElements(root,combinedSelector)];const isEditable=(node)=>node.parentElement?.isContentEditable;const feffNodes=elements.filter(isEditable).flatMap((el)=>{const addFeff=(position)=>this.addFeff(el,position,cursors);return[isZwnbsp(el.previousSibling)?el.previousSibling:addFeff("before"),isZwnbsp(el.nextSibling)?el.nextSibling:addFeff("after"),];}).filter((feff,i,array)=>!(i>0&&areCloseSiblings(array[i-1],feff)));return feffNodes;} 7529updateFeffs(root){const cursors=this.getCursors();const feffNodesBasedOnSelectors=this.padWithFeffs(root,cursors);const customFeffNodes=this.getResource("feff_providers").flatMap((p)=>p(root,cursors));const feffNodesToKeep=new Set([...feffNodesBasedOnSelectors,...customFeffNodes]);this.removeFeffs(root,cursors,{exclude:(node)=>feffNodesToKeep.has(node)||this.getResource("legit_feff_predicates").some((predicate)=>predicate(node)),});cursors.restore();} 7530getCursors(){const cursors=this.dependencies.selection.preserveSelection();const originalUpdate=cursors.update.bind(cursors);const originalRestore=cursors.restore.bind(cursors);let shouldRestore=false;cursors.update=(...args)=>{shouldRestore=true;return originalUpdate(...args);};cursors.restore=()=>{if(shouldRestore){originalRestore();}};return cursors;} 7531processContentForClipboard(clonedContent){descendants(clonedContent).filter(isTextNode).filter((node)=>
7531node.textContent.includes("\ufeff")).forEach((node)=>(node.textContent=node.textContent.replace(/\ufeff/g,"")));return clonedContent;}} 7532function areCloseSiblings(a,b){let next=a.nextSibling;while(next&&isTextNode(next)&&!next.textContent){next=next.nextSibling;} 7533return next===b;} 7534return __exports;});; 7535 7536/* /html_editor/static/src/main/font/color_picker_gradient_tab.js */ 7537odoo.define('@html_editor/main/font/color_picker_gradient_tab',['@odoo/owl','@web/core/l10n/translation','@web/core/registry','@web/core/utils/colors','@html_editor/main/font/gradient_picker/gradient_picker'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{registry}=require("@web/core/registry");const{applyOpacityToGradient,isColorGradient}=require("@web/core/utils/colors");const{GradientPicker}=require("@html_editor/main/font/gradient_picker/gradient_picker");const DEFAULT_GRADIENT_COLORS=["linear-gradient(135deg, rgb(255, 204, 51) 0%, rgb(226, 51, 255) 100%)","linear-gradient(135deg, rgb(102, 153, 255) 0%, rgb(255, 51, 102) 100%)","linear-gradient(135deg, rgb(47, 128, 237) 0%, rgb(178, 255, 218) 100%)","linear-gradient(135deg, rgb(203, 94, 238) 0%, rgb(75, 225, 236) 100%)","linear-gradient(135deg, rgb(214, 255, 127) 0%, rgb(0, 179, 204) 100%)","linear-gradient(135deg, rgb(255, 222, 69) 0%, rgb(69, 33, 0) 100%)","linear-gradient(135deg, rgb(222, 222, 222) 0%, rgb(69, 69, 69) 100%)","linear-gradient(135deg, rgb(255, 222, 202) 0%, rgb(202, 115, 69) 100%)",];const ColorPickerGradientTab=__exports.ColorPickerGradientTab=class ColorPickerGradientTab extends Component{static template="html_editor.ColorPickerGradientTab";static components={GradientPicker};static props={applyColor:Function,onColorClick:Function,onColorPreview:Function,onColorPointerOver:Function,onColorPointerOut:Function,onFocusin:Function,onFocusout:Function,setOnCloseCallback:{type:Function,optional:true},setOperationCallbacks:{type:Function,optional:true},defaultOpacity:{type:Number,optional:true},noTransparency:{type:Boolean,optional:true},selectedColor:{type:String,optional:true},"*":{optional:true},};setup(){this.state=useState({showGradientPicker:false,});this.applyOpacityToGradient=applyOpacityToGradient;this.DEFAULT_GRADIENT_COLORS=DEFAULT_GRADIENT_COLORS;} 7538getCurrentGradientColor(){if(isColorGradient(this.props.selectedColor)){return this.props.selectedColor;}} 7539toggleGradientPicker(){this.state.showGradientPicker=!this.state.showGradientPicker;}} 7540registry.category("color_picker_tabs").add("html_editor.gradient",{id:"gradient",name:_t("Gradient"),component:ColorPickerGradientTab,},{sequence:60});return __exports;});; 7541 7542/* /html_editor/static/src/main/font/color_plugin.js */ 7543odoo.define('@html_editor/main/font/color_plugin',['@html_editor/plugin','@html_editor/utils/color','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@web/core/utils/colors','@html_editor/utils/image','@html_editor/core/selection_plugin','@html_editor/utils/blocks','@html_editor/utils/selection'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{BG_CLASSES_REGEX,COLOR_COMBINATION_CLASSES_REGEX,hasAnyNodesColor,hasColor,TEXT_CLASSES_REGEX,}=require("@html_editor/utils/color");const{fillEmpty,removeClass,removeStyle,unwrapContents}=require("@html_editor/utils/dom");const{isElement,isEmptyBlock,isIconElement,isRedundantElement,isTextNode,isVisibleTextNode,isWhitespace,isZWS,PROTECTED_QWEB_SELECTOR,}=require("@html_editor/utils/dom_info");const{closestElement,descendants,selectElements}=require("@html_editor/utils/dom_traversal");const{isColorGradient,normalizeCSSColor,rgbaToHex}=require("@web/core/utils/colors");const{backgroundImageCssToParts,backgroundImagePartsToCss}=require("@html_editor/utils/image");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{isBlock}=require("@html_editor/utils/blocks");const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const COLOR_COMBINATION_CLASSES=[1,2,3,4,5].map((i)=>`o_cc${i}`);const COLOR_COMBINATION_SELECTOR=COLOR_COMBINATION_CLASSES.map((c)=>`.${c}`).join(", ");const ColorPlugin=__exports.ColorPlugin=class ColorPlugin extends Plugin{static id="color";static dependencies=["selection","split","history","format"];static shared=["colorElement","removeAllColor","getElementColors","getColorCombination","applyColor",];resources={user_commands:[{id:"applyColor",run:({color,mode})=>{this.applyColor(color,mode);this.dependencies.history.addStep();},isAvailable:isHtmlContentSupported,},],remove_all_formats_handlers:this.removeAllColor.bind(this),color_combination_getters:getColorCombinationFromClass,has_format_predicates:[(node)=>hasColor(closestElement(node),"color"),(node)=>hasColor(closestElement(node),"backgroundColor"),],format_class_predicates:(className)=>TEXT_CLASSES_REGEX.test(className)||BG_CLASSES_REGEX.test(className),normalize_handlers:this.normalize.bind(this),};normalize(root){for(const el of selectElements(root,"font")){if(isRedundantElement(el)){unwrapContents(el);}}} 7544getElementColors(el){const elStyle=getComputedStyle(el);const backgroundImage=elStyle.backgroundImage;const gradient=backgroundImageCssToParts(backgroundImage).gradient;const hasGradient=isColorGradient(gradient);const hasTextGradientClass=el.classList.contains("text-gradient");let backgroundColor=elStyle.backgroundColor;for(const processor of this.getResource("get_background_color_processors")){backgroundColor=processor(backgroundColor);} 7545return{color:hasGradient&&hasTextGradientClass?gradient:normalizeCSSColor(elStyle.color),backgroundColor:hasGradient&&!hasTextGradientClass?gradient:normalizeCSSColor(backgroundColor),};} 7546removeAllColor(){const colorModes=["color","backgroundColor"];let someColorWasRemoved=true;while(someColorWasRemoved){someColorWasRemoved=false;for(const mode of colorModes){let max=40;const hasAnySelectedNodeColor=(mode)=>{const nodes=this.dependencies.selection.getTargetedNodes().filter((n)=>(isTextNode(n)||isIconElement(n)||n.matches?.(`t, ${PROTECTED_QWEB_SELECTOR}`)||(mode==="backgroundColor"&&n.classList.contains("o_selected_td")))&&this.dependencies.selection.isNodeEditable(n));
7546return hasAnyNodesColor(nodes,mode);};while(hasAnySelectedNodeColor(mode)&&max>0){this.applyColor("",mode);someColorWasRemoved=true;max--;} 7547if(max===0){someColorWasRemoved=false;throw new Error("Infinite Loop in removeAllColor().");}}}} 7548applyColor(color,mode,previewMode=false){this.dependencies.selection.selectAroundNonEditable();if(mode==="backgroundColor"){for(const processor of this.getResource("apply_background_color_processors")){color=processor(color,mode);}} 7549if(this.delegateTo("color_apply_overrides",color,mode,previewMode)){return;} 7550const selection=this.dependencies.selection.getEditableSelection();let cursors;let targetedNodes;if(selection.isCollapsed){let zws;if(selection.anchorNode.nodeType===Node.TEXT_NODE&&selection.anchorNode.textContent==="\u200b"){zws=selection.anchorNode;}else{zws=this.dependencies.format.insertAndSelectZws();} 7551this.dependencies.selection.setSelection({anchorNode:zws,anchorOffset:1,},{normalize:false});cursors=this.dependencies.selection.preserveSelection();targetedNodes=[zws];}else{this.dependencies.split.splitSelection();cursors=this.dependencies.selection.preserveSelection();targetedNodes=this.dependencies.selection.getTargetedNodes().filter((node)=>this.dependencies.selection.isNodeEditable(node)&&node.nodeName!=="T"&&this.dependencies.selection.areNodeContentsFullySelected(node));if(isEmptyBlock(selection.endContainer)){targetedNodes.push(selection.endContainer,...descendants(selection.endContainer));}} 7552const findTopMostDecoration=(current)=>{const decoration=closestElement(current.parentNode,"s, u");return decoration?.textContent===current.textContent?findTopMostDecoration(decoration):current;};const hexColor=rgbaToHex(color).toLowerCase();const systemNodesSelector=this.getResource("system_node_selectors").join(", ");const selectedNodes=targetedNodes.filter((node)=>{if(systemNodesSelector&&closestElement(node,systemNodesSelector)){return false;} 7553if(!(this.checkPredicates("is_formattable_node_predicates",node)??true)){return false;} 7554if(mode==="backgroundColor"&&color){return!closestElement(node,"table.o_selected_table");} 7555if(closestElement(node).classList.contains("o_default_color")){return false;} 7556const li=closestElement(node,"li");if(li&&color&&this.dependencies.selection.areNodeContentsFullySelected(li)){const existingColor=li.style.color?li.style.color:[...li.classList].find((cls)=>TEXT_CLASSES_REGEX.test(cls));return rgbaToHex(existingColor).toLowerCase()!==hexColor;} 7557return true;}).map((node)=>findTopMostDecoration(node));const targetedFieldNodes=new Set(this.dependencies.selection.getTargetedNodes().map((node)=>closestElement(node,PROTECTED_QWEB_SELECTOR)).filter(Boolean));const getFonts=(selectedNodes)=>selectedNodes.flatMap((node)=>{let font=closestElement(node,"font")||closestElement(node,'[style*="color"]:not(li), [style*="background-color"]:not(li), [style*="background-image"]:not(li)')||closestElement(node,"span");const faNodes=font?[...selectElements(font,".fa")]:[];if(faNodes&&Array.from(faNodes).some((faNode)=>faNode.contains(node))){return font;} 7558if(isIconElement(node)){return node;} 7559const children=font&&descendants(font);const hasInlineGradient=font&&isColorGradient(font.style["background-image"]);const isFullySelected=children&&children.every((child)=>selectedNodes.includes(child)||selectedNodes.some((node)=>isElement(node)&&node.contains(child)));const isTextGradient=hasInlineGradient&&font.classList.contains("text-gradient");const shouldReplaceExistingGradient=isFullySelected&&((mode==="color"&&isTextGradient)||(mode==="backgroundColor"&&!isTextGradient));if(font&&font.nodeName!=="T"&&(font.nodeName!=="SPAN"||font.style[mode]||font.style.backgroundImage)&&(isColorGradient(color)||color===""||!hasInlineGradient||shouldReplaceExistingGradient)&&!this.dependencies.split.isUnsplittable(font)){const selectedChildren=children.filter((child)=>child.isConnected&&selectedNodes.includes(child));if(selectedChildren.length){if(isBlock(font)){const colorStyles=["color","background-color","background-image"];const newFont=this.document.createElement("font");for(const style of colorStyles){const styleValue=font.style[style];if(styleValue){this.colorElement(newFont,styleValue,style);font.style.removeProperty(style);}} 7560font.classList.forEach((className)=>{if(TEXT_CLASSES_REGEX.test(className)){font.classList.remove(className);newFont.classList.add(className);}});newFont.append(...font.childNodes);font.append(newFont);font=newFont;} 7561const closestGradientEl=closestElement(node,'font[style*="background-image"], span[style*="background-image"]');const isGradientBeingUpdated=closestGradientEl&&isColorGradient(color);const splitnode=isGradientBeingUpdated?closestGradientEl:font;font=this.dependencies.split.splitAroundUntil(selectedChildren,splitnode);
7561if(isGradientBeingUpdated){const classRegex=mode==="color"?TEXT_CLASSES_REGEX:BG_CLASSES_REGEX;for(const node of descendants(font)){if(node.nodeType===Node.ELEMENT_NODE&&(node.style[mode]||classRegex.test(node.className))){this.colorElement(node,"",mode);node.style.webkitTextFillColor="";if(!node.getAttribute("style")){unwrapContents(node);}}}}else if(mode==="color"&&(font.style.webkitTextFillColor||(closestGradientEl&&closestGradientEl.classList.contains("text-gradient")&&!shouldReplaceExistingGradient))){font.style.webkitTextFillColor=color;}}else{font=[];}}else if((node.nodeType===Node.TEXT_NODE&&(isVisibleTextNode(node)||isZWS(node)))||(node.nodeName==="BR"&&isEmptyBlock(node.parentNode))||(node.nodeType===Node.ELEMENT_NODE&&["inline","inline-block"].includes(getComputedStyle(node).display)&&!isWhitespace(node.textContent)&&!node.classList.contains("btn")&&!node.querySelector("font")&&node.nodeName!=="A"&&!(node.nodeName==="SPAN"&&node.style["fontSize"]))){const previous=node.previousSibling;const classRegex=mode==="color"?BG_CLASSES_REGEX:TEXT_CLASSES_REGEX;if(previous&&previous.nodeName==="FONT"&&!previous.style[mode==="color"?"backgroundColor":"color"]&&!classRegex.test(previous.className)&&selectedNodes.includes(previous.firstChild)&&selectedNodes.includes(previous.lastChild)){font=previous;}else{font=this.document.createElement("font");node.after(font);if(isTextGradient&&mode==="color"){font.style.webkitTextFillColor=color;}} 7562if(node.nodeName==="BR"||node.textContent){font.appendChild(node);}else{fillEmpty(font);}}else{font=[];} 7563return font;});for(const fieldNode of targetedFieldNodes){this.colorElement(fieldNode,color,mode);} 7564let fonts=getFonts(selectedNodes);if(!fonts.every((font)=>font.isConnected)){fonts=getFonts(selectedNodes);} 7565const fontsSet=new Set(fonts);for(const font of fontsSet){this.colorElement(font,color,mode);const attributeNames=font.getAttributeNames().filter((name)=>name!=="data-oe-zws-empty-inline");if(!attributeNames.length){cursors.update(callbacksForCursorUpdate.unwrap(font));unwrapContents(font);fontsSet.delete(font);}} 7566cursors.restore();} 7567colorElement(element,color,mode){const styleMode=mode==="color"?"color":"background-color";let parts=backgroundImageCssToParts(element.style["background-image"]);if(element.matches(COLOR_COMBINATION_SELECTOR)){removePresetGradient(element);} 7568const hasGradientStyle=element.style.backgroundImage.includes("-gradient");if(mode==="backgroundColor"){if(!color){removeClass(element,"o_cc",...COLOR_COMBINATION_CLASSES);} 7569const hasGradient=getComputedStyle(element).backgroundImage.includes("-gradient");delete parts.gradient;let newBackgroundImage=backgroundImagePartsToCss(parts);if(hasGradient&&!newBackgroundImage){newBackgroundImage="none";} 7570if(newBackgroundImage){element.style.backgroundImage=newBackgroundImage;}else{removeStyle(element,"background-image");} 7571removeStyle(element,styleMode);if(!color&&!element.style.backgroundImage){const leftovers=[...element.style].filter((prop)=>prop.startsWith("background-")&&element.style.getPropertyValue(prop)==="initial");removeStyle(element,...leftovers);}} 7572const classNamesToRemove=[...element.classList].filter((className)=>(mode==="color"?TEXT_CLASSES_REGEX:BG_CLASSES_REGEX).test(className));classNamesToRemove.push("text-gradient");removeClass(element,...classNamesToRemove);if(isColorGradient(color)){removeStyle(element,styleMode);parts.gradient=color;if(mode==="color"){removeStyle(element,"background-color");element.classList.add("text-gradient");} 7573this.applyColorStyle(element,"background-image",backgroundImagePartsToCss(parts));}else{delete parts.gradient;if(hasGradientStyle&&!backgroundImagePartsToCss(parts)){removeStyle(element,"background-image");} 7574if(color.startsWith("text")||color.startsWith("bg-")){removeStyle(element,styleMode);element.classList.add(color);}else if(color){this.applyColorStyle(element,styleMode,color);}else{removeStyle(element,styleMode);}} 7575if(color.startsWith("o_cc")){parts=backgroundImageCssToParts(element.style["background-image"]);removeClass(element,...COLOR_COMBINATION_CLASSES);element.classList.add("o_cc",color);
7575const hasBackgroundColor=!!getComputedStyle(element).backgroundColor;const hasGradient=getComputedStyle(element).backgroundImage.includes("-gradient");const backgroundImage=element.style["background-image"];if(hasBackgroundColor&&hasGradient&&!backgroundImage){element.style.backgroundImage="none";}} 7576this.fixColorCombination(element,color);} 7577fixColorCombination(element,color){const parts=backgroundImageCssToParts(element.style["background-image"]);const hasBackgroundColor=element.style["background-color"]||!!element.className.match(/\bbg-/)||parts.gradient;if(!hasBackgroundColor&&(isColorGradient(color)||color.startsWith("o_cc"))){removeStyle(element,"background-image");parts.gradient=backgroundImageCssToParts(getComputedStyle(element).backgroundImage).gradient;element.style["background-image"]=backgroundImagePartsToCss(parts);}} 7578getColorCombination(el,actionParam){for(const handler of this.getResource("color_combination_getters")){const value=handler(el,actionParam);if(value){return value;}}} 7579applyColorStyle(element,mode,color){if(this.delegateTo("apply_color_style_overrides",element,mode,color)){return;} 7580element.style[mode]=color;}} 7581function getColorCombinationFromClass(el){return el.className.match?.(COLOR_COMBINATION_CLASSES_REGEX)?.[0];} 7582function removePresetGradient(element){const oldBackgroundImage=element.style["background-image"];const parts=backgroundImageCssToParts(oldBackgroundImage);const currentGradient=parts.gradient;removeStyle(element,"background-image");const styleWithoutGradient=getComputedStyle(element);const presetGradient=backgroundImageCssToParts(styleWithoutGradient.backgroundImage).gradient;if(presetGradient!==currentGradient){const withGradient=backgroundImagePartsToCss(parts);if(withGradient&&withGradient!=="none"){element.style["background-image"]=withGradient;}else{removeStyle(element,"background-image");}}else{delete parts.gradient;const withoutGradient=backgroundImagePartsToCss(parts);if(withoutGradient&&withoutGradient!=="none"){element.style["background-image"]=withoutGradient;}else{removeStyle(element,"background-image");}}} 7583return __exports;});; 7584 7585/* /html_editor/static/src/main/font/color_selector.js */ 7586odoo.define('@html_editor/main/font/color_selector',['@web/core/utils/colors','@odoo/owl','@web/core/color_picker/color_picker','@web/core/utils/reactive','@html_editor/main/toolbar/toolbar','@html_editor/utils/formatting','@web/core/utils/hooks','@html_editor/dropdown_autovisibility_hook'],function(require){'use strict';let __exports={};const{isColorGradient}=require("@web/core/utils/colors");const{Component,useState}=require("@odoo/owl");const{useColorPicker,DEFAULT_COLORS,DEFAULT_THEME_COLOR_VARS,}=require("@web/core/color_picker/color_picker");const{effect}=require("@web/core/utils/reactive");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{getCSSVariableValue,getHtmlStyle}=require("@html_editor/utils/formatting");const{useChildRef}=require("@web/core/utils/hooks");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const ColorSelector=__exports.ColorSelector=class ColorSelector extends Component{static template="html_editor.ColorSelector";static props={...toolbarButtonProps,mode:{type:String},type:{type:String},getSelectedColors:Function,applyColor:Function,applyColorPreview:Function,applyColorResetPreview:Function,getUsedCustomColors:Function,getTargetedElements:Function,colorPrefix:{type:String},enabledTabs:{type:Array,optional:true},cssVarColorPrefix:{type:String,optional:true},onClose:Function,useDefaultThemeColors:{type:Boolean,optional:true},};static defaultProps={cssVarColorPrefix:"",enabledTabs:["solid","gradient","custom"],useDefaultThemeColors:true,};setup(){this.state=useState({});this.colorSelectorState=useState({isOpen:false});const htmlStyle=getHtmlStyle(document);const defaultThemeColors=DEFAULT_THEME_COLOR_VARS.map((color)=>getCSSVariableValue(color,htmlStyle));this.solidColors=[...DEFAULT_COLORS.flat(),...defaultThemeColors,getCSSVariableValue("body-color",htmlStyle),"#00000000",];effect((selectedColors)=>{this.state.selectedColor=selectedColors[this.props.mode];this.state.defaultTab="solid";this.state.selectedTab=this.getCorrespondingColorTab(selectedColors[this.props.mode]);this.state.getTargetedElements=this.props.getTargetedElements;this.state.mode=this.props.mode;},[this.props.getSelectedColors()]);const colorPickerRef=useChildRef();this.colorPicker=useColorPicker("root",{state:this.state,applyColor:this.props.applyColor,applyColorPreview:this.props.applyColorPreview,applyColorResetPreview:this.props.applyColorResetPreview,getUsedCustomColors:this.props.getUsedCustomColors,colorPrefix:this.props.colorPrefix,enabledTabs:this.props.enabledTabs,cssVarColorPrefix:this.props.cssVarColorPrefix,useDefaultThemeColors:this.props.useDefaultThemeColors,},{env:this.__owl__.childEnv,onClose:()=>{this.props.applyColorResetPreview();this.props.onClose();this.colorSelectorState.isOpen=false;},onOpen:()=>{this.colorSelectorState.isOpen=true;},ref:colorPickerRef,});useDropdownAutoVisibility(this.env.overlayState,colorPickerRef);} 7587getCorrespondingColorTab(color){if(!color||this.solidColors.includes(color.toUpperCase())){return"solid";}else if(isColorGradient(color)){return"gradient";}else{return"custom";}} 7588getSelectedColorStyle(){if(isColorGradient(this.state.selectedColor)){return`border-bottom: 2px solid transparent; border-image: ${this.state.selectedColor}; border-image-slice: 1`;} 7589return`border-bottom: 2px solid ${this.state.selectedColor}`;}} 7590return __exports;});; 7591 7592/* /html_editor/static/src/main/font/color_ui_plugin.js */ 7593odoo.define('@html_editor/main/font/color_ui_plugin',['@html_editor/core/selection_plugin','@html_editor/plugin','@web/core/l10n/translation','@html_editor/main/font/color_selector','@odoo/owl','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@web/core/utils/colors','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{ColorSelector}=require("@html_editor/main/font/color_selector");const{reactive}=require("@odoo/owl");const{isTextNode}=require("@html_editor/utils/dom_info");const{closestElement}=require("@html_editor/utils/dom_traversal");const{isCSSColor,normalizeCSSColor,RGBA_REGEX}=require("@web/core/utils/colors");const{withSequence}=require("@html_editor/utils/resource");const RGBA_OPACITY=0.6;const HEX_OPACITY="99";const ColorUIPlugin=__exports.ColorUIPlugin=class ColorUIPlugin extends Plugin{static id="colorUi";static dependencies=["color","history","selection"];static shared=["getPropsForColorSelector"];resources={toolbar_items:[{id:"forecolor",groupId:"decoration",namespaces:["compact","expanded"],description:_t("Apply Font Color"),Component:ColorSelector,props:this.getPropsForColorSelector("foreground"),isAvailable:isHtmlContentSupported,},{id:"backcolor",groupId:"decoration",description:_t("Apply Backgroun
7593d Color"),Component:ColorSelector,props:this.getPropsForColorSelector("background"),isAvailable:isHtmlContentSupported,},],selectionchange_handlers:withSequence(100,this.updateSelectedColor.bind(this)),get_background_color_processors:this.getBackgroundColorProcessor.bind(this),apply_background_color_processors:this.applyBackgroundColorProcessor.bind(this),selected_background_color_providers:withSequence(10,this.computeBackgroundColorForTextNode.bind(this)),};setup(){this.selectedColors=reactive({color:"",backgroundColor:""});this.previewableApplyColor=this.dependencies.history.makePreviewableOperation((color,mode,previewMode)=>this.dependencies.color.applyColor(color,mode,previewMode));} 7594getPropsForColorSelector(type){const mode=type==="foreground"?"color":"backgroundColor";return{type,mode,getUsedCustomColors:()=>this.getUsedCustomColors(mode),getSelectedColors:()=>this.selectedColors,applyColor:(color)=>this.applyColorCommit({color,mode}),applyColorPreview:(color)=>this.applyColorPreview({color,mode}),applyColorResetPreview:this.applyColorResetPreview.bind(this),colorPrefix:mode==="color"?"text-":"bg-",onClose:()=>this.dependencies.selection.focusEditable(),getTargetedElements:()=>{const nodes=this.dependencies.selection.getTargetedNodes().filter(isTextNode);return nodes.map((node)=>closestElement(node));},};} 7595applyColorCommit({color,mode}){this.previewableApplyColor.commit(color,mode);this.updateSelectedColor();} 7596applyColorPreview({color,mode}){this.previewableApplyColor.preview(color,mode,true);this.updateSelectedColor();} 7597applyColorResetPreview(){this.previewableApplyColor.revert();this.updateSelectedColor();} 7598getUsedCustomColors(mode){const allFont=this.editable.querySelectorAll("font");const usedCustomColors=new Set();for(const font of allFont){if(isCSSColor(font.style[mode])){usedCustomColors.add(normalizeCSSColor(font.style[mode]));}} 7599return usedCustomColors;} 7600computeBackgroundColorForTextNode(){const nodes=this.dependencies.selection.getTargetedNodes().filter(isTextNode);if(nodes.length===0){return;} 7601const el=closestElement(nodes[0]);if(!el){return;} 7602return this.dependencies.color.getElementColors(el).backgroundColor;} 7603updateSelectedColor(){let backgroundColor;for(const provider of this.getResource("selected_background_color_providers")){const providedBackgroundColor=provider();if(providedBackgroundColor){backgroundColor=providedBackgroundColor;break;}} 7604this.selectedColors.backgroundColor=backgroundColor||"#00000000";const nodes=this.dependencies.selection.getTargetedNodes().filter(isTextNode);if(nodes.length===0){this.selectedColors.color="";return;} 7605const el=closestElement(nodes[0]);if(!el){this.selectedColors.color="";return;} 7606this.selectedColors.color=this.dependencies.color.getElementColors(el).color;} 7607getActiveColorTabEl(){return document.querySelector(".o_font_color_selector .btn-tab.active");} 7608getBackgroundColorProcessor(backgroundColor){const activeTab=this.getActiveColorTabEl();if(backgroundColor.startsWith("rgba")&&(!activeTab||activeTab.classList.contains("solid-tab"))){const values=backgroundColor.match(RGBA_REGEX)||[];const alpha=parseFloat(values.pop());if(alpha===RGBA_OPACITY){backgroundColor=`rgb(${values.slice(0, 3).join(", ")})`;}} 7609return backgroundColor;} 7610applyBackgroundColorProcessor(brackgroundColor){const activeTab=this.getActiveColorTabEl();if(activeTab?.classList.contains("solid-tab")&&brackgroundColor.startsWith("#")){brackgroundColor+=HEX_OPACITY;} 7611return brackgroundColor;}} 7612return __exports;});; 7613 7614/* /html_editor/static/src/main/font/font_family_plugin.js */ 7615odoo.define('@html_editor/main/font/font_family_plugin',['@html_editor/plugin','@web/core/l10n/translation','@html_editor/main/font/font_family_selector','@odoo/owl','@html_editor/utils/dom_traversal','@html_editor/utils/resource','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{FontFamilySelector}=require("@html_editor/main/font/font_family_selector");const{reactive}=require("@odoo/owl");const{closestElement}=require("@html_editor/utils/dom_traversal");const{READ,withSequence}=require("@html_editor/utils/resource");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const defaultFontFamily=__exports.defaultFontFamily={name:"Default system font",nameShort:"Default font",fontFamily:false,};const fontFamilyItems=__exports.fontFamilyItems=[defaultFontFamily,{name:"Arial (sans-serif)",nameShort:"Arial",fontFamily:"Arial, sans-serif"},{name:"Verdana (sans-serif)",nameShort:"Verdana",fontFamily:"Verdana, sans-serif"},{name:"Tahoma (sans-serif)",nameShort:"Tahoma",fontFamily:"Tahoma, sans-serif"},{name:"Trebuchet MS (sans-serif)",nameShort:"Trebuchet MS",fontFamily:'"Trebuchet MS", sans-serif',},{name:"Courier New (monospace)",nameShort:"Courier New",fontFamily:'"Courier New", monospace',},];const FontFamilyPlugin=__exports.FontFamilyPlugin=class FontFamilyPlugin extends Plugin{static id="fontFamily";static dependencies=["split","selection","dom","format","font"];fontFamily=reactive({displayName:defaultFontFamily.nameShort});resources={toolbar_items:[withSequence(15,{id:"font-family",groupId:"font",description:_t("Select font family"),Component:FontFamilySelector,props:{fontFamilyItems:fontFamilyItems,currentFontFamily:this.fontFamily,onSelected:(item)=>{this.dependencies.format.formatSelection("fontFamily",{applyStyle:item.fontFamily!==false,formatProps:item,});this.fontFamily.displayName=item.nameShort;},},isAvailable:(selection)=>isHtmlContentSupported(selection)&&(this.config.allowFontFamily??true),}),],selectionchange_handlers:withSequence(READ,this.updateCurrentFontFamily.bind(this)),post_undo_handlers:this.updateCurrentFontFamily.bind(this),post_redo_handlers:this.updateCurrentFontFamily.bind(this),};updateCurrentFontFamily(ev){const selelectionData=this.dependencies.selection.getSelectionData();if(!selelectionData.documentSelectionIsInEditable){return;} 7616const anchorElement=closestElement(selelectionData.editableSelection.anchorNode);const anchorElementFontFamily=getComputedStyle(anchorElement).fontFamily;const currentFontItem=anchorElementFontFamily&&fontFamilyItems.find((item)=>item.fontFamily===anchorElementFontFamily);this.fontFamily.displayName=(currentFontItem||defaultFontFamily).nameShort;}} 7617return __exports;});; 7618 7619/* /html_editor/static/src/main/font/font_family_selector.js */ 7620odoo.define('@html_editor/main/font/font_family_selector',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@html_editor/main/toolbar/toolbar','@html_editor/dropdown_autovisibility_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const{useChildRef}=require("@web/core/utils/hooks");const FontFamilySelector=__exports.FontFamilySelector=class FontFamilySelector extends Component{static template="html_editor.FontFamilySelector";static props={document:{optional:true},fontFamilyItems:Object,currentFontFamily:Object,onSelected:Function,...toolbarButtonProps,};static components={Dropdown,DropdownItem};setup(){this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);}} 7621return __exports;});; 7622 7623/* /html_editor/static/src/main/font/font_plugin.js */ 7624odoo.define('@html_editor/main/font/font_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/formatting','@html_editor/utils/position','@web/core/l10n/translation','@html_editor/main/font/font_selector','@html_editor/utils/base_container','@html_editor/utils/resource','@odoo/owl','@html_editor/main/font/font_size_selector','@html_editor/core/selection_plugin','@html_editor/utils/functions'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{isBlock,closestBlock}=require("@html_editor/utils/blocks");const{unwrapContents}=require("@html_editor/utils/dom");const{isParagraphRelatedElement,isRedundantElement,isEmptyBlock,isVisibleTextNode,isZWS,isContentEditableAncestor,}=require("@html_editor/utils/dom_info");const{ancestors,childNodes,closestElement,createDOMPathGenerator,descendants,selectElements,}=require("@html_editor/utils/dom_traversal");const{convertNumericToUnit,getCSSVariableValue,getHtmlStyle,getFontSizeDisplayValue,FONT_SIZE_CLASSES,}=require("@html_editor/utils/formatting");const{DIRECTIONS}=require("@html_editor/utils/position");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{FontSelector}=require("@html_editor/main/font/font_selector");const{getBaseContainerSelector,SUPPORTED_BASE_CONTAINER_NAMES,}=require("@html_editor/utils/base_container");const{READ,withSequence}=require("@html_editor/utils/resource");const{reactive}=require("@odoo/owl");const{FontSizeSelector}=require("@html_editor/main/font/font_size_selector");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{weakMemoize}=require("@html_editor/utils/functions");const fontSizeItems=__exports.fontSizeItems=[{variableName:"display-1-font-size",className:"display-1-fs"},{variableName:"display-2-font-size",className:"display-2-fs"},{variableName:"display-3-font-size",className:"display-3-fs"},{variableName:"display-4-font-size",className:"display-4-fs"},{variableName:"h1-font-size",className:"h1-fs"},{variableName:"h2-font-size",className:"h2-fs"},{variableName:"h3-font-size",className:"h3-fs"},{variableName:"h4-font-size",className:"h4-fs"},{variableName:"h5-font-size",className:"h5-fs"},{variableName:"h6-font-size",className:"h6-fs"},{variableName:"font-size-base",className:"base-fs"},{variableName:"small-font-size",className:"o_small-fs"},];const rightLeafOnlyNotBlockPath=createDOMPathGenerator(DIRECTIONS.RIGHT,{leafOnly:true,stopTraverseFunction:isBlock,stopFunction:isBlock,});const headingTags=__exports.headingTags=["H1","H2","H3","H4","H5","H6"];const handledElemSelector=[...headingTags,"PRE","BLOCKQUOTE"].join(", ");const FontPlugin=__exports.FontPlugin=class FontPlugin extends Plugin{static id="font";static dependencies=["baseContainer","input","split","selection","dom","format","lineBreak",];resources={font_items:[withSequence(10,{name:_t("Header 1 Display 1"),tagName:"h1",extraClass:"display-1",}),...[{name:_t("Header 1"),tagName:"h1"},{name:_t("Header 2"),tagName:"h2"},{name:_t("Header 3"),tagName:"h3"},{name:_t("Header 4"),tagName:"h4"},{name:_t("Header 5"),tagName:"h5"},{name:_t("Header 6"),tagName:"h6"},].map((item)=>withSequence(20,item)),withSequence(30,{name:_t("Normal"),tagName:"div",selector:getBaseContainerSelector("DIV"),}),withSequence(40,{name:_t("Paragraph"),tagName:"p"}),withSequence(50,{name:_t("Code"),tagName:"pre"}),withSequence(60,{name:_t("Quote"),tagName:"blockquote"}),],user_commands:[{id:"setTagHeading",run:({level}={})=>this.dependencies.dom.setBlock({tagName:`H${level ?? 1}`}),isAvailable:this.blockFormatIsAvailable.bind(this),},{id:"setTagHeading1",title:_t("Heading 1"),description:_t("Big section heading"),icon:"fa-header",run:()=>this.dependencies.dom.setBlock({tagName:"H1"}),isAvailable:this.blockFormatIsAvailable.bind(this),},{id:"setTagHeading2",title:_t("Heading 2"),description:_t("Medium section heading"),icon:"fa-header",run:()=>this.dependencies.dom.setBlock({tagName:"H2"}),isAvailable:this.blockFormatIsAvailable.bind(this),},{id:"setTagHeading3",title:_t("Heading 3"),description:_t("Small section heading"),icon:"fa-header",run:()=>this.dependencies.dom.setBlock({tagName:"H3"}),isAvailable:this.blockFormatIsAvailable.bind(this),},{id:"setTagParagraph",title:_t("Text"),description:_t("Paragraph block"),icon:"fa-paragraph",run:()=>{this.dependencies.dom.setBlock({tagName:this.dependencies.baseContainer.getDefaultNodeName(),});},isAvailable:this.blockFormatIsAvailable.bind(this),},{id:"setTagQuote",title:_t("Quote"),description:_t("Add a blockquote section"),icon:"fa-quote-right",run:()=>this.dependencies.dom.setBlock({tagName:"blockquote"}),isAvailable:this.blockFormatIsAvailable.bind(this),},{id:"setTagPre",title:_t("Code"),description:_t("Add a code section"),icon:"fa-code",run:()=>this.dependencies.dom.setBlock({tagName:"pre"}),isAvailable:this.blockFormatIsAvailable.bind(this),},],toolbar_groups:[withSequence(10,{id:"font",}),],toolbar_items:[withSequence(10,{id:"font",groupId:"font",namespaces:["compact","expanded"],description:_t("Select font style"),Component:FontSelector,props:{getItems:()=>this.availableFontItems,getDisplay:()=>this.font,onSelected:(item)=>{this.dependencies.dom.setBlock({tagName:item.tagName,extraClass:item.extraClass,});this.updateFontSelectorParams();},},isAvailable:this.blockFormatIsAvailable.bind(this),}),withSequence(20,{id:"font-size",groupId:"font",namespaces:["compact","expanded"],description:_t("Select font size"),Component:FontSizeSelector,props:{getItems:()=>this.fontSizeItems,getDisplay:()=>this.fontSize,onFontSizeInput:(size)=>{this.dependencies.format.formatSelection("fontSize",{formatProps:{size},applyStyle:true,});this.updateFontSizeSelectorParams();},onSelected:(item)=>{this.dependencies.format.formatSelection("setFontSizeClassName",{formatProps:{className:item.className},applyStyle:true,});this.updateFontSizeSelectorParams();},onBlur:()=>this.dependencies.selection.focusEditable(),document:this.document,},isAvailable:isHtmlContentSupported,}),],powerbox_categories:withSequence(5,{id:"format",name:_t("Format")}),powerbox_items:[{categoryId:"format",commandId:"setTagHeading1",keywords:[_t("title")],},{categoryId:"format",commandId:"setTagHeading2",keywords:[_t("title")],},{categoryId:"format",commandId:"setTagHeading3",keywords:[_t("title")],},{categoryId:"format",commandId:"setTagParagraph",},{categoryId:"format",commandId:"setTagQuote",},{categoryId:"format",commandId:"setTagPre",},],shorthands:[{pattern:/^#$/,commandId:"setTagHeading",commandParams:{level:1},},{pattern:/^##$/,commandId:"setTagHeading",commandParams:{level:2},},{pattern:/^###$/,commandId:"setTagHeading",commandParams:{level:3},},{pattern:/^####$/,commandId:"setTagHeading",commandParams:{level:4},},{pattern:/^#####$/,commandId:"setTagHeading",commandParams:{level:5},},{pattern:/^######$/,commandId:"setTagHeading",commandParams:{level:6},},{pattern:/^>$/,commandId:"setTagQuote",},],hints:[{selector:"H1",text:_t("Heading 1")},{selector:"H2",text:_t("Heading 2")},{selector:"H3",text:_t("Heading 3")},{selector:"H4",text:_t("Heading 4")},{selector:"H5",text:_t("Heading 5")},{selector:"H6",text:_t("Heading 6")},{selector:"PRE",text:_t("Code")},{selector:"BLOCKQUOTE",text:_t("Quote")},],selectionchange_handlers:[withSequence(READ,this.updateFontSelectorParams.bind(this)),withSequence(READ,this.updateFontSizeSelectorParams.bind(this)),],post_undo_handlers:[this.updateFontSelectorParams.bind(this),this.updateFontSizeSelectorParams.bind(this),],post_redo_handlers:[this.updateFontSelectorParams.bind(this),this.updateFontSizeSelectorParams.bind(this),],normalize_handlers:this.normalize.bind(this),split_element_block_overrides:[this.handleSplitBlockHeading.bind(this),this.handleSplitBlockPRE.bind(this),this.handleSplitBlockquote.bind(this),],delete_backward_overrides:withSequence(20,this.handleDeleteBackward.bind(this)),delete_backward_word_overrides:this.handleDeleteBackward.bind(this),are_shorthands_available_predicates:(node)=>{if(closestElement(node,"pre")){return false;}},is_powerbox_available_predicates:(node)=>{if(closestElement(node,"pre")){return false;}},clipboard_content_processors:this.processContentForClipboard.bind(this),before_insert_processors:this.handleInsertWithinPre.bind(this),format_class_predicates:(className)=>[...FONT_SIZE_CLASSES,"o_default_font_size"].includes(className),};setup(){this.fontSize=reactive({displayName:""});this.font=reactive({displayName:""});this.blockFormatIsAvailableMemoized=weakMemoize((selection)=>isHtmlContentSu
7624pported(selection)&&this.dependencies.dom.canSetBlock());this.availableFontItems=this.getResource("font_items").filter(({tagName})=>!SUPPORTED_BASE_CONTAINER_NAMES.includes(tagName.toUpperCase())||this.config.baseContainers.includes(tagName.toUpperCase()));} 7625normalize(root){for(const el of selectElements(root,"strong, b, span[style*='font-weight: bolder'], small")){if(isRedundantElement(el)){unwrapContents(el);}}} 7626get fontName(){const sel=this.dependencies.selection.getSelectionData().deepEditableSelection;const anchorNode=sel.anchorNode;const block=closestBlock(anchorNode);const tagName=block.tagName.toLowerCase();const matchingItems=this.availableFontItems.filter((item)=>item.selector?block.matches(item.selector):item.tagName===tagName);const matchingItemsWitoutExtraClass=matchingItems.filter((item)=>!item.extraClass);if(!matchingItems.length){return _t("Normal");} 7627return(matchingItems.find((item)=>block.classList.contains(item.extraClass))||(matchingItemsWitoutExtraClass.length&&matchingItemsWitoutExtraClass[0])).name;} 7628get fontSizeName(){const sel=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!sel){return fontSizeItems[0].name;} 7629return Math.round(getFontSizeDisplayValue(sel,this.document));} 7630get fontSizeItems(){const style=getHtmlStyle(this.document);const nameAlreadyUsed=new Set();return fontSizeItems.flatMap((item)=>{const strValue=getCSSVariableValue(item.variableName,style);if(!strValue){return[];} 7631const remValue=parseFloat(strValue);const pxValue=convertNumericToUnit(remValue,"rem","px",style);const roundedValue=Math.round(pxValue);if(nameAlreadyUsed.has(roundedValue)){return[];} 7632nameAlreadyUsed.add(roundedValue);return[{...item,tagName:"span",name:roundedValue}];}).sort((a,b)=>a.name-b.name);} 7633blockFormatIsAvailable(selection){return this.blockFormatIsAvailableMemoized(selection);} 7634handleSplitBlockPRE({targetNode,targetOffset}){const closestPre=closestElement(targetNode,"pre");const closestBlockNode=closestBlock(targetNode);if(!closestPre||(closestBlockNode.nodeName!=="PRE"&&((closestBlockNode.textContent&&!isZWS(closestBlockNode))||closestBlockNode.nextSibling))){return;} 7635const nodesAfterTarget=[...rightLeafOnlyNotBlockPath(targetNode,targetOffset)];if(!nodesAfterTarget.length||(nodesAfterTarget.length===1&&nodesAfterTarget[0].nodeName==="BR")||isEmptyBlock(closestBlockNode)){const[beforeElement,afterElement]=this.dependencies.split.splitElementBlock({targetNode,targetOffset,blockToSplit:closestBlockNode,});const isPreBlock=beforeElement.nodeName==="PRE";const baseContainer=isPreBlock?this.dependencies.baseContainer.createBaseContainer():afterElement;if(isPreBlock){baseContainer.replaceChildren(...afterElement.childNodes);afterElement.replaceWith(baseContainer);}else{beforeElement.remove();closestPre.after(afterElement);} 7636const dir=closestBlockNode.getAttribute("dir")||closestPre.getAttribute("dir");if(dir){baseContainer.setAttribute("dir",dir);} 7637this.dependencies.selection.setCursorStart(baseContainer);}else{const lineBreak=this.document.createElement("br");targetNode.insertBefore(lineBreak,targetNode.childNodes[targetOffset]);this.dependencies.selection.setCursorEnd(lineBreak);} 7638return true;} 7639handleSplitBlockquote({targetNode,targetOffset,blockToSplit}){const closestQuote=closestElement(targetNode,"blockquote");const closestBlockNode=closestBlock(targetNode);const blockQuotedir=closestQuote&&closestQuote.getAttribute("dir");if(!closestQuote||closestBlockNode.nodeName!=="BLOCKQUOTE"){if(closestBlockNode.parentElement===closestQuote&&closestBlockNode.parentElement.lastElementChild===closestBlockNode&&!closestBlockNode.textContent){closestQuote.after(closestBlockNode);if(blockQuotedir&&!closestBlockNode.getAttribute("dir")){closestBlockNode.setAttribute("dir",blockQuotedir);} 7640this.dependencies.selection.setSelection({anchorNode:closestBlockNode,anchorOffset:0,});return true;} 7641return;} 7642const selection=this.dependencies.selection.getEditableSelection();const previousElementSibling=selection.anchorNode?.childNodes[selection.anchorOffset-1];const nextElementSibling=selection.anchorNode?.childNodes[selection.anchorOffset];if(previousElementSibling?.tagName==="BR"&&nextElementSibling?.tagName==="BR"){nextElementSibling.remove();previousElementSibling.remove();this.dependencies.split.splitElementBlock({targetNode,targetOffset,blockToSplit,});this.dependencies.dom.setBlock({tagName:this.dependencies.baseContainer.getDefaultNodeName(),});return true;} 7643this.dependencies.lineBreak.insertLineBreakElement({targetNode,targetOffset});return true;} 7644handleSplitBlockHeading(params){const closestHeading=closestElement(params.targetNode,(element)=>headingTags.includes(element.tagName));if(closestHeading){const[,newElement]=this.dependencies.split.splitElementBlock(params);if(newElement&&headingTags.includes(newElement.tagName)&&!descendants(newElement).some(isVisibleTextNode)){const baseContainer=this.dependencies.baseContainer.createBaseContainer();const dir=newElement.getAttribute("dir");
7644if(dir){baseContainer.setAttribute("dir",dir);} 7645newElement.replaceWith(baseContainer);baseContainer.replaceChildren(this.document.createElement("br"));this.dependencies.selection.setCursorStart(baseContainer);} 7646return true;}} 7647handleDeleteBackward({startContainer,startOffset,endContainer,endOffset}){const rangeIsCollapsed=startContainer===endContainer&&startOffset===endOffset;const closestHandledElement=closestElement(endContainer,handledElemSelector);if(!rangeIsCollapsed&&closestHandledElement?.tagName!=="BLOCKQUOTE"){return;} 7648if(!closestHandledElement||!isEmptyBlock(closestHandledElement)){return;} 7649if(this.getResource("unremovable_node_predicates").some((p)=>p(closestHandledElement))){return;} 7650const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(...closestHandledElement.childNodes);closestHandledElement.after(baseContainer);closestHandledElement.remove();this.dependencies.selection.setCursorStart(baseContainer);return true;} 7651updateFontSelectorParams(){this.font.displayName=this.fontName;} 7652updateFontSizeSelectorParams(){this.fontSize.displayName=this.fontSizeName;} 7653processContentForClipboard(clonedContents,selection){const commonAncestorElement=closestElement(selection.commonAncestorContainer);if(commonAncestorElement&&!isBlock(clonedContents.firstChild)){const blockEl=closestBlock(commonAncestorElement);const ancestorsList=[commonAncestorElement,...ancestors(commonAncestorElement,blockEl),];for(const ancestor of ancestorsList){if(isContentEditableAncestor(ancestor)){break;} 7654if(!isBlock(ancestor)||isParagraphRelatedElement(ancestor)){const clone=ancestor.cloneNode();clone.append(...childNodes(clonedContents));clonedContents.appendChild(clone);}}} 7655return clonedContents;} 7656handleInsertWithinPre(insertContainer,block){if(block.nodeName!=="PRE"){return insertContainer;} 7657for(const cb of this.getResource("before_insert_within_pre_processors")){insertContainer=cb(insertContainer);} 7658const isDeepestBlock=(node)=>isBlock(node)&&![...node.querySelectorAll("*")].some(isBlock);let linebreak;const processNode=(node)=>{const children=childNodes(node);if(isDeepestBlock(node)&&node.nextSibling){linebreak=this.document.createTextNode("\n");node.append(linebreak);} 7659if(node.nodeType===Node.ELEMENT_NODE){unwrapContents(node);} 7660for(const child of children){processNode(child);}};for(const node of childNodes(insertContainer)){processNode(node);} 7661return insertContainer;}} 7662return __exports;});; 7663 7664/* /html_editor/static/src/main/font/font_selector.js */ 7665odoo.define('@html_editor/main/font/font_selector',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@html_editor/main/toolbar/toolbar','@html_editor/dropdown_autovisibility_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const{useChildRef}=require("@web/core/utils/hooks");const FontSelector=__exports.FontSelector=class FontSelector extends Component{static template="html_editor.FontSelector";static props={...toolbarButtonProps,getItems:Function,getDisplay:Function,onSelected:Function,};static components={Dropdown,DropdownItem};setup(){this.items=this.props.getItems();this.state=useState(this.props.getDisplay());this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);} 7666onSelected(item){this.props.onSelected(item);}} 7667return __exports;});; 7668 7669/* /html_editor/static/src/main/font/font_size_selector.js */ 7670odoo.define('@html_editor/main/font/font_size_selector',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@html_editor/main/toolbar/toolbar','@web/core/dropdown/dropdown_hooks','@web/core/utils/timing','@web/core/browser/cookie','@html_editor/utils/formatting','@html_editor/dropdown_autovisibility_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onMounted,useEffect,useRef,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{useDebounced}=require("@web/core/utils/timing");const{cookie}=require("@web/core/browser/cookie");const{getCSSVariableValue,getHtmlStyle}=require("@html_editor/utils/formatting");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const{useChildRef}=require("@web/core/utils/hooks");const MAX_FONT_SIZE=144;const FontSizeSelector=__exports.FontSizeSelector=class FontSizeSelector extends Component{static template="html_editor.FontSizeSelector";static props={getItems:Function,getDisplay:Function,onFontSizeInput:Function,onSelected:Function,onBlur:{type:Function,optional:true},document:{validate:(p)=>p.nodeType===Node.DOCUMENT_NODE},...toolbarButtonProps,};static components={Dropdown,DropdownItem};setup(){this.items=this.props.getItems();this.state=useState(this.props.getDisplay());this.dropdown=useDropdownState();this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);
7670this.iframeContentRef=useRef("iframeContent");this.debouncedCustomFontSizeInput=useDebounced(this.onCustomFontSizeInput,200);onMounted(()=>{const iframeEl=this.iframeContentRef.el;const initFontSizeInput=()=>{const iframeDoc=iframeEl.contentWindow.document;if(this.fontSizeInput?.closest("body")===iframeDoc.body||!iframeDoc.body){return;} 7671this.fontSizeInput=iframeDoc.createElement("input");const isDarkMode=cookie.get("color_scheme")==="dark";const htmlStyle=getHtmlStyle(document);const backgroundColor=getCSSVariableValue(isDarkMode?"gray-200":"white",htmlStyle);const color=getCSSVariableValue("black",htmlStyle);const fontFamily=getCSSVariableValue("o-system-fonts",htmlStyle);Object.assign(iframeDoc.body.style,{padding:"0",margin:"0",});Object.assign(this.fontSizeInput.style,{width:"100%",height:"100%",border:"none",outline:"none",textAlign:"center",backgroundColor:backgroundColor,color:color,fontFamily:fontFamily,});this.fontSizeInput.type="text";this.fontSizeInput.name="font-size-input";this.fontSizeInput.autocomplete="off";this.fontSizeInput.value=this.state.displayName;iframeDoc.body.appendChild(this.fontSizeInput);this.fontSizeInput.addEventListener("click",()=>{if(!this.dropdown.isOpen){this.dropdown.open();}});this.fontSizeInput.addEventListener("input",this.debouncedCustomFontSizeInput);this.fontSizeInput.addEventListener("keydown",this.onKeyDownFontSizeInput.bind(this));};if(iframeEl.contentDocument.readyState==="complete"){initFontSizeInput();} 7672iframeEl.addEventListener("load",initFontSizeInput);});useEffect(()=>{if(this.fontSizeInput){this.fontSizeInput.value=this.state.displayName;}},()=>[this.state.displayName]);useEffect(()=>{if(this.fontSizeInput){if(this.dropdown.isOpen){this.fontSizeInput.select();}else if(this.iframeContentRef.el?.contains(this.props.document.activeElement)){this.fontSizeInput.blur();this.props.onBlur?.();}}},()=>[this.dropdown.isOpen]);} 7673onCustomFontSizeInput(ev){let fontSize=parseInt(ev.target.value,10);if(fontSize>0){fontSize=Math.min(fontSize,MAX_FONT_SIZE);if(this.state.displayName!==fontSize){this.props.onFontSizeInput(`${fontSize}px`);}else{this.fontSizeInput.value=this.state.displayName;}} 7674this.fontSizeInput.focus();} 7675onKeyDownFontSizeInput(ev){if(["Enter","Tab"].includes(ev.key)&&this.dropdown.isOpen){this.dropdown.close();}else if(["ArrowUp","ArrowDown"].includes(ev.key)){const fontSizeSelectorMenu=document.querySelector(".o_font_size_selector_menu div");if(!fontSizeSelectorMenu){return;} 7676ev.target.blur();const fontSizeMenuItemToFocus=ev.key==="ArrowUp"?fontSizeSelectorMenu.lastElementChild:fontSizeSelectorMenu.firstElementChild;if(fontSizeMenuItemToFocus){fontSizeMenuItemToFocus.focus();}}} 7677onSelected(item){this.props.onSelected(item);}} 7678return __exports;});; 7679 7680/* /html_editor/static/src/main/font/gradient_picker/gradient_picker.js */ 7681odoo.define('@html_editor/main/font/gradient_picker/gradient_picker',['@odoo/owl','@web/core/color_picker/custom_color_picker/custom_color_picker','@web/core/utils/colors'],function(require){'use strict';let __exports={};const{Component,onWillUpdateProps,useState,useRef}=require("@odoo/owl");const{CustomColorPicker:ColorPicker}=require("@web/core/color_picker/custom_color_picker/custom_color_picker");const{isColorGradient,standardizeGradient,rgbaToHex,convertCSSColorToRgba,}=require("@web/core/utils/colors");const GradientPicker=__exports.GradientPicker=class GradientPicker extends Component{static components={ColorPicker};static template="html_editor.GradientPicker";static props={onGradientChange:{type:Function,optional:true},onGradientPreview:{type:Function,optional:true},setOnCloseCallback:{type:Function,optional:true},setOperationCallbacks:{type:Function,optional:true},selectedGradient:{type:String,optional:true},noTransparency:{type:Boolean,optional:true},};setup(){this.state=useState({type:"linear",angle:135,currentColorIndex:0,size:"closest-side",});this.positions=useState({x:25,y:25});this.colors=useState([{hex:"#DF7CC4",percentage:0},{hex:"#6C3582",percentage:100},]);this.cssGradients=useState({preview:"",linear:"",radial:"",sliderThumbStyle:""});this.knobRef=useRef("gradientAngleKnob");if(this.props.selectedGradient&&isColorGradient(this.props.selectedGradient)){this.setGradientFromString(this.props.selectedGradient);}else{this.onColorGradientChange();} 7682onWillUpdateProps((newProps)=>
7682{if(newProps.selectedGradient){this.setGradientFromString(newProps.selectedGradient);}});} 7683setGradientFromString(gradient){if(!gradient||!isColorGradient(gradient)){return;} 7684gradient=standardizeGradient(gradient);const colors=[...gradient.matchAll(/(#[0-9a-f]{6}|rgba?\(\s*[0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*[,\s*[0-9.]*]?\s*\)|[a-z]+)\s*([[0-9]+%]?)/g),].filter((color)=>rgbaToHex(color[1])!=="#");this.colors.splice(0,this.colors.length);for(const color of colors){this.colors.push({hex:rgbaToHex(color[1]),percentage:color[2].replace("%","")});} 7685const isLinear=gradient.startsWith("linear-gradient(");if(isLinear){const angle=gradient.match(/(-?[0-9]+)deg/);if(angle){this.state.angle=parseInt(angle[1]);}}else{this.state.type="radial";const sizeMatch=gradient.match(/(closest|farthest)-(side|corner)/);const size=sizeMatch?sizeMatch[0]:"farthest-corner";this.state.size=size;const position=gradient.match(/ at ([0-9]+)% ([0-9]+)%/)||["","50","50"];this.positions.x=position[1];this.positions.y=position[2];} 7686this.updateCssGradients();} 7687selectType(type){this.state.type=type;this.onColorGradientChange();} 7688onAngleChange(ev){const angle=parseInt(ev.target.value);if(!isNaN(angle)){const clampedAngle=Math.min(Math.max(angle,0),360);ev.target.value=clampedAngle;this.state.angle=clampedAngle;this.onColorGradientChange();}} 7689onPositionChange(position,ev){const inputValue=parseFloat(ev.target.value);if(!isNaN(inputValue)){const clampedValue=Math.min(Math.max(inputValue,0),100);ev.target.value=clampedValue;this.positions[position]=clampedValue;this.onColorGradientChange();}} 7690onColorChange(color){const hex=rgbaToHex(color.cssColor);this.colors[this.state.currentColorIndex].hex=hex;this.onColorGradientChange();} 7691onColorPreview(color){const hex=rgbaToHex(color.cssColor);this.colors[this.state.currentColorIndex].hex=hex;this.onColorGradientPreview();} 7692onSizeChange(size){this.state.size=size;this.onColorGradientChange();} 7693onColorPercentageChange(colorIndex,ev){this.state.currentColorIndex=colorIndex;this.colors[colorIndex].percentage=ev.target.value;this.sortColors();this.onColorGradientChange();} 7694onGradientPreviewClick(ev){const width=parseInt(window.getComputedStyle(ev.target).width,10);const percentage=Math.round((100*ev.offsetX)/width);this.addColorStop(percentage);} 7695addColorStop(percentage){let color;let previousColor=this.colors.findLast((color)=>color.percentage<=percentage);let nextColor=this.colors.find((color)=>color.percentage>percentage);if(!previousColor&&nextColor){color=nextColor.hex;}else if(!nextColor&&previousColor){color=previousColor.hex;}else if(nextColor&&previousColor){const previousRatio=(nextColor.percentage-percentage)/(nextColor.percentage-previousColor.percentage);const nextRatio=1-previousRatio;previousColor=convertCSSColorToRgba(previousColor.hex);nextColor=convertCSSColorToRgba(nextColor.hex);const red=Math.round(previousRatio*previousColor.red+nextRatio*nextColor.red);const green=Math.round(previousRatio*previousColor.green+nextRatio*nextColor.green);const blue=Math.round(previousRatio*previousColor.blue+nextRatio*nextColor.blue);const opacity=Math.round(previousRatio*previousColor.opacity+nextRatio*nextColor.opacity);color=`rgba(${red}, ${green}, ${blue}, ${opacity / 100})`;} 7696this.colors.push({hex:color,percentage});this.sortColors();this.state.currentColorIndex=this.colors.findIndex((color)=>color.percentage===percentage);this.onColorGradientChange();} 7697removeColor(colorIndex){if(this.colors.length<=2){return;} 7698this.colors.splice(colorIndex,1);this.state.currentColorIndex=0;this.onColorGradientChange();} 7699sortColors(){this.colors=this.colors.sort((a,b)=>a.percentage-b.percentage);} 7700updateCssGradients(){const gradientColors=this.colors.map((color)=>`${color.hex} ${color.percentage}%`).join(", ");let sliderThumbStyle="";for(let i=0;i<this.colors.length;i++){const selector=`.gradient-colors div:nth-child(${i + 1}) input[type="range"]`;const style=`background-color: ${this.colors[i].hex};`;sliderThumbStyle+=`${selector}::-webkit-slider-thumb { ${style} }\n`;sliderThumbStyle+=`${selector}::-moz-range-thumb { ${style} }\n`;} 7701this.cssGradients.preview=`linear-gradient(90deg, ${gradientColors})`;this.cssGradients.linear=`linear-gradient(${this.state.angle}deg, ${gradientColors})`;this.cssGradients.radial=`radial-gradient(circle ${this.state.size} at ${this.positions.x}% ${this.positions.y}%, ${gradientColors})`;this.cssGradients.sliderThumbStyle=sliderThumbStyle;} 7702onColorGradientChange(){this.updateCssGradients();this.props?.onGradientChange(this.cssGradients[this.state.type]);} 7703onColorGradientPreview(){this.updateCssGradients();this.props.onGradientPreview?.({gradient:this.cssGradients[this.state.type]});} 7704get currentColorHex(){return this.colors?.[this.state.currentColorIndex]?.hex||"#000000";} 7705onKnobMouseDown(ev){const knobEl=this.knobRef.el;if(!knobEl){return;} 7706const knobRadius=knobEl.offsetWidth/2;
7706const knobRect=knobEl.getBoundingClientRect();const centerX=knobRect.left+knobRadius;const centerY=knobRect.top+knobRadius;const updateAngle=(ev)=>{const distanceX=ev.clientX-centerX;const distanceY=ev.clientY-centerY;const angle=Math.atan2(distanceY,distanceX)*(180/Math.PI);this.state.angle=Math.round((angle+360)%360);};updateAngle(ev);this.updateCssGradients();const onKnobMouseMove=(ev)=>{updateAngle(ev);this.updateCssGradients();};const onKnobMouseUp=()=>{document.removeEventListener("mousemove",onKnobMouseMove);this.onColorGradientChange();};document.addEventListener("mousemove",onKnobMouseMove);document.addEventListener("mouseup",onKnobMouseUp,{once:true});}} 7707return __exports;});; 7708 7709/* /html_editor/static/src/main/hint_plugin.js */ 7710odoo.define('@html_editor/main/hint_plugin',['@html_editor/plugin','@html_editor/utils/dom_info','@html_editor/utils/dom','@html_editor/utils/dom_traversal','@html_editor/utils/blocks','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{isEditorTab,isEmptyBlock,isProtected}=require("@html_editor/utils/dom_info");const{removeClass}=require("@html_editor/utils/dom");const{descendants,selectElements}=require("@html_editor/utils/dom_traversal");const{closestBlock}=require("@html_editor/utils/blocks");const{debounce}=require("@web/core/utils/timing");const HintPlugin=__exports.HintPlugin=class HintPlugin extends Plugin{static id="hint";static dependencies=["history","selection"];resources={selectionchange_handlers:this.triggerDebouncedUpdateHints.bind(this),external_history_step_handlers:()=>{this.clearHints();this.updateHints();},normalize_handlers:this.normalize.bind(this),clean_for_save_handlers:({root})=>this.clearHints(root),content_updated_handlers:this.updateHints.bind(this),hint_targets_providers:(selectionData,editable)=>{if(!selectionData.currentSelectionIsInEditable||!selectionData.documentSelection){return[];} 7711const blockEl=closestBlock(selectionData.documentSelection.anchorNode);if(this.dependencies.selection.isNodeEditable(blockEl)){return[blockEl];}else{return[];}},system_classes:["o-we-hint"],system_attributes:["o-we-hint-text"],};setup(){this.updateHints(this.editable);const shouldDebounce=this.config.debounceHints!==false;if(shouldDebounce){this.debouncedUpdateHints=debounce(this.updateHints.bind(this),30);}else{this.debouncedUpdateHints=this.updateHints.bind(this);}} 7712destroy(){super.destroy();this.clearHints();} 7713normalize(){this.clearHints();this.updateHints();} 7714triggerDebouncedUpdateHints(selectionData=this.dependencies.selection.getSelectionData()){if(selectionData.documentSelectionIsInEditable){this.clearHints();} 7715this.debouncedUpdateHints();} 7716updateHints(){const selectionData=this.dependencies.selection.getSelectionData();const editableSelection=selectionData.editableSelection;this.clearHints();if(editableSelection.isCollapsed){const hints=this.getResource("hints");for(const provideTargets of this.getResource("hint_targets_providers")){for(const target of provideTargets(selectionData,this.editable)){const nodeHint=hints.find((h)=>target.matches(h.selector))?.text;if(target&&nodeHint&&isEmptyBlock(target)&&!isProtected(target)&&!descendants(target).some(isEditorTab)){this.makeHint(target,nodeHint);}}}}} 7717makeHint(el,text){this.dispatchTo("make_hint_handlers",el);el.setAttribute("o-we-hint-text",text);el.classList.add("o-we-hint");} 7718removeHint(el){el.removeAttribute("o-we-hint-text");removeClass(el,"o-we-hint");this.getResource("system_style_properties").forEach((n)=>el.style.removeProperty(n));} 7719clearHints(root=this.editable){for(const elem of selectElements(root,".o-we-hint")){this.removeHint(elem);}}} 7720return __exports;});; 7721 7722/* /html_editor/static/src/main/inline_code.js */ 7723odoo.define('@html_editor/main/inline_code',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/utils/resource','@html_editor/main/toolbar/toolbar_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{isBlock,closestBlock}=require("@html_editor/utils/blocks");const{splitTextNode,unwrapContents}=require("@html_editor/utils/dom");const{isElement,isTextNode,isVisible,isZwnbsp}=require("@html_editor/utils/dom_info");const{closestElement,selectElements,findFurthest}=require("@html_editor/utils/dom_traversal");const{DIRECTIONS,nodeSize}=require("@html_editor/utils/position");const{withSequence}=require("@html_editor/utils/resource");const{DISABLED_NAMESPACE}=require("@html_editor/main/toolbar/toolbar_plugin");const InlineCodePlugin=__exports.InlineCodePlugin=class InlineCodePlugin extends Plugin{static id="inlineCode";static dependencies=["clipboard","feff","history","input","selection","split"];resources={input_handlers:this.onInput.bind(this),selectionchange_handlers:this.handleSelectionChange.bind(this),normalize_handlers:this.normalize.bind(this),feff_providers:(root,cursors)=>[...selectElements(root,".o_inline_code")].flatMap((code)=>
7723this.dependencies.feff.surroundWithFeffs(code,cursors)),toolbar_namespace_providers:withSequence(70,(targetedNodes)=>{const hasInlineCode=targetedNodes.some((node)=>closestElement(node,"code.o_inline_code"));if(targetedNodes.length&&hasInlineCode&&targetedNodes.every((node)=>closestElement(node,"code.o_inline_code")||!isVisible(node))){return DISABLED_NAMESPACE;}}),paste_overrides:(selection,clipboardData)=>{const caretNode=selection.direction===DIRECTIONS.RIGHT?selection.anchorNode:selection.focusNode;if(closestElement(caretNode,"code.o_inline_code")){this.dependencies.clipboard.pasteText(clipboardData.getData("text/plain"));return true;}},is_formattable_node_predicates:(node)=>{if(closestElement(node,"code.o_inline_code")){return false;}},is_powerbox_available_predicates:(node)=>{if(closestElement(node,"code.o_inline_code")){return false;}},link_compatible_selection_predicates:()=>{const targetedNodes=this.dependencies.selection.getTargetedNodes();if(targetedNodes.length&&targetedNodes.every((node)=>closestElement(node,"code.o_inline_code"))){return false;}},};setup(){this.addDomListener(this.document,"keydown",this.onKeyDown.bind(this));} 7724handleSelectionChange(){if(this.historySavePointRestore){delete this.historySavePointRestore;}} 7725onKeyDown(){const selection=this.dependencies.selection.getEditableSelection();if(selection.isCollapsed||closestElement(selection.anchorNode,"code")||closestElement(selection.focusNode,"code")){return;} 7726const targetBlocks=this.dependencies.selection.getTargetedBlocks();const hasTextNode=this.dependencies.selection.getTargetedNodes().some(isTextNode);if(targetBlocks.size===1&&hasTextNode){this.historySavePointRestore=this.dependencies.history.makeSavePoint();}} 7727onInput(ev){const selection=this.dependencies.selection.getEditableSelection();if(ev.data!=="`"||closestElement(selection.anchorNode,"code")){return;} 7728if(this.historySavePointRestore){this.historySavePointRestore();let{anchorNode,anchorOffset,focusNode,focusOffset,direction}=this.dependencies.split.splitSelection();const blockEl=closestBlock(anchorNode);const deepChild=(node,offset)=>(node===blockEl?node.childNodes[offset]:node);anchorNode=deepChild(anchorNode,anchorOffset);focusNode=deepChild(focusNode,focusOffset);if(direction===DIRECTIONS.LEFT){[anchorNode,anchorOffset,focusNode,focusOffset]=[focusNode,focusOffset,anchorNode,anchorOffset,];} 7729const furthestAnchorElement=findFurthest(anchorNode,blockEl,(n)=>!isBlock(n));let start=this.dependencies.split.splitAroundUntil(anchorNode,furthestAnchorElement);const furthestFocusElement=findFurthest(focusNode,blockEl,(n)=>!isBlock(n));const end=this.dependencies.split.splitAroundUntil(focusNode,furthestFocusElement);let codeElement=this.document.createElement("code");codeElement.classList.add("o_inline_code");start.before(codeElement);while(start){if(isElement(start)){for(const code of selectElements(start,"code")){start=unwrapContents(code)[0];}} 7730const next=start.nextSibling;if(start.nodeName==="IMG"){if(start!==end&&next){codeElement=this.document.createElement("code");codeElement.classList.add("o_inline_code");}}else{if(!codeElement.isConnected){start.before(codeElement);} 7731codeElement.appendChild(start);} 7732if(start===end){break;} 7733start=next;} 7734this.dispatchTo("to_inline_code_processors",codeElement);this.dependencies.selection.setSelection({anchorNode:codeElement,anchorOffset:nodeSize(codeElement),});this.dependencies.history.addStep();delete this.historySavePointRestore;return;} 7735let textNode=selection.startContainer;const wholeText=textNode.wholeText;const textHasTwoTicks=/`[^`]+`/.test(wholeText);if(textHasTwoTicks&&wholeText.replace(/`/g,"").length){let offset=selection.startOffset;let sibling=textNode.previousSibling;while(sibling&&sibling.nodeType===Node.TEXT_NODE){if(!isZwnbsp(sibling)){offset+=sibling.textContent.length;} 7736sibling.textContent+=textNode.textContent;textNode.remove();textNode=sibling;sibling=sibling.previousSibling;} 7737sibling=textNode.nextSibling;while(sibling&&sibling.nodeType===Node.TEXT_NODE){if(!isZwnbsp(sibling)){textNode.textContent+=sibling.textContent;} 7738sibling.remove();sibling=sibling.nextSibling;} 7739this.dependencies.selection.setSelection({anchorNode:textNode,anchorOffset:offset,});this.dependencies.history.addStep();const insertedBacktickIndex=offset-1;const textBeforeInsertedBacktick=textNode.textContent.substring(0,insertedBacktickIndex);let startOffset,endOffset;const isClosingForward=textBeforeInsertedBacktick.includes("`");if(isClosingForward){startOffset=textBeforeInsertedBacktick.lastIndexOf("`");endOffset=insertedBacktickIndex;}else{const textAfterInsertedBacktick=textNode.textContent.substring(offset);startOffset=insertedBacktickIndex;endOffset=offset+textAfterInsertedBacktick.indexOf("`");} 7740if(endOffset&&endOffset<textNode.textContent.length){splitTextNode(textNode,endOffset+1,DIRECTIONS.LEFT);} 7741if(startOffset){splitTextNode(textNode,startOffset);} 7742const splitLimit=findFurthest(textNode,closestBlock(textNode),(n)=>!isBlock(n));const splitNode=this.dependencies.split.splitAroundUntil(textNode,splitLimit);const codeElement=this.document.createElement("code");codeElement.classList.add("o_inline_code");codeElement.textContent=splitNode.textContent.substring(1,splitNode.textContent.length-1);splitNode.replaceWith(codeElement);if(!codeElement.textContent.length){this.dependencies.history.addStep();this.dependencies.selection.setSelection({anchorNode:codeElement.firstChild,anch
7742orOffset:1,});}else if(isClosingForward){this.dependencies.history.addStep();this.dependencies.selection.setSelection({anchorNode:codeElement.nextSibling,anchorOffset:1,});}else{this.dependencies.history.addStep();this.dependencies.selection.setSelection({anchorNode:codeElement.firstChild,anchorOffset:0,});}}} 7743normalize(rootEl){for(const el of selectElements(rootEl,"code.o_inline_code")){if([...el.childNodes].every((node)=>node.nodeType===Node.TEXT_NODE&&/^\uFEFF*$/.test(node.nodeValue))){el.remove();}}}} 7744return __exports;});; 7745 7746/* /html_editor/static/src/main/link/command_category.js */ 7747odoo.define('@html_editor/main/link/command_category',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const commandCategoryRegistry=registry.category("command_categories");commandCategoryRegistry.add("shortcut_conflict",{},{sequence:5});return __exports;});; 7748 7749/* /html_editor/static/src/main/link/link_paste_plugin.js */ 7750odoo.define('@html_editor/main/link/link_paste_plugin',['@html_editor/utils/dom_traversal','@html_editor/main/link/utils','@html_editor/utils/url','@html_editor/plugin','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{closestElement}=require("@html_editor/utils/dom_traversal");const{URL_REGEX,cleanZWChars}=require("@html_editor/main/link/utils");const{isImageUrl}=require("@html_editor/utils/url");const{Plugin}=require("@html_editor/plugin");const{childNodeIndex}=require("@html_editor/utils/position");const LinkPastePlugin=__exports.LinkPastePlugin=class LinkPastePlugin extends Plugin{static id="linkPaste";static dependencies=["link","clipboard","selection","dom","history"];resources={before_paste_handlers:this.selectFullySelectedLink.bind(this),paste_text_overrides:this.handlePasteText.bind(this),};handlePasteText(selection,text){let splitAroundUrl;if(!text.match(/\${.*}/gi)){splitAroundUrl=text.split(URL_REGEX);splitAroundUrl=splitAroundUrl.filter((_,index)=>(index+1)%3);} 7751if(!splitAroundUrl||splitAroundUrl.length<3||closestElement(selection.anchorNode,"pre")){return false;} 7752if(splitAroundUrl.length===3&&!splitAroundUrl[0]&&!splitAroundUrl[2]){this.handlePasteTextUrl(selection,text);}else{this.handlePasteTextMultiUrl(selection,splitAroundUrl);} 7753return true;} 7754handlePasteTextUrl(selection,text){const selectionIsInsideALink=!!closestElement(selection.anchorNode,"a");const url=/^https?:\/\//i.test(text)?text:"http://"+text;if(selectionIsInsideALink){this.handlePasteTextUrlInsideLink(text,url);return;} 7755if(this.delegateTo("paste_url_overrides",text,url)){return;} 7756this.dependencies.link.insertLink(url,text);} 7757handlePasteTextUrlInsideLink(text,url){if(isImageUrl(url)){const img=this.document.createElement("IMG");img.setAttribute("src",url);this.dependencies.dom.insert(img);}else{this.dependencies.dom.insert(text);}} 7758handlePasteTextMultiUrl(selection,splitAroundUrl){const selectionIsInsideALink=!!closestElement(selection.anchorNode,"a");for(let i=0;i<splitAroundUrl.length;i++){const url=/^https?:\/\//gi.test(splitAroundUrl[i])?splitAroundUrl[i]:"http://"+splitAroundUrl[i];if(i%2&&!selectionIsInsideALink){this.dependencies.dom.insert(this.dependencies.link.createLink(url,splitAroundUrl[i]));}else if(splitAroundUrl[i]!==""){this.dependencies.clipboard.pasteText(splitAroundUrl[i]);}}} 7759selectFullySelectedLink(selection){const link=closestElement(selection.anchorNode,"a");if(link?.parentElement?.isContentEditable&&cleanZWChars(selection.textContent())===cleanZWChars(link.innerText)&&!this.getResource("unremovable_node_predicates").some((p)=>p(link))){this.dependencies.selection.setSelection({anchorNode:link.parentElement,anchorOffset:childNodeIndex(link)+(selection.direction?0:1),focusNode:link.parentElement,focusOffset:childNodeIndex(link)+(selection.direction?1:0),});}}} 7760return __exports;});; 7761 7762/* /html_editor/static/src/main/link/link_plugin.js */ 7763odoo.define('@html_editor/main/link/link_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/utils/dom','@html_editor/utils/selection','@web/core/l10n/translation','@html_editor/main/link/link_popover','@html_editor/utils/position','@html_editor/main/link/utils','@html_editor/utils/dom_info','@web/core/utils/concurrency','@web/core/network/rpc','@web/core/utils/functions','@html_editor/utils/resource','@html_editor/utils/blocks','@html_editor/core/selection_plugin','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement,selectElements}=require("@html_editor/utils/dom_traversal");const{mergeAdjacentTextNodes,unwrapContents}=require("@html_editor/utils/dom");const{findInSelection,callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{LinkPopover}=require("@html_editor/main/link/link_popover");const{DIRECTIONS,leftPos,nodeSize,rightPos}=require("@html_editor/utils/position");const{EMAIL_REGEX,URL_REGEX,cleanZWChars,deduceURLfromText}=require("@html_editor/main/link/utils");const{isContentEditable,isElement,isPhrasingContent,isProtected,isProtecting,isVisible,isZwnbsp,}=require("@html_editor/utils/dom_info");const{KeepLast}=require("@web/core/utils/concurrency");const{rpc}=require("@web/core/network/rpc");const{memoize}=require("@web/core/utils/functions");const{withSequence}=require("@html_editor/utils/resource");const{isBlock,closestBlock}=require("@html_editor/utils/blocks");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{isBrowserFirefox,isBrowserSafari}=require("@web/core/browser/feature_detection");function isLinkActive(selection){const linkElementAnchor=closestElement(selection.anchorNode,"A");const linkElementFocus=closestElement(selection.focusNode,"A");if(linkElementFocus&&linkElementAnchor){return linkElementAnchor===linkElementFocus;} 7764if(linkElementAnchor||linkElementFocus){return true;} 7765return false;} 7766function isPositionAtEdgeofLink(link,offset){const childNodes=[...link.childNodes];if(!childNodes.length){return"end";}
7767let firstVisibleIndex=childNodes.findIndex(isVisible);firstVisibleIndex=firstVisibleIndex===-1?0:firstVisibleIndex;if(offset<=firstVisibleIndex){return"start";} 7768let lastVisibleIndex=childNodes.reverse().findIndex(isVisible);lastVisibleIndex=lastVisibleIndex===-1?0:childNodes.length-lastVisibleIndex;if(offset>=lastVisibleIndex){return"end";} 7769return false;} 7770async function fetchExternalMetaData(url){try{return await rpc("/html_editor/link_preview_external",{preview_url:url,});}catch{return;}} 7771async function fetchInternalMetaData(url){const keepLastPromise=new KeepLast();const urlParsed=new URL(url);if(urlParsed.protocol!==window.location.protocol){urlParsed.protocol=window.location.protocol;} 7772const result=await keepLastPromise.add(fetch(urlParsed)).then((response)=>response.text()).then(async(content)=>{const html_parser=new window.DOMParser();const doc=html_parser.parseFromString(content,"text/html");const internalUrlMetaData=await rpc("/html_editor/link_preview_internal",{preview_url:urlParsed.href,});internalUrlMetaData["favicon"]=doc.querySelector("link[rel~='icon']");internalUrlMetaData["ogTitle"]=doc.querySelector("[property='og:title']");internalUrlMetaData["title"]=doc.querySelector("title");return internalUrlMetaData;}).catch((error)=>{if(error instanceof Error){return Promise.reject(error);}});return result;} 7773async function fetchAttachmentMetaData(url,ormService){try{const urlParsed=new URL(url,window.location.origin);const attachementId=parseInt(urlParsed.pathname.split("/").pop());const result=(await ormService.read("ir.attachment",[attachementId],["name","mimetype","type"]))[0];return result||{name:url,type:"url"};}catch{return{name:url,type:"url"};}} 7774const LinkPlugin=__exports.LinkPlugin=class LinkPlugin extends Plugin{static id="link";static dependencies=["dom","history","input","selection","split","lineBreak","overlay","color","baseContainer","feff",];static defaultConfig={allowStripDomain:true,};static shared=["createLink","insertLink","getPathAsUrlCommand"];resources={user_commands:[{id:"openLinkTools",title:_t("Link"),description:_t("Add a link"),icon:"fa-link",run:({link,type}={})=>this.openLinkTools(link,type),isAvailable:(selection)=>{const linkEl=findInSelection(selection,"a");return linkEl?this.getResource("link_popovers").some((p)=>p.isAvailable(linkEl)):isHtmlContentSupported(selection);},},{id:"removeLinkFromSelection",title:_t("Remove Link"),description:_t("Remove Link"),icon:"fa-unlink",isAvailable:(selection)=>
7774{if(!isHtmlContentSupported(selection)){return false;} 7775for(const node of this.dependencies.selection.getTargetedNodes()){const linkEl=closestElement(node,"a");if(linkEl&&!this.isLinkImmutable(linkEl)&&linkEl.parentElement.isContentEditable){return true;}}},run:this.removeLinkFromSelection.bind(this),},],toolbar_groups:[withSequence(40,{id:"link",namespaces:["compact","expanded"]}),withSequence(30,{id:"image_link",namespaces:["image","icon"]}),],toolbar_items:[{id:"link",groupId:"link",commandId:"openLinkTools",isActive:isLinkActive,isDisabled:()=>!this.isLinkAllowedOnSelection(),},{id:"unlink",groupId:"link",commandId:"removeLinkFromSelection",isDisabled:()=>this.removeLinkFromSelectionIsDisabled(),},{id:"link",groupId:"image_link",commandId:"openLinkTools",isActive:isLinkActive,isDisabled:()=>!this.isLinkAllowedOnSelection(),},{id:"unlink",groupId:"image_link",commandId:"removeLinkFromSelection",isDisabled:()=>this.removeLinkFromSelectionIsDisabled(),},],powerbox_categories:withSequence(50,{id:"navigation",name:_t("Navigation")}),powerbox_items:[{categoryId:"navigation",commandId:"openLinkTools",},{title:_t("Button"),description:_t("Add a button"),categoryId:"navigation",commandId:"openLinkTools",commandParams:{type:"primary"},},],power_buttons:withSequence(10,{commandId:"openLinkTools",commandParams:{type:"primary"},description:_t("Add a button"),icon:"fa-square",}),link_popovers:[withSequence(50,{PopoverClass:LinkPopover,isAvailable:(linkEl)=>!linkEl||!this.isLinkImmutable(linkEl),getProps:(props)=>props,}),],immutable_link_selectors:['[data-bs-toggle="tab"]','[data-bs-toggle="collapse"]','[data-bs-toggle="dropdown"]',".dropdown-item","[data-oe-model]",":has(>[data-oe-model])",".o_prevent_link_editor a",],legit_empty_link_predicates:(linkEl)=>linkEl.hasAttribute("data-mimetype"),unsplittable_node_predicates:(node)=>node.nodeName==="A",fully_selected_node_predicates:(node,selection)=>node.nodeName==="A"&&!node.classList.contains("btn")&&cleanZWChars(selection.textContent())===cleanZWChars(node.innerText),beforeinput_handlers:[withSequence(5,this.onBeforeInputPrepareConvertToLink.bind(this)),this.onBeforeInputFixFirefoxSelection.bind(this),withSequence(20,this.onBeforeInputConvertToLink.bind(this)),],input_handlers:[this.onInputDeleteNormalizeLink.bind(this),this.onInputConvertToLink.bind(this),],before_delete_handlers:this.updateCurrentLinkSyncState.bind(this),delete_handlers:this.onInputDeleteNormalizeLink.bind(this),before_paste_handlers:this.updateCurrentLinkSyncState.bind(this),after_paste_handlers:this.onPasteNormalizeLink.bind(this),selectionchange_handlers:this.handleSelectionChange.bind(this),clean_for_save_handlers:({root})=>this.removeEmptyLinks(root),normalize_handlers:this.normalizeLink.bind(this),after_insert_handlers:this.handleAfterInsert.bind(this),on_will_remove_handlers:()=>this.closeLinkTools(),split_element_block_overrides:this.handleSplitBlock.bind(this),insert_line_break_element_overrides:this.handleInsertLineBreak.bind(this),delete_image_overrides:this.deleteImageLink.bind(this),delete_backward_overrides:withSequence(15,this.handleDeleteBackward.bind(this)),double_click_overrides:this.doubleClickLinkOverrides.bind(this),triple_click_overrides:this.tripleClickButtonOverrides.bind(this),to_inline_code_processors:(node)=>{this.removeEmptyLinks(node);for(const btn of selectElements(node,"a.btn")){[...btn.attributes].forEach((attr)=>attr.name!=="href"&&btn.removeAttribute(attr.name));}},};setup(){this.initializePopovers();this.currentOverlay=this.getActivePopover().overlay;this.addDomListener(this.editable,"click",(ev)=>{const linkEl=ev.target.closest("a");if(linkEl){const selection=this.dependencies.selection.getEditableSelection();const clickedInsideNonEditableLink=!linkEl.isContentEditable&&!isContentEditable(closestElement(selection.anchorNode));if(ev.ctrlKey||ev.metaKey){window.open(linkEl.href,"_blank");}else if(clickedInsideNonEditableLink){this.dependencies.selection.setSelection({anchorNode:linkEl,anchorOffset:0,});} 7776ev.preventDefault();}});this.addDomListener(this.editable,"pointerdown",(ev)=>{const clickedEl=this.document.elementFromPoint(ev.clientX,ev.clientY);if(!clickedEl||!isContentEditable(clickedEl)){return;} 7777let caretPosition={};if(this.document.caretPositionFromPoint){const pos=this.document.caretPositionFromPoint(ev.clientX,ev.clientY);caretPosition=pos;}else if(this.document.caretRangeFromPoint){const range=document.caretRangeFromPoint(ev.clientX,ev.clientY);caretPosition.offsetNode=range?.startContainer;caretPosition.offset=range?.startOffset;} 7778const link=caretPosition?.offsetNode&&closestElement(caretPosition.offsetNode,"A");if(clickedEl.nodeName==="A"&&isZwnbsp(caretPosition.offsetNode)){const isFirstFeff=!caretPosition.offsetNode.previousSibling;if(isFirstFeff&&caretPosition.offset===0){ev.preventDefault();this.dependencies.selection.setSelection({anchorNode:clickedEl,anchorOffset:1,});}}else if(clickedEl.nodeName!=="A"&&link){ev.preventDefault();const anchorFeff=nodeSize(caretPosition.offsetNode)===caretPosition.offset?link.nextSibling:link.previousSibling;if(anchorFeff&&isZwnbsp(anchorFeff)){this.dependencies.selection.setSelection({anchorNode:anchorFeff,anchorOffset:1,});}}});this.addDomListener(this.editable,"auxclick",(ev)=>{if(ev.button===1){const link=closestElement(ev.target,"a");if(link?.href){window.open(link.href,"_blank");ev.preventDefault();}}});this.unregisterLinkCommandCallback=this.services.command?.add("Create link",()=>{this.dependencies.selection.focusEditable();setTimeout(()=>this.openLinkTools());},{hotkey:"control+k",category:"shortcut_conflict",isAvailable:()=>{const selectionData=this.dependencies.selection.getSelectionData();return(selectionData.documentSelectionIsInEditable&&isHtmlContentSupported(selectionData.editableSelection)&&this.isLinkAllowedOnSelection());},});this.getExternalMetaData=memoize(fetchExternalMetaData);
7778this.getInternalMetaData=memoize(fetchInternalMetaData);this.getAttachmentMetadata=memoize((url)=>fetchAttachmentMetaData(url,this.services.orm));this.LinkPopoverState={editing:false};this.newlyInsertedLinks=new Set();} 7779destroy(){this.unregisterLinkCommandCallback?.();} 7780createLink(url,label=""){const link=this.document.createElement("a");if(url!==undefined){link.setAttribute("href",url);} 7781for(const[param,value]of Object.entries(this.config.defaultLinkAttributes||{})){link.setAttribute(param,`${value}`);} 7782link.innerText=label;this.dispatchTo("create_link_handlers",link);return link;} 7783insertLink(url,label){const selection=this.dependencies.selection.getEditableSelection();let link=closestElement(selection.anchorNode,"a");if(link){link.setAttribute("href",url);link.innerText=label;}else{link=this.createLink(url,label);this.dependencies.dom.insert(link);} 7784this.dependencies.history.addStep();const linkParent=link.parentElement;const linkOffset=Array.from(linkParent.childNodes).indexOf(link);this.dependencies.selection.setSelection({anchorNode:linkParent,anchorOffset:linkOffset+1},{normalize:false});} 7785getPathAsUrlCommand(text,url){const pasteAsURLCommand={title:_t("Paste as URL"),description:_t("Create an URL."),icon:"fa-link",run:()=>{this.dispatchTo("before_paste_handlers",this.dependencies.selection.getEditableSelection());this.dependencies.dom.insert(this.createLink(url,text));this.dependencies.history.addStep();},};return pasteAsURLCommand;} 7786isLinkAllowedOnSelection(){const isLinkCompatible=this.checkPredicates("link_compatible_selection_predicates");if(isLinkCompatible!==undefined){return isLinkCompatible;} 7787const targetedNodes=this.dependencies.selection.getTargetedNodes();const targetedBlocks=targetedNodes.filter(isBlock);const linksInSelection=targetedNodes.filter((n)=>n.tagName==="A");return(linksInSelection.length<2&&targetedBlocks.every((node)=>targetedNodes.every((other)=>node.contains(other)||other.contains(node)))&&targetedNodes.some(this.dependencies.selection.isNodeEditable));} 7788openLinkTools(linkElement,type){this.currentOverlay.close();this.LinkPopoverState.editing=false;let selection=this.dependencies.selection.getEditableSelection();const commonAncestor=closestElement(selection.commonAncestorContainer);const isNonEditableLink=commonAncestor.nodeName==="A"&&!commonAncestor.isContentEditable;if(!this.isLinkAllowedOnSelection()&&!isNonEditableLink){return this.services.notification.add(_t("Unable to create a link on the current selection."),{type:"danger"});} 7789let cursorsToRestore=this.dependencies.selection.preserveSelection();linkElement=linkElement||findInSelection(selection,"a");this.type=type;if(linkElement&&(!linkElement.contains(selection.anchorNode)||!linkElement.contains(selection.focusNode))){this.extendLinkToSelection(linkElement,selection);linkElement=findInSelection(selection,"a");this.dependencies.history.addStep();cursorsToRestore=this.dependencies.selection.preserveSelection();} 7790this.linkInDocument=linkElement;if(!linkElement){linkElement=this.createLink(undefined,selection.textContent());} 7791const selectionTextContent=cleanZWChars(selection?.textContent());const isImage=!!findInSelection(selection,"img, .fa");const applyCallback=(url,label,classes,customStyle,linkTarget,attachmentId,relValue)=>{if(this.linkInDocument){if(url){this.linkInDocument.href=url;}else{this.linkInDocument.removeAttribute("href");} 7792if(relValue){this.linkInDocument.setAttribute("rel",relValue);}else{this.linkInDocument.removeAttribute("rel");} 7793if(linkTarget){this.linkInDocument.setAttribute("target",linkTarget);}else{this.linkInDocument.removeAttribute("target");} 7794if(!isImage){if(classes){this.linkInDocument.className=classes;}else{this.linkInDocument.removeAttribute("class");} 7795if(customStyle){this.linkInDocument.setAttribute("style",customStyle);}else{this.linkInDocument.removeAttribute("style");} 7796if(this.linkInDocument.childElementCount==0&&cleanZWChars(this.linkInDocument.innerText)!==label){this.linkInDocument.innerText=label;cursorsToRestore=null;}}}else if(url){if((selectionTextContent&&selectionTextContent===label)||isImage){const link=this.createLink(url);if(relValue){link.setAttribute("rel",relValue);} 7797const image=isImage&&findInSelection(selection,"img");const figure=image?.parentElement?.matches("figure[contenteditable=false]")&&image.parentElement;if(figure){figure.before(link);link.append(figure);if(link.parentElement===this.editable){const baseContainer=this.dependencies.baseContainer.createBaseContainer();link.before(baseContainer);baseContainer.append(link);}}else{const content=this.dependencies.selection.extractContent(selection);link.append(content);link.normalize();cursorsToRestore=null;selection=this.dependencies.selection.getEditableSelection();const anchorClosestElement=closestElement(selection.anchorNode);
7797if(commonAncestor!==anchorClosestElement){const[anchorNode,anchorOffset]=rightPos(anchorClosestElement);this.dependencies.selection.setSelection({anchorNode,anchorOffset},{normalize:false});} 7798this.dependencies.dom.insert(link);} 7799this.linkInDocument=link;}else if(label){const link=this.createLink(url,label);if(classes){link.className=classes;} 7800if(customStyle){link.setAttribute("style",customStyle);} 7801if(linkTarget){link.setAttribute("target",linkTarget);} 7802this.linkInDocument=link;cursorsToRestore=null;this.dependencies.dom.insert(link);}} 7803if(attachmentId){this.linkInDocument.dataset.attachmentId=attachmentId;}};this.restoreSavePoint=this.dependencies.history.makeSavePoint();const props={document:this.document,linkElement,isImage:isImage,onApply:(...args)=>{delete this._isNavigatingByMouse;applyCallback(...args);this.closeLinkTools(cursorsToRestore);this.dependencies.selection.focusEditable();this.dependencies.history.addStep();},onChange:applyCallback,onDiscard:()=>{this.restoreSavePoint();if(linkElement.isConnected){this.openLinkTools(linkElement);}else{this.linkInDocument=null;this.currentOverlay.close();} 7804this.dependencies.selection.focusEditable();},onRemove:()=>{this.removeLinkInDocument();this.linkInDocument=null;this.currentOverlay.close();},onCopy:()=>{this.linkInDocument=null;this.currentOverlay.close();},onEdit:()=>{this.restoreSavePoint=this.dependencies.history.makeSavePoint();},getInternalMetaData:this.getInternalMetaData,getExternalMetaData:this.getExternalMetaData,getAttachmentMetadata:this.getAttachmentMetadata,recordInfo:this.config.getRecordInfo?.()||{},canEdit:(!this.linkInDocument||!this.linkInDocument.classList.contains("o_link_readonly"))&&this.linkInDocument?.isContentEditable,canRemove:this.linkInDocument&&this.linkInDocument.parentElement.isContentEditable&&!this.isUnremovable(this.linkInDocument),canUpload:this.config.allowFile,onUpload:this.config.onAttachmentChange,type:this.type||"",LinkPopoverState:this.LinkPopoverState,showReplaceTitleBanner:this.newlyInsertedLinks.has(linkElement),allowCustomStyle:this.config.allowCustomStyle,allowTargetBlank:this.config.allowTargetBlank,allowStripDomain:this.config.allowStripDomain,};const popover=this.getActivePopover(linkElement);if(popover){this.currentOverlay=popover.overlay;if(!linkElement.href&&(!this.linkInDocument||this.linkInDocument?.isContentEditable)){this.LinkPopoverState.editing=true;} 7805this.currentOverlay.open({props:popover.getProps(props)});if(this.linkInDocument){if(this.newlyInsertedLinks.has(this.linkInDocument)){this.newlyInsertedLinks.delete(this.linkInDocument);}}}} 7806closeLinkTools(cursors=null){const link=this.linkInDocument;this.linkInDocument=null;if(this.currentOverlay.isOpen&&document.querySelector(".o-we-linkpopover")){this.currentOverlay.close();if(link&&link.isConnected){this.dependencies.selection.setSelection({anchorNode:link,anchorOffset:0,focusNode:link,focusOffset:nodeSize(link),});const saveCustomStyle=link.getAttribute("style");link.removeAttribute("style");this.dependencies.color.removeAllColor();if(saveCustomStyle&&this.config.allowCustomStyle&&link.className.includes("custom")){link.setAttribute("style",saveCustomStyle);} 7807if(cleanZWChars(link.textContent)===""&&!link.querySelector("img, .fa")){const[anchorNode,anchorOffset]=rightPos(link);this.dependencies.selection.setSelection({anchorNode,anchorOffset},{normalize:false});link.remove();}else if(cursors){cursors.restore();}else{this.dependencies.selection.setCursorEnd(link);}}}} 7808normalizeLink(root){for(const anchorEl of selectElements(root,"a")){if(/btn(-[a-z0-9_-]*)custom/.test(anchorEl.className)){continue;} 7809const{color}=anchorEl.style;const childNodes=[...anchorEl.childNodes];if(color&&childNodes.every(isPhrasingContent)){anchorEl.style.removeProperty("color");const font=selectElements(anchorEl,"font").next().value;if(font&&cleanZWChars(anchorEl.textContent)===font.textContent){continue;} 7810const newFont=this.document.createElement("font");newFont.append(...childNodes);anchorEl.appendChild(newFont);this.dependencies.color.colorElement(newFont,color,"color");} 7811const hasUnsupportedMedia=anchorEl.querySelector("a, iframe");
7811if(hasUnsupportedMedia){this.removeLinkInDocument(anchorEl);}}} 7812handleSelectionChange(selectionData){const selection=selectionData.editableSelection;const anchorNode=this.document.getSelection()?.anchorNode;const isSelectionInProtected=this.document.getSelection()?.isCollapsed&&(isProtecting(anchorNode)||isProtected(anchorNode));if(!selectionData.currentSelectionIsInEditable||isSelectionInProtected){const popoverEl=document.querySelector(".o-we-linkpopover");const anchorNode=document.getSelection()?.anchorNode;if((popoverEl&&!selectionData.documentSelection)||(anchorNode&&isElement(anchorNode)&&anchorNode.closest(".o-we-linkpopover"))){return;} 7813this.linkInDocument=null;this.closeLinkTools();}else if(!selection.isCollapsed){const imageNode=findInSelection(selection,"img, .fa");const parentElement=imageNode?.parentElement;const linkContainingImage=imageNode&&closestElement(imageNode,"a");if(linkContainingImage&&this.isLinkAllowedOnSelection()&&parentElement.contains(selection.anchorNode)&&parentElement.contains(selection.focusNode)){this.openLinkTools(linkContainingImage);}else{this.linkInDocument=null;this.closeLinkTools();}}else{const closestLinkElement=closestElement(selection.anchorNode,"A");const isLinkEditable=this.getResource("is_link_editable_predicates").some((p)=>p(closestLinkElement));if(closestLinkElement){if(closestLinkElement!==this.linkInDocument||!this.currentOverlay.isOpen){this.openLinkTools(closestLinkElement);}}else if(isLinkEditable){this.openLinkTools(closestLinkElement);}else{this.linkInDocument=null;this.closeLinkTools();}}} 7814extendLinkToSelection(linkElement){this.dependencies.split.splitSelection();const selectedNodes=this.dependencies.selection.getTargetedNodes();let before=linkElement.previousSibling;while(before!==null&&selectedNodes.includes(before)){linkElement.insertBefore(before,linkElement.firstChild);before=linkElement.previousSibling;} 7815let after=linkElement.nextSibling;while(after&&selectedNodes.includes(after)){linkElement.appendChild(after);after=linkElement.nextSibling;} 7816this.dependencies.selection.setCursorEnd(linkElement);} 7817isUnremovable(linkEl){return this.getResource("unremovable_node_predicates").some((p)=>p(linkEl));} 7818removeLinkInDocument(link=this.linkInDocument){if(!link.parentElement.isContentEditable||this.isUnremovable(link)){return;} 7819const cursors=this.dependencies.selection.preserveSelection();if(link&&link.isContentEditable&&link.parentElement.isContentEditable){cursors.update(callbacksForCursorUpdate.unwrap(link));unwrapContents(link);} 7820cursors.restore();this.linkInDocument=null;this.dependencies.selection.focusEditable();this.dependencies.history.addStep();} 7821removeLinkFromSelectionIsDisabled(selection){for(const node of this.dependencies.selection.getTargetedNodes()){const linkEl=closestElement(node,"a");if(linkEl&&!this.isLinkImmutable(linkEl)&&!this.isUnremovable(linkEl)){return false;}} 7822return true;} 7823removeLinkFromSelection(){const selection=this.dependencies.split.splitSelection();let{anchorNode,focusNode,anchorOffset,focusOffset}=selection;const direction=selection.direction;let[startLink,endLink]=[closestElement(anchorNode,"a"),closestElement(focusNode,"a"),];let cursors;if(startLink){cursors=this.dependencies.selection.preserveSelection();this.dependencies.feff.removeFeffs(startLink,cursors);cursors.restore();} 7824if(endLink&&startLink!==endLink){cursors=this.dependencies.selection.preserveSelection();this.dependencies.feff.removeFeffs(endLink,cursors);cursors.restore();} 7825({anchorNode,focusNode,anchorOffset,focusOffset}=this.dependencies.selection.getEditableSelection());cursors=this.dependencies.selection.preserveSelection();let targetedNodes=this.dependencies.selection.getTargetedNodes();const selectedImageNodes=targetedNodes.filter((node)=>node.tagName==="IMG");if(selectedImageNodes.length&&startLink&&endLink&&startLink===endLink){for(const imageNode of selectedImageNodes){let imageLink;const figure=closestElement(imageNode,"figure");
7825if(direction===DIRECTIONS.RIGHT){imageLink=this.dependencies.split.splitAroundUntil(figure||imageNode,endLink);}else{imageLink=this.dependencies.split.splitAroundUntil(figure||imageNode,startLink);} 7826cursors.update(callbacksForCursorUpdate.unwrap(imageLink));unwrapContents(imageLink);if(figure&&figure.parentElement!==this.editable){unwrapContents(figure.parentElement);} 7827[startLink,endLink]=[closestElement(anchorNode,"a"),closestElement(focusNode,"a"),];} 7828cursors.restore();if(selectedImageNodes.length===1&&selectedImageNodes.length===targetedNodes.length){this.dependencies.history.addStep();return;}} 7829const startBlock=closestBlock(startLink);const endBlock=closestBlock(endLink);if(startLink&&startLink.isConnected&&startLink.parentElement.isContentEditable&&!this.isUnremovable(startLink)){anchorNode=this.dependencies.split.splitAroundUntil(anchorNode,startLink);anchorOffset=direction===DIRECTIONS.RIGHT?0:nodeSize(anchorNode);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset},{normalize:true});} 7830if(endLink&&endLink.isConnected&&endLink.parentElement.isContentEditable&&!this.isUnremovable(endLink)){focusNode=this.dependencies.split.splitAroundUntil(focusNode,closestElement(focusNode,"a"));focusOffset=direction===DIRECTIONS.RIGHT?nodeSize(focusNode):0;this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset},{normalize:true});} 7831targetedNodes=this.dependencies.selection.getTargetedNodes();const links=new Set(targetedNodes.map((node)=>closestElement(node,"a")).filter((a)=>a&&a.isContentEditable&&a.parentElement.isContentEditable&&!this.isUnremovable(a)));if(links.size){for(const link of links){cursors.update(callbacksForCursorUpdate.unwrap(link));unwrapContents(link);} 7832cursors.restore();} 7833if(startBlock){this.removeEmptyLinks(startBlock);} 7834if(endBlock&&endBlock!==startBlock){this.removeEmptyLinks(endBlock);} 7835this.dependencies.history.addStep();} 7836removeEmptyLinks(root){const remove=(node)=>{for(const child of node.childNodes){remove(child);} 7837if(!this.isUnremovable(node)){node.before(...node.childNodes);node.remove();}};for(const link of root.querySelectorAll("a")){if([...link.childNodes].some(isVisible)||!link.parentElement.isContentEditable||this.isUnremovable(link)||this.getResource("legit_empty_link_predicates").some((p)=>p(link))){continue;} 7838remove(link);}} 7839updateCurrentLinkSyncState(){const{anchorNode}=this.dependencies.selection.getEditableSelection();const linkEl=closestElement(anchorNode,"a");if(linkEl&&linkEl.isContentEditable){const label=linkEl.innerText;const url=deduceURLfromText(label,linkEl);const href=linkEl.getAttribute("href");if(url&&(url===href||url+"/"===href||url===deduceURLfromText(href,linkEl))){this.isCurrentLinkInSync=true;}}} 7840onBeforeInputPrepareConvertToLink(ev){if(ev.inputType==="insertParagraph"||ev.inputType==="insertLineBreak"||(ev.inputType==="insertText"&&ev.data===" ")){this.convertToLink=this.prepareConvertToLink();if(this.convertToLink&&ev.inputType==="insertText"&&isBrowserSafari()){ev.preventDefault();const{anchorNode}=this.dependencies.selection.getEditableSelection();anchorNode.textContent="\u00a0"+anchorNode.textContent;this.dependencies.selection.setSelection({anchorNode,anchorOffset:1,});this.dependencies.history.addStep();this.convertToLink();this.dependencies.history.addStep();delete this.convertToLink;}}} 7841onBeforeInputFixFirefoxSelection(ev){const selection=this.document.getSelection();if(ev.inputType==="insertText"&&selection.isCollapsed&&selection.anchorNode.nodeType===Node.TEXT_NODE&&selection.anchorNode.parentElement.tagName==="A"){const offset=selection.anchorOffset;selection.collapse(selection.anchorNode,0);selection.collapse(selection.anchorNode,offset);} 7842this.updateCurrentLinkSyncState();} 7843onBeforeInputConvertToLink(ev){if(this.convertToLink){if(ev.inputType==="insertParagraph"||ev.inputType==="insertLineBreak"){this.convertToLink();this.dependencies.history.addStep();delete this.convertToLink;}}} 7844onInputConvertToLink(ev){if(this.convertToLink){if(ev.inputType==="insertText"&&ev.data===" "){this.convertToLink();this.dependencies.history.addStep();delete this.convertToLink;}}} 7845onInputDeleteNormalizeLink(){const{anchorNode}=this.dependencies.selection.getEditableSelection();const linkEl=closestElement(anchorNode,"a");if(linkEl&&linkEl.isContentEditable){const label=linkEl.innerText;const url=deduceURLfromText(label,linkEl);if(url&&this.isCurrentLinkInSync){linkEl.setAttribute("href",url);this.isCurrentLinkInSync=false;if(this.currentOverlay.isOpen){this.currentOverlay.close();}}}} 7846onPasteNormalizeLink(){this.updateCurrentLinkSyncState();this.onInputDeleteNormalizeLink();} 7847deleteImageLink(imageToDelete){if(imageToDelete.parentElement.tagName==="A"&&!this.isUnremovable(imageToDelete.parentElement)&&imageToDelete.parentElement.parentElement.isContentEditable){const cursors=this.dependencies.selection.preserveSelection();cursors.update(callbacksForCursorUpdate.remove(imageToDelete));imageToDelete.remove();this.closeLinkTools(cursors);this.dependencies.history.addStep();return true;} 7848return false;} 7849handleAutomaticLinkInsertion(){const convertToLink=this.prepareConvertToLink();if(convertToLink){return convertToLink();}} 7850prepareConvertToLink(){let selection=this.dependencies.selection.getEditableSelection();if(isHtmlContentSupported(selection)&&!closestElement(selection.anchorNode,"a")&&selection.anchorNode.nodeType===Node.TEXT_NODE){const cursor=this.dependencies.selection.preserveSelection();
7850mergeAdjacentTextNodes(selection.anchorNode.parentNode,cursor);cursor.restore();selection=this.dependencies.selection.getEditableSelection();const textSliced=selection.anchorNode.textContent.slice(0,selection.anchorOffset);const textNodeSplitted=textSliced.split(/\s/);const potentialUrl=textNodeSplitted.pop();const match=[...potentialUrl.matchAll(new RegExp(URL_REGEX.source,URL_REGEX.flags+"g")),].pop();if(match){const nodeForSelectionRestore=selection.anchorNode.splitText(selection.anchorOffset);let url;if(!EMAIL_REGEX.test(match[0])){url=match[2]?match[0]:"https://"+match[0];}else{url="mailto:"+match[0];} 7851const startOffset=selection.anchorOffset-potentialUrl.length+match.index;const text=selection.anchorNode.textContent.slice(startOffset,startOffset+match[0].length);const textNodeToReplace=selection.anchorNode.splitText(startOffset);textNodeToReplace.splitText(match[0].length);this.dependencies.selection.setSelection({anchorNode:nodeForSelectionRestore,anchorOffset:0},{normalize:false});const link=this.createLink(url,text);return()=>{textNodeToReplace.splitText(match[0].length);textNodeToReplace.parentNode.replaceChild(link,textNodeToReplace);if(link.getAttribute("href")===link.textContent){this.newlyInsertedLinks.add(link);} 7852return nodeForSelectionRestore;};}}} 7853handleSplitBlock(params){return this.handleEnterAtEdgeOfLink(params,this.dependencies.split.splitElementBlock);} 7854handleInsertLineBreak(params){return this.handleEnterAtEdgeOfLink(params,this.dependencies.lineBreak.insertLineBreakElement);} 7855handleEnterAtEdgeOfLink(params,splitOrLineBreakCallback){let{targetNode,targetOffset,blockToSplit}=params;if(targetNode.tagName!=="A"){return;} 7856const edge=isPositionAtEdgeofLink(targetNode,targetOffset);if(!edge){return;} 7857[targetNode,targetOffset]=edge==="start"?leftPos(targetNode):rightPos(targetNode);blockToSplit=targetNode;splitOrLineBreakCallback({...params,targetNode,targetOffset,blockToSplit});return true;} 7858handleDeleteBackward({startContainer,startOffset,endContainer,endOffset}){if(startContainer!==endContainer||startOffset!==0||endOffset!==1){return;} 7859if(startContainer.nodeType!==Node.TEXT_NODE||startContainer.textContent!="\uFEFF"){return;} 7860const previousSibling=startContainer.previousSibling;if(previousSibling?.nodeType!==Node.ELEMENT_NODE||!previousSibling.matches("a.btn")){return;} 7861this.dependencies.selection.setSelection({anchorNode:startContainer.previousSibling,anchorOffset:startContainer.previousSibling.childNodes.length-1,});return true;} 7862handleAfterInsert(insertedNodes){for(const node of insertedNodes){if(node.nodeType===Node.ELEMENT_NODE){for(const link of selectElements(node,"A")){if(link.getAttribute("href")===link.textContent&&!this.isImage){this.newlyInsertedLinks.add(link);}}}}} 7863initializePopovers(){this.overlays=[];this.getResource("link_popovers").map((link_popover)=>{this.overlays.push({overlay:this.dependencies.overlay.createOverlay(link_popover.PopoverClass,{closeOnPointerdown:true,},{sequence:50,}),isAvailable:link_popover.isAvailable,getProps:(...args)=>({...link_popover.getProps(...args),publicAttachments:this.config.publicAttachments,}),});});} 7864getActivePopover(linkElement){return this.overlays.find((overlay)=>overlay.isAvailable(linkElement));} 7865isLinkImmutable(linkEl){return this.getResource("immutable_link_selectors").some((s)=>linkEl.matches(s));} 7866doubleClickLinkOverrides(ev){const clickedLink=closestElement(ev.target,"a");if(clickedLink){this.dependencies.selection.modifySelection("extend","backward","word");this.document.getSelection().collapseToStart();this.dependencies.selection.modifySelection("extend","forward","word");const{anchorNode,focusNode,anchorOffset,focusOffset}=this.dependencies.selection.getEditableSelection();if(clickedLink.contains(anchorNode)&&!clickedLink.contains(focusNode)){this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode:clickedLink,focusOffset:nodeSize(clickedLink)-1,});}else if(!clickedLink.contains(anchorNode)&&clickedLink.contains(focusNode)){this.dependencies.selection.setSelection({anchorNode:clickedLink,anchorOffset:1,focusNode,focusOffset,});}else if(!clickedLink.contains(anchorNode)&&!clickedLink.contains(focusNode)){this.dependencies.selection.setSelection({anchorNode:clickedLink,anchorOffset:1,focusNode:clickedLink,focusOffset:nodeSize(clickedLink)-1,});}else{this.dependencies.selection.setSelection({anchorNode,anchorOffset,focu
7866sNode,focusOffset,});} 7867return true;}} 7868tripleClickButtonOverrides(ev){const selection=this.dependencies.selection.getEditableSelection();const buttonElement=isBrowserFirefox()?findInSelection(selection,"a.btn"):closestElement(selection.anchorNode,"a.btn");if(buttonElement){this.dependencies.selection.setSelection({anchorNode:buttonElement,anchorOffset:0,focusNode:buttonElement,focusOffset:nodeSize(buttonElement),});ev.preventDefault();return true;}}} 7869return __exports;});; 7870 7871/* /html_editor/static/src/main/link/link_popover.js */ 7872odoo.define('@html_editor/main/link/link_popover',['@web/session','@web/core/l10n/translation','@odoo/owl','@web/core/utils/hooks','@web/core/browser/browser','@html_editor/main/link/utils','@web/core/color_picker/color_picker','@web/core/checkbox/checkbox'],function(require){'use strict';let __exports={};const{session}=require("@web/session");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Component,useState,onMounted,useRef,useEffect,useExternalListener,onWillUnmount,}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{browser}=require("@web/core/browser/browser");const{cleanZWChars,deduceLinkUrl,normalizeLinkUrlInput}=require("@html_editor/main/link/utils");const{useColorPicker}=require("@web/core/color_picker/color_picker");const{CheckBox}=require("@web/core/checkbox/checkbox");const DEFAULT_CUSTOM_TEXT_COLOR="#714B67";const DEFAULT_CUSTOM_FILL_COLOR="#ffffff";const isCSSVariable=(color)=>color.match(/^o-color-\d$|^\d{3}$/);const formatColor=(color)=>{if(color.match(/^o-color-\d$/gm)){return`var(--hb-cp-${color})`;} 7873if(color.match(/^\d{3}$/gm)){return`var(--${color})`;} 7874return color;};function useContentChange(el,callback){onMounted(()=>{el.addEventListener("keyup",callback);});onWillUnmount(()=>{el.removeEventListener("keyup",callback);});} 7875const LinkPopover=__exports.LinkPopover=class LinkPopover extends Component{static template="html_editor.linkPopover";static props={document:{validate:(p)=>p.nodeType===Node.DOCUMENT_NODE},linkElement:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE},onApply:Function,onChange:Function,onDiscard:Function,onRemove:Function,onCopy:Function,onEdit:Function,getInternalMetaData:Function,getExternalMetaData:Function,getAttachmentMetadata:Function,isImage:Boolean,showReplaceTitleBanner:Boolean,type:String,LinkPopoverState:Object,recordInfo:Object,canEdit:{type:Boolean,optional:true},canRemove:{type:Boolean,optional:true},canUpload:{type:Boolean,optional:true},onUpload:{type:Function,optional:true},allowCustomStyle:{type:Boolean,optional:true},allowTargetBlank:{type:Boolean,optional:true},allowStripDomain:{type:Boolean,optional:true},publicAttachments:{type:Boolean,optional:true},formatColor:{type:Function,optional:true},};static defaultProps={canEdit:true,canRemove:true,formatColor:formatColor,};static components={CheckBox};colorsData=[{type:"",label:_t("Link"),btnPreview:"link"},{type:"primary",label:_t("Button Primary"),btnPreview:"primary"},{type:"secondary",label:_t("Button Secondary"),btnPreview:"secondary"},{type:"custom",label:_t("Custom"),btnPreview:"custom"},];buttonSizesData=[{size:"sm",label:_t("Small")},{size:"",label:_t("Medium")},{size:"lg",label:_t("Large")},];borderData=[{style:"solid",label:"âââ"},{style:"dashed",label:"âââ"},{style:"dotted",label:"âââ"},{style:"double",label:"âââ"},];buttonShapeData=[{shape:"",label:"Default"},{shape:"rounded-circle",label:"Default + Rounded"},{shape:"outline",label:"Outline"},{shape:"outline rounded-circle",label:"Outline + Rounded"},{shape:"fill",label:"Fill"},{shape:"fill rounded-circle",label:"Fill + Rounded"},{shape:"flat",label:"Flat"},];setup(){this.ui=useService("ui");this.notificationService=useService("notification");this.uploadService=useService("uploadLocalFiles");const linkElement=this.props.linkElement;const textContent=cleanZWChars(linkElement.textContent);const labelEqualsUrl=textContent===linkElement.getAttribute("href")||textContent+"/"===linkElement.getAttribute("href");const computedStyle=this.props.document.defaultView.getComputedStyle(linkElement);const currentRelValues=linkElement.rel.split(" ");this.state=useState({editing:this.props.LinkPopoverState.editing,url:linkElement.getAttribute("href")||deduceLinkUrl(textContent,linkElement),label:labelEqualsUrl?"":textContent,previewIcon:{type:"fa",value:"fa-globe",},urlTitle:"",urlDescription:"",linkPreviewName:"",imgSrc:"",type:this.props.type||linkElement.className.match(/btn(-[a-z0-9_-]*)(primary|secondary|custom)/)?.pop()||"",linkTarget:linkElement.target==="_blank"?"_blank":"",directDownload:true,isDocument:false,buttonSize:linkElement.className.match(/btn-(sm|lg)/)?.[1]||"",buttonShape:this.getButtonShape(),customBorderSize:computedStyle.borderWidth.replace("px","")||"0",customBorderStyle:computedStyle.borderStyle||"solid",
7875isImage:this.props.isImage,showReplaceTitleBanner:this.props.showReplaceTitleBanner,canReplaceTitle:!linkElement.querySelector("img,.fa"),showLabel:!linkElement.childElementCount,stripDomain:true,showAdvancedOptions:false,relAttributeOptions:{nofollow:{label:"nofollow",description:_t("Tells search engines not to follow this link"),isChecked:currentRelValues.includes("nofollow"),},noreferrer:{label:"noreferrer",description:_t("Removes referrer information sent to the target site"),isChecked:currentRelValues.includes("noreferrer"),},sponsored:{label:"sponsored",description:_t("Indicates the link is sponsored or paid content"),isChecked:currentRelValues.includes("sponsored"),},noopener:{label:"noopener",description:_t("Prevents the new page from accessing the original window (security)"),isChecked:currentRelValues.includes("noopener"),},},});const getTargetedElements=()=>[this.props.linkElement];this.customTextColorState=useState({selectedColor:computedStyle.color||DEFAULT_CUSTOM_TEXT_COLOR,defaultTab:"solid",getTargetedElements,mode:"color",});this.customTextResetPreviewColor=this.customTextColorState.selectedColor;this.customFillColorState=useState({selectedColor:(computedStyle.backgroundImage==="none"?undefined:computedStyle.backgroundImage)||computedStyle.backgroundColor||DEFAULT_CUSTOM_FILL_COLOR,defaultTab:"solid",getTargetedElements,mode:"background-color",});this.customFillResetPreviewColor=this.customFillColorState.selectedColor;this.customBorderColorState=useState({selectedColor:computedStyle.borderColor||DEFAULT_CUSTOM_TEXT_COLOR,defaultTab:"solid",getTargetedElements,mode:"border-color",});this.customBorderResetPreviewColor=this.customBorderColorState.selectedColor;if(this.props.allowCustomStyle){const createCustomColorPicker=(refName,colorStateRef,resetValueRef)=>useColorPicker(refName,{state:this[colorStateRef],enabledTabs:colorStateRef==="customFillColorState"?["solid","custom","gradient"]:["solid","custom"],getUsedCustomColors:()=>[],colorPrefix:"",cssVarColorPrefix:"hb-cp-",applyColor:(colorValue)=>{this[colorStateRef].selectedColor=colorValue;this[resetValueRef]=colorValue;},applyColorPreview:(colorValue)=>{this[colorStateRef].selectedColor=colorValue;this.onChange();},applyColorResetPreview:()=>{this[colorStateRef].selectedColor=this[resetValueRef];this.onChange();},},{env:this.__owl__.childEnv,sequence:1051,});this.customTextColorPicker=createCustomColorPicker("customTextColorButton","customTextColorState","customTextResetPreviewColor");this.customFillColorPicker=createCustomColorPicker("customFillColorButton","customFillColorState","customFillResetPreviewColor");this.customBorderColorPicker=createCustomColorPicker("customBorderColorButton","customBorderColorState","customBorderResetPreviewColor");} 7876this.updateDocumentState();this.editingWrapper=useRef("editing-wrapper");this.inputRef=useRef(this.state.isImage||(this.state.label&&!this.state.url)?"url":"label");useEffect((el)=>{if(el){el.focus();}},()=>[this.inputRef.el]);if(!this.state.editing){this.loadAsyncLinkPreview();} 7877const onPointerDown=(ev)=>{if(this.state.isImage){return;} 7878this.state.url||="#";if(this.editingWrapper?.el&&!this.editingWrapper.el.contains(ev.target)){this.onClickApply();}};useExternalListener(this.props.document,"pointerdown",onPointerDown);if(this.props.document!==document){useExternalListener(document,"pointerdown",onPointerDown);} 7879useContentChange(this.props.linkElement,()=>{this.state.urlTitle=this.props.linkElement.textContent;});} 7880toggleAdvancedOptions(){this.state.showAdvancedOptions=!this.state.showAdvancedOptions;} 7881toggleRelAttr(attr){const option=this.state.relAttributeOptions[attr];option.isChecked=!option.isChecked;} 7882discard(){this.props.onDiscard();this.cancelUpload?.();} 7883onChange(){this.props.onChange(this.state.url,this.state.label,this.classes,this.customStyles,this.state.linkTarget,this.state.attachmentId);this.updateDocumentState();} 7884onClickApply(){const relOptions=this.state.relAttributeOptions;const relValue=Object.keys(relOptions).filter((key)=>relOptions[key].isChecked).join(" ");this.state.editing=false;this.applyDeducedUrl();this.props.onApply(this.state.url,this.state.label,this.classes,this.customStyles,this.state.linkTarget,this.state.attachmentId,relValue);} 7885applyDeducedUrl(){if(this.state.label===""){this.state.label=this.state.url;} 7886this.state.url=normalizeLinkUrlInput(this.state.url,this.props.linkElement);if(this.props.allowStripDomain&&this.state.stripDomain&&this.isAbsoluteURLInCurrentDomain()){const urlObj=new URL(this.state.url,window.location.origin);this.state.url=this.state.url.replace(urlObj.origin,"");}} 7887onClickEdit(){this.state.editing=true;this.props.onEdit();this.updateUrlAndLabel();} 7888updateUrlAndLabel(){this.state.url=this.props.linkElement.getAttribute("href");const textContent=cleanZWChars(this.props.linkElement.textContent);const labelEqualsUrl=textContent===this.props.linkElement.getAttribute("href")||textContent+"/"===this.props.linkElement.getAttribute("href");this.state.label=labelEqualsUrl?"":textContent;} 7889async onClickCopy(ev){ev.preventDefault();await browser.navigator.clipboard.writeText(this.props.linkElement.href||"");this.notificationService.add(_t("Link copied to clipboard."),{type:"success",});this.props.onCopy();} 7890onClickRemove(){this.props.onRemove();} 7891onKeydownEnter(ev){const isAutoCompleteDropdownOpen=document.querySelector(".o-autocomplete--dropdown-menu");if(ev.key==="Enter"&&!isAutoCompleteDropdownOpen&&this.state.url){ev.preventDefault();this.onClickApply();}} 7892onKeydown(ev){if(!this.editingWrapper?.el){return;} 7893if(ev.key==="Escape"){ev.preventDefault();ev.stopImmediatePropagation();this.onClickApply();}else if(ev.key=="Tab"){ev.preventDefault();const focusableElements=[...this.editingWrapper.el.querySelectorAll("input, select, button:not([disabled])"),];const currentIndex=focusableElements.indexOf(document.activeElement);
7893const nextIndex=(currentIndex+(ev.shiftKey?-1:1)+focusableElements.length)%focusableElements.length;focusableElements[nextIndex].focus();}} 7894onInput(){this.onChange();} 7895onClickReplaceTitle(){this.state.label=this.state.urlTitle;this.onClickApply();} 7896onClickDirectDownload(checked){this.state.directDownload=checked;this.state.url=this.state.url.replace("&download=true","");if(this.state.directDownload){this.state.url+="&download=true";}} 7897onClickNewWindow(checked){this.state.linkTarget=checked?"_blank":"";if(!checked){this.state.relAttributeOptions.noopener.isChecked=false;}} 7898onClickStripDomain(checked){this.state.stripDomain=checked;} 7899async updateDocumentState(){const url=this.state.url;const urlObject=URL.parse(url,document.URL);if(url&&(url.startsWith("/web/content/")||(urlObject&&urlObject.pathname.startsWith("/web/content")&&urlObject.host===document.location.host))){const{type}=await this.props.getAttachmentMetadata(url);this.state.isDocument=type!=="url";this.state.directDownload=url.includes("&download=true");}else{this.state.isDocument=false;this.state.directDownload=true;}} 7900getButtonShape(){const shapeToRegex=(shape)=>{const parts=shape.trim().split(/\s+/);const regexParts=parts.map((cls)=>{if(["outline","fill"].includes(cls)){cls=`btn-${cls}`;} 7901return`(?=.*\\b${cls}\\b)`;});return{regex:new RegExp(regexParts.join("")),nbParts:parts.length};};let shapeMatched="";let matchScore=0;for(const{shape}of this.buttonShapeData){if(!shape){continue;} 7902const{regex,nbParts}=shapeToRegex(shape);if(regex.test(this.props.linkElement.className)){if(matchScore<nbParts){matchScore=nbParts;shapeMatched=shape;}}} 7903return shapeMatched;} 7904resetPreview(){this.state.previewIcon={type:"fa",value:"fa-globe"};this.state.urlTitle=this.state.url||_t("No URL specified");this.state.urlDescription="";this.state.linkPreviewName="";} 7905async loadAsyncLinkPreview(){let url;if(this.state.url===""){this.resetPreview();this.state.previewIcon.value="fa-question-circle-o";return;} 7906if(this.isLogoutUrl()){this.resetPreview();this.state.urlTitle=_t("Logout");this.state.previewIcon.value="fa-sign-out";return;} 7907if(this.isAttachmentUrl()){const{mimetype}=await this.props.getAttachmentMetadata(this.state.url);this.resetPreview();this.state.urlTitle=this.props.linkElement.textContent;this.state.previewIcon={type:"mimetype",value:mimetype};return;} 7908try{url=new URL(this.state.url,document.URL);}catch{this.notificationService.add(_t("This URL is invalid. Preview couldn't be updated."),{type:"danger",});return;} 7909this.resetPreview();const protocol=url.protocol;if(!protocol.startsWith("http")){const faMap={"mailto:":"fa-envelope-o","tel:":"fa-phone"};const icon=faMap[protocol];if(icon){this.state.previewIcon.value=icon;}}else if(window.location.hostname!==url.hostname&&!new RegExp(`^https?://${session.db}\\.odoo\\.com(/.*)?$`).test(url.origin)){this.state.previewIcon={type:"imgSrc",value:`https://www.google.com/s2/favicons?sz=16&domain=${encodeURIComponent(url)}`,};const externalMetadata=await this.props.getExternalMetaData(this.state.url).catch((error)=>{console.warn(`Error fetching external metadata for ${url.href}:`,error);return{};});this.state.urlTitle=externalMetadata?.og_title||this.state.url;this.state.urlDescription=externalMetadata?.og_description||"";this.state.imgSrc=externalMetadata?.og_image||"";if(externalMetadata?.og_image&&this.state.label&&this.state.urlTitle===this.state.url){this.state.urlTitle=this.state.label;}}else{const internalMetadata=await this.props.getInternalMetaData(url.href).catch((error)=>{if(!session.test_mode){console.warn(`Error fetching internal metadata for ${url.href}:`,error);} 7910return{};});if(internalMetadata.favicon){this.state.previewIcon={type:"imgSrc",value:internalMetadata.favicon.href,};} 7911if(internalMetadata.error_msg){this.notificationService.add(internalMetadata.error_msg,{type:"warning",});}else if(internalMetadata.other_error_msg){console.error("Internal meta data retrieve error for link preview: "+ 7912internalMetadata.other_error_msg);}else{this.state.linkPreviewName=internalMetadata.link_preview_name||internalMetadata.display_name||internalMetadata.name;this.state.urlDescription=internalMetadata?.description||"";this.state.urlTitle=this.state.linkPreviewName?this.state.linkPreviewName:this.state.url;} 7913if((internalMetadata.ogTitle||internalMetadata.title)&&!this.state.linkPreviewName){this.state.urlTitle=internalMetadata.ogTitle?internalMetadata.ogTitle.getAttribute("content"):internalMetadata.title.text.trim();}}} 7914get classes(){const classes=[...this.props.linkElement.classList].filter((value)=>!value.match(/^(btn.*|rounded-circle|flat|(text|bg)-(o-color-\d$|\d{3}$))$/));let stylePrefix="";if(this.state.type){if(this.state.buttonSize){classes.push(`btn-${this.state.buttonSize}`);} 7915if(this.state.buttonShape){const buttonShape=this.state.buttonShape.split(" ");if(["outline","fill"].includes(buttonShape[0])){stylePrefix=`${buttonShape[0]}-`;}
7916classes.push(buttonShape.slice(stylePrefix?1:0).join(" "));} 7917classes.push(`btn`,`btn-${stylePrefix}${this.state.type}`);} 7918const textColor=this.customTextColorState.selectedColor;if(isCSSVariable(textColor)){classes.push(`text-${textColor}`);} 7919const fillColor=this.customFillColorState.selectedColor;if(isCSSVariable(fillColor)){classes.push(`bg-${fillColor}`);} 7920return classes.filter(Boolean).join(" ");} 7921get customStyles(){if(!this.props.allowCustomStyle||this.state.type!=="custom"){return false;} 7922let customStyles="";const textColor=this.customTextColorState.selectedColor;if(!isCSSVariable(textColor)){customStyles+=`color: ${textColor}; `;} 7923const fillColor=this.customFillColorState.selectedColor;if(!isCSSVariable(fillColor)){const backgroundProperty=fillColor.includes("gradient")?"background-image":"background-color";customStyles+=`${backgroundProperty}: ${fillColor}; `;} 7924const borderColor=this.customBorderColorState.selectedColor;customStyles+=`border-width: ${this.state.customBorderSize}px; `;customStyles+=`border-color: ${formatColor(borderColor)}; `;customStyles+=`border-style: ${this.state.customBorderStyle}; `;return customStyles;} 7925async uploadFile(){const{upload,getURL}=this.uploadService;const{resModel,resId}=this.props.recordInfo;const setAbortCallback=(abortFn)=>{this.cancelUpload=abortFn;};const[attachment]=await upload({resModel,resId},{accessToken:true,setAbortCallback});delete this.cancelUpload;if(!attachment){return;} 7926this.props.onUpload?.(attachment);this.state.url=getURL(attachment,{download:true,unique:true,accessToken:true});this.state.label||=attachment.name;this.state.attachmentId=attachment.id;this.onChange();} 7927isLogoutUrl(){return!!this.state.url.match(/\/web\/session\/logout\b/);} 7928isAttachmentUrl(){return!!this.state.url.match(/\/web\/content\/\d+/);} 7929isAbsoluteURLInCurrentDomain(){let hasProtocol;try{hasProtocol=!!new URL(this.state.url).protocol;}catch{hasProtocol=false;} 7930if(!hasProtocol){return false;} 7931const urlObj=new URL(this.state.url,window.location.origin);return(urlObj.origin===window.location.origin||new RegExp(`^https?://${session.db}\\.odoo\\.com(/.*)?$`).test(urlObj.origin));}} 7932return __exports;});; 7933 7934/* /html_editor/static/src/main/link/link_selection_odoo_plugin.js */ 7935odoo.define('@html_editor/main/link/link_selection_odoo_plugin',['@html_editor/plugin','@html_editor/utils/blocks'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{isBlock}=require("@html_editor/utils/blocks");const OdooLinkSelectionPlugin=__exports.OdooLinkSelectionPlugin=class OdooLinkSelectionPlugin extends Plugin{static id="odooLinkSelection";resources={ineligible_link_for_zwnbsp_predicates:[(link)=>[link,...link.querySelectorAll("*")].some((el)=>el.nodeName==="IMG"||isBlock(el)),(link)=>link.matches("a.nav-link"),],ineligible_link_for_selection_indication_predicates:(link)=>link.matches(".btn"),};} 7936return __exports;});; 7937 7938/* /html_editor/static/src/main/link/link_selection_plugin.js */ 7939odoo.define('@html_editor/main/link/link_selection_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/utils/dom','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement,selectElements}=require("@html_editor/utils/dom_traversal");const{removeClass}=require("@html_editor/utils/dom");const{isProtected,isProtecting}=require("@html_editor/utils/dom_info");const LinkSelectionPlugin=__exports.LinkSelectionPlugin=class LinkSelectionPlugin extends Plugin{static id="linkSelection";static dependencies=["selection","feff"];static shared=["padLinkWithZwnbsp"];resources={selectionchange_handlers:this.resetLinkInSelection.bind(this),clean_for_save_handlers:({root})=>this.clearLinkInSelectionClass(root),normalize_handlers:()=>this.resetLinkInSelection(),feff_providers:this.addFeffsToLinks.bind(this),system_classes:["o_link_in_selection"],};addFeffsToLinks(root,cursors){return[...selectElements(root,"a")].filter(this.isLinkEligibleForZwnbsp.bind(this)).flatMap((link)=>this.dependencies.feff.surroundWithFeffs(link,cursors));} 7940padLinkWithZwnbsp(link){const cursors=this.dependencies.selection.preserveSelection();this.dependencies.feff.surroundWithFeffs(link,cursors);
7940cursors.restore();} 7941isLinkEligibleForZwnbsp(link){const{anchorNode,focusNode}=this.dependencies.selection.getEditableSelection();const isLinkSelected=link.contains(anchorNode)||link.contains(focusNode);const linkHasContentOrSelected=isLinkSelected||link.textContent.replaceAll("\ufeff","");return(linkHasContentOrSelected&&link.isContentEditable&&link.parentElement.isContentEditable&&this.editable.contains(link)&&!isProtected(link)&&!isProtecting(link)&&!this.getResource("ineligible_link_for_zwnbsp_predicates").some((p)=>p(link)));} 7942isLinkEligibleForVisualIndication(link){return(this.isLinkEligibleForZwnbsp(link)&&!this.getResource("ineligible_link_for_selection_indication_predicates").some((predicate)=>predicate(link)));} 7943resetLinkInSelection(selectionData=this.dependencies.selection.getSelectionData()){this.clearLinkInSelectionClass(this.editable);const{anchorNode,focusNode}=selectionData.editableSelection;const[anchorLink,focusLink]=[anchorNode,focusNode].map((node)=>closestElement(node,"a"));const singleLinkInSelection=anchorLink===focusLink&&anchorLink;if(singleLinkInSelection&&this.isLinkEligibleForVisualIndication(singleLinkInSelection)&&this.document.activeElement===this.editable){singleLinkInSelection.classList.add("o_link_in_selection");}} 7944clearLinkInSelectionClass(root){for(const link of selectElements(root,".o_link_in_selection")){removeClass(link,"o_link_in_selection");}}} 7945return __exports;});; 7946 7947/* /html_editor/static/src/main/link/powerbox_url_paste_plugin.js */ 7948odoo.define('@html_editor/main/link/powerbox_url_paste_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const MediaUrlPastePlugin=__exports.MediaUrlPastePlugin=class MediaUrlPastePlugin extends Plugin{static id="mediaUrlPaste";static dependencies=["link","dom","history","powerbox"];resources={paste_url_overrides:this.openPowerboxOnUrlPaste.bind(this),};openPowerboxOnUrlPaste(text,url){const commands=this.getResource("paste_media_url_command_providers").map((provider)=>provider(url)).filter(Boolean);if(commands.length){commands.push(this.dependencies.link.getPathAsUrlCommand(text,url));const restoreSavepoint=this.dependencies.history.makeSavePoint();this.dependencies.dom.insert(text);this.dependencies.history.addStep();this.dependencies.powerbox.openPowerbox({commands,onApplyCommand:restoreSavepoint});return true;}}} 7949return __exports;});; 7950 7951/* /html_editor/static/src/main/link/utils.js */ 7952odoo.define('@html_editor/main/link/utils',[],function(require){'use strict';let __exports={};const tldWhitelist=["com","net","org","ac","ad","ae","af","ag","ai","al","am","an","ao","aq","ar","as","at","au","aw","ax","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bl","bm","bn","bo","br","bq","bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm","cn","co","cr","cs","cu","cv","cw","cx","cy","cz","dd","de","dj","dk","dm","do","dz","ec","ee","eg","eh","er","es","et","eu","fi","fj","fk","fm","fo","fr","ga","gb","gd","ge","gf","gg","gh","gi","gl","gm","gn","gp","gq","gr","gs","gt","gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","mc","md","me","mf","mg","mh","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt","mu","mv","mw","mx","my","mz","na","nc","ne","nf","ng","ni","nl","no","np","nr","nu","nz","om","pa","pe","pf","pg","ph","pk","pl","pm","pn","pr","ps","pt","pw","py","qa","re","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","sh","si","sj","sk","sl","sm","sn","so","sr","ss","st","su","sv","sx","sy","sz","tc","td","tf","tg","th","tj","tk","tl","tm","tn","to","tp","tr","tt","tv","tw","tz","ua","ug","uk","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt","yu","za","zm","zr","zw","co\\.uk"];const urlRegexBase=`|(?:www.))[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z][a-zA-Z0-9]{1,62}|(?:[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.(?:${tldWhitelist.join( 7953 "|" 7954)})\\b))(?:(?:[/?#])[^\\s]*[^!.,})\\]'"\`\\s]|(?:[^!(){}.,[\\]'"\`\\s]+))?`;const httpCapturedRegex=`(https?:\\/\\/)`;const URL_REGEX=__exports.URL_REGEX=new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`,"i");const EMAIL_REGEX=__exports.EMAIL_REGEX=/^(mailto:)?[\w-.]+@(?:[\w-]+\.)+[\w-]{2,4}$/i;const PHONE_REGEX=__exports.PHONE_REGEX=/^(?=.*\d)(tel:(?:\/\/)?)?\+? ?[\d(][\d .\-()/]{2,24}$/;__exports.cleanZWChars=cleanZWChars;function cleanZWChars(text){return text.replace(/\u200B|\uFEFF/g,"");} 7955__exports.deduceURLfromText=deduceURLfromText;function deduceURLfromText(text,link){const label=cleanZWChars(text).trim();let match=label.match(EMAIL_REGEX);if(match){return match[1]?match[0]:"mailto:"+match[0];} 7956match=label.match(URL_REGEX);if(match&&match[0]===label){const currentHttpProtocol=(link?.href.match(/^http(s)?:\/\//gi)||[])[0];if(match[2]){return match[0];}else if(currentHttpProtocol){return currentHttpProtocol+match[0];}else{return"https://"+match[0];}} 7957match=label.match(PHONE_REGEX);if(match){return(match[1]?match[0]:"tel:"+match[0]).replace(/\s+/g,"");} 7958return null;} 7959function correctLinkUrl(url){if(url&&!url.startsWith("tel:")&&!url.startsWith("mailto:")&&!url.includes("://")&&!url.startsWith("/")&&!url.startsWith("#")&&!url.startsWith("${")){url="https://"+url;} 7960if(url&&(url.startsWith("http:")||url.startsWith("https:"))){url=URL.parse(url)?url:"";} 7961return url;} 7962__exports.deduceLinkUrl=deduceLinkUrl;function deduceLinkUrl(text,link){text=text.trim();if(/^(https?:|mailto:|tel:)/.test(text)){return text;} 7963return deduceURLfromText(text,link)||"";} 7964__exports.normalizeLinkUrlInput=normalizeLinkUrlInput;function normalizeLinkUrlInput(text,link){return correctLinkUrl(deduceLinkUrl(text,link)||text);} 7965return __exports;});; 7966 7967/* /html_editor/static/src/main/list/list_plugin.js */ 7968odoo.define('@html_editor/main/list/list_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/position','@web/core/l10n/translation','@html_editor/main/list/utils','@html_editor/utils/selection','@html_editor/utils/resource','@html_editor/utils/formatting','@html_editor/utils/color','@html_editor/utils/base_container','@html_editor/main/list/list_selector','@odoo/owl','@html_editor/main/toolbar/toolbar','@html_editor/core/selection_plugin','@web/core/utils/objects','@html_editor/utils/functions','@web/core/utils/colors'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{removeClass,removeEmptyTextNodes,removeStyle,toggleClass,unwrapContents,wrapInlinesInBlocks,}=require("@html_editor/utils/dom");const{getDeepestPosition,isElement,isEmptyBlock,isListElement,isListItemElement,isParagraphRelatedElement,isPhrasingContent,isProtected,isProtecting,isShrunkBlock,isVisibleTextNode,listElementSelector,}=require("@html_editor/utils/dom_info");const{closestElement,descendants,getAdjacents,selectElements,ancestors,childNodes,firstLeaf,lastLeaf,}=require("@html_editor/utils/dom_traversal");const{childNodeIndex,nodeSize}=require("@html_editor/utils/position");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{compareListTypes,createList,insertListAfter,isListItem}=require("@html_editor/main/list/utils");const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{withSequence}=require("@html_editor/utils/resource");const{FONT_SIZE_CLASSES,getFontSizeOrClass,getHtmlStyle}=require("@html_editor/utils/formatting");const{getTextColorOrClass,TEXT_CLASSES_REGEX}=require("@html_editor/utils/color");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{ListSelector}=require("@html_editor/main/list/list_selector");const{reactive}=require("@odoo/owl");const{composeToolbarButton}=require("@html_editor/main/toolbar/toolbar");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{pick}=require("@web/core/utils/objects");const{weakMemoize}=require("@html_editor/utils/functions");const{isColorGradient}=require("@web/core/utils/colors");const listSelectorItems=[{id:"bulleted_list",commandId:"toggleListUL",mode:"UL",},{id:"numbered_list",commandId:"toggleListOL",mode:"OL",},{id:"checklist",commandId:"toggleListCL",mode:"CL",},];const ListPlugin=__exports.ListPlugin=class ListPlugin extends Plugin{static id="list";static dependencies=["baseContainer","tabulation","history","input","split","selection","delete","dom","color",];static defaultConfig={allowChecklist:true,};toolbarListSelectorKey=reactive({value:0});resources={user_commands:[{id:"toggleListUL",title:_t("Bulleted list"),description:_t("Create a simple bulleted list"),icon:"fa-list-ul",run:()=>this.toggleListCommand({mode:"UL"}),isAvailable:this.canToggleList.bind(this),},{id:"toggleListOL",title:_t("Numbered list"),description:_t("Create a list with numbering"),icon:"fa-list-ol",run:({listStyle}={})=>this.toggleListCommand({mode:"OL",listStyle}),isAvailable:this.canToggleList.bind(this),},{id:"toggleListCL",title:_t("Checklist"),description:_t("Track tasks with a checklist"),icon:"fa-check-square-o",run:()=>this.toggleListCommand({mode:"CL"}),isAvailable:(selection)=>this.config.allowChecklist&&this.canToggleList(selection),},],shortcuts:[{hotkey:"control+shift+7",commandId:"toggleListOL"},{hotkey:"control+shift+8",commandId:"toggleListUL"},{hotkey:"control+shift+9",commandId:"toggleListCL"},],shorthands:[{pattern:/^1[.)]$/,commandId:"toggleListOL",},{pattern:/^a[.)]$/,commandId:"toggleListOL",commandParams:{listStyle:"lower-alpha"},},{pattern:/^A[.)]$/,commandId:"toggleListOL",commandParams:{listStyle:"upper-alpha"},},{pattern:/^[-*]$/,commandId:"toggleListUL",},{pattern:/^\[\]$/,commandId:"toggleListCL",},],toolbar_items:[withSequence(5,{id:"list",groupId:"layout",description:_t("Toggle List"),Component:ListSelector,props:{getButtons:()=>this.listSelectorButtons,getListMode:this.getListMode.bind(this),key:this.toolbarListSelectorKey,},isAvailable:this.canToggleList.bind(this),}),],powerbox_items:[{categoryId:"structure",commandId:"toggleListUL",},{categoryId:"structure",commandId:"toggleListOL",},{categoryId:"structure",commandId:"toggleListCL",},].map((item)=>withSequence(5,item)),power_buttons:[{commandId:"toggleListUL"},{commandId:"toggleListOL"},{commandId:"toggleListCL"},].map((item)=>withSequence(15,item)),hints:[{selector:`LI, LI > ${baseContainerGlobalSelector}`,text:_t("List")}],normalize_handlers:this.normalize.bind(this),step_added_handlers:this.updateToolbarButtons.bind(this),delete_handlers:this.adjustListPaddingOnDelete.bind(this),delete_backward_overrides:this.handleDeleteBackward.bind(this),delete_range_overrides:this.handleDeleteRange.bind(this),tab_overrides:this.handleTab.bind(this),shift_tab_overrides:this.handleShiftTab.bind(this),split_element_block_overrides:this.handleSplitBlock.bind(this),color_apply_overrides:this.applyColorToListItem.bind(this),format_selection_handlers:this.applyFormatToListItem.bind(this),node_to_insert_processors:this.processNodeToInsert.bind(this),clipboard_content_processors:this.processContentForClipboard.bind(this),before_insert_within_pre_processors:this.insertListWithinPre.bind(this),before_insert_processors:this.handleInsert.bind(this),triple_click_overrides:this.handleTripleClick.bind(this),fully_selected_node_predicates:(node,selection,range)=>{if(node.nodeName==="LI"){const nonListChildren=childNodes(node).filter((n)=>!["UL","OL"].includes(n.nodeName));if(!nonListChildren.length){return;} 7969const startLeaf=firstLeaf(nonListChildren[0]);const endLeaf=lastLeaf(nonListChildren[nonListChildren.length-1]);return(range.isPointInRange(startLeaf,0)&&range.isPointInRange(endLeaf,no
7969deSize(endLeaf)));}},selection_placeholder_container_predicates:(container)=>{if(isListItemElement(container)){return true;}},};setup(){this.addDomListener(this.editable,"touchstart",this.onPointerdown);this.addDomListener(this.editable,"mousedown",this.onPointerdown);this.listSelectorButtons=this.getListSelectorButtons();this.canToggleListMemoized=weakMemoize((selection)=>isHtmlContentSupported(selection)&&this.getBlocksToToggleList().length>0);} 7970toggleListCommand({mode,listStyle}={}){this.toggleList(mode,listStyle);this.dependencies.history.addStep();} 7971getBlocksToToggleList(){const targetedBlocks=[...this.dependencies.selection.getTargetedBlocks()];return targetedBlocks.filter((block)=>!descendants(block).some((descendant)=>targetedBlocks.includes(descendant))&&block.isContentEditable&&!["OL","UL"].includes(block.tagName));} 7972canToggleList(selection){return this.canToggleListMemoized(selection);} 7973toggleList(mode,listStyle){if(!["UL","OL","CL"].includes(mode)){throw new Error(`Invalid list type: ${mode}`);} 7974if(mode==="CL"&&!!listStyle){throw new Error(`listStyle is not compatible with "CL" list type`);} 7975const sameModeListItems=new Set();const nonListBlocks=new Set();const listsToSwitch=new Set();for(const block of this.getBlocksToToggleList()){const li=closestElement(block,isListItem);if(li){if(this.getListMode(li.parentElement)===mode){sameModeListItems.add(li);}else{listsToSwitch.add(li.parentElement);}}else{nonListBlocks.add(block);}} 7976if(listsToSwitch.size||nonListBlocks.size){for(const list of listsToSwitch){const cursors=this.dependencies.selection.preserveSelection();const newList=this.switchListMode(list,mode);cursors.remapNode(list,newList).restore();} 7977for(const block of nonListBlocks){const list=this.blockToList(block,mode,listStyle);if(listStyle){list.style.listStyle=listStyle;}}}else{for(const li of sameModeListItems){this.liToBlocks(li);}}} 7978normalize(root=this.editable){const closestNestedLI=closestElement(root,"li:has(ul, ol)");if(closestNestedLI&&closestNestedLI.closest("ul, ol")){root=closestNestedLI.parentElement;} 7979for(let element of selectElements(root,"ul, ol, li")){if(isProtected(element)||isProtecting(element)){continue;} 7980for(const fn of[this.liWithoutParentToP,this.mergeSimilarLists,this.normalizeLI,this.normalizeNestedList,]){const updatedElement=fn.call(this,element);if(updatedElement){element=updatedElement;}}} 7981for(const floatClass of["float-start","float-end"]){const parentClass=`o-${floatClass}-parent`;for(const el of selectElements(root,`.${parentClass}`)){if(![...el.children].some((el)=>el.classList.contains(floatClass))){el.classList.remove(parentClass);}} 7982for(const el of selectElements(root,`:not(.${parentClass}) > .${floatClass}`)){el.parentElement.classList.add(parentClass);}}} 7983blockToList(element,mode){if(element.matches(baseContainerGlobalSelector)){return this.baseContainerToList(element,mode);} 7984if(element.matches("td, th, li.nav-item, blockquote")){return this.blockContentsToList(element,mode);} 7985let list;const cursors=this.dependencies.selection.preserveSelection();if(element===this.editable){const callingNode=element.firstChild;const group=getAdjacents(callingNode,(n)=>!isBlock(n));list=insertListAfter(this.document,callingNode,mode,group);}else{const parent=element.parentNode;const childIndex=childNodeIndex(element);list=insertListAfter(this.document,element,mode,[element]);cursors.update((cursor)=>{if(cursor.node===parent){if(cursor.offset===childIndex){[cursor.node,cursor.offset]=[list.firstChild,0];}else if(cursor.offset===childIndex+1){[cursor.node,cursor.offset]=[list.firstChild,1];}}});if(element.hasAttribute("dir")){list.setAttribute("dir",element.getAttribute("dir"));}} 7986cursors.restore();return list;} 7987baseContainerToList(baseContainer,mode){const cursors=this.dependencies.selection.preserveSelection();const list=insertListAfter(this.document,baseContainer,mode,childNodes(baseContainer));const textAlign=baseContainer.style.getPropertyValue("text-align");if(textAlign){list.firstElementChild.style.setProperty("text-align",textAlign);baseContainer.style.removeProperty("text-align");} 7988this.dependencies.dom.copyAttributes(baseContainer,list);this.adjustListPadding(list);baseContainer.remove();
7988cursors.remapNode(baseContainer,list.firstChild).restore();return list;} 7989blockContentsToList(block,mode){const cursors=this.dependencies.selection.preserveSelection();const list=insertListAfter(this.document,block.lastChild,mode,[...block.childNodes]);cursors.remapNode(block,list.firstChild).restore();return list;} 7990convertList(node,newMode){if(!["UL","OL","LI"].includes(node.tagName)){return;} 7991const listMode=this.getListMode(node);if(listMode&&newMode!==listMode){node=this.switchListMode(node,newMode);} 7992for(const child of node.children){this.convertList(child,newMode);} 7993return node;} 7994getListMode(listContainerEl){if(!["UL","OL"].includes(listContainerEl.tagName)){return;} 7995if(listContainerEl.tagName==="OL"){return"OL";} 7996return listContainerEl.classList.contains("o_checklist")?"CL":"UL";} 7997switchListMode(list,newMode){if(this.getListMode(list)===newMode){return;} 7998const newTag=newMode==="CL"?"UL":newMode;const newList=this.dependencies.dom.setTagName(list,newTag);newList.style.removeProperty("list-style");for(const li of newList.children){li.style.removeProperty("list-style");if(!isListElement(li.firstChild)){li.classList.remove("oe-nested");}} 7999removeClass(newList,"o_checklist");if(newMode==="CL"){newList.classList.add("o_checklist");} 8000this.adjustListPadding(newList);return newList;} 8001liToBlocks(li){while(li){li=this.outdentLI(li);}} 8002liWithoutParentToP(element){const isOrphan=element.nodeName==="LI"&&!element.closest("ul, ol");if(!isOrphan){return;} 8003const cursors=this.dependencies.selection.preserveSelection();wrapInlinesInBlocks(element,{baseContainerNodeName:this.dependencies.baseContainer.getDefaultNodeName(),cursors,});cursors.update(callbacksForCursorUpdate.unwrap(element));unwrapContents(element);cursors.restore();} 8004mergeSimilarLists(element){if(!element.matches("ul, ol, li.oe-nested")||(element.matches("li.oe-nested")&&!element.querySelector("ul, ol"))){return;} 8005const previousSibling=element.previousElementSibling;if(previousSibling&&element.isContentEditable&&previousSibling.isContentEditable&&(compareListTypes(previousSibling,element)||(element.tagName==="LI"&&isListItem(previousSibling)&&isListElement(element.firstChild)))){const cursors=this.dependencies.selection.preserveSelection();cursors.update(callbacksForCursorUpdate.merge(element));previousSibling.append(...element.childNodes);element.remove();this.adjustListPadding(previousSibling);cursors.restore();return previousSibling;}} 8006normalizeLI(element){if(!isListItem(element)){return;} 8007if(element.firstChild?.nodeType===Node.ELEMENT_NODE&&isListElement(element.firstChild)){element.classList.add("oe-nested");} 8008element.classList.toggle("o_checked_has_nested_list",element.classList.contains("o_checked")&&!!element.querySelector("ul, ol"));if([...element.children].some((child)=>!isPhrasingContent(child)&&!this.dependencies.split.isUnsplittable(child))){const cursors=this.dependencies.selection.preserveSelection();wrapInlinesInBlocks(element,{baseContainerNodeName:this.dependencies.baseContainer.getDefaultNodeName(),cursors,});cursors.restore();}} 8009normalizeNestedList(element){if(element.tagName==="LI"){return;} 8010if(["UL","OL"].includes(element.parentElement?.tagName)){const cursors=this.dependencies.selection.preserveSelection();let li;if(element.previousElementSibling?.nodeName==="LI"){li=element.previousElementSibling;}else{li=this.document.createElement("li");li.classList.add("oe-nested");} 8011element.parentElement.insertBefore(li,element);li.appendChild(element);cursors.restore();}} 8012indentLI(li){const lip=li.previousElementSibling||this.document.createElement("li");if(!lip.hasChildNodes()){lip.classList.add("oe-nested");} 8013const parentLi=li.parentElement;const nextSiblingLi=li.nextSibling;const destul=li.previousElementSibling?.querySelector("ol, ul")||li.querySelector("ol, ul")||li.closest("ol, ul");const cursors=this.dependencies.selection.preserveSelection();parentLi.removeChild(li);const ul=createList(this.document,this.getListMode(destul));lip.append(ul);li.before(lip);ul.append(li);const nestedLists=childNodes(li).filter((n)=>isListElement(n));ul.after(...nestedLists);parentLi.insertBefore(lip,nextSiblingLi);cursors.update((cursor)=>{if(cursor.node===lip.parentNode){const childIndex=childNodeIndex(lip);
8013if(cursor.offset===childIndex){[cursor.node,cursor.offset]=[ul,0];}else if(cursor.offset===childIndex+1){[cursor.node,cursor.offset]=[ul,1];}}});cursors.restore();} 8014outdentLI(li){const listToSplit=li.querySelector("ol, ul")||li.nextElementSibling;if(listToSplit){this.splitList(listToSplit);} 8015if(isListItem(li.parentNode.parentNode)){this.outdentNestedLI(li);return li;} 8016this.outdentTopLevelLI(li);return null;} 8017splitList(node){const cursors=this.dependencies.selection.preserveSelection();const currentList=closestElement(node,"ul, ol");const newList=currentList.cloneNode(false);const isList=isListElement(node);const wrapperLi=isList?this.document.createElement("li"):node;if(isList){wrapperLi.classList.add("oe-nested");newList.append(wrapperLi);cursors.update(callbacksForCursorUpdate.after(node.parentNode.parentNode,newList));node.parentNode.parentNode.after(newList);}else if(isListItem(node.parentNode.parentNode)){const lip=this.document.createElement("li");lip.classList.add("oe-nested");lip.append(newList);cursors.update(callbacksForCursorUpdate.after(node.parentNode.parentNode,lip));node.parentNode.parentNode.after(lip);}else{cursors.update(callbacksForCursorUpdate.after(node.parentNode,newList));node.parentNode.after(newList);} 8018const moveFrom=isList?node.parentElement:node;while(moveFrom.nextSibling){cursors.update(callbacksForCursorUpdate.append(newList,moveFrom.nextSibling));newList.append(moveFrom.nextSibling);} 8019const moveTo=isList?wrapperLi:newList;cursors.update(callbacksForCursorUpdate.prepend(moveTo,node));moveTo.prepend(node);cursors.restore();this.adjustListPadding(currentList);this.adjustListPadding(newList);return newList;} 8020outdentNestedLI(li){const cursors=this.dependencies.selection.preserveSelection();const ul=li.parentNode;const lip=ul.parentNode;cursors.update(callbacksForCursorUpdate.after(lip,li));lip.after(li);while(ul.nextSibling){cursors.update(callbacksForCursorUpdate.append(li,ul.nextSibling));li.append(ul.nextSibling);} 8021if(!ul.children.length){cursors.update(callbacksForCursorUpdate.remove(ul));ul.remove();} 8022if(!lip.children.length&&lip.classList.contains("oe-nested")){cursors.update(callbacksForCursorUpdate.remove(lip));lip.remove();} 8023this.adjustListPadding(li.parentElement);cursors.restore();} 8024outdentTopLevelLI(li){const cursors=this.dependencies.selection.preserveSelection();const ul=li.parentNode;const children=childNodes(li);if(!children.every(isBlock)){const baseContainer=this.dependencies.baseContainer.createBaseContainer();for(const child of children){cursors.update(callbacksForCursorUpdate.append(baseContainer,child));baseContainer.append(child);} 8025if(isShrunkBlock(baseContainer)){baseContainer.append(this.document.createElement("br"));} 8026li.append(baseContainer);cursors.remapNode(li,baseContainer);} 8027const blocksToMove=childNodes(li);for(const block of blocksToMove.toReversed()){cursors.update(callbacksForCursorUpdate.after(ul,block));ul.after(block);} 8028const dir=li.getAttribute("dir")||ul.getAttribute("dir");const textAlign=li.style.getPropertyValue("text-align");const liColorStyle=getTextColorOrClass(li);const liFontSizeStyle=getFontSizeOrClass(li);const wrapChildren=(parent,tag)=>{const wrapper=this.document.createElement(tag);wrapper.append(...parent.childNodes);parent.replaceChildren(wrapper);cursors.remapNode(parent,wrapper);return wrapper;};for(const block of blocksToMove){if(dir&&!block.getAttribute("dir")){block.setAttribute("dir",dir);} 8029if(textAlign&&!block.style.getPropertyValue("text-align")){block.style.setProperty("text-align",textAlign);} 8030if(liColorStyle){const font=wrapChildren(block,"font");this.dependencies.color.colorElement(font,liColorStyle.value,"color");} 8031if(liFontSizeStyle&&!isEmptyBlock(block)){const span=wrapChildren(block,"span");if(liFontSizeStyle.type==="font-size"){span.style.fontSize=liFontSizeStyle.value;}else if(liFontSizeStyle.type==="class"){span.classList.add(liFontSizeStyle.value);}}} 8032cursors.update(callbacksForCursorUpdate.remove(li));li.remove();if(!ul.firstElementChild){cursors.update(callbacksForCursorUpdate.remove(ul));ul.remove();}else{this.adjustListPadding(ul);}
8033cursors.restore();} 8034indentListNodes(listNodes){for(const li of listNodes){this.indentLI(li);}} 8035outdentListNodes(listNodes){for(const li of listNodes){this.outdentLI(li);}} 8036separateListItems(){const listItems=new Set();const navListItems=new Set();const nonListItems=[];const blocks=[...this.dependencies.selection.getTargetedBlocks()].filter((n)=>!n.querySelector("li"));for(const block of blocks){const closestLI=block.closest("li");if(closestLI){if(closestLI.classList.contains("nav-item")){navListItems.add(closestLI);}else if(closestLI.isContentEditable){listItems.add(closestLI);}}else if(!["UL","OL"].includes(block.tagName)){nonListItems.push(block);}} 8037return{listItems:[...listItems],navListItems:[...navListItems],nonListItems};} 8038processNodeToInsert({nodeToInsert,container}){if(isListItemElement(container)&&isParagraphRelatedElement(nodeToInsert)){nodeToInsert=this.dependencies.dom.setTagName(nodeToInsert,"LI");} 8039const listEl=container&&closestElement(container,listElementSelector);if(!listEl){return nodeToInsert;} 8040const mode=container&&this.getListMode(listEl);if(isListItemElement(nodeToInsert)&&nodeToInsert.querySelector("ol, ul")){return this.convertList(nodeToInsert,mode);} 8041if(isListElement(nodeToInsert)){return this.convertList(nodeToInsert,this.getListMode(nodeToInsert));} 8042return nodeToInsert;} 8043handleTab(){const selection=this.dependencies.selection.getEditableSelection();const closestLI=closestElement(selection.anchorNode,"LI");if(closestLI){const block=closestBlock(selection.anchorNode);const isLiContainsUnSpittable=isParagraphRelatedElement(block)&&ancestors(block,closestLI).find((node)=>this.dependencies.split.isUnsplittable(node));if(isLiContainsUnSpittable){return;}} 8044const{listItems,navListItems,nonListItems}=this.separateListItems();if(listItems.length||navListItems.length){this.indentListNodes(listItems);this.dependencies.tabulation.indentBlocks(nonListItems);const listsToAdjustPadding=new Set(listItems.map((li)=>closestElement(li,"ul, ol")).filter(Boolean));for(const list of listsToAdjustPadding){this.adjustListPadding(list);} 8045this.dependencies.history.addStep();return true;}} 8046handleShiftTab(){const selection=this.dependencies.selection.getEditableSelection();const closestLI=closestElement(selection.anchorNode,"LI");if(closestLI){const block=closestBlock(selection.anchorNode);const isLiContainsUnSpittable=isParagraphRelatedElement(block)&&ancestors(block,closestLI).find((node)=>this.dependencies.split.isUnsplittable(node));if(isLiContainsUnSpittable){return;}} 8047const{listItems,navListItems,nonListItems}=this.separateListItems();if(listItems.length||navListItems.length){this.outdentListNodes(listItems);this.dependencies.tabulation.outdentBlocks(nonListItems);this.dependencies.history.addStep();return true;}} 8048handleSplitBlock(params){const closestLI=closestElement(params.targetNode,"LI");const isTargetInUnsplittable=closestLI&&ancestors(params.targetNode,closestLI).find((node)=>this.dependencies.split.isUnsplittable(node));if(!closestLI||isTargetInUnsplittable){return;} 8049if(isEmptyBlock(closestLI)){this.outdentLI(closestLI);return true;} 8050const[,newLI]=this.dependencies.split.splitElementBlock({...params,blockToSplit:closestLI,});if(newLI){if(closestLI.classList.contains("o_checked")){removeClass(newLI,"o_checked");} 8051const[anchorNode,anchorOffset]=getDeepestPosition(newLI,0);this.dependencies.selection.setSelection({anchorNode,anchorOffset});this.adjustListPadding(newLI.parentElement);} 8052return true;} 8053handleDeleteBackward(range){const{startContainer,startOffset,endContainer,endOffset}=range;const closestLIendContainer=closestElement(endContainer,"LI");if(!closestLIendContainer){return;} 8054const isCursorAtStartofLI=(startContainer===endContainer&&startOffset===endOffset)||closestElement(startContainer,"LI")!==closestLIendContainer;if(!isCursorAtStartofLI){return;} 8055let element=closestLIendContainer;while(["LI","UL","OL"].includes(element.tagName)){if(this.dependencies.split.isUnsplittable(element)){return;} 8056element=element.parentElement;} 8057if(!closestLIendContainer.classList.contains("oe-nested")){closestLIendContainer.classList.add("oe-nested");closestLIendContainer.classList.remove("o_checked");}else{const list=closestElement(closestLIendContainer,"ul[dir], ol[dir]");const dir=list?.getAttribute("dir");
8057if(dir){closestLIendContainer.setAttribute("dir",dir);} 8058this.liToBlocks(closestLIendContainer);} 8059return true;} 8060handleDeleteRange(range){const{startContainer,endContainer}=range;const startCheckedLi=closestElement(startContainer,"li.o_checked");if(!startCheckedLi){return;} 8061const endLi=closestElement(endContainer,"li");if(startCheckedLi===endLi){return;} 8062range=this.dependencies.delete.deleteRange(range);this.dependencies.selection.setSelection({anchorNode:range.startContainer,anchorOffset:range.startOffset,});if(isEmptyBlock(startCheckedLi)){removeClass(startCheckedLi,"o_checked");} 8063return true;} 8064processContentForClipboard(clonedContents,selection){const closestLi=closestElement(selection.commonAncestorContainer,"LI");if(closestLi&&closestLi.childNodes.length>1&&this.dependencies.selection.areNodeContentsFullySelected(selection.commonAncestorContainer)){const outermostSingleChildAncestor=closestElement(selection.commonAncestorContainer,(el)=>el===closestLi||el.parentElement?.childNodes.length!==1);if(outermostSingleChildAncestor===closestLi||outermostSingleChildAncestor.parentElement===closestLi){let[li,list]=[closestLi.cloneNode(),closestLi.parentElement.cloneNode()];if(outermostSingleChildAncestor.parentElement===closestLi){[li,list]=[outermostSingleChildAncestor.parentElement.cloneNode(),outermostSingleChildAncestor.parentElement.parentElement.cloneNode(),];li.append(outermostSingleChildAncestor.cloneNode(true));}else{li.append(...childNodes(clonedContents));} 8065list.append(li);return(clonedContents=list);}} 8066if(clonedContents.firstChild.nodeName==="LI"){const list=selection.commonAncestorContainer.cloneNode();list.replaceChildren(...childNodes(clonedContents));clonedContents=list;} 8067return clonedContents;} 8068insertListWithinPre(node){const listItems=node.querySelectorAll("li:not(.oe-nested)");for(const li of listItems){const nestingLvl=ancestors(li).filter(isListElement).length-1;const list=closestElement(li,"ul, ol");const listMode=this.getListMode(list);let char;if(listMode==="CL"){char="[] ";}else if(listMode==="OL"){const children=childNodes(li.parentElement).filter((n)=>!n.classList.contains("oe-nested"));char=`${children.indexOf(li) + 1}. `;}else{char="* ";} 8069const prefix=" ".repeat(nestingLvl*4)+char;li.prepend(this.document.createTextNode(prefix));} 8070return node;} 8071onPointerdown(ev){const node=ev.target;const isChecklistItem=node.tagName=="LI"&&this.getListMode(node.parentElement)=="CL";if(!isChecklistItem){return;} 8072let offsetX=ev.offsetX;let offsetY=ev.offsetY;if(ev.type==="touchstart"){const rect=node.getBoundingClientRect();offsetX=ev.touches[0].clientX-rect.x;offsetY=ev.touches[0].clientY-rect.y;} 8073if(isChecklistItem&&this.isPointerInsideCheckbox(node,offsetX,offsetY)){toggleClass(node,"o_checked");const{documentSelectionIsInEditable}=this.dependencies.selection.getSelectionData();if(!documentSelectionIsInEditable){this.editable.focus();this.dependencies.selection.setSelection({anchorNode:node,anchorOffset:0});} 8074ev.preventDefault();this.dependencies.history.addStep();}} 8075handleTripleClick(ev){const node=ev.target;const isChecklistItem=node.tagName==="LI"&&this.getListMode(node.parentElement)==="CL";if(isChecklistItem&&this.isPointerInsideCheckbox(node,ev.offsetX,ev.offsetY)){return true;}} 8076isPointerInsideCheckbox(li,pointerOffsetX,pointerOffsetY){const beforeStyle=this.window.getComputedStyle(li,":before");const checkboxPosition={left:parseInt(beforeStyle.left),top:parseInt(beforeStyle.top),};checkboxPosition.right=checkboxPosition.left+parseInt(beforeStyle.width);checkboxPosition.bottom=checkboxPosition.top+parseInt(beforeStyle.height);return(pointerOffsetX>=checkboxPosition.left&&pointerOffsetX<=checkboxPosition.right&&pointerOffsetY>=checkboxPosition.top&&pointerOffsetY<=checkboxPosition.bottom);} 8077applyColorToListItem(color,mode){this.dependencies.split.splitSelection();const targetedNodes=this.dependencies.selection.getTargetedNodes();const listItems=new Set(targetedNodes.map((n)=>closestElement(n,"li")).filter(Boolean));if(!listItems.size||(mode!=="color"&&color)||isColorGradient(color)){return;} 8078const cursors=this.dependencies.selection.preserveSelection();for(const listItem of listItems){removeEmptyTextNodes(listItem,cursors);if(this.dependencies.selection.areNodeContentsFullySelected(listItem)){for(const node of[listItem,...descendants(listItem).filter((n)=>isElement(n)&&closestElement(n,"LI")===listItem),]){const classesToRemove=[...node.classList].filter((cls)=>cls==="o_default_color"||TEXT_CLASSES_REGEX.test(cls));removeClass(node,...classesToRemove);if(node.style.color){removeStyle(node,"color");} 8079if(node.style.backgroundColor){removeStyle(node,"background-color");}} 8080if(color){this.dependencies.color.colorElement(listItem,color,mode);const sublists=childNodes(listItem).filter(isListElement);for(const list of sublists){list.classList.add("o_default_color");}}}else if(color===""&&(listItem.style.color||[...listItem.classList].some((cls)=>TEXT_CLASSES_REGEX.test(cls)))){const textNodes=targetedNodes.filter((n)=>isVisibleTextNode(n)&&closestElement(n,"li")===listItem);for(const node of textNodes){const font=this.document.createElement("font");font.classList.add("o_default_color");node.before(font);cursors.update(callbacksForCursorUpdate.before(node,font));font.append(node);
8080cursors.update(callbacksForCursorUpdate.append(font,node));}}} 8081cursors.restore();} 8082applyFormatToListItem(formatName,{formatProps,applyStyle}={}){if(!["setFontSizeClassName","fontSize"].includes(formatName)){return;} 8083this.dependencies.split.splitSelection();const targetedNodes=this.dependencies.selection.getTargetedNodes();const listItems=new Set(targetedNodes.map((n)=>closestElement(n,"li")).filter(Boolean));if(!listItems.size){return false;} 8084const listsSet=new Set();const cursors=this.dependencies.selection.preserveSelection();for(const listItem of listItems){const hasOnlyBaseBlocks=[...descendants(listItem)].filter(isBlock).every((n)=>n.matches(`${baseContainerGlobalSelector}, ol, ul, li`));const hasExistingFontSize=FONT_SIZE_CLASSES.some((c)=>listItem.classList.contains(c))||listItem.style.fontSize;if(!hasOnlyBaseBlocks||(!applyStyle&&!hasExistingFontSize)){continue;} 8085removeEmptyTextNodes(listItem,cursors);if(this.dependencies.selection.areNodeContentsFullySelected(listItem)){for(const node of[listItem,...descendants(listItem).filter((n)=>isElement(n)&&closestElement(n,"LI")===listItem),]){removeClass(node,...FONT_SIZE_CLASSES,"o_default_font_size");if(node.style.fontSize){node.style.fontSize="";}} 8086if(applyStyle){if(formatName==="setFontSizeClassName"){listItem.classList.add(formatProps.className);}else if(formatName==="fontSize"){listItem.style.fontSize=formatProps.size;} 8087const sublists=childNodes(listItem).filter(isListElement);for(const list of sublists){list.classList.add("o_default_font_size");}}}else if(!applyStyle&&hasExistingFontSize){const textNodes=targetedNodes.filter((n)=>isVisibleTextNode(n)&&closestElement(n,"li")===listItem);for(const node of textNodes){const span=this.document.createElement("span");span.classList.add("o_default_font_size");node.before(span);cursors.update(callbacksForCursorUpdate.before(node,span));span.append(node);cursors.update(callbacksForCursorUpdate.append(span,node));}} 8088listsSet.add(listItem.parentElement);} 8089cursors.restore();for(const list of listsSet){this.adjustListPadding(list);} 8090return true;} 8091adjustListPadding(list){if(!isListElement(list)||![...list.children].some(getFontSizeOrClass)){return;} 8092list.style.removeProperty("padding-inline-start");if(list.classList.contains("o_checklist")){return;} 8093const largestMarker=list.children[Symbol.iterator]().map((li)=>{const markerWidth=parseFloat(this.window.getComputedStyle(li,"::marker").width);return isNaN(markerWidth)?0:markerWidth;}).reduce((accumulator,currentValue)=>Math.max(accumulator,currentValue));const largestMarkerPadding=Math.round(largestMarker)*(list.nodeName==="UL"?2:1);const defaultPadding=parseFloat(getHtmlStyle(this.document).fontSize)*2;if(largestMarkerPadding>defaultPadding){list.style.paddingInlineStart=`${largestMarkerPadding}px`;}} 8094adjustListPaddingOnDelete(){const selection=this.document.getSelection();if(!selection.isCollapsed||!selection.anchorNode){return;} 8095const listItem=closestElement(selection.anchorNode);if(isListItem(listItem)){this.adjustListPadding(listItem.parentElement);}} 8096updateToolbarButtons(){this.toolbarListSelectorKey.value++;} 8097getListSelectorButtons(){return listSelectorItems.filter((item)=>item.commandId!="toggleListCL"||this.config.allowChecklist).map((item)=>{const command=this.resources.user_commands.find((cmd)=>cmd.id===item.commandId);const button=composeToolbarButton(command,item);return{...pick(button,"id","icon","run","mode"),description:command.title,};});} 8098handleInsert(container,block){if(!this.config.allowChecklist){for(const list of container.querySelectorAll(".o_checklist > li")){this.liToBlocks(list);}} 8099return container;}} 8100return __exports;});; 8101 8102/* /html_editor/static/src/main/list/list_selector.js */ 8103odoo.define('@html_editor/main/list/list_selector',['@odoo/owl','@web/core/dropdown/dropdown','@html_editor/main/toolbar/toolbar','@html_editor/utils/dom_traversal','@html_editor/dropdown_autovisibility_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{closestElement}=require("@html_editor/utils/dom_traversal");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const{useChildRef}=require("@web/core/utils/hooks");const ListSelector=__exports.ListSelector=class ListSelector extends Component{static template="html_editor.ListSelector";static props={...toolbarButtonProps,getButtons:Function,getListMode:Function,key:Object,};static components={Dropdown};setup(){this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);} 8104getActiveMode(){const{editableSelection:selection}=this.props.getSelection();const closestLI=closestElement(selection.anchorNode,"LI");return closestLI&&this.props.getListMode(closestLI.parentNode);}} 8105return __exports;});; 8106 8107/* /html_editor/static/src/main/list/utils.js */ 8108odoo.define('@html_editor/main/list/utils',['@html_editor/utils/dom','@html_editor/utils/dom_traversal','@html_editor/utils/formatting'],function(require){'use strict';let __exports={};const{removeStyle,unwrapContents}=require("@html_editor/utils/dom");const{closestElement,firstLeaf,lastLeaf}=require("@html_editor/utils/dom_traversal");const{getFontSizeOrClass}=require("@html_editor/utils/formatting");__exports.createList=createList;function createList(document,mode){const node=document.createElement(mode==="OL"?"OL":"UL");if(mode==="CL"){node.classList.add("o_checklist");} 8109return node;} 8110__exports.insertListAfter=insertListAfter;function insertListAfter(document,afterNode,mode,content=[]){const list=createList(document,mode);afterNode.after(list);const li=document.createElement("LI");li.append(...content);if(content.length===1&&content[0].nodeType===Node.ELEMENT_NODE){const firstLeafNode=firstLeaf(content[0]);const lastLeafNode=lastLeaf(content[0]);const firstClosestFont=closestElement(firstLeafNode,"font");const lastClosestFont=closestElement(lastLeafNode,"font");if(firstClosestFont&&lastClosestFont&&firstClosestFont===lastClosestFont){li.style.color=firstClosestFont.style.color;removeStyle(firstClosestFont,"color");
8110if(!firstClosestFont.hasAttributes()){unwrapContents(firstClosestFont);}} 8111const firstClosestSpan=closestElement(firstLeafNode,"span");const lastClosestSpan=closestElement(lastLeafNode,"span");let fontSizeStyle;if(firstClosestSpan&&lastClosestSpan&&firstClosestSpan===lastClosestSpan&&(fontSizeStyle=getFontSizeOrClass(firstClosestSpan))){if(fontSizeStyle.type==="font-size"){li.style.fontSize=fontSizeStyle.value;}else if(fontSizeStyle.type==="class"){li.classList.add(fontSizeStyle.value);} 8112unwrapContents(firstClosestSpan);}} 8113list.append(li);return list;} 8114__exports.compareListTypes=compareListTypes;function compareListTypes(a,b){if(!a||!b||a.tagName!==b.tagName){return false;} 8115if(a.classList.contains("o_checklist")!==b.classList.contains("o_checklist")){return false;} 8116if(a.tagName==="LI"){if(a.classList.contains("oe-nested")!==b.classList.contains("oe-nested")){return false;} 8117return compareListTypes(a.firstElementChild,b.firstElementChild);} 8118return true;} 8119__exports.isListItem=isListItem;function isListItem(node){return node.nodeName==="LI"&&!node.classList.contains("nav-item");} 8120return __exports;});; 8121 8122/* /html_editor/static/src/main/local_overlay_plugin.js */ 8123odoo.define('@html_editor/main/local_overlay_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const LocalOverlayPlugin=__exports.LocalOverlayPlugin=class LocalOverlayPlugin extends Plugin{static id="localOverlay";static shared=["makeLocalOverlay"];setup(){this.localOverlayContainer=this.config.localOverlayContainers?.ref.el;this.localOverlays=new Set();} 8124makeLocalOverlay(containerId){const container=this.document.createElement("div");container.className=`oe-local-overlay`;container.setAttribute("data-oe-local-overlay-id",containerId);if(this.localOverlayContainer){this.localOverlayContainer.append(container);this.localOverlays.add(container);} 8125return container;} 8126destroy(){for(const container of this.localOverlays){container.remove();} 8127this.localOverlays.clear();super.destroy();}} 8128return __exports;});; 8129 8130/* /html_editor/static/src/main/media/dblclick_image_preview_plugin.js */ 8131odoo.define('@html_editor/main/media/dblclick_image_preview_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const DoubleClickImagePreviewPlugin=__exports.DoubleClickImagePreviewPlugin=class DoubleClickImagePreviewPlugin extends Plugin{static id="dblclickImagePreview";static dependencies=["image"];setup(){this.addDomListener(this.editable,"dblclick",(e)=>{if(e.target.tagName==="IMG"){this.dependencies.image.previewImage();}});}} 8132return __exports;});; 8133 8134/* /html_editor/static/src/main/media/file_plugin.js */ 8135odoo.define('@html_editor/main/media/file_plugin',['@html_editor/main/media/media_dialog/document_selector','@html_editor/plugin','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/utils/resource','@web/core/l10n/translation','@html_editor/core/selection_plugin','@html_editor/main/toolbar/toolbar_plugin'],function(require){'use strict';let __exports={};const{DocumentSelector,renderStaticFileBox,}=require("@html_editor/main/media/media_dialog/document_selector");const{Plugin}=require("@html_editor/plugin");const{isEmpty}=require("@html_editor/utils/dom_info");const{closestElement,firstLeaf,lastLeaf}=require("@html_editor/utils/dom_traversal");const{nodeSize}=require("@html_editor/utils/position");const{withSequence}=require("@html_editor/utils/resource");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{DISABLED_NAMESPACE}=require("@html_editor/main/toolbar/toolbar_plugin");const FilePlugin=__exports.FilePlugin=class FilePlugin extends Plugin{static id="file";static dependencies=["clipboard","dom","history","selection"];static defaultConfig={allowFile:true,};resources={user_commands:{id:"uploadFile",title:_t("Upload a file"),description:_t("Add a download box"),icon:"fa-upload",run:this.uploadAndInsertFiles.bind(this),isAvailable:(selection)=>this.isUploadCommandAvailable(selection)&&isHtmlContentSupported(selection),},powerbox_items:{categoryId:"media",commandId:"uploadFile",keywords:[_t("file"),_t("document")
8135],},power_buttons:withSequence(5,{commandId:"uploadFile",description:_t("Upload a file"),}),unsplittable_node_predicates:(node)=>node.classList?.contains("o_file_box"),...(this.config.allowFile&&this.config.allowMediaDocuments&&{media_dialog_extra_tabs:{id:"DOCUMENTS",title:_t("Documents"),Component:this.componentForMediaDialog,sequence:15,},}),selectors_for_feff_providers:()=>".o_file_box",toolbar_namespace_providers:withSequence(80,(targetedNodes,editableSelection)=>closestElement(editableSelection.anchorNode,".o_file_box")&&DISABLED_NAMESPACE),functional_empty_node_predicates:(node)=>node?.nodeName==="SPAN"&&node.classList.contains("o_file_box"),is_node_editable_predicates:(node)=>{if(node?.nodeName==="SPAN"&&node.classList.contains("o_file_box")){return false;}},is_powerbox_available_predicates:(node)=>{if(closestElement(node,".o_file_box")){return false;}},are_shorthands_available_predicates:(node)=>{if(closestElement(node,".o_file_box")){return false;}},paste_overrides:(selection,clipboardData)=>{if(closestElement(selection.anchorNode,".o_file_box")){this.dependencies.clipboard.pasteText(clipboardData.getData("text/plain"));return true;}},};setup(){this.addDomListener(this.editable,"click",this.onClick);this.addDomListener(this.editable,"keydown",this.onKeyDown);this.addDomListener(this.document,"pointerdown",this.onPointerDown);} 8136onClick(ev){const fileNameEl=closestElement(ev.target,".o_file_name_container .o_link_readonly");if(!fileNameEl||fileNameEl.isContentEditable){return;} 8137ev.preventDefault();ev.stopPropagation();fileNameEl.setAttribute("contenteditable","true");let anchorNode,anchorOffset;if(this.document.caretPositionFromPoint){const pos=this.document.caretPositionFromPoint(ev.clientX,ev.clientY);anchorNode=pos?.offsetNode;anchorOffset=pos?.offset;}else if(this.document.caretRangeFromPoint){const range=document.caretRangeFromPoint(ev.clientX,ev.clientY);anchorNode=range?.startContainer;anchorOffset=range?.startOffset;} 8138if(anchorNode&&fileNameEl.contains(anchorNode)){this.dependencies.selection.setSelection({anchorNode,anchorOffset});}else{this.dependencies.selection.setCursorStart(fileNameEl);}} 8139onKeyDown(ev){const fileNameEl=closestElement(ev.target,".o_file_name_container .o_link_readonly");if(!fileNameEl){return;} 8140const selection=this.dependencies.selection.getEditableSelection();const firstLeafNode=firstLeaf(fileNameEl);const lastLeafNode=lastLeaf(fileNameEl);switch(ev.key){case"ArrowLeft":if(selection.isCollapsed&&(isEmpty(fileNameEl)||(selection.anchorNode===firstLeafNode&&selection.anchorOffset===0))){ev.preventDefault();} 8141break;case"ArrowRight":if(selection.isCollapsed&&(isEmpty(fileNameEl)||(selection.anchorNode===lastLeafNode&&selection.anchorOffset===nodeSize(lastLeafNode)))){ev.preventDefault();} 8142break;case"ArrowUp":ev.preventDefault();this.dependencies.selection.setCursorStart(fileNameEl);break;case"ArrowDown":ev.preventDefault();this.dependencies.selection.setCursorEnd(fileNameEl);break;case"Enter":ev.preventDefault();break;}} 8143onPointerDown(ev){const activeElement=this.document.activeElement;const fileNameEl=closestElement(activeElement,".o_file_name_container .o_link_readonly");if(!fileNameEl||fileNameEl.contains(ev.target)){return;} 8144activeElement.setAttribute("contenteditable","false");} 8145get recordInfo(){return this.config.getRecordInfo?.()||{};} 8146isUploadCommandAvailable(){return this.config.allowFile;} 8147get componentForMediaDialog(){return DocumentSelector;} 8148async uploadAndInsertFiles(){const uploadParams=this.config.publicAttachments?{}:{...this.recordInfo};const attachments=await this.services.uploadLocalFiles.upload(uploadParams,{multiple:true,accessToken:true,});if(!attachments.length){this.editable.focus();return;} 8149if(this.config.onAttachmentChange){attachments.forEach(this.config.onAttachmentChange);} 8150const fileCards=attachments.map(this.renderDownloadBox.bind(this));fileCards.forEach(this.dependencies.dom.insert);this.dependencies.history.addStep();} 8151renderDownloadBox(attachment){const url=this.services.uploadLocalFiles.getURL(attachment,{download:true,unique:true,accessToken:true,});const{name:filename,mimetype,id}=attachment;return renderStaticFileBox(filename,mimetype,url,id);}} 8152return __exports;});; 8153 8154/* /html_editor/static/src/main/media/icon_color_plugin.js */ 8155odoo.define('@html_editor/main/media/icon_color_plugin',['@html_editor/plugin','@html_editor/utils/resource','@web/core/l10n/translation','@html_editor/main/font/color_selector','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{withSequence}=require("@html_editor/utils/resource");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{ColorSelector}=require("@html_editor/main/font/color_selector");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const IconColorPlugin=__exports.IconColorPlugin=class IconColorPlugin extends Plugin{static id="iconColor";static dependencies=["icon","colorUi"];resources={toolbar_groups:withSequence(1,{id:"icon_color",namespaces:["icon"]}),toolbar_items:[{id:"icon_forecolor",groupId:"icon_color",description:_t("Select Font Color"),Component:ColorSelector,props:this.dependencies.colorUi.getPropsForColorSelector("foreground"),isAvailable:isHtmlContentSupported,},{id:"icon_backcolor",groupId:"icon_color",description:_t("Select Backgroun
8155d Color"),Component:ColorSelector,props:this.dependencies.colorUi.getPropsForColorSelector("background"),isAvailable:isHtmlContentSupported,},],};} 8156return __exports;});; 8157 8158/* /html_editor/static/src/main/media/icon_plugin.js */ 8159odoo.define('@html_editor/main/media/icon_plugin',['@html_editor/utils/resource','@html_editor/plugin','@web/core/l10n/translation','@html_editor/main/media/media_dialog/media_dialog','@html_editor/core/selection_plugin','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{withSequence}=require("@html_editor/utils/resource");const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{MediaDialog}=require("@html_editor/main/media/media_dialog/media_dialog");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{ICON_SELECTOR,isElement,isIconElement,isZwnbsp}=require("@html_editor/utils/dom_info");const{closestElement}=require("@html_editor/utils/dom_traversal");const IconPlugin=__exports.IconPlugin=class IconPlugin extends Plugin{static id="icon";static dependencies=["history","selection","color","dialog"];toolbarNamespace="icon";resources={user_commands:[{id:"resizeIcon1",description:_t("Resize icon 1x"),run:()=>this.resizeIcon({size:"1"}),isAvailable:isHtmlContentSupported,},{id:"resizeIcon2",description:_t("Resize icon 2x"),run:()=>this.resizeIcon({size:"2"}),isAvailable:isHtmlContentSupported,},{id:"resizeIcon3",description:_t("Resize icon 3x"),run:()=>this.resizeIcon({size:"3"}),isAvailable:isHtmlContentSupported,},{id:"resizeIcon4",description:_t("Resize icon 4x"),run:()=>this.resizeIcon({size:"4"}),isAvailable:isHtmlContentSupported,},{id:"resizeIcon5",description:_t("Resize icon 5x"),run:()=>this.resizeIcon({size:"5"}),isAvailable:isHtmlContentSupported,},{id:"toggleSpinIcon",description:_t("Toggle icon spin"),icon:"fa-play",run:this.toggleSpinIcon.bind(this),isAvailable:isHtmlContentSupported,},{id:"replaceIcon",description:_t("Replace icon"),run:this.openIconDialog.bind(this),isAvailable:isHtmlContentSupported,},],toolbar_namespace_providers:[(targetedNodes)=>{if(!targetedNodes.length){return;} 8160const isIconInTargetedNodes=targetedNodes.some(isIconElement);const isIconRelatedNode=(node)=>{if(node.classList?.contains("fa")||node.parentElement?.classList.contains("fa")||(node.querySelector?.(":scope > .fa")&&node.isContentEditable!==false)){return true;} 8161if(isZwnbsp(node)&&isIconInTargetedNodes){return(node.nextElementSibling?.classList?.contains("fa")||node.previousElementSibling?.classList?.contains("fa"));} 8162if(isElement(node)&&node.children.length===1&&isIconElement(node.children[0])){return true;} 8163return false;};if(targetedNodes.every(isIconRelatedNode)){return this.toolbarNamespace;}},],toolbar_groups:[withSequence(2,{id:"icon_size",namespaces:["icon"]}),withSequence(3,{id:"icon_spin",namespaces:["icon"]}),withSequence(3,{id:"icon_replace",namespaces:["icon"]}),],toolbar_items:[{id:"icon_size_1",groupId:"icon_size",commandId:"resizeIcon1",text:"1x",isActive:()=>this.hasIconSize("1"),},{id:"icon_size_2",groupId:"icon_size",commandId:"resizeIcon2",text:"2x",isActive:()=>this.hasIconSize("2"),},{id:"icon_size_3",groupId:"icon_size",commandId:"resizeIcon3",text:"3x",isActive:()=>this.hasIconSize("3"),},{id:"icon_size_4",groupId:"icon_size",commandId:"resizeIcon4",text:"4x",isActive:()=>this.hasIconSize("4"),},{id:"icon_size_5",groupId:"icon_size",commandId:"resizeIcon5",text:"5x",isActive:()=>this.hasIconSize("5"),},{id:"icon_spin",groupId:"icon_spin",commandId:"toggleSpinIcon",isActive:()=>this.hasSpinIcon(),},{id:"icon_replace",groupId:"icon_replace",commandId:"replaceIcon",text:_t("Replace"),},],selected_background_color_providers:withSequence(5,this.computeBackgroundColorForIcon.bind(this)),};getTargetedIcon(){const targetedNodes=this.dependencies.selection.getTargetedNodes();return targetedNodes.find((node)=>isElement(node)&&node.matches(ICON_SELECTOR));} 8164resizeIcon({size}){const targetedIcon=this.getTargetedIcon();if(!targetedIcon){return;} 8165for(const classString of targetedIcon.classList){if(classString.match(/^fa-[2-5]x$/)){targetedIcon.classList.remove(classString);}} 8166if(size!=="1"){targetedIcon.classList.add(`fa-${size}x`);} 8167this.dependencies.history.addStep();} 8168toggleSpinIcon(){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8169selectedIcon.classList.toggle("fa-spin");this.dependencies.history.addStep();} 8170hasIconSize(size){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8171if(size==="1"){return![...selectedIcon.classList].some((classString)=>classString.match(/^fa-[2-5]x$/));} 8172return selectedIcon.classList.contains(`fa-${size}x`);} 8173hasSpinIcon(){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8174return selectedIcon.classList.contains("fa-spin");} 8175openIconDialog(){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8176this.dependencies.dialog.addDialog(MediaDialog,{visibleTabs:["ICONS"],media:selectedIcon,save:(el)=>this.onSaveIcon(el,selectedIcon),});} 8177onSaveIcon(icon,prevIcon){for(const attribute of icon.attributes){prevIcon.setAttribute(attribute.no
8177deName,attribute.nodeValue);} 8178this.dependencies.history.addStep();} 8179computeBackgroundColorForIcon(){const nodes=this.dependencies.selection.getTargetedNodes().filter((node)=>node.classList?.contains("fa"));if(nodes.length===0){return;} 8180const el=closestElement(nodes[0],"font");if(!el){return;} 8181return this.dependencies.color.getElementColors(el).backgroundColor;}} 8182return __exports;});; 8183 8184/* /html_editor/static/src/main/media/image_crop.js */ 8185odoo.define('@html_editor/main/media/image_crop',['@html_editor/utils/image_processing','@html_editor/main/media/image_plugin','@web/core/l10n/translation','@odoo/owl','@web/core/utils/hooks','@web/core/utils/scrolling'],function(require){'use strict';let __exports={};const{activateCropper,loadImage,loadImageInfo,cropperDataFieldsWithAspectRatio,}=require("@html_editor/utils/image_processing");const{IMAGE_SHAPES}=require("@html_editor/main/media/image_plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Component,useRef,onMounted,onWillDestroy,markup,useExternalListener,status,}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{scrollTo,closestScrollableY}=require("@web/core/utils/scrolling");const cropperAspectRatios=__exports.cropperAspectRatios={"0/0":{label:_t("Flexible"),value:0},"16/9":{label:"16:9",value:16/9},"4/3":{label:"4:3",value:4/3},"1/1":{label:"1:1",value:1},"2/3":{label:"2:3",value:2/3},};const ImageCrop=__exports.ImageCrop=class ImageCrop extends Component{static template="html_editor.ImageCrop";static props={document:{validate:(p)=>p.nodeType===Node.DOCUMENT_NODE},media:{optional:true},onClose:{type:Function,optional:true},onSave:{type:Function,optional:true},};setup(){this.aspectRatios=cropperAspectRatios;this.notification=useService("notification");this.media=this.props.media;this.document=this.props.document;this.elRef=useRef("el");this.cropperWrapper=useRef("cropperWrapper");this.imageRef=useRef("imageRef");this.applyButtonRef=useRef("applyButton");this.discardButtonRef=useRef("discardButton");this.isCropperActive=false;useExternalListener(this.document,"mousedown",this.onDocumentMousedown,{capture:true,});useExternalListener(this.document,"keydown",this.onDocumentKeydown,{capture:true,});useExternalListener(document,"keydown",this.onDocumentKeydown,{capture:true,});useExternalListener(this.document,"selectionchange",()=>{if(!this.props.media.isConnected){this.closeCropper();}},{capture:true});onMounted(()=>{this.hasModifiedImageClass=this.media.classList.contains("o_modified_image_to_save");if(this.hasModifiedImageClass){this.media.classList.remove("o_modified_image_to_save");} 8186this.show();});onWillDestroy(this.closeCropper);} 8187closeCropper(){if(!this.isCropperActive&&!this.forceClose){return;} 8188this.cropper?.destroy?.();this.media.setAttribute("src",this.initialSrc);if(this.hasModifiedImageClass&&!this.media.classList.contains("o_modified_image_to_save")){this.media.classList.add("o_modified_image_to_save");} 8189this.props?.onClose?.();this.isCropperActive=false;} 8190async reset(){if(this.cropper){this.cropper.reset();if(this.aspectRatio!=="0/0"){this.aspectRatio="0/0";this.cropper.setAspectRatio(cropperAspectRatios[this.aspectRatio].value);} 8191await this.save();}} 8192async show(){if(this.isCropperActive){return;} 8193const src=this.media.getAttribute("src");const data={...this.media.dataset};this.initialSrc=src;this.aspectRatio=data.aspectRatio||"0/0";Object.assign(this.media.dataset,await loadImageInfo(this.media));const isIllustration=/^\/(?:html|web)_editor\/shape\/illustration\//.test(this.media.dataset.originalSrc);this.uncroppable=false;if(this.media.dataset.originalSrc&&!isIllustration){this.originalSrc=this.media.dataset.originalSrc;this.originalId=this.media.dataset.originalId;}else{this.uncroppable=true;} 8194if(this.uncroppable){this.notification.add(markup(_t("This type of image is not supported for cropping.<br/>If you want to crop it, please first download it from the original source and upload it in Odoo.")),{title:_t("This image is an external image"),type:"warning",});this.forceClose=true;return this.closeCropper();} 8195await this.scrollToInvisibleImage();await loadImage(this.originalSrc,this.media);if(status(this)!=="mounted"){return;} 8196const cropperImage=this.imageRef.el;[cropperImage.style.width,cropperImage.style.height]=[this.media.width+"px",this.media.height+"px",];const sel=this.document.getSelection();sel&&sel.removeAllRanges();let offset=undefined;if(!this.media.getClientRects().length){offset={top:0,left:0};}else{const rect=this.media.getBoundingClientRect();
8196offset={top:rect.top,left:rect.left,};} 8197offset.left+=parseInt(this.media.style.paddingLeft||0);offset.top+=parseInt(this.media.style.paddingRight||0);const frameElement=this.media.ownerDocument.defaultView.frameElement;if(frameElement){const frameRect=frameElement.getBoundingClientRect();offset.left+=frameRect.left;offset.top+=frameRect.top;} 8198this.cropperWrapper.el.style.left=`${offset.left}px`;this.cropperWrapper.el.style.top=`${offset.top}px`;await loadImage(this.originalSrc,cropperImage);if(status(this)!=="mounted"){return;} 8199this.cropper=await activateCropper(cropperImage,cropperAspectRatios[this.aspectRatio]?.value||0,this.media.dataset,{onReady:(cropper)=>{const cropperMove=cropper.face;for(const shape of IMAGE_SHAPES){cropperMove.classList.toggle(shape,this.media.classList.contains(shape));}},});this.isCropperActive=true;this.applyButtonRef.el?.focus({preventScroll:true});} 8200async save(){const cropperData=this.getCropperData(this.cropper);this.props.onSave?.({aspectRatio:this.aspectRatio,...cropperData,});this.closeCropper();} 8201resetCropBox(){this.cropper.clear();this.cropper.crop();} 8202async scrollToInvisibleImage(){const rect=this.media.getBoundingClientRect();const viewportTop=this.document.documentElement.scrollTop||0;const viewportBottom=viewportTop+window.innerHeight;const scrollable=closestScrollableY(this.media);if(rect.top<viewportTop||viewportBottom-rect.bottom<100){await scrollTo(this.media,{behavior:"smooth",...(scrollable&&{scrollable}),});}} 8203onZoom(scale){this.cropper.zoom(scale);} 8204onReset(){this.cropper.reset();} 8205onRotate(degree){this.cropper.rotate(degree);} 8206onFlip(scaleDirection){const amount=this.cropper.getData()[scaleDirection]*-1;this.cropper[scaleDirection](amount);} 8207setAspectRatio(ratio){this.cropper.reset();this.aspectRatio=ratio;this.cropper.setAspectRatio(cropperAspectRatios[this.aspectRatio].value);} 8208onDocumentMousedown(ev){if(this.props.document.body.contains(ev.target)&&(this.elRef.el===ev.target||!this.elRef.el.contains(ev.target))){return this.closeCropper();}} 8209onDocumentKeydown(ev){if(!this.isCropperActive){return;} 8210if(ev.key==="Enter"){ev.preventDefault();ev.stopImmediatePropagation();if(ev.target===this.discardButtonRef.el){return this.closeCropper();} 8211return this.save();}else if(["Backspace","Escape"].includes(ev.key)){ev.preventDefault();ev.stopImmediatePropagation();return this.closeCropper();}} 8212getCropperData(cropper){return Object.fromEntries(cropperDataFieldsWithAspectRatio.map((field)=>[field,cropper.getData()[field]]).filter(([,value])=>value));} 8213async onCropZoom(){await new Promise((res)=>setTimeout(res,0));this.resetCropBox();}} 8214return __exports;});; 8215 8216/* /html_editor/static/src/main/media/image_crop_plugin.js */ 8217odoo.define('@html_editor/main/media/image_crop_plugin',['@web/core/l10n/translation','@web/core/registry','@html_editor/plugin','@html_editor/main/media/image_crop','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{registry}=require("@web/core/registry");const{Plugin}=require("@html_editor/plugin");const{ImageCrop}=require("@html_editor/main/media/image_crop");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const ImageCropPlugin=__exports.ImageCropPlugin=class ImageCropPlugin extends Plugin{static id="imageCrop";static dependencies=["selection","history","imagePostProcess"];static shared=["openCropImage"];resources={user_commands:[{id:"cropImage",run:this.openCropImage.bind(this),description:_t("Crop image"),icon:"fa-crop",isAvailable:isHtmlContentSupported,},],toolbar_items:[{id:"image_crop",commandId:"cropImage",groupId:"image_modifiers",},],};getTargetedImage(){const targetedNodes=this.dependencies.selection.getTargetedNodes();return targetedNodes.find((node)=>node.tagName==="IMG");} 8218async openCropImage(targetedImg,imageCropProps={}){targetedImg=targetedImg||this.getTargetedImage();if(!targetedImg){return;} 8219return registry.category("main_components").add("ImageCropping",{Component:ImageCrop,props:{media:targetedImg,onSave:async(newDataset)=>{const updateImageAttributes=await this.dependencies.imagePostProcess.processImage({img:targetedImg,newDataset,});updateImageAttributes();this.dependencies.history.addStep();},document:this.document,...imageCropProps,onClose:()=>{registry.category("main_components").remove("ImageCropping");imageCropProps.onClose?.();},},});}} 8220return __exports;});; 8221 8222/* /html_editor/static/src/main/media/image_description.js */ 8223odoo.define('@html_editor/main/media/image_description',['@odoo/owl','@web/core/dialog/dialog','@html_editor/main/toolbar/toolbar','@web/core/h
8223otkeys/hotkey_hook'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const ImageDescription=__exports.ImageDescription=class ImageDescription extends Component{static components={Dialog};static props={...toolbarButtonProps,openImageDescriptionPopover:Function,};static template="html_editor.ImageDescription";} 8224const ImageDescriptionPopover=__exports.ImageDescriptionPopover=class ImageDescriptionPopover extends Component{static props={close:Function,description:{type:String,optional:true,},onConfirm:Function,tooltip:{type:String,optional:true,},};static template="html_editor.ImageDescriptionPopover";setup(){this.state={description:this.props.description,tooltip:this.props.tooltip,};this.inputRef=useRef("description");useEffect((el)=>el?.focus(),()=>[this.inputRef.el]);useHotkey("escape",()=>this.props.close());} 8225onSave(){this.props.onConfirm(this.state.description||"",this.state.tooltip||"");this.props.close();}} 8226return __exports;});; 8227 8228/* /html_editor/static/src/main/media/image_plugin.js */ 8229odoo.define('@html_editor/main/media/image_plugin',['@html_editor/plugin','@web/core/l10n/translation','@html_editor/utils/url','@html_editor/main/media/image_description','@html_editor/main/media/image_toolbar_dropdown','@web/core/file_viewer/file_viewer_hook','@html_editor/core/selection_plugin','@html_editor/utils/position','@html_editor/utils/resource','@html_editor/main/media/image_transform_button','@html_editor/utils/selection','@html_editor/utils/blocks','@html_editor/utils/dom','@odoo/owl'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{isImageUrl}=require("@html_editor/utils/url");const{ImageDescription,ImageDescriptionPopover}=require("@html_editor/main/media/image_description");const{ImageToolbarDropdown}=require("@html_editor/main/media/image_toolbar_dropdown");const{createFileViewer}=require("@web/core/file_viewer/file_viewer_hook");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{boundariesOut}=require("@html_editor/utils/position");const{READ,withSequence}=require("@html_editor/utils/resource");const{ImageTransformButton}=require("@html_editor/main/media/image_transform_button");const{callbacksForCursorUpdate}=require("@html_editor/utils/selection");const{closestBlock}=require("@html_editor/utils/blocks");const{fillEmpty}=require("@html_editor/utils/dom");const{reactive}=require("@odoo/owl");function hasShape(imagePlugin,shapeName){return()=>imagePlugin.isSelectionShaped(shapeName);} 8230const IMAGE_SHAPES=__exports.IMAGE_SHAPES=["rounded","rounded-circle","shadow","img-thumbnail"];const IMAGE_PADDING=[{name:"None",value:0},{name:"Small",value:1},{name:"Medium",value:2},{name:"Large",value:3},{name:"XL",value:5},];const IMAGE_SIZE=[{name:"Default",value:""},{name:"100%",value:"100%"},{name:"50%",value:"50%"},{name:"25%",value:"25%"},];const ImagePlugin=__exports.ImagePlugin=class ImagePlugin extends Plugin{static id="image";static dependencies=["history","dom","selection","overlay"];static shared=["getTargetedImage","previewImage","resetImageTransformation"];static defaultConfig={allowImageTransform:true};toolbarNamespace="image";resources={user_commands:[{id:"deleteImage",description:_t("Remove (DELETE) image"),icon:"fa-trash text-danger",run:this.deleteImage.bind(this),isAvailable:isHtmlContentSupported,},{id:"previewImage",description:_t("Preview image"),icon:"fa-search-plus",run:this.previewImage.bind(this),isAvailable:isHtmlContentSupported,},{id:"setImageShapeRounded",description:_t("Set shape: Rounded"),icon:"fa-square",run:()=>this.setImageShape("rounded",{excludeClasses:["rounded-circle"]}),isAvailable:isHtmlContentSupported,},{id:"setImageShapeCircle",description:_t("Set shape: Circle"),icon:"fa-circle-o",run:()=>this.setImageShape("rounded-circle",{excludeClasses:["rounded"]}),isAvailable:isHtmlContentSupported,},{id:"setImageShapeShadow",description:_t("Set shape: Shadow"),icon:"fa-sun-o",run:()=>this.setImageShape("shadow"),isAvailable:isHtmlContentSupported,},{id:"setImageShapeThumbnail",description:_t("Set shape: Thumbnail"),icon:"fa-picture-o",run:()=>this.setImageShape("img-thumbnail"),isAvailable:isHtmlContentSupported,},{id:"resizeImage",run:this.resizeImage.bind(this),isAvailable:isHtmlContentSupported,}
8230,],toolbar_namespace_providers:[(targetedNodes)=>{if(targetedNodes.length&&targetedNodes.every((node)=>node.nodeName==="IMG")){return this.toolbarNamespace;}},],toolbar_groups:[withSequence(23,{id:"image_preview",namespaces:["image"]}),withSequence(24,{id:"image_description",namespaces:["image"]}),withSequence(25,{id:"image_shape",namespaces:["image"]}),withSequence(26,{id:"image_padding",namespaces:["image"]}),withSequence(26,{id:"image_size",namespaces:["image"]}),withSequence(26,{id:"image_modifiers",namespaces:["image"]}),withSequence(32,{id:"image_delete",namespaces:["image"]}),],toolbar_items:[{id:"image_preview",groupId:"image_preview",commandId:"previewImage",},{id:"image_description",description:_t("Edit media description"),groupId:"image_description",Component:ImageDescription,props:{openImageDescriptionPopover:this.openImageDescriptionPopover.bind(this),},isAvailable:isHtmlContentSupported,},{id:"shape_rounded",groupId:"image_shape",commandId:"setImageShapeRounded",isActive:hasShape(this,"rounded"),},{id:"shape_circle",groupId:"image_shape",commandId:"setImageShapeCircle",isActive:hasShape(this,"rounded-circle"),},{id:"shape_shadow",groupId:"image_shape",commandId:"setImageShapeShadow",isActive:hasShape(this,"shadow"),},{id:"shape_thumbnail",groupId:"image_shape",commandId:"setImageShapeThumbnail",isActive:hasShape(this,"img-thumbnail"),},{id:"image_padding",groupId:"image_padding",description:_t("Set image padding"),Component:ImageToolbarDropdown,props:{name:"image_padding",icon:"html_editor.ImagePaddingIcon",items:IMAGE_PADDING,onSelected:(item)=>{this.setImagePadding({size:item.value});},},isAvailable:isHtmlContentSupported,},{id:"image_size",groupId:"image_size",description:_t("Resize image"),Component:ImageToolbarDropdown,props:{name:"image_size",getDisplay:()=>this.imageSize,items:IMAGE_SIZE,onSelected:(item)=>{this.resizeImage({size:item.value});this.updateImageParams();},},isAvailable:(selection)=>isHtmlContentSupported(selection)&&(this.config.allowImageResize??true),},{id:"image_transform",groupId:"image_modifiers",description:_t("Transform the picture (click twice to reset transformation)"),Component:ImageTransformButton,props:this.getImageTransformProps(),isAvailable:(selection)=>this.config.allowImageTransform&&isHtmlContentSupported(selection),},{id:"image_delete",groupId:"image_delete",commandId:"deleteImage",},],selectionchange_handlers:withSequence(READ,this.updateImageParams.bind(this)),post_undo_handlers:this.updateImageParams.bind(this),post_redo_handlers:this.updateImageParams.bind(this),paste_media_url_command_providers:this.getCommandForImageUrlPaste.bind(this),};setup(){this.imageSize=reactive({displayName:"Default"});this.addDomListener(this.editable,"pointerdown",(e)=>{const selection=this.dependencies.selection.getEditableSelection();if(selection.isCollapsed&&e.target.tagName==="IMG"){this.setSelectionAroundImage(e.target);}});this.addDomListener(this.editable,"pointerup",(e)=>{if(e.target.tagName==="IMG"){this.setSelectionAroundImage(e.target);}});this.fileViewer=createFileViewer();this.overlay=this.dependencies.overlay.createOverlay(ImageDescriptionPopover,{className:"popover",});} 8231destroy(){super.destroy();} 8232get imageSizeName(){const targetedImg=this.getTargetedImage();if(!targetedImg){return"Default";} 8233return targetedImg.style.width||"Default";} 8234setImagePadding({size}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8235for(const classString of targetedImg.classList){if(classString.match(/^p-[0-9]$/)){targetedImg.classList.remove(classString);}} 8236targetedImg.classList.add(`p-${size}`);this.dependencies.history.addStep();} 8237resizeImage({size}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8238targetedImg.style.width=size||"";this.dependencies.history.addStep();} 8239setImageShape(className,{excludeClasses=[]}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8240for(const classString of excludeClasses){if(targetedImg.classList.contains(classString)){targetedImg.classList.remove(classString);}} 8241targetedImg.classList.toggle(className);this.dependencies.history.addStep();} 8242previewImage(){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8243let imageName;this.getResource("image_name_predicates").find((p)=>{imageName=p(targetedImg);return imageName;});const fileModel={isImage:true,isViewable:true,name:imageName||targetedImg.src,defaultSource:targetedImg.src,downloadUrl:targetedImg.src,};this.document.getSelection().collapseToEnd();this.document.activeElement.blur();this.fileViewer.open(fileModel);} 8244deleteImage(){const targetedImg=this.getTargetedImage();if(targetedImg){if(this.delegateTo("delete_image_overrides",targetedImg)){return;} 8245const cursors=this.dependencies.selection.preserveSelection();cursors.update(callbacksForCursorUpdate.remove(targetedImg));const blockEl=closestBlock(targetedImg.parentElement);targetedImg.remove();
8245cursors.restore();fillEmpty(blockEl);this.dependencies.history.addStep();}} 8246getTargetedImage(){const targetedNodes=this.dependencies.selection.getTargetedNodes();return targetedNodes.find((node)=>node.tagName==="IMG");} 8247hasImageSize(size){const targetedImg=this.getTargetedImage();return targetedImg?.style?.width===size;} 8248isSelectionShaped(shape){const targetedNodes=this.dependencies.selection.getTargetedNodes().filter((n)=>n.tagName==="IMG"&&n.classList.contains(shape));return targetedNodes.length>0;} 8249getImageAttribute(attributeName){const targetedNodes=this.dependencies.selection.getTargetedNodes();const targetedImg=targetedNodes.find((node)=>node.tagName==="IMG");return targetedImg.getAttribute(attributeName)||undefined;} 8250getCommandForImageUrlPaste(url){if(isImageUrl(url)){return{title:_t("Embed Image"),description:_t("Embed the image in the document."),icon:"fa-image",run:()=>{this.dispatchTo("before_paste_handlers",this.dependencies.selection.getEditableSelection());const img=this.document.createElement("IMG");img.setAttribute("src",url);this.dependencies.dom.insert(img);this.dependencies.history.addStep();},};}} 8251updateImageDescription({description,tooltip}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8252targetedImg.setAttribute("alt",description);targetedImg.setAttribute("title",tooltip);this.dependencies.history.addStep();} 8253resetImageTransformation(image){const stylePropertiesToRemove=["transform","transform-box","transform-origin","transform-style","width","height",];for(const styleProperty of stylePropertiesToRemove){image.style.removeProperty(styleProperty);} 8254this.dependencies.history.addStep();} 8255getImageTransformProps(){return{id:"image_transform",icon:"fa-object-ungroup",title:_t("Transform the picture (click twice to reset transformation)"),getTargetedImage:this.getTargetedImage.bind(this),resetImageTransformation:this.resetImageTransformation.bind(this),addStep:this.dependencies.history.addStep.bind(this),document:this.document,editable:this.editable,activeTitle:_t("Click again to reset transformation"),};} 8256updateImageParams(){this.imageSize.displayName=this.imageSizeName;} 8257openImageDescriptionPopover(){const image=this.getTargetedImage();if(image){this.overlay.open({target:image,props:{close:()=>this.overlay.close(),description:this.getImageAttribute("alt"),tooltip:this.getImageAttribute("title"),onConfirm:(description,tooltip)=>{this.updateImageDescription({description,tooltip});},},});}} 8258setSelectionAroundImage(img){const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesOut(img);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});this.dependencies.selection.focusEditable();}} 8259return __exports;});; 8260 8261/* /html_editor/static/src/main/media/image_post_process_plugin.js */ 8262odoo.define('@html_editor/main/media/image_post_process_plugin',['@html_editor/utils/image_processing','@html_editor/plugin','@html_editor/utils/perspective_utils'],function(require){'use strict';let __exports={};const{activateCropper,getAspectRatio,getDataURLBinarySize,getImageSizeFromCache,isGif,isWebGLEnabled,loadImage,loadImageDataURL,loadImageInfo,}=require("@html_editor/utils/image_processing");const{Plugin}=require("@html_editor/plugin");const{getAffineApproximation,getProjective}=require("@html_editor/utils/perspective_utils");const DEFAULT_IMAGE_QUALITY=__exports.DEFAULT_IMAGE_QUALITY="92";const ImagePostProcessPlugin=__exports.ImagePostProcessPlugin=class ImagePostProcessPlugin extends Plugin{static id="imagePostProcess";static dependencies=["style"];static shared=["processImage","getProcessedImageSize"];async _processImage({img,newDataset={},onImageInfoLoaded}){const processContext={};if(!newDataset.originalSrc||!newDataset.mimetypeBeforeConversion){Object.assign(newDataset,await loadImageInfo(img));} 8263if(onImageInfoLoaded){if(await onImageInfoLoaded(newDataset)){return;}} 8264for(const cb of this.getResource("process_image_warmup_handlers")){const addedContext=await cb(img,newDataset);if(addedContext){if(addedContext.newDataset){Object.assign(newDataset,addedContext.newDataset);} 8265Object.assign(processContext,addedContext);}} 8266const data=getImageTransformationData({...img.dataset,...newDataset});const{mimetypeBeforeConversion,formatMimetype,width,height,resizeWidth,filter,glFilter,filterOptions,aspectRatio,quality,}=data;const{postProcessCroppedCanvas,perspective,getHeight}=processContext;const originalImg=await loadImage(data.originalSrc);const originalSrc=originalImg.getAttribute("src");if(!(await isImageSupportedForProcessing(img,formatMimetype||mimetypeBeforeConversion))){const[postUrl,postDataset]=await this.postProcessImage(await loadImageDataURL(originalSrc),newDataset,processContext);return{url:postUrl,newDataset:postDataset};} 8267const container=document.createElement("div");container.appendChild(originalImg);const cropper=await activateCropper(originalImg,aspectRatio,data);const croppedCanvas=cropper.getCroppedCanvas(width,height);cropper.destroy();const processedCanvas=(await postProcessCroppedCanvas?.(croppedCanvas))||croppedCanvas;const canvas=document.createElement("canvas");canvas.width=resizeWidth||processedCanvas.width;canvas.height=getHeight?getHeight(canvas):(processedCanvas.height*canvas.width)/processedCanvas.width;const ctx=canvas.getContext("2d");ctx.imageSmoothingQuality="high";ctx.mozImageSmoothingEnabled=true;ctx.webkitImageSmoothingEnabled=true;ctx.msImageSmoothingEnabled=true;ctx.imageSmoothingEnabled=true;if(perspective){const points=JSON.parse(perspective);const divisions=10;const w=processedCanvas.width,h=processedCanvas.height;const project=getProjective(w,h,[[(canvas.width/100)*points[0][0],(canvas.height/100)*points[0][1]],[(canvas.width/100)*points[1][0],(canvas.height/100)*points[1][1]],[(canvas.width/100)*points[2][0],(canvas.height/100)*points[2][1]],[(canvas.width/100)*points[3][0],(canvas.height/100)*points[3][1]],]);for(let i=0;i<divisions;i++){for(let j=0;
8267j<divisions;j++){const[dx,dy]=[w/divisions,h/divisions];const upper={origin:[i*dx,j*dy],sides:[dx,dy],flange:0.1,overlap:0,};const lower={origin:[i*dx+dx,j*dy+dy],sides:[-dx,-dy],flange:0,overlap:0.1,};for(const{origin,sides,flange,overlap}of[upper,lower]){const[[a,c,e],[b,d,f]]=getAffineApproximation(project,[origin,[origin[0]+sides[0],origin[1]],[origin[0],origin[1]+sides[1]],]);const ox=(i!==divisions?overlap*sides[0]:0)+flange*sides[0];const oy=(j!==divisions?overlap*sides[1]:0)+flange*sides[1];origin[0]+=flange*sides[0];origin[1]+=flange*sides[1];sides[0]-=flange*sides[0];sides[1]-=flange*sides[1];ctx.save();ctx.setTransform(a,b,c,d,e,f);ctx.beginPath();ctx.moveTo(origin[0]-ox,origin[1]-oy);ctx.lineTo(origin[0]+sides[0],origin[1]-oy);ctx.lineTo(origin[0]+sides[0],origin[1]);ctx.lineTo(origin[0],origin[1]+sides[1]);ctx.lineTo(origin[0]-ox,origin[1]+sides[1]);ctx.closePath();ctx.clip();ctx.drawImage(processedCanvas,0,0);ctx.restore();}}}}else{ctx.drawImage(processedCanvas,0,0,processedCanvas.width,processedCanvas.height,0,0,canvas.width,canvas.height);} 8268const canUseWebGL=glFilter&&isWebGLEnabled()&&window.WebGLImageFilter;if(canUseWebGL){const glf=new window.WebGLImageFilter();const cv=document.createElement("canvas");cv.width=canvas.width;cv.height=canvas.height;applyAll=_applyAll.bind(null,canvas);glFilters[glFilter](glf,cv,filterOptions);const filtered=glf.apply(canvas);ctx.drawImage(filtered,0,0,filtered.width,filtered.height,0,0,canvas.width,canvas.height);} 8269ctx.fillStyle=filter||"#0000";ctx.fillRect(0,0,canvas.width,canvas.height);newDataset.mimetype=formatMimetype||mimetypeBeforeConversion;const dataURL=canvas.toDataURL(newDataset.mimetype,quality/100);const newSize=getDataURLBinarySize(dataURL);const originalSize=getImageSizeFromCache(originalSrc);const isChanged=!!perspective||!!glFilter||originalImg.width!==canvas.width||originalImg.height!==canvas.height||originalImg.width!==processedCanvas.width||originalImg.height!==processedCanvas.height;let url=isChanged||originalSize>=newSize?dataURL:await loadImageDataURL(originalSrc);[url,newDataset]=await this.postProcessImage(url,newDataset,processContext);return{url,newDataset};} 8270async processImage(params){const processed=await this._processImage(params);if(!processed){return()=>{};} 8271return()=>this.updateImageAttributes(params.img,processed.url,processed.newDataset);} 8272async getProcessedImageSize(img){const processed=await this._processImage({img});return getDataURLBinarySize(processed.url);} 8273async postProcessImage(url,newDataset,processContext){for(const cb of this.getResource("process_image_post_handlers")){const[newUrl,handlerDataset]=(await cb(url,newDataset,processContext))||[];url=newUrl||url;newDataset=handlerDataset||newDataset;} 8274return[url,newDataset];} 8275updateImageAttributes(el,url,newDataset){el.classList.add("o_modified_image_to_save");if(el.tagName==="IMG"){el.setAttribute("src",url);}else{this.dependencies.style.setBackgroundImageUrl(el,url);} 8276for(const key in newDataset){const value=newDataset[key];if(value){el.dataset[key]=value;}else{delete el.dataset[key];}} 8277this.dispatchTo("on_image_updated_handlers",{imageEl:el});}} 8278__exports.getImageTransformationData=getImageTransformationData;function getImageTransformationData(dataset){const data=Object.assign({glFilter:"",filter:"#0000",forceModification:false,},dataset);for(const key of["width","height","resizeWidth"]){data[key]=parseFloat(data[key]);} 8279if(!("quality"in data)){data.quality=DEFAULT_IMAGE_QUALITY;} 8280data.aspectRatio=data.aspectRatio?getAspectRatio(data.aspectRatio):0;return data;} 8281function shouldTransformImage(data){return(data.perspective||data.glFilter||data.width||data.height||data.resizeWidth||data.aspectRatio);} 8282__exports.shouldPreventGifTransformation=shouldPreventGifTransformation;function shouldPreventGifTransformation(data){return isGif(data.mimetypeBeforeConversion)&&!shouldTransformImage(data);} 8283const defaultImageFilterOptions=__exports.defaultImageFilterOptions={blend:"normal",filterColor:"",blur:"0",desaturateLuminance:"0",saturation:"0",contrast:"0",brightness:"0",sepia:"0",};__exports.isImageSupportedForProcessing=isImageSupportedForProcessing;async function isImageSupportedForProcessing(imgEl,originalImgMimetype){if(!["image/jpeg","image/png","image/webp"].includes(originalImgMimetype)){return false;}
8284return!!(imgEl.dataset.originalSrc||(await loadImageInfo(imgEl)).originalSrc);} 8285const _applyAll=(result,filter,filters)=>{filters.forEach((f)=>{if(f[0]==="blend"){const cv=f[1];const ctx=result.getContext("2d");ctx.globalCompositeOperation=f[2];ctx.globalAlpha=f[3];ctx.drawImage(cv,0,0);ctx.globalCompositeOperation="source-over";ctx.globalAlpha=1.0;}else{filter.addFilter(...f);}});};let applyAll;const glFilters={blur:(filter)=>filter.addFilter("blur",10),1977:(filter,cv)=>{const ctx=cv.getContext("2d");ctx.fillStyle="rgb(243, 106, 188)";ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"screen",0.3],["brightness",0.1],["contrast",0.1],["saturation",0.3],]);},aden:(filter,cv)=>{const ctx=cv.getContext("2d");ctx.fillStyle="rgb(66, 10, 14)";ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"darken",0.2],["brightness",0.2],["contrast",-0.1],["saturation",-0.15],["hue",20],]);},brannan:(filter,cv)=>{const ctx=cv.getContext("2d");ctx.fillStyle="rgb(161, 44, 191)";ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"lighten",0.31],["sepia",0.5],["contrast",0.4],]);},earlybird:(filter,cv)=>{const ctx=cv.getContext("2d");const gradient=ctx.createRadialGradient(cv.width/2,cv.height/2,0,cv.width/2,cv.height/2,Math.hypot(cv.width,cv.height)/2);gradient.addColorStop(0.2,"#D0BA8E");gradient.addColorStop(1,"#1D0210");ctx.fillStyle=gradient;ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"overlay",0.2],["sepia",0.2],["contrast",-0.1],]);},inkwell:(filter,cv)=>{applyAll(filter,[["sepia",0.3],["brightness",0.1],["contrast",-0.1],["desaturateLuminance"],]);},maven:(filter,cv)=>{applyAll(filter,[["sepia",0.25],["brightness",-0.05],["contrast",-0.05],["saturation",0.5],]);},toaster:(filter,cv)=>{const ctx=cv.getContext("2d");const gradient=ctx.createRadialGradient(cv.width/2,cv.height/2,0,cv.width/2,cv.height/2,Math.hypot(cv.width,cv.height)/2);gradient.addColorStop(0,"#0F4E80");gradient.addColorStop(1,"#3B003B");ctx.fillStyle=gradient;ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"screen",0.5],["brightness",-0.1],["contrast",0.5],]);},walden:(filter,cv)=>{const ctx=cv.getContext("2d");ctx.fillStyle="#CC4400";ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"screen",0.3],["sepia",0.3],["brightness",0.1],["saturation",0.6],["hue",350],]);},valencia:(filter,cv)=>{const ctx=cv.getContext("2d");ctx.fillStyle="#3A0339";ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"exclusion",0.5],["sepia",0.08],["brightness",0.08],["contrast",0.08],]);},xpro:(filter,cv)=>{const ctx=cv.getContext("2d");const gradient=ctx.createRadialGradient(cv.width/2,cv.height/2,0,cv.width/2,cv.height/2,Math.hypot(cv.width,cv.height)/2);gradient.addColorStop(0.4,"#E0E7E6");gradient.addColorStop(1,"#2B2AA1");ctx.fillStyle=gradient;ctx.fillRect(0,0,cv.width,cv.height);applyAll(filter,[["blend",cv,"color-burn",0.7],["sepia",0.3],]);},custom:(filter,cv,filterOptions)=>{const options=Object.assign(defaultImageFilterOptions,JSON.parse(filterOptions||"{}"));const filters=[];if(options.filterColor){const ctx=cv.getContext("2d");ctx.fillStyle=options.filterColor;ctx.fillRect(0,0,cv.width,cv.height);filters.push(["blend",cv,options.blend,1]);} 8286delete options.blend;delete options.filterColor;filters.push(...Object.entries(options).map(([filter,amount])=>[filter,parseInt(amount)/100]));applyAll(filter,filters);},};return __exports;});; 8287 8288/* /html_editor/static/src/main/media/image_save_plugin.js */ 8289odoo.define('@html_editor/main/media/image_save_plugin',['@html_editor/plugin','@html_editor/utils/image','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{backgroundImageCssToParts,backgroundImagePartsToCss,getImageSrc,}=require("@html_editor/utils/image");const{rpc}=require("@web/core/network/rpc");const ImageSavePlugin=__exports.ImageSavePlugin=class ImageSavePlugin extends Plugin{static id="imageSave";static shared=["savePendingImages"];resources={before_save_handlers:this.savePendingImages.bind(this),...(this.config.dropImageAsAttachment&&{added_image_handlers:(img)=>img.classList.add("o_b64_image_to_save"),}),};async savePendingImages(editableEl=this.editable){const getClosestSavable=(el)=>{for(const provider of this.getResource("closest_savable_providers")){const value=provider(el);if(value){return value;}}};const oldSrcToNewSrcMap=new Map();const b64Proms=[...editableEl.querySelectorAll(".o_b64_image_to_save")].map(async(el)=>{const{resModel,resId}=this.getRecordInfo(getClosestSavable(el));const oldSrc=el.getAttribute("src");await this.saveB64Image(el,resModel,resId);oldSrcToNewSrcMap.set(oldSrc,el.getAttribute("src"));});const modifiedProms=[...editableEl.querySelectorAll(".o_modified_image_to_save")].map(async(el)=>{const{resModel,resId}=this.getRecordInfo(getClosestSavable(el));const oldSrc=el.getAttribute("src");await this.saveModifiedImage(el,resModel,resId);oldSrcToNewSrcMap.set(oldSrc,el.getAttribute("src"));});const proms=[...b64Proms,...modifiedProms];const hasChange=!!proms.length;if(hasChange){await Promise.all(proms);} 8290return hasChange?oldSrcToNewSrcMap:undefined;} 8291createAttachment({el,imageData,resModel,resId}){return rpc("/html_editor/attachment/add_data",{name:el.dataset.f
8291ileName||"",data:imageData,is_image:true,res_model:resModel,res_id:resId,});} 8292async saveB64Image(el,resModel,resId){const imageData=el.getAttribute("src").split("base64,")[1];if(!imageData){el.classList.remove("o_b64_image_to_save");return;} 8293const attachment=await this.createAttachment({el,imageData,resId,resModel,});if(!attachment){return;} 8294if(attachment.mimetype==="image/webp"){el.classList.add("o_modified_image_to_save");el.dataset.originalId=attachment.id;el.dataset.mimetype=attachment.mimetype;el.dataset.fileName=attachment.name;return this.saveModifiedImage(el,resModel,resId);}else{let src=attachment.image_src;if(!attachment.public){let accessToken=attachment.access_token;if(!accessToken){[accessToken]=await this.services.orm.call("ir.attachment","generate_access_token",[attachment.id]);} 8295src+=`?access_token=${encodeURIComponent(accessToken)}`;} 8296el.setAttribute("src",src);} 8297el.classList.remove("o_b64_image_to_save");} 8298async saveModifiedImage(el,resModel,resId){const isBackground=!el.matches("img");let altData=undefined;const isImageField=!!el.closest("[data-oe-type=image]");if(el.dataset.mimetype==="image/webp"&&isImageField){altData={};const image=document.createElement("img");image.src=getImageSrc(el);await new Promise((resolve)=>image.addEventListener("load",resolve));const originalSize=Math.max(image.width,image.height);const smallerSizes=[1024,512,256,128].filter((size)=>size<originalSize);for(const size of[originalSize,...smallerSizes]){const ratio=size/originalSize;const canvas=document.createElement("canvas");canvas.width=image.width*ratio;canvas.height=image.height*ratio;const ctx=canvas.getContext("2d");ctx.fillStyle="rgb(255, 255, 255)";ctx.fillRect(0,0,canvas.width,canvas.height);ctx.drawImage(image,0,0,image.width,image.height,0,0,canvas.width,canvas.height);altData[size]={"image/jpeg":canvas.toDataURL("image/jpeg").split(",")[1],};
8298if(size!==originalSize){altData[size]["image/webp"]=canvas.toDataURL("image/webp").split(",")[1];}}} 8299let attachmentNotFound=false;let newAttachmentSrc;try{newAttachmentSrc=await rpc(`/html_editor/modify_image/${encodeURIComponent(el.dataset.originalId)}`,{res_model:resModel,res_id:parseInt(resId),data:getImageSrc(el).split(",")[1],alt_data:altData,mimetype:isBackground?el.dataset.mimetype:el.getAttribute("src").split(":")[1].split(";")[0],name:el.dataset.fileName?el.dataset.fileName:null,});}catch{newAttachmentSrc="/html_editor/static/src/img/placeholder_thumbnail.png";attachmentNotFound=true;} 8300el.classList.remove("o_modified_image_to_save");let targetEl=el;if(isBackground){const parts=backgroundImageCssToParts(el.style["background-image"]);parts.url=`url('${newAttachmentSrc}')`;const combined=backgroundImagePartsToCss(parts);el.style["background-image"]=combined;}else{if(attachmentNotFound){targetEl=document.createElement("img");el.insertAdjacentElement("afterend",targetEl);el.remove();} 8301targetEl.src=newAttachmentSrc;} 8302this.dispatchTo("on_image_saved_handlers",{imageEl:targetEl});} 8303getRecordInfo(editableEl=null){return this.config.getRecordInfo?this.config.getRecordInfo(editableEl):{};}} 8304return __exports;});; 8305 8306/* /html_editor/static/src/main/media/image_toolbar_dropdown.js */ 8307odoo.define('@html_editor/main/media/image_toolbar_dropdown',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@html_editor/main/toolbar/toolbar','@web/core/utils/hooks','@html_editor/dropdown_autovisibility_hook'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useChildRef}=require("@web/core/utils/hooks");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const ImageToolbarDropdown=__exports.ImageToolbarDropdown=class ImageToolbarDropdown extends Component{static components={Dropdown,DropdownItem};static props={...toolbarButtonProps,name:String,icon:{type:String,optional:true},onSelected:Function,items:Array,getDisplay:{type:Function,optional:true},};static template="html_editor.ImageToolbarDropdown";setup(){this.items=this.props.items;if(this.props.getDisplay){this.state=useState(this.props.getDisplay());} 8308this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);} 8309onSelected(item){this.props.onSelected(item);}} 8310return __exports;});; 8311 8312/* /html_editor/static/src/main/media/image_transform_button.js */ 8313odoo.define('@html_editor/main/media/image_transform_button',['@odoo/owl','@html_editor/main/toolbar/toolbar','@web/core/registry','@html_editor/main/media/image_transformation'],function(require){'use strict';let __exports={};const{Component,useExternalListener,useState}=require("@odoo/owl");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{registry}=require("@web/core/registry");const{ImageTransformation}=require("@html_editor/main/media/image_transformation");__exports.useImageTransform=useImageTransform;function useImageTransform({document,closeImageTransformation,buttonSelector}){let pointerDownInsideTransform=false;useExternalListener(document,"pointerdown",(ev)=>{if(isNodeInsideTransform(ev.target)){pointerDownInsideTransform=true;}else{closeImageTransformation();pointerDownInsideTransform=false;}});useExternalListener(document,"click",(ev)=>{if(!isNodeInsideTransform(ev.target)&&!pointerDownInsideTransform){closeImageTransformation();} 8314pointerDownInsideTransform=false;},{capture:true});useExternalListener(document,"selectionchange",(ev)=>{closeImageTransformation();});function isNodeInsideTransform(node){if(!node){return false;} 8315if(node.nodeType===Node.TEXT_NODE){node=node.parentElement;} 8316if(node.matches(buttonSelector)){return true;} 8317if(isImageTransformationOpen()&&node.matches(".transfo-controls, .transfo-controls *")){return true;} 8318return false;} 8319function isImageTransformationOpen(){return registry.category("main_components").contains("ImageTransformation");} 8320return{isImageTransformationOpen};} 8321const ImageTransformButton=__exports.ImageTransformButton=class ImageTransformButton extends Component{static template="html_editor.ImageTransformButton";static props={id:String,icon:String,title:String,getTargetedImage:Function,resetImageTransformation:Function,addStep:Function,document:{validate:(p)=>p.nodeType===Node.DOCUMENT_NODE},editable:{validate:(p)=>p.nodeType===Node.ELEMENT_NODE},...toolbarButtonProps,activeTitle:String,};setup(){this.state=useState({active:false});this.transform=useImageTransform({document:this.props.document,closeImageTransformation:this.closeImageTransformation.bind(this),buttonSelector:'[name="image_transform"], [name="image_transform"] *',});} 8322onButtonClick(){this.handleImageTransformation(this.props.getTargetedImage());} 8323handleImageTransformation(image){if(this.transform.isImageTransformationOpen()){this.props.resetImageTransformation(image);this.closeImageTransformation();}else{this.openImageTransformation(image);}} 8324openImageTransformation(image){this.state.active=true;registry.category("main_components").add("ImageTransformation",{Component:ImageTransformation,props:{image,document:this.props.document,editable:this.props.editable,destroy:()=>this.closeImageTransformation(),onChange:()=>this.props.addStep(),},});} 8325closeImageTransformation(){this.state.active=false;if(this.transform.isImageTransformationOpen()){registry.category("main_components").remove("ImageTransformation");}}} 8326return __exports;});; 8327 8328/* /html_editor/static/src/main/media/image_transformation.js */ 8329odoo.define('@html_editor/main/media/image_transformation',['@odoo/owl','@web/core/h
8329otkeys/hotkey_hook','@html_editor/position_hook','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{Component,onMounted,useExternalListener,useRef}=require("@odoo/owl");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{usePositionHook}=require("@html_editor/position_hook");const{closestElement}=require("@html_editor/utils/dom_traversal");const rad=Math.PI/180;const MIN_IMAGE_SIZE=20;const ImageTransformation=__exports.ImageTransformation=class ImageTransformation extends Component{static template="html_editor.ImageTransformation";static props={document:{validate:(p)=>p.nodeType===Node.DOCUMENT_NODE},editable:{validate:(p)=>p.nodeType===Node.ELEMENT_NODE},image:{validate:(p)=>p.tagName==="IMG"},destroy:{type:Function},onChange:{type:Function,optional:true},onApply:{type:Function,optional:true},onComponentMounted:{type:Function,optional:true},};static defaultProps={onComponentMounted:()=>{},};setup(){this.isCurrentlyTransforming=false;this.document=this.props.document;this.image=this.props.image;this.transfoContainer=useRef("transfoContainer");this.transfoControls=useRef("transfoControls");this.transfoCenter=useRef("transfoCenter");this.computeImageTransformations();onMounted(()=>{this.positionTransfoContainer();this.props.onComponentMounted();});useExternalListener(window,"mousemove",this.mouseMove);useExternalListener(window,"mouseup",this.mouseUp);if(this.document.defaultView.frameElement){const iframeWindow=this.document.defaultView;useExternalListener(iframeWindow,"mousemove",this.mouseMove);useExternalListener(iframeWindow,"mouseup",this.mouseUp);} 8330useExternalListener(this.document,"selectionchange",()=>this.destroy());useExternalListener(this.document,"keydown",(ev)=>{if(["Backspace","Delete"].includes(ev.key)){this.destroy();}});useHotkey("escape",()=>this.destroy());usePositionHook({el:this.props.editable},this.document,()=>{if(!this.isCurrentlyTransforming){this.resetHandlers();}});} 8331destroy(){this.props.onApply?.();this.props.destroy();} 8332mouseMove(ev){if(!this.transfo.active){return;} 8333ev.preventDefault();const{pageX,pageY}=this.normalizeCoordinates(ev);const settings=this.transfo.settings;const center=this.transfo.active.center;const cdx=center.left-pageX;const cdy=center.top-pageY;if(this.transfo.active.type=="rotator"){let ang;const dang=Math.atan(settings.width/settings.height)/rad;if(cdy){ang=Math.atan(-cdx/cdy)/rad;}else{ang=0;} 8334if(pageY>=center.top&&pageX>=center.left){ang+=180;}else if(pageY>=center.top&&pageX<center.left){ang+=180;}else if(pageY<center.top&&pageX<center.left){ang+=360;} 8335ang-=dang;if(!ev.ctrlKey){settings.angle=Math.round(ang/this.transfo.settings.rotationStep)*this.transfo.settings.rotationStep;}else{settings.angle=ang;} 8336this.positionTransfoContainer();const new_center=this.getOffset(this.transfoCenter.el);const x=center.left-new_center.left;const y=center.top-new_center.top;const angle=ang*rad;settings.translatex+=x*Math.cos(angle)-y*Math.sin(-angle);settings.translatey+=-x*Math.sin(angle)+y*Math.cos(-angle);}else if(this.transfo.active.type=="position"){const angle=settings.angle*rad;const x=pageX-this.transfo.active.pageX;const y=pageY-this.transfo.active.pageY;this.transfo.active.pageX=pageX;this.transfo.active.pageY=pageY;const dx=x*Math.cos(angle)-y*Math.sin(-angle);const dy=-x*Math.sin(angle)+y*Math.cos(-angle);settings.translatex+=dx;settings.translatey+=dy;}else if(this.transfo.active.type.length===2){const width=this.transfo.active.width;const height=this.transfo.active.height;const deltaX=pageX-this.transfo.active.pageX;const deltaY=pageY-this.transfo.active.pageY;let newWidth=width;let newHeight=height;if(this.transfo.active.type.indexOf("t")!=-1){newHeight=height-deltaY;} 8337if(this.transfo.active.type.indexOf("b")!=-1){newHeight=height+deltaY;} 8338if(this.transfo.active.type.indexOf("l")!=-1){newWidth=width-deltaX;} 8339if(this.transfo.active.type.indexOf("r")!=-1){newWidth=width+deltaX;} 8340if(newWidth<MIN_IMAGE_SIZE){newWidth=MIN_IMAGE_SIZE;} 8341if(newHeight<MIN_IMAGE_SIZE){newHeight=MIN_IMAGE_SIZE;} 8342if(ev.shiftKey&&(this.transfo.active.type==="tl"||this.transfo.active.type==="bl"||this.transfo.active.type==="tr"||this.transfo.active.type==="br")){const aspectRatio=width/height;if(Math.abs(deltaX)>Math.abs(deltaY)){newHeight=newWidth/aspectRatio;}else{newWidth=newHeight*aspectRatio;}} 8343this.image.style.width=newWidth+"px";this.image.style.height="auto";settings.width=newWidth;} 8344settings.angle=Math.round(settings.angle);settings.translatex=Math.round(settings.translatex);settings.translatey=Math.round(settings.translatey);const prevImageTransform=this.image.style.transform;this.image.style.transform="";this.transfo.settings.pos=this.getOffset(this.image);this.image.style.transform=prevImageTransform;this.positionTransfoContainer();} 8345convertPixelWidthToPercentage(){const currentPixelWidth=this.image.offsetWidth;const container=closestElement(this.image.parentElement,(node)=>node.offsetWidth>currentPixelWidth);const containerStyles=window.getComputedStyle(container);const widthPercent=(currentPixelWidth/(container.offsetWidth- 8346parseFloat(containerStyles.paddingLeft)- 8347parseFloat(containerStyles.paddingRight)- 8348parseFloat(containerStyles.borderLeftWidth)-
8349parseFloat(containerStyles.borderRightWidth)))*100;this.image.style.width=Math.min(100,widthPercent).toFixed(2)+"%";} 8350mouseUp(){if(!this.transfo.active){return;} 8351this.isCurrentlyTransforming=false;if(this.transfo.active.type.length===2){this.convertPixelWidthToPercentage();} 8352this.transfo.active=null;this.props.onApply?.();this.props.onChange?.();} 8353mouseDown(ev){if(this.transfo.active){return;} 8354this.isCurrentlyTransforming=true;let type="position";const target=ev.target.closest("div");if(target.classList.contains("transfo-rotator")){type="rotator";}else if(target.classList.contains("transfo-scaler-tl")){type="tl";}else if(target.classList.contains("transfo-scaler-tr")){type="tr";}else if(target.classList.contains("transfo-scaler-br")){type="br";}else if(target.classList.contains("transfo-scaler-bl")){type="bl";}else if(target.classList.contains("transfo-scaler-tc")){type="tc";}else if(target.classList.contains("transfo-scaler-bc")){type="bc";}else if(target.classList.contains("transfo-scaler-ml")){type="ml";}else if(target.classList.contains("transfo-scaler-mr")){type="mr";} 8355const{pageX,pageY}=this.normalizeCoordinates(ev);this.transfo.active={type:type,pageX:pageX,pageY:pageY,width:parseFloat(getComputedStyle(this.image).width),height:parseFloat(getComputedStyle(this.image).height),center:this.getOffset(this.transfoCenter.el),};} 8356computeImageTransformations(){this.transfo={};const transform=this.image.style.transform||"";this.transfo.settings={};this.transfo.settings.angle=transform.indexOf("rotate")!=-1?parseFloat(transform.match(/rotate\(([^)]+)deg\)/)[1]):0;this.image.style.transform="";this.transfo.settings.pos=this.getOffset(this.image);this.transfo.settings.width=parseFloat(getComputedStyle(this.image).width);this.transfo.settings.height=parseFloat(getComputedStyle(this.image).height);const translatex=transform.match(/translateX\(([0-9.-]+)(%|px)\)/);const translatey=transform.match(/translateY\(([0-9.-]+)(%|px)\)/);this.transfo.settings.translate="%";if(translatex&&translatex[2]==="%"){this.transfo.settings.translatexp=parseFloat(translatex[1]);this.transfo.settings.translatex=(this.transfo.settings.translatexp/100)*this.transfo.settings.width;}else{this.transfo.settings.translatex=translatex?parseFloat(translatex[1]):0;} 8357if(translatey&&translatey[2]==="%"){this.transfo.settings.translateyp=parseFloat(translatey[1]);this.transfo.settings.translatey=(this.transfo.settings.translateyp/100)*this.transfo.settings.height;}else{this.transfo.settings.translatey=translatey?parseFloat(translatey[1]):0;} 8358this.transfo.settings.css=window.getComputedStyle(this.image,null);this.transfo.settings.rotationStep=5;} 8359positionTransfoContainer(){const settings=this.transfo.settings;const width=parseFloat(getComputedStyle(this.image).width);const height=parseFloat(getComputedStyle(this.image).height);settings.translatexp=Math.round((settings.translatex/width)*1000)/10;settings.translateyp=Math.round((settings.translatey/height)*1000)/10;this.setImageTransformation(this.image);this.transfoContainer.el.style.position="absolute";this.transfoContainer.el.style.width=width+"px";this.transfoContainer.el.style.height=height+"px";this.transfoContainer.el.style.top=settings.pos.top+"px";this.transfoContainer.el.style.left=settings.pos.left+"px";const controls=this.transfoControls.el;this.setImageTransformation(controls);controls.style.width=width+"px";controls.style.height=height+"px";controls.style.cursor="move";} 8360setImageTransformation(element){let transform="";if(this.transfo.settings.angle!==0){transform+=" rotate("+this.transfo.settings.angle+"deg) ";} 8361if(this.transfo.settings.translatex){transform+=" translateX("+ 8362(this.transfo.settings.translate==="%"?this.transfo.settings.translatexp+"%":this.transfo.settings.translatex+"px")+") ";} 8363if(this.transfo.settings.translatey){transform+=" translateY("+ 8364(this.transfo.settings.translate==="%"?this.transfo.settings.translateyp+"%":this.transfo.settings.translatey+"px")+") ";} 8365element.style.transform=transform;} 8366normalizeCoordinates(ev){const evView=ev.view;const iframeWindow=this.document.defaultView;const frameElement=iframeWindow.frameElement;if(evView===iframeWindow&&frameElement){const frameRect=frameElement.getBoundingClientRect();return{pageX:ev.clientX+frameRect.left+frameElement.clientLeft+window.pageXOffset,pageY:ev.clientY+frameRect.top+frameElement.clientTop+window.pageYOffset,};} 8367return{pageX:ev.pageX,pageY:ev.pageY};} 8368getOffset(target){if(!target.getClientRects().length){return{top:0,left:0};}else{const rect=target.getBoundingClientRect();const frameElement=target.ownerDocument.defaultView.frameElement;const offset={top:0,left:0};if(frameElement){const frameRect=frameElement.getBoundingClientRect();offset.left+=frameRect.left+frameElement.clientLeft;offset.top+=frameRect.top+frameElement.clientTop;}
8369return{top:rect.top+window.pageYOffset+offset.top,left:rect.left+window.pageXOffset+offset.left,};}} 8370resetHandlers(){this.computeImageTransformations();this.positionTransfoContainer();}} 8371return __exports;});; 8372 8373/* /html_editor/static/src/main/media/media_plugin.js */ 8374odoo.define('@html_editor/main/media/media_plugin',['@html_editor/plugin','@html_editor/utils/dom_info','@web/core/l10n/translation','@html_editor/main/media/media_dialog/media_dialog','@html_editor/core/selection_plugin','@html_editor/utils/position','@html_editor/utils/resource','@html_editor/utils/dom_traversal','@web/core/utils/search','@html_editor/utils/formatting'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{ICON_SELECTOR,MEDIA_SELECTOR,EDITABLE_MEDIA_CLASS,isIconElement,isMediaElement,isProtected,isProtecting,paragraphRelatedElementsSelector,isContentEditable,}=require("@html_editor/utils/dom_info");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{MediaDialog,TABS}=require("@html_editor/main/media/media_dialog/media_dialog");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{boundariesOut,rightPos}=require("@html_editor/utils/position");const{withSequence}=require("@html_editor/utils/resource");const{closestElement}=require("@html_editor/utils/dom_traversal");const{fuzzyLookup}=require("@web/core/utils/search");const{FORMATTABLE_TAGS}=require("@html_editor/utils/formatting");const MediaPlugin=__exports.MediaPlugin=class MediaPlugin extends Plugin{static id="media";static dependencies=["selection","history","dom","dialog"];static shared=["openMediaDialog"];static defaultConfig={allowImage:true,allowMediaDocuments:true,};resources={user_commands:[{id:"replaceImage",description:_t("Replace media"),icon:"fa-exchange",run:this.replaceImage.bind(this),isAvailable:isHtmlContentSupported,},{id:"insertMedia",title:_t("Media"),description:this.config.allowVideo?_t("Insert image, icon or video"):_t("Insert image or icon"),icon:"fa-file-image-o",run:(params,context={})=>this.openMediaDialog({activeTab:this.getActiveDialogTab(context.searchTerm),}),isAvailable:isHtmlContentSupported,},],toolbar_groups:withSequence(31,{id:"replace_image",namespaces:["image"]}),toolbar_items:[{id:"replace_image",groupId:"replace_image",commandId:"replaceImage",},],powerbox_categories:withSequence(40,{id:"media",name:_t("Media")}),...(this.config.allowImage&&{powerbox_items:this.getInsertMediaPowerboxItem(),}),power_buttons:withSequence(1,{commandId:"insertMedia"}),closest_savable_providers:withSequence(20,(el)=>this.editable),clean_for_save_handlers:({root})=>this.cleanForSave(root),normalize_handlers:this.normalizeMedia.bind(this),selectionchange_handlers:this.selectAroundIcon.bind(this),unsplittable_node_predicates:isIconElement,is_node_editable_predicates:this.isEditableMediaElement.bind(this),clipboard_content_processors:this.clean.bind(this),clipboard_text_processors:(text)=>text.replace(/\u200B/g,""),functional_empty_node_predicates:isMediaElement,selectors_for_feff_providers:()=>`:is(${paragraphRelatedElementsSelector}, ${FORMATTABLE_TAGS.join( 8375 ", " 8376 )}, A, LI) > :is(${ICON_SELECTOR})`,};setup(){this.availableTabs=[...Object.values(TABS),...this.getResource("media_dialog_extra_tabs"),];} 8377getInsertMediaPowerboxItem(){const self=this;return{categoryId:"media",commandId:"insertMedia",get keywords(){return self.availableTabs.map((tab)=>tab.title);},};} 8378getRecordInfo(editableEl=null){return this.config.getRecordInfo?this.config.getRecordInfo(editableEl):{};} 8379isEditableMediaElement(node){if((isMediaElement(node)||node.nodeName==="IMG")&&(node.classList.contains(EDITABLE_MEDIA_CLASS)||isContentEditable(node))){return true;}} 8380replaceImage(){const targetedNodes=this.dependencies.selection.getTargetedNodes();const node=targetedNodes.find((node)=>node.tagName==="IMG");if(node){this.openMediaDialog({node});}} 8381normalizeMedia(node){const mediaElements=[...node.querySelectorAll(MEDIA_SELECTOR)];if(node.matches(MEDIA_SELECTOR)){mediaElements.push(node);} 8382for(const el of mediaElements){if(isProtected(el)||isProtecting(el)){continue;} 8383el.setAttribute("contenteditable",el.hasAttribute("contenteditable")?el.getAttribute("contenteditable"):"false");if(isIconElement(el)&&el.textContent!=="\u200B"){el.textContent="\u200B";}}} 8384clean(root){for(const el of root.querySelectorAll(MEDIA_SELECTOR)){if(isIconElement(el)){el.textContent="";}}} 8385cleanForSave(root){for(const el of root.querySelectorAll(MEDIA_SELECTOR)){if(isIconElement(el)){el.textContent="";} 8386el.removeAttribute("contenteditable");}} 8387async onSaveMediaDialog(element,{node}){if(!element){throw new Error("Element is required: onSaveMediaDialog");} 8388if(node){const changedIcon=isIconElement(node)&&isIconElement(element);if(changedIcon){for(const attribute of element.attributes){node.setAttribute(attribute.no
8388deName,attribute.nodeValue);} 8389element=node;}else{node.replaceWith(element);} 8390this.dispatchTo("on_replaced_media_handlers",{newMediaEl:element});}else{this.dependencies.dom.insert(element);this.dispatchTo("on_added_media_handlers",{newMediaEl:element});} 8391const[anchorNode,anchorOffset]=rightPos(element);this.dependencies.selection.setSelection({anchorNode,anchorOffset});this.dispatchTo("after_save_media_dialog_handlers",element);this.dependencies.history.addStep();} 8392openMediaDialog(params={},editableEl=null){const oldSave=params.save||((element)=>this.onSaveMediaDialog(element,{node:params.node}));params.save=async(...args)=>{const selection=args[0];const elements=selection?selection[Symbol.iterator]?selection:[selection]:[];for(const onMediaDialogSaved of this.getResource("on_media_dialog_saved_handlers")){await onMediaDialogSaved(elements,{node:params.node});} 8393return oldSave(...args);};const{resModel,resId,field,type}=this.getRecordInfo(editableEl);const mediaDialogClosedPromise=this.dependencies.dialog.addDialog(MediaDialog,{resModel,resId,useMediaLibrary:!!(field&&((resModel==="ir.ui.view"&&field==="arch")||type==="html")),media:params.node,onAttachmentChange:this.config.onAttachmentChange||(()=>{}),noImages:!this.config.allowImage,extraTabs:this.getResource("media_dialog_extra_tabs"),...this.config.mediaModalParams,...params,});return mediaDialogClosedPromise;} 8394selectAroundIcon({editableSelection}){if(!editableSelection.isCollapsed){return;} 8395const iconEl=closestElement(editableSelection.anchorNode,isIconElement);if(!iconEl){return;} 8396const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesOut(iconEl);const iconOuterBoundaries={anchorNode,anchorOffset,focusNode,focusOffset};this.dependencies.selection.setSelection(iconOuterBoundaries);} 8397getActiveDialogTab(searchTerm){if(!searchTerm){return undefined;} 8398const matchedTabs=fuzzyLookup(searchTerm,this.availableTabs,(tab)=>tab.title);if(!matchedTabs.length){return undefined;} 8399return matchedTabs[0].id;}} 8400return __exports;});; 8401 8402/* /html_editor/static/src/main/media/video_plugin.js */ 8403odoo.define('@html_editor/main/media/video_plugin',['@html_editor/plugin','@html_editor/main/media/media_dialog/video_selector','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{VideoSelector}=require("@html_editor/main/media/media_dialog/video_selector");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const VideoPlugin=__exports.VideoPlugin=class VideoPlugin extends Plugin{static id="video";static defaultConfig={allowVideo:true,};resources={...(this.config.allowVideo&&{media_dialog_extra_tabs:{id:"VIDEOS",title:_t("Videos"),Component:this.componentForMediaDialog,sequence:30,},}),};get componentForMediaDialog(){return VideoSelector;}} 8404return __exports;});; 8405 8406/* /html_editor/static/src/main/movenode_plugin.js */ 8407odoo.define('@html_editor/main/movenode_plugin',['@html_editor/utils/drag_and_drop','@html_editor/utils/position','@odoo/owl','@html_editor/plugin','@html_editor/utils/dom_traversal','@web/core/l10n/translation','@web/core/utils/strings','@html_editor/utils/base_container','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{useNativeDraggable}=require("@html_editor/utils/drag_and_drop");const{childNodeIndex,leftPos,nodeSize,rightPos}=require("@html_editor/utils/position");const{xml}=require("@odoo/owl");const{Plugin}=require("@html_editor/plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{escape}=require("@web/core/utils/strings");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{getDeepestPosition,isContentEditable}=require("@html_editor/utils/dom_info");const WIDGET_CONTAINER_WIDTH=25;const WIDGET_MOVE_SIZE=20;const ALLOWED_ELEMENTS="h1, h2, h3, p, hr, pre, blockquote, li";const MoveNodePlugin=__exports.MoveNodePlugin=class MoveNodePlugin extends Plugin{static id="movenode";static dependencies=["baseContainer","selection","history","position","localOverlay"];resources={layout_geometry_change_handlers:()=>
8407{if(this.currentMovableElement){this.setMovableElement(this.currentMovableElement);} 8408this.updateHooks();},};setup(){this.intersectionObserver=new IntersectionObserver(this.intersectionObserverCallback.bind(this),{root:document,});this.visibleMovableElements=new Set();this.elementHookMap=new Map();this.addDomListener(this.editable,"mousemove",this.onMousemove,true);this.addDomListener(this.editable,"touchmove",this.onMousemove,true);this.addDomListener(this.document,"keydown",this.onDocumentKeydown,true);this.addDomListener(this.document,"mousemove",this.onDocumentMousemove,true);this.addDomListener(this.document,"touchmove",this.onDocumentMousemove,true);this.widgetHookContainer=this.dependencies.localOverlay.makeLocalOverlay("oe-widget-hooks-container");this.widgetContainer=this.dependencies.localOverlay.makeLocalOverlay("oe-widgets-container");this.dragHelperContainer=this.dependencies.localOverlay.makeLocalOverlay("oe-movenode-helper-container");this.dropzonesContainer=this.dependencies.localOverlay.makeLocalOverlay("oe-dropzones-container");this.dropzoneHintContainer=this.dependencies.localOverlay.makeLocalOverlay("oe-dropzone-hint-container");this.scrollableElement=closestElement(this.editable.parentElement);while(this.scrollableElement&&getComputedStyle(this.scrollableElement).overflowY!=="auto"){this.scrollableElement=this.scrollableElement.parentElement;} 8409this.scrollableElement=this.scrollableElement||this.editable;this.resetHooksNextMousemove=true;this.mutationObserver=new MutationObserver(()=>{this.resetHooksNextMousemove=true;this.removeMoveWidget();});this.mutationObserver.observe(this.editable,{childList:true,subtree:true,characterData:true,characterDataOldValue:true,});} 8410destroy(){super.destroy();this.intersectionObserver.disconnect();this.mutationObserver.disconnect();this.smoothScrollOnDrag&&this.smoothScrollOnDrag.destroy();} 8411intersectionObserverCallback(entries){for(const entry of entries){const element=entry.target;if(entry.isIntersecting&&element.isConnected){this.visibleMovableElements.add(element);this.resetHooksNextMousemove=true;}else{this.visibleMovableElements.delete(element);const hookElement=this.elementHookMap.get(element);if(hookElement){hookElement.style.display=`none`;}}}} 8412updateHooks(){const isRTL=this.config.direction==="rtl";const editableStyles=getComputedStyle(this.editable);this.editableRect=this.editable.getBoundingClientRect();if(isRTL){const paddingRight=parseInt(editableStyles.paddingRight,10)||0;this.editableRect.width=this.editableRect.width-paddingRight+(WIDGET_CONTAINER_WIDTH+5);}else{const paddingLeft=parseInt(editableStyles.paddingLeft,10)||0;
8412this.editableRect.x=this.editableRect.x+paddingLeft-(WIDGET_CONTAINER_WIDTH+5);this.editableRect.width=this.editableRect.width-paddingLeft+(WIDGET_CONTAINER_WIDTH+5);} 8413const containerRect=this.widgetHookContainer.getBoundingClientRect();const elements=this.getMovableElements();const elementsToGarbageCollect=new Set(this.elementHookMap.keys());for(const index in elements){const element=elements[index];elementsToGarbageCollect.delete(element);let hookElement=this.elementHookMap.get(element);if(!hookElement){hookElement=document.createElement("div");this.elementHookMap.set(element,hookElement);hookElement.classList.add("oe-dropzone-hook");hookElement.addEventListener("mouseenter",()=>{if(element!==this.currentMovableElement){this.setMovableElement(element);}});this.widgetHookContainer.append(hookElement);hookElement.style.display=`none`;this.intersectionObserver.observe(element);} 8414hookElement.style.zIndex=index;} 8415for(const element of elementsToGarbageCollect){this.visibleMovableElements.delete(element);this.elementHookMap.get(element).remove();this.intersectionObserver.unobserve(element);this.elementHookMap.delete(element);} 8416const visibleElements=[...this.visibleMovableElements];const elementRects=visibleElements.map((element)=>element.getBoundingClientRect());const elementStyles=visibleElements.map((element)=>{const style=getComputedStyle(element);return{marginTop:parseInt(style.marginTop,10)||0,marginBottom:parseInt(style.marginBottom,10)||0,};});for(const index in visibleElements){const element=visibleElements[index];const elementRect=elementRects[index];const hookElement=this.elementHookMap.get(element);const{marginTop,marginBottom}=elementStyles[index];let hookBox;if(element.tagName==="HR"){hookBox=new DOMRect(isRTL?elementRect.x-containerRect.left:elementRect.x-containerRect.left-WIDGET_CONTAINER_WIDTH,elementRect.y-containerRect.top-marginTop,elementRect.width+WIDGET_CONTAINER_WIDTH,elementRect.height+marginTop+marginBottom);}else if(element.tagName==="LI"){hookBox=new DOMRect(elementRect.x-containerRect.left-WIDGET_CONTAINER_WIDTH-WIDGET_MOVE_SIZE,elementRect.y-containerRect.top-marginTop,WIDGET_CONTAINER_WIDTH,elementRect.height+marginTop+marginBottom);}else{hookBox=new DOMRect(isRTL?elementRect.right-containerRect.left:elementRect.x-containerRect.left-WIDGET_CONTAINER_WIDTH,elementRect.y-containerRect.top-marginTop,WIDGET_CONTAINER_WIDTH,elementRect.height+marginTop+marginBottom);} 8417hookElement.style.left=`${hookBox.x}px`;hookElement.style.top=`${hookBox.y}px`;hookElement.style.width=`${hookBox.width}px`;hookElement.style.height=`${hookBox.height}px`;hookElement.style.display=`block`;}} 8418_updateAnchorWidgets(newAnchorWidget){const movableElement=newAnchorWidget&&closestElement(newAnchorWidget,(node)=>this.isNodeMovable(node)&&node.matches([ALLOWED_ELEMENTS,baseContainerGlobalSelector,...this.getResource("move_node_whitelist_selectors"),].join(", ")));if(movableElement&&movableElement!==this.currentMovableElement){this.setMovableElement(movableElement);}} 8419getMovableElements(){const elems=[];for(const el of this.editable.querySelectorAll([ALLOWED_ELEMENTS,baseContainerGlobalSelector,...this.getResource("move_node_whitelist_selectors"),].join(", "))){if(this.isNodeMovable(el)){elems.push(el);}} 8420return elems;} 8421getDroppableElements(draggableNode){return this.getMovableElements().filter((node)=>!closestElement(node.parentElement,(n)=>n===draggableNode));} 8422setMovableElement(movableElement){this.removeMoveWidget();this.currentMovableElement=movableElement;this.dispatchTo("set_movable_element_handlers",movableElement);const isRTL=this.config.direction==="rtl";const containerRect=this.widgetContainer.getBoundingClientRect();const anchorBlockRect=this.currentMovableElement.getBoundingClientRect();const anchorX=isRTL?this.currentMovableElement.tagName==="LI"?anchorBlockRect.right+WIDGET_MOVE_SIZE:anchorBlockRect.right:this.currentMovableElement.tagName==="LI"?anchorBlockRect.x-WIDGET_MOVE_SIZE:anchorBlockRect.x;let anchorY=anchorBlockRect.y;if(this.currentMovableElement.tagName.match(/H[1-6]/)){anchorY+=(anchorBlockRect.height-WIDGET_MOVE_SIZE)/2;} 8423this.moveWidget=this.document.createElement("div");this.moveWidget.className="oe-sidewidget-move oi oi-draggable";this.widgetContainer.append(this.moveWidget);let moveWidgetOffsetTop=0;if(movableElement.tagName==="HR"){const style=getComputedStyle(movableElement);moveWidgetOffsetTop=parseInt(style.marginTop,10)||0;} 8424this.moveWidget.style.width=`${WIDGET_MOVE_SIZE}px`;this.moveWidget.style.height=`${WIDGET_MOVE_SIZE}px`;this.moveWidget.style.top=`${anchorY - containerRect.y - moveWidgetOffsetTop}px`;this.moveWidget.style.left=isRTL?`${anchorX - containerRect.x + WIDGET_CONTAINER_WIDTH - WIDGET_MOVE_SIZE}px`:`${anchorX - containerRect.x - WIDGET_CONTAINER_WIDTH}px`;const dragToMoveTooltip=_t("Drag to move");const clickToSelectTooltip=_t("Click to select");this.services.tooltip.add(this.moveWidget,{template:xml` 8425 <div class="o-tooltip tooltip-inner text-start px-3"> 8426 ${escape(dragToMoveTooltip)}<br/> 8427 ${escape(clickToSelectTooltip)} 8428 </div>`,arrow:true,});this.addDomListener(this.moveWidget,"click",()=>{const isNodeContentEditable=isContentEditable(movableElement);const[anchorNode,anchorOffset]=isNodeContentEditable?getDeepestPosition(movableElement,0):leftPos(movableElement);const[focusNode,focusOffset]=isNodeContentEditable?getDeepestPosition(movableElement,nodeSize(movableElement)):rightPos(movableElement);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focu
8428sNode,focusOffset,});this.dependencies.selection.focusEditable();});if(this.scrollableElement){this.smoothScrollOnDrag&&this.smoothScrollOnDrag.destroy();this.smoothScrollOnDrag=useNativeDraggable(simpleDraggableHook,{ref:{el:this.widgetContainer},elements:".oe-sidewidget-move",onDragStart:()=>this.startDropzones(movableElement,containerRect),onDragEnd:()=>this._stopDropzones(movableElement),helper:()=>{const container=movableElement.tagName==="LI"?movableElement.parentElement.cloneNode(false):document.createElement("div");if(container.tagName==="OL"){const originalIndex=childNodeIndex(movableElement)+1;container.setAttribute("start",originalIndex);} 8429container.append(movableElement.cloneNode(true));const style=getComputedStyle(movableElement);container.style.height=style.height;container.style.width=style.width;container.style.paddingLeft="25px";container.style.opacity="0.4";this.dragHelperContainer.append(container);return container;},});}} 8430removeMoveWidget(){this.dispatchTo("unset_movable_element_handlers");this.moveWidget?.remove();this.moveWidget=undefined;this.currentMovableElement=undefined;} 8431startDropzones(movableElement,containerRect,directions=["north","south"]){this.removeMoveWidget();const elements=this.getDroppableElements(movableElement);this.dropzonesContainer.replaceChildren();this.editable.classList.add("oe-editor-dragging");for(const element of elements){const originalRect=element.getBoundingClientRect();const style=getComputedStyle(element);const marginTop=parseInt(style.marginTop,10);const marginBottom=parseInt(style.marginBottom,10);const marginLeft=parseInt(style.marginLeft,10);const marginRight=parseInt(style.marginRight,10);const isRTL=this.config.direction==="rtl";const dropzoneRect=new DOMRect(isRTL?originalRect.left-marginLeft:originalRect.left-marginLeft-WIDGET_CONTAINER_WIDTH,originalRect.top-marginTop,originalRect.width+marginLeft+marginRight+WIDGET_CONTAINER_WIDTH,originalRect.height+marginTop+marginBottom);const dropzoneHintRect=new DOMRect(originalRect.left-marginLeft,originalRect.top-marginTop,originalRect.width+marginLeft+marginRight,originalRect.height+marginTop+marginBottom);const dropzoneBox=document.createElement("div");dropzoneBox.className=`oe-dropzone-box`;dropzoneBox.style.top=`${dropzoneRect.top - containerRect.top}px`;dropzoneBox.style.left=element.tagName=="LI"?`${dropzoneRect.left - containerRect.left - WIDGET_MOVE_SIZE}px`:`${dropzoneRect.left - containerRect.left}px`;dropzoneBox.style.width=`${dropzoneRect.width}px`;dropzoneBox.style.height=`${dropzoneRect.height}px`;const dropzoneHintBox=document.createElement("div");dropzoneHintBox.className=`oe-dropzone-box`;dropzoneHintBox.style.top=`${dropzoneHintRect.top - containerRect.top}px`;dropzoneHintBox.style.left=`${dropzoneHintRect.left - containerRect.left}px`;dropzoneHintBox.style.width=`${dropzoneHintRect.width}px`;dropzoneHintBox.style.height=`${dropzoneHintRect.height}px`;const sideElements={};for(const direction of directions){const sideElement=document.createElement("div");sideElement.className=`oe-dropzone-box-side oe-dropzone-box-side-${direction}`;sideElements[direction]=sideElement;dropzoneBox.append(sideElement);const onEnter=()=>{this._currentZone=[direction];removeDropHint();this._currentDropHint=document.createElement("div");this._currentDropHint.className=`oe-current-drop-hint`;const currentDropHintSize=4;const currentDropHintSizeHalf=currentDropHintSize/2;if(direction==="north"){this._currentDropHint.style["top"]=`-${currentDropHintSizeHalf}px`;this._currentDropHint.style["width"]=`100%`;this._currentDropHint.style["height"]=`${currentDropHintSize}px`;dropzoneHintBox.append(this._currentDropHint);this._currentDropHintElementPosition=["top",element];}else if(direction==="south"){this._currentDropHint.style["bottom"]=`-${currentDropHintSizeHalf}px`;this._currentDropHint.style["width"]=`100%`;this._currentDropHint.style["height"]=`${currentDropHintSize}px`;dropzoneHintBox.append(this._currentDropHint);this._currentDropHintElementPosition=["bottom",element];}else if(direction==="west"){this._currentDropHint.style["left"]=`-${currentDropHintSizeHalf}px`;this._currentDropHint.style["height"]=`100%`;this._currentDropHint.style["width"]=`${currentDropHintSize}px`;dropzoneHintBox.append(this._currentDropHint);this._currentDropHintElementPosition=["left",element];}else if(direction==="east"){this._currentDropHint.style["right"]=`-${currentDropHintSizeHalf}px`;this._currentDropHint.style["height"]=`100%`;this._currentDropHint.style["width"]=`${currentDropHintSize}px`;dropzoneHintBox.append(this._currentDropHint);this._currentDropHintElementPosition=["right",element];}};sideElement.addEventListener("mouseenter",onEnter);sideElement.addEventListener("pointerenter",onEnter);const removeDropHint=()=>{if(this._currentDropHint){this._currentDropHint.remove();this._currentDropHint=null;} 8432this._currentDropHintElementPosition=null;};dropzoneBox.addEventListener("mouseleave",removeDropHint);dropzoneBox.addEventListener("pointerleave",removeDropHint);} 8433this.dropzonesContainer.append(dropzoneBox);this.dropzoneHintContainer.append(dropzoneHintBox);}} 8434_stopDropzones(movableElement){this.editable.classList.remove("oe-editor-dragging");this.dropzonesContainer.replaceChildren();this.dropzoneHintContainer.replaceChildren();if(this._currentDropHintElementPosition){const cursors=this.dependencies.selection.preserveSelection();const[position,focusElelement]=this._currentDropHintElementPosition;this._currentDropHintElementPosition=undefined;const previousParent=movableElement.parentElement;const isFocusInsideList=["UL","OL"].includes(focusElelement?.parentElement?.tagName);if(movableElement.tagName==="LI"&&!isFocusInsideList){const wrapperList=previousParent.cloneNode(false);wrapperList.appendChild(movableElement);movableElement=wrapperList;}else if(movableElement.tagName!=="LI"&&isFocusInsideList){const wrapperLI=this.document.createElement("LI");wrapperLI.appendChild(movableElement);movableElement=wrapperLI;} 8435if(position==="top"){focusElelement.before(movableElement);}else if(position==="bottom"){focusElelement.after(movableElement);} 8436if(previousParent.innerHTML.trim()===""){if(["UL","OL"].includes(previousParent.tagName)){previousParent.remove();}else{const baseContainer=this.dependencies.baseContainer.createBaseContainer();const br=document.createElement("br");baseContainer.append(br);previousParent.append(baseContainer);}} 8437const isSelectionInsideMovedNode=movableElement.contains(cursors.anchor.node)&&movableElement.contains(cursors.focus.node);
8437if(isSelectionInsideMovedNode){cursors.restore();}else{const selectionPosition=getDeepestPosition(movableElement,0);this.dependencies.selection.setSelection({anchorNode:selectionPosition[0],anchorOffset:selectionPosition[1],});} 8438this.dependencies.selection.focusEditable();this.dependencies.history.addStep();}} 8439onMousemove(e){this._updateAnchorWidgets(e.target);} 8440onDocumentKeydown(){this.removeMoveWidget();} 8441onDocumentMousemove(e){if(this.resetHooksNextMousemove){this.resetHooksNextMousemove=false;this.removeMoveWidget();this.updateHooks();} 8442const clientX=e.clientX??e.touches?.[0]?.clientX;const clientY=e.clientY??e.touches?.[0]?.clientY;if(this.editableRect&&!isPointInside(this.editableRect,clientX,clientY)){this.removeMoveWidget();}} 8443isNodeMovable(node){const blacklistSelectors=this.getResource("move_node_blacklist_selectors").join(", ");if(blacklistSelectors&&node.matches(blacklistSelectors)){return false;} 8444return(node.parentElement?.getAttribute("contentEditable")==="true"||(node.tagName==="LI"&&node.parentElement.isContentEditable));}} 8445function isPointInside(rect,x,y){return rect.left<=x&&rect.right>=x&&rect.top<=y&&rect.bottom>=y;} 8446const simpleDraggableHook={acceptedParams:{helper:[Function],},edgeScrolling:{enable:true},onComputeParams({ctx,params}){ctx.helper=params.helper;ctx.followCursor=false;ctx.tolerance=0;},onDragStart({ctx}){ctx.current.element=ctx.helper();ctx.current.element.style.left=`${ctx.pointer.x + 10}px`;ctx.current.element.style.top=`${ctx.pointer.y + 10}px`;ctx.current.element.style.position="fixed";document.body.classList.remove("pe-none");document.body.style.cursor="grabbing";return ctx.current;},onDrag({ctx}){ctx.current.element.style.left=`${ctx.pointer.x}px`;ctx.current.element.style.top=`${ctx.pointer.y}px`;},onDragEnd({ctx}){ctx.current.element.remove();if(document.body.style.cursor==="grabbing"){document.body.style.cursor="";} 8447return ctx.current;},};return __exports;});; 8448 8449/* /html_editor/static/src/main/placeholder_plugin.js */ 8450odoo.define('@html_editor/main/placeholder_plugin',['@html_editor/utils/base_container','@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/utils/dom_info','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{Plugin}=require("@html_editor/plugin");const{childNodes}=require("@html_editor/utils/dom_traversal");const{isEmptyBlock}=require("@html_editor/utils/dom_info");const{withSequence}=require("@html_editor/utils/resource");const PlaceholderPlugin=__exports.PlaceholderPlugin=class PlaceholderPlugin extends Plugin{static id="placeholder";resources={...(this.config.placeholder&&{hints:[withSequence(1,{selector:`.odoo-editor-editable:not(:focus) > ${baseContainerGlobalSelector}:only-child`,text:this.config.placeholder,}),],hint_targets_providers:(selectionData,editable)=>{const el=editable.firstChild;if(!selectionData.documentSelectionIsInEditable&&childNodes(editable).length===1&&isEmptyBlock(el)&&el.matches(baseContainerGlobalSelector)){return[el];}else{return[];}},}),};} 8451return __exports;});; 8452 8453/* /html_editor/static/src/main/position_plugin.js */ 8454odoo.define('@html_editor/main/position_plugin',['@html_editor/utils/dom_traversal','@html_editor/plugin','@web/core/utils/timing','@web/core/utils/scrolling'],function(require){'use strict';let __exports={};const{ancestors}=require("@html_editor/utils/dom_traversal");const{Plugin}=require("@html_editor/plugin");const{debounce,throttleForAnimation}=require("@web/core/utils/timing");const{couldBeScrollableX,couldBeScrollableY}=require("@web/core/utils/scrolling");const PositionPlugin=__exports.PositionPlugin=class PositionPlugin extends Plugin{static id="position";resources={external_history_step_handlers:this.layoutGeometryChange.bind(this),history_reset_from_steps_handlers:this.layoutGeometryChange.bind(this),step_added_handlers:this.layoutGeometryChange.bind(this),before_filter_mutation_record_handlers:this.handlePotentialLayoutGeometryChange.bind(this),};setup(){this.layoutGeometryChange=throttleForAnimation(this.layoutGeometryChange.bind(this));this.debouncedLayoutGeometryChange=debounce(this.layoutGeometryChange.bind(this),"animationFrame");this.resizeObserver=new ResizeObserver(this.layoutGeometryChange);this.resizeObserver.observe(this.document.body);this.resizeObserver.observe(this.editable);this.addDomListener(window,"resize",this.layoutGeometryChange);if(this.window!==window){this.addDomListener(this.window,"resize",this.layoutGeometryChange);} 8455const scrollableElements=[this.editable,...ancestors(this.editable).filter((node)=>couldBeScrollableX(node)||couldBeScrollableY(node)),];for(const scrollableElement of scrollableElements){this.addDomListener(scrollableElement,"scroll",()=>{this.layoutGeometryChange();});this.resizeObserver.observe(scrollableElement);}} 8456handlePotentialLayoutGeometryChange(records){for(const record of records){if(record.type==="classList"||(record.type==="attributes"&&record.attributeName==="style")){this.debouncedLayoutGeometryChange();return;}}} 8457destroy(){this.resizeObserver.disconnect();super.destroy();} 8458layoutGeometryChange(){this.dispatchTo("layout_geometry_change_handlers");}} 8459return __exports;});; 8460 8461/* /html_editor/static/src/main/power_buttons_plugin.js */ 8462odoo.define('@html_editor/main/power_buttons_plugin',['@html_editor/plugin','@html_editor/utils/base_container','@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@web/core/utils/objects','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{closestBlock}=require("@html_editor/utils/blocks");const{isEditorTab,isEmptyBlock}=require("@html_editor/utils/dom_info");const{closestElement,descendants}=require("@html_editor/utils/dom_traversal");const{omit,pick}=require("@web/core/utils/objects");const{debounce}=require("@web/core/utils/timing");const MIN_WIDTH_FOR_POWER_BUTTONS=600;const PowerButtonsPlugin=__exports.PowerButtonsPlugin=class PowerButtonsPlugin extends Plugin{static id="powerButtons";static dependencies=["baseContainer","selection","position","localOverlay","powerbox","userCommand","history",];resources={layout_geometry_change_handlers:this.updatePowerButtons.bind(this),selectionchange_handlers:this.triggerDebouncedUpdatePowerButtons.bind(this),post_mount_component_handlers:this.updatePowerButtons.bind(this),};setup(){this.powerButtonsOverlay=this.dependencies.localOverlay.makeLocalOverlay("oe-power-buttons-overlay");this.createPowerButtons();const shouldDebounce=this.config.debouncePowerbuttons!==false;if(shouldDebounce){this.debouncedUpdatePowerButtons=debounce(this.updatePowerButtons.bind(this),30);}else{this.debouncedUpdatePowerButtons=this.updatePowerButtons.bind(this);}} 8463createPowerButtons(){const composePowerButton=(item)=>{const command=this.dependencies.userCommand.getCommand(item.commandId);return{...pick(command,"description","icon"),...omit(item,"commandId","commandParams"),run:()=>command.run(item.commandParams),isAvailable:(selection)=>
8463[command.isAvailable,item.isAvailable].filter(Boolean).every((predicate)=>predicate(selection)),};};const renderButton=({description,icon,text,run})=>{const btn=this.document.createElement("button");let className="power_button btn px-2 py-1 cursor-pointer";if(icon){const iconLibrary=icon.includes("fa-")?"fa":"oi";className+=` ${iconLibrary} ${icon}`;}else{const span=this.document.createElement("span");span.textContent=text;span.className="d-flex align-items-center text-nowrap";span.style.height="1em";btn.append(span);} 8464btn.className=className;btn.title=description;this.addDomListener(btn,"pointerdown",(ev)=>ev.preventDefault());this.addDomListener(btn,"click",()=>this.applyCommand(run));return btn;};const powerButtonsDefinitions=this.getResource("power_buttons");const powerButtons=powerButtonsDefinitions.map(composePowerButton);this.descriptionToElementMap=new Map(powerButtons.map((pb)=>[pb,renderButton(pb)]));this.powerButtonsContainer=this.document.createElement("div");this.powerButtonsContainer.className=`o_we_power_buttons d-flex justify-content-center invisible position-absolute`;this.powerButtonsContainer.append(...this.descriptionToElementMap.values());this.powerButtonsOverlay.append(this.powerButtonsContainer);} 8465triggerDebouncedUpdatePowerButtons(){this.powerButtonsContainer.classList.add("invisible");this.debouncedUpdatePowerButtons();} 8466updatePowerButtons(){this.powerButtonsContainer.classList.add("invisible");const{documentSelection,editableSelection,currentSelectionIsInEditable}=this.dependencies.selection.getSelectionData();if(!currentSelectionIsInEditable){return;} 8467const block=closestBlock(documentSelection.anchorNode);const blockRect=block.getBoundingClientRect();const editableRect=this.editable.getBoundingClientRect();if(documentSelection.isCollapsed&&block?.matches(baseContainerGlobalSelector)&&editableRect.bottom>blockRect.top&&isEmptyBlock(block)&&!descendants(block).some(isEditorTab)&&this.editable.offsetWidth>=MIN_WIDTH_FOR_POWER_BUTTONS&&!closestElement(documentSelection.anchorNode,"td, th, li")&&!block.style.textAlign&&this.getResource("power_buttons_visibility_predicates").every((predicate)=>predicate(documentSelection))){const direction=closestElement(block,"[dir]")?.getAttribute("dir");for(const[{isAvailable},buttonElement]of this.descriptionToElementMap.entries()){const shouldHide=Boolean(!isAvailable(editableSelection));buttonElement.classList.toggle("d-none",shouldHide);} 8468this.setPowerButtonsPosition(block,blockRect,direction);this.powerButtonsContainer.classList.remove("invisible");this.powerButtonsContainer.setAttribute("dir",direction);}} 8469getPlaceholderWidth(block){const hintText=block.getAttribute("o-we-hint-text");const cs=getComputedStyle(block);const canvas=this.canvas||(this.canvas=document.createElement("canvas"));const ctx=canvas.getContext("2d");ctx.font=cs.font;const width=ctx.measureText(hintText).width;return width;} 8470setPowerButtonsPosition(block,blockRect,direction){const overlayRect=this.powerButtonsOverlay.getBoundingClientRect();let referenceRect={top:0,left:0};let frameElement;try{frameElement=this.document.defaultView.frameElement;}catch{} 8471if(frameElement){referenceRect=frameElement.getBoundingClientRect();} 8472const placeholderWidth=this.getPlaceholderWidth(block);let newButtonContainerLeft;const editableRect=this.editable.getBoundingClientRect();if(direction==="rtl"){newButtonContainerLeft=blockRect.right-(overlayRect.left-referenceRect.left)-placeholderWidth-30;if(newButtonContainerLeft<=0){this.powerButtonsContainer.querySelectorAll(".power_button:not(:last-child)").forEach((el)=>el.classList.add("d-none"));newButtonContainerLeft=blockRect.right- 8473(overlayRect.left-referenceRect.left)- 8474placeholderWidth- 847530;} 8476this.powerButtonsContainer.style.transform="translateX(-100%)";}else{this.powerButtonsContainer.style.transform="unset";newButtonContainerLeft=blockRect.left-(overlayRect.left-referenceRect.left)+placeholderWidth+30;if(newButtonContainerLeft+this.powerButtonsContainer.offsetWidth>editableRect.right+referenceRect.left){this.powerButtonsContainer.querySelectorAll(".power_button:not(:last-child)").forEach((el)=>el.classList.add("d-none"));}} 8477this.powerButtonsContainer.style.left=newButtonContainerLeft+"px";this.powerButtonsContainer.style.top=blockRect.top-(overlayRect.top-referenceRect.top)+"px";} 8478async applyCommand(commandFn){const btns=[...this.powerButtonsContainer.querySelectorAll(".btn")];btns.forEach((btn)=>btn.classList.add("disabled"));await commandFn();btns.forEach((btn)=>btn.classList.remove("disabled"));}} 8479return __exports;});; 8480 8481/* /html_editor/static/src/main/powerbox/powerbox.js */ 8482odoo.define('@html_editor/main/powerbox/powerbox',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onPatched,useEffect,useExternalListener,useRef}=require("@odoo/owl");const Powerbox=__exports.Powerbox=class Powerbox extends Component{static template="html_editor.Powerbox";static props={document:{validate:(doc)=>doc.constructor.name==="HTMLDocument"},close:Function,state:Object,activateCommand:Function,applyCommand:Function,};
8482setup(){const ref=useRef("root");onPatched(()=>{const activeCommand=ref.el.querySelector(".o-we-command.active");if(activeCommand){activeCommand.scrollIntoView({block:"nearest",inline:"nearest"});}});this.mouseSelectionActive=false;const onMouseMove=()=>(this.mouseSelectionActive=true);useExternalListener(this.props.document,"mousemove",onMouseMove);useEffect((ownDoc,propsDoc)=>{if(ownDoc&&propsDoc&&ownDoc!==propsDoc){ownDoc.addEventListener("mousemove",onMouseMove);return()=>ownDoc.removeEventListener("mousemove",onMouseMove);}},()=>[ref.el?.ownerDocument,this.props.document]);} 8483get commands(){return this.props.state.commands;} 8484get currentIndex(){return this.props.state.currentIndex;} 8485get showCategories(){return this.props.state.showCategories;} 8486onScroll(){this.mouseSelectionActive=false;} 8487onMouseEnter(index){if(this.mouseSelectionActive){this.props.activateCommand(index);}}} 8488return __exports;});; 8489 8490/* /html_editor/static/src/main/powerbox/powerbox_plugin.js */ 8491odoo.define('@html_editor/main/powerbox/powerbox_plugin',['@html_editor/plugin','@odoo/owl','@web/core/l10n/translation','@web/core/utils/arrays','@html_editor/main/powerbox/powerbox','@html_editor/utils/resource','@web/core/utils/objects','@html_editor/utils/base_container','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{reactive}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{rotate}=require("@web/core/utils/arrays");const{Powerbox}=require("@html_editor/main/powerbox/powerbox");const{withSequence}=require("@html_editor/utils/resource");const{omit,pick}=require("@web/core/utils/objects");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{closestElement}=require("@html_editor/utils/dom_traversal");const PowerboxPlugin=__exports.PowerboxPlugin=class PowerboxPlugin extends Plugin{static id="powerbox";static dependencies=["overlay","selection","history","userCommand"];static shared=["closePowerbox","getAvailablePowerboxCommands","openPowerbox","updatePowerbox",];resources={powerbox_categories:[withSequence(10,{id:"structure",name:_t("Structure")}),withSequence(60,{id:"widget",name:_t("Widget")}),withSequence(100,{id:"modules",name:_t("Modules")}),],hints:withSequence(30,{selector:baseContainerGlobalSelector,text:_t('Type "/" for commands'),}),};setup(){this.overlay=this.dependencies.overlay.createOverlay(Powerbox);this.state=reactive({});this.overlayProps={document:this.document,close:()=>this.overlay.close(),state:this.state,activateCommand:(currentIndex)=>{this.state.currentIndex=currentIndex;},applyCommand:this.applyCommand.bind(this),};this.powerboxCommands=this.makePowerboxCommands();this.addDomListener(this.editable.ownerDocument,"keydown",this.onKeyDown,{capture:true,});} 8492getAvailablePowerboxCommands(){const selection=this.dependencies.selection.getEditableSelection();const blacklistSelector=this.getResource("powerbox_blacklist_selectors").join(", ");if(blacklistSelector&&closestElement(selection.anchorNode).matches(blacklistSelector)){return[];} 8493return this.powerboxCommands.filter((cmd)=>cmd.isAvailable(selection));} 8494makePowerboxCommands(){const powerboxItems=this.getResource("powerbox_items");const categories=this.getResource("powerbox_categories");const categoryDict=Object.fromEntries(categories.map((category)=>[category.id,category]));return powerboxItems.map((item)=>{const command=this.dependencies.userCommand.getCommand(item.commandId);return{...pick(command,"title","description","icon"),...omit(item,"commandId","commandParams"),categoryName:categoryDict[item.categoryId].name,run:(context)=>command.run(item.commandParams,context),isAvailable:(selection)=>[command.isAvailable,item.isAvailable].filter(Boolean).every((predicate)=>predicate(selection)),};});} 8495openPowerbox({commands,categories,onApplyCommand=()=>{},onClose=()=>{}}={}){this.closePowerbox();if(!commands.length){return;} 8496this.onApplyCommand=onApplyCommand;this.onClose=onClose;this.updatePowerbox(commands,categories);} 8497updatePowerbox(commands,categories){if(categories){const orderCommands=[];for(const category of categories){orderCommands.push(...commands.filter((command)=>command.categoryId===category.id));} 8498commands=orderCommands;} 8499Object.assign(this.state,{showCategories:!!categories,commands,currentIndex:0,});this.overlay.open({props:this.overlayProps});} 8500closePowerbox(){if(!this.overlay.isOpen){return;} 8501this.onClose();this.overlay.close();} 8502onKeyDown(ev){if(!this.overlay.isOpen){return;} 8503const key=ev.key;switch(key){case"Escape":ev.stopImmediatePropagation();this.closePowerbox();break;case"Enter":case"Tab":ev.preventDefault();ev.stopImmediatePropagation();this.applyCommand(this.state.commands[this.state.currentIndex]);break;case"ArrowUp":{ev.preventDefault();ev.stopImmediatePropagation();this.state.currentIndex=rotate(this.state.currentIndex,this.state.commands,-1);break;} 8504case"ArrowDown":{ev.preventDefault();ev.stopImmediatePropagation();this.state.currentIndex=rotate(this.state.currentIndex,this.state.commands,1);break;} 8505case"ArrowLeft":case"ArrowRight":{this.closePowerbox();break;}}} 8506applyCommand(command){const context={};this.onApplyCommand(command,context);command.run(context);this.closePowerbox();}} 8507return __exports;});; 8508 8509/* /html_editor/static/src/main/powerbox/search_powerbox_plugin.js */ 8510odoo.define('@html_editor/main/powerbox/search_powerbox_plugin',['@web/core/utils/search','@html_editor/plugin','@web/core/l10n/translation','@html_editor/utils/resource','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{fuzzyLookup}=require("@web/core/utils/search");const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{withSequence}=require("@html_editor/utils/resource");const{closestElement}=require("@html_editor/utils/dom_traversal");const SearchPowerboxPlugin=__exports.SearchPowerboxPlugin=class SearchPowerboxPlugin extends Plugin{static id="searchPowerbox";static dependencies=["powerbox","selection","history","input"];resources={beforeinput_handlers:this.onBeforeInput.bind(this),input_handlers:this.onInput.bind(this),delete_handlers:this.update.bind(this),post_undo_handlers:this.update.bind(this),post_redo_handlers:this.update.bind(this),user_commands:{id:"openSearchPowerbox",run:()=>{const selection=this.dependencies.selection.getEditableSelection();this.historySavePointRestore=this.dependencies.history.makeSavePoint();this.powerButtonAnchorEl=closestElement(selection.anchorNode);this.openSearchPowerbox();},},power_buttons:withSequence(100,{commandId:"openSearchPowerbox",description:_t("More options"),icon:"oi-ellipsis-v",}),};setup(){const categoryIds=new Set();for(const category of this.getResource("powerbox_categories")){if(categoryIds.has(category.id)){throw new Error(`Duplicate category id: ${category.id}`);} 8511categoryIds.add(category.id);} 8512this.categories=this.getResource("powerbox_categories");this.shouldUpdate=false;this.addDomListener(this.editable,"pointerdown",()=>{if(this.powerButtonAnchorEl){this.powerButtonAnchorEl=false;}});} 8513onBeforeInput(ev){if(ev.data==="/"){this.historySavePointRestore=this.dependencies.history.makeSavePoint();}} 8514onInput(ev){this.searchTerm=undefined;if(ev.data==="/"){this.openSearchPowerbox();}else{this.update();}} 8515update(){if(!this.shouldUpdate){return;} 8516const selection=this.dependencies.selection.getEditableSelection();this.searchNode=selection.startContainer;if(!this.isSearching(selection)){this.dependencies.powerbox.closePowerbox();return;} 8517const searchTerm=this.searchNode.nodeValue?.slice(this.offset+1,selection.endOffset);if(!searchTerm){this.dependencies.powerbox.updatePowerbox(this.enabledCommands,this.categories);return;} 8518if(searchTerm.includes(" ")){this.dependencies.powerbox.closePowerbox();return;} 8519const commands=this.filterCommands(searchTerm);if(!commands.length){this.dependencies.powerbox.closePowerbox();this.shouldUpdate=true;return;} 8520this.searchTerm=searchTerm;this.dependencies.powerbox.updatePowerbox(commands);} 8521filterCommands(searchTerm){return fuzzyLookup(searchTerm,this.enabledCommands,(cmd)=>[cmd.title,cmd.categoryName,cmd.description,...(cmd.keywords||[]),]);} 8522isSearching(selection){return(this.powerButtonAnchorEl===closestElement(this.searchNode)||(selection.endContainer===this.searchNode&&this.searchNode.nodeValue&&this.searchNode.nodeValue[this.offset]==="/"&&selection.endOffset>=this.offset));} 8523openSearchPowerbox(){const selection=this.dependencies.selection.getEditableSelection();if(!(this.checkPredicates("is_powerbox_available_predicates",selection.anchorNode)??true)){return;} 8524this.offset=selection.startOffset-1;this.enabledCommands=this.dependencies.powerbox.getAvailablePowerboxCommands();this.dependencies.powerbox.openPowerbox({commands:this.enabledCommands,categories:this.categories,onApplyCommand:(command,context)=>{context.searchTerm=this.searchTerm;this.historySavePointRestore?.();},onClose:()=>{this.shouldUpdate=false;this.powerButtonAnchorEl=false;},});this.shouldUpdate=true;} 8525openPowerbox(){const selection=this.dependencies.selection.getEditableSelection();this.offset=selection.startOffset-1;this.enabledCommands=this.dependencies.powerbox.getAvailablePowerboxCommands();this.dependencies.powerbox.openPowerbox({commands:this.enabledCommands,categories:this.categories,onApplyCommand:(command,context)=>{context.searchTerm=this.searchTerm;this.historySavePointRestore?.();},onClose:()=>{this.shouldUpdate=false;},});this.shouldUpdate=true;}} 8526return __exports;});; 8527 8528/* /html_editor/static/src/main/selection_placeholder_plugin.js */ 8529odoo.define('@html_editor/main/selection_placeholder_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{fillEmpty}=require("@html_editor/utils/dom");const{allowsParagraphRelatedElements,isContentEditable,isEmpty,isNotEditableNode,isPhrasingContent,}=require("@html_editor/utils/dom_info");const{closestElement,getAdjacentNextSiblings,getAdjacentPreviousSiblings,}=require("@html_editor/utils/dom_traversal");const{withSequence}=require("@html_editor/utils/resource");const BLINKER_CLASS="o-horizontal-caret";
8529const PLACEHOLDER_ATTRIBUTE="data-selection-placeholder";const PLACEHOLDER_SELECTOR=`[${PLACEHOLDER_ATTRIBUTE}]`;const SelectionPlaceholderPlugin=__exports.SelectionPlaceholderPlugin=class SelectionPlaceholderPlugin extends Plugin{static id="selectionPlaceholder";static dependencies=["baseContainer","history","selection"];resources={external_history_step_handlers:this.updatePlaceholders.bind(this),normalize_handlers:withSequence(100,this.updatePlaceholders.bind(this)),step_added_handlers:this.updatePlaceholders.bind(this),selectionchange_handlers:(selectionData)=>this.onSelectionChange(selectionData),clean_for_save_handlers:withSequence(0,({root})=>{for(const placeholder of root.querySelectorAll(PLACEHOLDER_SELECTOR)){placeholder.remove();}}),split_element_block_overrides:({blockToSplit})=>{if(blockToSplit.hasAttribute(PLACEHOLDER_ATTRIBUTE)){this.persistPlaceholder(blockToSplit);return true;}},selection_blocker_predicates:(blocker)=>{if((blocker.nodeType===Node.ELEMENT_NODE&&blocker.hasAttribute(PLACEHOLDER_ATTRIBUTE))||!isBlock(blocker)){return false;}else if(isNotEditableNode(blocker)){return true;}},selection_placeholder_container_predicates:(container)=>{if(!isContentEditable(container)||isPhrasingContent(container)||!allowsParagraphRelatedElements(container)){return false;}else if(container.getAttribute("contenteditable")==="true"){return true;}},power_buttons_visibility_predicates:({anchorNode})=>
8529!closestElement(anchorNode,PLACEHOLDER_SELECTOR),move_node_blacklist_selectors:PLACEHOLDER_SELECTOR,system_node_selectors:PLACEHOLDER_SELECTOR,system_classes:BLINKER_CLASS,};setup(){this.addDomListener(this.editable,"focusout",()=>this.editable.querySelectorAll(`.${BLINKER_CLASS}`).forEach(this.cleanBlinker),{isGlobal:true});this.addDomListener(this.editable,"focusin",()=>this.resetBlinkerClasses(),{isGlobal:true,});} 8530updatePlaceholders(){const checkPredicate=(resourceId,node)=>{const results=this.getResource(resourceId).map((p)=>p(node)).filter((result)=>result!==undefined);return!!results.length&&results.every(Boolean);};const isSelectionBlocker=(node)=>checkPredicate("selection_blocker_predicates",node);const placeholderParents=[this.editable,...this.editable.querySelectorAll("*")].filter((container)=>checkPredicate("selection_placeholder_container_predicates",container));const marginUpdates=[];for(const placeholder of this.editable.querySelectorAll(PLACEHOLDER_SELECTOR)){const siblings=["before","after"].map((side)=>getNonWhitespaceSibling(side,placeholder));if(!isEmpty(placeholder)||!siblings.filter(Boolean).length){this.persistPlaceholder(placeholder);}else if(!placeholderParents.includes(placeholder.parentElement)||!siblings.every((sibling)=>!sibling||isSelectionBlocker(sibling))){placeholder.remove();}else{const update=this.prepareMarginUpdate(placeholder,...siblings);if(update){marginUpdates.push(update);}}} 8531const blockers=[...new Set(placeholderParents.flatMap((element)=>[...element.children])),].filter((element)=>isSelectionBlocker(element));const pendingMarginUpdates=[];for(const blocker of blockers){for(const side of["before","after"]){const sibling=getNonWhitespaceSibling(side,blocker);if(!sibling||isSelectionBlocker(sibling)){const placeholder=this.dependencies.baseContainer.createBaseContainer();fillEmpty(placeholder);placeholder.setAttribute(PLACEHOLDER_ATTRIBUTE,"");const siblings=side==="before"?[sibling,blocker]:[blocker,sibling];blocker[side](placeholder);pendingMarginUpdates.push({placeholder,siblings,});}}} 8532for(const{placeholder,siblings}of pendingMarginUpdates){const update=this.prepareMarginUpdate(placeholder,...siblings);if(update){marginUpdates.push(update);}} 8533for(const update of marginUpdates){update();} 8534this.resetBlinkerClasses();} 8535prepareMarginUpdate(placeholder,previous,next){const marginBefore=previous?getMargin(previous,"bottom"):0;const marginAfter=next?getMargin(next,"top"):0;const middleMargin=Math.abs(marginBefore-marginAfter)/2;if(middleMargin){const positiveMargin=Math.abs(middleMargin-(marginAfter>=marginBefore?marginAfter:marginBefore));const negativeMargin=-1-middleMargin;const marginTop=marginAfter>=marginBefore?positiveMargin:negativeMargin;const marginBottom=marginAfter>=marginBefore?negativeMargin:positiveMargin;return()=>(placeholder.style.margin=`${marginTop}px 0 ${marginBottom}px`);}} 8536persistPlaceholder(placeholder){placeholder.removeAttribute(PLACEHOLDER_ATTRIBUTE);this.cleanBlinker(placeholder);placeholder.removeAttribute("style");} 8537cleanBlinker(blinker){if(blinker.className===BLINKER_CLASS){blinker.removeAttribute("class");}else{blinker.classList.remove(BLINKER_CLASS);}} 8538resetBlinkerClasses(selection=this.dependencies.selection.getEditableSelection()){const anchorPlaceholder=selection.isCollapsed&&closestElement(selection.anchorNode,PLACEHOLDER_SELECTOR);if(anchorPlaceholder&&this.document.activeElement.contains(anchorPlaceholder)){anchorPlaceholder.classList.add(BLINKER_CLASS);} 8539for(const blinker of this.editable.querySelectorAll(`.${BLINKER_CLASS}`)){if(blinker!==anchorPlaceholder||!this.document.activeElement.contains(blinker)){this.cleanBlinker(blinker);}}} 8540onSelectionChange(selectionData){const selection=selectionData.editableSelection;this.resetBlinkerClasses(selection);if(selection.isCollapsed){const anchor=closestElement(selection.anchorNode);if(closestBlock(anchor.parentElement)===this.editable&&anchor?.hasAttribute(PLACEHOLDER_ATTRIBUTE)&&!getNonWhitespaceSibling("next",anchor)){this.persistPlaceholder(anchor);if(this.dependencies.history.getIsCurrentStepModified()){this.dependencies.history.addStep();}}}}} 8541const getNonWhitespaceSibling=(side,node)=>{const siblings=side==="before"?getAdjacentPreviousSiblings(node):getAdjacentNextSiblings(node);return siblings.find((sibling)=>!(sibling.nodeType===Node.TEXT_NODE&&!sibling.textContent.trim()));};const getMargin=(element,side)=>+element.ownerDocument.defaultView.getComputedStyle(element) 8542[side==="top"?"marginTop":"marginBottom"].replace("px","");return __exports;});; 8543 8544/* /html_editor/static/src/main/separator_plugin.js */ 8545odoo.define('@html_editor/main/separator_plugin',['@web/core/l10n/translation','@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_traversal','@html_editor/utils/dom_info','@html_editor/core/selection_plugin','@html_editor/utils/dom','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Plugin}=require("@html_editor/plugin");const{closestBlock}=require("@html_editor/utils/blocks");const{closestElement,firstLeaf,selectElements}=require("@html_editor/utils/dom_traversal");const{isEmptyBlock,isListItemElement,paragraphRelatedElementsSelector,}=require("@html_editor/utils/dom_info");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{removeClass}=require("@html_editor/utils/dom");const{withSequence}=require("@html_editor/utils/resource");const{fillEmpty}=require("@html_editor/utils/dom");const SeparatorPlugin=__exports.SeparatorPlugin=class SeparatorPlugin extends Plugin{static id="separator";static dependencies=["selection","history","split","delete","lineBreak","baseContainer"];resources={user_commands:[{id:"insertSeparator",title:_t("Separator"),description:_t("Insert a horizontal rule separator"),icon:"fa-minus",run:this.insertSeparator.bind(this),isAvailable:isHtmlContentSupported,},],powerbox_items:withSequence(1,{categoryId:"structure",commandId:"insertSeparator",ke
8545ywords:[_t("divider"),_t("line")],}),content_not_editable_providers:(rootEl)=>[...selectElements(rootEl,"hr")],contenteditable_to_remove_selector:"hr[contenteditable]",shorthands:[{pattern:/^---$/,commandId:"insertSeparator",},],selectionchange_handlers:this.handleSelectionInHr.bind(this),deselect_custom_selected_nodes_handlers:this.deselectHR.bind(this),clean_for_save_handlers:({root})=>{this.deselectHR(root);},};insertSeparator(){const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;const block=closestBlock(selection.startContainer);const element=closestElement(selection.startContainer,paragraphRelatedElementsSelector)||(block&&!isListItemElement(block)?block:null);if(element&&element!==this.editable){const sep=this.document.createElement("hr");const firstLeafNode=firstLeaf(block);if(isEmptyBlock(element)||(selection.anchorNode===firstLeafNode&&selection.anchorOffset===0)){element.before(sep);}else{element.after(sep);const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);sep.after(baseContainer);this.dependencies.selection.setCursorStart(baseContainer);}} 8546this.dependencies.history.addStep();} 8547deselectHR(root=this.editable){for(const hr of root.querySelectorAll(".o_selected_hr")){removeClass(hr,"o_selected_hr");}} 8548handleSelectionInHr(selectionData){this.deselectHR();if(!selectionData.documentSelectionIsInEditable){return;} 8549const targetedNodes=this.dependencies.selection.getTargetedNodes();for(const node of targetedNodes){if(node.nodeName==="HR"){node.classList.toggle("o_selected_hr",true);}}}} 8550return __exports;});; 8551 8552/* /html_editor/static/src/main/star_plugin.js */ 8553odoo.define('@html_editor/main/star_plugin',['@html_editor/plugin','@html_editor/utils/html','@web/core/l10n/translation','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{parseHTML}=require("@html_editor/utils/html");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const StarPlugin=__exports.StarPlugin=class StarPlugin extends Plugin{static id="star";static dependencies=["dom","history"];resources={user_commands:[{id:"addStars",title:_t("Stars"),description:_t("Insert a rating"),icon:"fa-star",run:this.addStars.bind(this),isAvailable:isHtmlContentSupported,},],powerbox_items:[{title:_t("3 Stars"),description:_t("Insert a rating over 3 stars"),categoryId:"widget",icon:"fa-star-o",commandId:"addStars",commandParams:{length:3},},{title:_t("5 Stars"),description:_t("Insert a rating over 5 stars"),categoryId:"widget",commandId:"addStars",commandParams:{length:5},},],selectors_for_feff_providers:()=>".o_stars",};setup(){this.addDomListener(this.editable,"pointerdown",this.onMouseDown);} 8554onMouseDown(ev){const node=ev.target;const isStar=(node)=>node.nodeType===Node.ELEMENT_NODE&&(node.classList.contains("fa-star")||node.classList.contains("fa-star-o"));if(isStar(node)&&node.parentElement&&node.parentElement.className.includes("o_stars")){const allStars=Array.from(node.parentElement.childNodes).filter(isStar);const currentStarIndex=allStars.indexOf(node);const previousStars=allStars.slice(0,currentStarIndex);const nextStars=allStars.slice(currentStarIndex+1);if(nextStars.length||previousStars.length){const shouldToggleOff=node.classList.contains("fa-star")&&(!nextStars[0]||!nextStars[0].classList.contains("fa-star"));for(const star of[...previousStars,node]){star.classList.toggle("fa-star-o",shouldToggleOff);star.classList.toggle("fa-star",!shouldToggleOff);} 8555for(const star of nextStars){star.classList.toggle("fa-star-o",true);star.classList.toggle("fa-star",false);} 8556this.dependencies.history.addStep();} 8557ev.stopPropagation();ev.preventDefault();}} 8558addStars({length}){const stars=Array.from({length},()=>'<i class="fa fa-star-o"></i>').join("");const html=`<span contenteditable="false" class="o_stars">${stars}</span>`;this.dependencies.dom.insert(parseHTML(this.document,html));this.dependencies.history.addStep();}} 8559return __exports;});; 8560 8561/* /html_editor/static/src/main/table/table_align_plugin.js */ 8562odoo.define('@html_editor/main/table/table_align_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@web/core/l10n/translation','@odoo/owl','@html_editor/main/table/table_align_selector'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{reactive}=require("@odoo/owl");const{TableAlignSelector}=require("@html_editor/main/table/table_align_selector");const verticalAlignmentItems=[{mode:"top",template:"html_editor.VerticalAlignTop",},{mode:"middle",template:"html_editor.VerticalAlignMiddle",},{mode:"bottom",template:"html_editor.VerticalAlignBottom",},];const TableAlignPlugin=__exports.TableAlignPlugin=class TableAlignPlugin extends Plugin{static id="tableAlign";static dependencies=["history","selection"];resources={user_commands:[{id:"alignTop",run:()=>this.setVerticalAlignment("top"),},{id:"alignMiddle",run:()=>this.setVerticalAlignment("middle"),},{id:"alignBottom",run:()=>this.setVerticalAlignment("bottom"),},],toolbar_items:[{id:"table_alignment",groupId:"layout",description:_t("Vertical align table cells content"),isAvailable:()=>this.dependencies.selection.getTargetedNodes().some((node)=>closestElement(node,"td, th")),Component:TableAlignSelector,props:{getItems:()=>verticalAlignmentItems,getDisplay:()=>this.verticalAlignMode,onSelected:(item)=>{this.setVerticalAlignment(item.mode);},},},],selectionchange_handlers:this.updateVerticalAlignParams.bind(this),post_undo_handlers:this.updateVerticalAlignParams.bind(this),post_redo_handlers:this.updateVerticalAlignParams.bind(this),remove_all_formats_handlers:this.setVerticalAlignment.bind(this),has_format_predicates:(node)=>closestElement(node,"td, th")?.style.verticalAlign,};setup(){this.verticalAlignMode=reactive({displayName:""});} 8563get currentVerticalAlign(){const targetedCells=this.dependencies.selection.getTargetedNodes().map((node)=>
8563closestElement(node,"td, th")).filter(Boolean);if(!targetedCells.length){return"";} 8564const verticalAlign=targetedCells[0].style.verticalAlign;return verticalAlign&&targetedCells.every((cell)=>cell.style.verticalAlign===verticalAlign)?verticalAlign:"";} 8565setVerticalAlignment(mode=""){const targetedCells=new Set(this.dependencies.selection.getTargetedNodes().map((node)=>closestElement(node,"td, th")).filter(Boolean));let isAlignmentUpdated=false;for(const cell of targetedCells){if(cell.isContentEditable&&cell.style.verticalAlign!==mode){cell.style.verticalAlign=mode;isAlignmentUpdated=true;}} 8566if(isAlignmentUpdated){this.dependencies.history.addStep();} 8567this.updateVerticalAlignParams();} 8568updateVerticalAlignParams(){this.verticalAlignMode.displayName=this.currentVerticalAlign;}} 8569return __exports;});; 8570 8571/* /html_editor/static/src/main/table/table_align_selector.js */ 8572odoo.define('@html_editor/main/table/table_align_selector',['@odoo/owl','@web/core/dropdown/dropdown','@html_editor/main/toolbar/toolbar','@html_editor/dropdown_autovisibility_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{toolbarButtonProps}=require("@html_editor/main/toolbar/toolbar");const{useDropdownAutoVisibility}=require("@html_editor/dropdown_autovisibility_hook");const{useChildRef}=require("@web/core/utils/hooks");const TableAlignSelector=__exports.TableAlignSelector=class TableAlignSelector extends Component{static template="html_editor.TableAlignSelector";static props={getItems:Function,getDisplay:Function,onSelected:Function,...toolbarButtonProps,};static components={Dropdown};setup(){this.items=this.props.getItems();this.state=useState(this.props.getDisplay());this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);} 8573onSelected(item){this.props.onSelected(item);}} 8574return __exports;});; 8575 8576/* /html_editor/static/src/main/table/table_menu.js */ 8577odoo.define('@html_editor/main/table/table_menu',['@html_editor/utils/dom_traversal','@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{closestElement}=require("@html_editor/utils/dom_traversal");const{Component,onMounted,useEffect,useExternalListener,useRef}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const TableMenu=__exports.TableMenu=class TableMenu extends Component{static template="html_editor.TableMenu";static props={type:String,moveColumn:Function,addColumn:Function,removeColumn:Function,moveRow:Function,addRow:Function,removeRow:Function,turnIntoHeader:Function,turnIntoRow:Function,resetRowHeight:Function,resetColumnWidth:Function,resetTableSize:Function,clearColumnContent:Function,clearRowContent:Function,close:Function,dropdownState:Object,target:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE},document:{validate:(el)=>el.nodeType===Node.DOCUMENT_NODE},direction:{type:String,optional:true},};static defaultProps={direction:"ltr"};static components={Dropdown,DropdownItem};setup(){this.dropdownRef=useRef("dropdown");onMounted(()=>{this.overlayEl=this.dropdownRef.el;});useEffect(()=>{if(this.props.type==="column"){this.isFirst=this.props.target.cellIndex===0;this.isLast=!this.props.target.nextElementSibling;}else{const tr=this.props.target.parentElement;this.isFirst=!tr.previousElementSibling;this.isLast=!tr.nextElementSibling;this.isTableHeader=[...tr.children][0].nodeName==="TH";} 8578this.items=this.props.type==="column"?this.colItems():this.rowItems();this.updatePosition();},()=>[this.props.target]);if(this.props.document.defaultView.frameElement){useExternalListener(this.props.document,"scroll",()=>{this.updatePosition();});useExternalListener(this.props.document,"pointerdown",(ev)=>{if(!this.overlayEl.contains(ev.target)){this.props.close();}});}} 8579get hasCustomTableSize(){const tBody=closestElement(this.props.target,"tbody");if(!tBody){return false;} 8580const rows=[...tBody.rows];const firstRowCells=[...rows[0].cells];const rowHasHeight=rows.some((row)=>row.style.height);const cellHasWidth=firstRowCells.some((cell)=>cell.style.width);return rowHasHeight||cellHasWidth;} 8581get hasCustomRowHeight(){return!!this.props.target.closest("tr").style.height;} 8582get hasCustomColumnWidth(){return(!!this.props.target.closest("td")?.style?.width||!!this.props.target.closest("th")?.style?.width);} 8583updatePosition(){const{target,type,direction}=this.props;if(!this.overlayEl||!target){return;} 8584let frameRect={top:0,left:0};let frameElement;try{frameElement=this.props.document.defaultView.frameElement;}catch{} 8585if(frameElement){frameRect=frameElement.getBoundingClientRect();} 8586const targetRect=target.getBoundingClientRect();const container=this.overlayEl.parentElement;const containerRect=container.getBoundingClientRect();const top=frameRect.top+targetRect.top-containerRect.top;const left=frameRect.left+targetRect.left-containerRect.left;this.overlayEl.classList.remove("h-100","w-100");if(type==="column"){Object.assign(this.overlayEl.style,{position:"absolute",top:`${top - this.overlayEl.offsetHeight}px`,left:`${left}px`,width:`${targetRect.width}px`,});}else{const isLTR=direction==="ltr";const inlineStartOffset=isLTR?left:containerRect.right-(frameRect.left+targetRect.right);Object.assign(this.overlayEl.style,{position:"absolute",top:`${top}px`,insetInlineStart:`${inlineStartOffset - this.overlayEl.offsetWidth}px`,height:`${targetRect.height}px`,});}} 8587onSelected(item){item.action(this.props.target);this.props.close();} 8588colItems(){const ltr=this.props.direction==="ltr";return[!this.isFirst&&{name:"move_left",icon:"fa-chevron-left disabled",text:ltr?_t("Move left"):_t("Move right"),action:this.props.moveColumn.bind(this,"left"),},!this.isLast&&{name:"move_right",icon:"fa-chevron-right",text:ltr?_t("Move right"):_t("Move left"),action:this.props.moveColumn.bind(this,"right"),},{name:"insert_left",icon:"fa-plus",text:ltr?_t("Insert left"):_t("Insert r
8588ight"),action:this.props.addColumn.bind(this,"before"),},{name:"insert_right",icon:"fa-plus",text:ltr?_t("Insert right"):_t("Insert left"),action:this.props.addColumn.bind(this,"after"),},{name:"delete",icon:"fa-trash",text:_t("Delete"),action:this.props.removeColumn.bind(this),},this.hasCustomColumnWidth&&{name:"reset_column_size",icon:"fa-table",text:_t("Reset column size"),action:(target)=>this.props.resetColumnWidth(target.closest("td, th")),},this.hasCustomTableSize&&{name:"reset_table_size",icon:"fa-table",text:_t("Reset table size"),action:(target)=>this.props.resetTableSize(target.closest("tbody")),},{name:"clear_content",icon:"fa-times-circle",text:_t("Clear content"),action:this.props.clearColumnContent.bind(this),},].filter(Boolean);} 8589rowItems(){return[this.isFirst&&!this.isTableHeader&&{name:"make_header",icon:"fa-th-large",text:_t("Turn into header"),action:(target)=>this.props.turnIntoHeader(target.parentElement),},this.isFirst&&this.isTableHeader&&{name:"remove_header",icon:"fa-table",text:_t("Turn into row"),action:(target)=>this.props.turnIntoRow(target.parentElement),},!this.isFirst&&{name:"move_up",icon:"fa-chevron-up",text:_t("Move up"),action:(target)=>this.props.moveRow("up",target.parentElement),},!this.isLast&&{name:"move_down",icon:"fa-chevron-down",text:_t("Move down"),action:(target)=>this.props.moveRow("down",target.parentElement),},!this.isTableHeader&&{name:"insert_above",icon:"fa-plus",text:_t("Insert above"),action:(target)=>this.props.addRow("before",target.parentElement),},{name:"insert_below",icon:"fa-plus",text:_t("Insert below"),action:(target)=>this.props.addRow("after",target.parentElement),},{name:"delete",icon:"fa-trash",text:_t("Delete"),action:(target)=>this.props.removeRow(target.parentElement),},this.hasCustomRowHeight&&{name:"reset_row_size",icon:"fa-table",text:_t("Reset row size"),action:(target)=>this.props.resetRowHeight(target.closest("tr")),},this.hasCustomTableSize&&{name:"reset_table_size",icon:"fa-table",text:_t("Reset table size"),action:(target)=>this.props.resetTableSize(target.closest("tbody")),},{name:"clear_content",icon:"fa-times-circle",text:_t("Clear content"),action:(target)=>this.props.clearRowContent(target.parentElement),}
8589,].filter(Boolean);}} 8590return __exports;});; 8591 8592/* /html_editor/static/src/main/table/table_picker.js */ 8593odoo.define('@html_editor/main/table/table_picker',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,useExternalListener,useState}=require("@odoo/owl");const TablePicker=__exports.TablePicker=class TablePicker extends Component{static template="html_editor.TablePicker";static props={insertTable:Function,editable:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE,},overlay:Object,direction:String,};setup(){this.state=useState({cols:3,rows:3,});useExternalListener(this.props.editable.ownerDocument,"keydown",(ev)=>{ev.stopPropagation();const key=ev.key;const isRTL=this.props.direction==="rtl";switch(key){case"Enter":ev.preventDefault();this.insertTable();break;case"ArrowUp":ev.preventDefault();if(this.state.rows>1){this.state.rows-=1;} 8594break;case"ArrowDown":this.state.rows+=1;ev.preventDefault();break;case"ArrowLeft":ev.preventDefault();if(isRTL){this.state.cols+=1;}else{if(this.state.cols>1){this.state.cols-=1;}} 8595break;case"ArrowRight":ev.preventDefault();if(isRTL){if(this.state.cols>1){this.state.cols-=1;}}else{this.state.cols+=1;} 8596break;default:ev.stopImmediatePropagation();this.props.overlay.close();break;}},{capture:true});} 8597updateSize(cols,rows){this.state.cols=cols;this.state.rows=rows;} 8598insertTable(){this.props.insertTable({cols:this.state.cols,rows:this.state.rows});this.props.overlay.close();}} 8599return __exports;});; 8600 8601/* /html_editor/static/src/main/table/table_plugin.js */ 8602odoo.define('@html_editor/main/table/table_plugin',['@html_editor/plugin','@html_editor/utils/base_container','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/html','@html_editor/utils/position','@html_editor/utils/resource','@html_editor/utils/selection','@html_editor/utils/table','@web/core/browser/feature_detection','@web/core/h
8602otkeys/hotkey_service','@html_editor/core/selection_plugin','@web/core/utils/colors'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{isBlock}=require("@html_editor/utils/blocks");const{fillEmpty,fillShrunkPhrasingParent,removeClass,removeStyle,}=require("@html_editor/utils/dom");const{getDeepestPosition,isProtected,isProtecting,isEmptyBlock,nextLeaf,previousLeaf,isTableCell,}=require("@html_editor/utils/dom_info");const{ancestors,closestElement,createDOMPathGenerator,descendants,firstLeaf,lastLeaf,selectElements,}=require("@html_editor/utils/dom_traversal");const{parseHTML}=require("@html_editor/utils/html");const{DIRECTIONS,leftPos,rightPos,nodeSize}=require("@html_editor/utils/position");const{withSequence}=require("@html_editor/utils/resource");const{findInSelection}=require("@html_editor/utils/selection");const{getColumnIndex,getRowIndex,getTableCells}=require("@html_editor/utils/table");const{isBrowserFirefox}=require("@web/core/browser/feature_detection");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{rgbaToHex}=require("@web/core/utils/colors");const BORDER_SENSITIVITY=__exports.BORDER_SENSITIVITY=5;const tableInnerComponents=new Set(["THEAD","TBODY","TFOOT","TR","TH","TD"]);function isUnremovableTableComponent(node,root){if(!tableInnerComponents.has(node.nodeName)){return false;} 8603if(!root){return true;} 8604const closestTable=closestElement(node,"table");return!root.contains(closestTable);} 8605const TablePlugin=__exports.TablePlugin=class TablePlugin extends Plugin{static id="table";static dependencies=["baseContainer","dom","history","selection","delete","split","color",];static shared=["insertTable","addColumn","addRow","removeColumn","removeRow","moveColumn","turnIntoHeader","turnIntoRow","moveRow","resetRowHeight","resetColumnWidth","resetTableSize","clearColumnContent","clearRowContent",];resources={user_commands:[{id:"insertTable",run:(params)=>{this.insertTable(params);},isAvailable:isHtmlContentSupported,},],toolbar_namespace_providers:[withSequence(90,(targetedNodes,editableSelection)=>closestElement(editableSelection.anchorNode,".o_selected_td")&&"compact"),],selectionchange_handlers:withSequence(5,this.updateSelectionTable.bind(this)),clipboard_content_processors:this.processContentForClipboard.bind(this),clean_for_save_handlers:({root})=>this.deselectTable(root),before_line_break_handlers:this.resetTableSelection.bind(this),before_split_block_handlers:this.resetTableSelection.bind(this),before_insert_processors:this.normalizeTableStructure.bind(this),tab_overrides:withSequence(20,this.handleTab.bind(this)),shift_tab_overrides:withSequence(20,this.handleShiftTab.bind(this)),delete_range_overrides:this.handleDeleteRange.bind(this),color_apply_overrides:this.applyTableColor.bind(this),unremovable_node_predicates:isUnremovableTableComponent,unsplittable_node_predicates:(node)=>node.nodeName==="TABLE"||tableInnerComponents.has(node.nodeName),fully_selected_node_predicates:(node)=>!!closestElement(node,".o_selected_td"),targeted_nodes_processors:this.adjustTargetedNodes.bind(this),move_node_whitelist_selectors:"table",selection_blocker_predicates:(node)=>{if(node.nodeName==="TABLE"){return true;}},selection_placeholder_container_predicates:(container)=>{if(container.nodeName==="TABLE"){return false;}else if(["TD","TH"].includes(container.nodeName)&&container.closest(".o_table")){return true;}},normalize_handlers:[this.distributeTableColorsToAllCells.bind(this),this.populateTableSpans.bind(this),],overlay_selection_target_rect_providers:this.getTableSelectionRangeRect.bind(this),selected_background_color_providers:withSequence(5,this.computeBackgroundColorForTable.bind(this)),};setup(){this.addDomListener(this.editable,"mousedown",this.onMousedown);this.addDomListener(this.editable,"mouseup",this.onMouseup);this.addDomListener(this.editable,"keydown",(ev)=>{this._isKeyDown=true;const arrowHandled=["arrowup","control+arrowup","arrowdown","control+arrowdown"];if(arrowHandled.includes(getActiveHotkey(ev))){this.navigateCell(ev);} 8606const shiftArrowHandled=["shift+arrowup","shift+arrowright","shift+arrowdown","shift+arrowleft","control+shift+arrowup","control+shift+arrowright","control+shift+arrowdown","control+shift+arrowleft",];if(shiftArrowHandled.includes(getActiveHotkey(ev))){this.isShiftArrowKeyboardSelection=true;this.updateTableKeyboardSelection(ev);}});this.onMousemove=this.onMousemove.bind(this);this.normalizeTableStructure(this.editable);this.editable.querySelectorAll("table").forEach((table)=>{const tBody=table.tBodies[0];for(const property of["width","marginLeft"]){if(table.style[property]){tBody.style[property]=table.style[property];}} 8607removeStyle(table,"width","margin-left");});} 8608handleTab(){const selection=this.dependencies.selection.getEditableSelection();const inTable=closestElement(selection.anchorNode,"table");if(inTable){const shouldAddNewRow=!this.shiftCursorToTableCell(1);if(shouldAddNewRow){this.addRow("after",findInSelection(selection,"tr"));this.shiftCursorToTableCell(1);this.dependencies.history.addStep();} 8609return true;}} 8610handleShiftTab(){const selection=this.dependencies.selection.getEditableSelection();const inTable=closestElement(selection.anchorNode,"table");if(inTable){this.shiftCursorToTableCell(-1);return true;}} 8611distributeTableColorsToAllCells(root){[...root.querySelectorAll("table")].filter((table)=>
8611table.style["color"]||table.style["backgroundColor"]).forEach((table)=>{const tds=[...table.querySelectorAll("td")].filter((td)=>closestElement(td,"table")===table);for(const td of tds){td.style["color"]=td.style["color"]||table.style["color"];td.style["backgroundColor"]=td.style["backgroundColor"]||table.style["backgroundColor"];} 8612table.style["color"]="";table.style["backgroundColor"]="";});} 8613createTable({rows=2,cols=2}={}){const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillShrunkPhrasingParent(baseContainer);const baseContainerHtml=baseContainer.outerHTML;const tdsHtml=new Array(cols).fill(`<td>${baseContainerHtml}</td>`).join("");const trsHtml=new Array(rows).fill(`<tr>${tdsHtml}</tr>`).join("");const tableHtml=`<table class="table table-bordered o_table"><tbody>${trsHtml}</tbody></table>`;return parseHTML(this.document,tableHtml);} 8614_insertTable({rows=2,cols=2}={}){const newTable=this.createTable({rows,cols});const[table]=this.dependencies.dom.insert(newTable);return table;} 8615insertTable({rows=2,cols=2}={}){const table=this._insertTable({rows,cols});this.dependencies.selection.setCursorStart(table.querySelector(baseContainerGlobalSelector));this.dependencies.history.addStep();} 8616addColumn(position,reference){const columnIndex=getColumnIndex(reference);const tBody=closestElement(reference,"tbody");const tBodyWidth=tBody.style.width&&parseFloat(tBody.style.width);const referenceColumn=tBody.querySelectorAll(`tr :is(td, th):nth-of-type(${columnIndex + 1})`);const referenceCellWidth=reference.style.width?parseFloat(reference.style.width):reference.clientWidth;const firstRow=tBody.querySelector("tr");const firstRowCells=[...firstRow.children].filter((child)=>child.nodeName==="TD"||child.nodeName==="TH");let totalWidth=0;if(tBodyWidth){for(const cell of firstRowCells){const width=parseFloat(cell.style.width);cell.style.width=width+"px";const newWidth=Math.max(Math.round((width*tBodyWidth)/(tBodyWidth+referenceCellWidth-1)),13);cell.style.width=newWidth+"px";totalWidth+=newWidth;}} 8617referenceColumn.forEach((cell,rowIndex)=>{const newCell=this.document.createElement(cell.tagName);const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(this.document.createElement("br"));newCell.append(baseContainer);cell[position](newCell);if(rowIndex===0&&cell.classList.contains("o_table_header")){newCell.classList.add("o_table_header");} 8618if(rowIndex===0&&tBodyWidth){newCell.style.width=cell.style.width;totalWidth+=parseFloat(cell.style.width);}});if(tBodyWidth){if(totalWidth!==tBodyWidth-1){firstRowCells[firstRowCells.length-1].style.width=parseFloat(firstRowCells[firstRowCells.length-1].style.width)+ 8619(tBodyWidth-totalWidth-1)+"px";} 8620tBody.style.width=tBodyWidth+"px";}} 8621addRow(position,reference){const referenceRowHeight=reference.style.height&&parseFloat(reference.style.height);const newRow=this.document.createElement("tr");if(referenceRowHeight){newRow.style.height=referenceRowHeight+"px";} 8622const cells=reference.querySelectorAll("td, th");const referenceRowWidths=[...cells].map((cell)=>cell.style.width);newRow.append(...Array.from(cells).map(()=>{const td=this.document.createElement("td");const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(this.document.createElement("br"));td.append(baseContainer);return td;}));reference[position](newRow);if(referenceRowHeight){newRow.style.height=referenceRowHeight+"px";} 8623if(getRowIndex(newRow)===0){let columnIndex=0;for(const column of newRow.children){column.style.width=referenceRowWidths[columnIndex];cells[columnIndex].style.width="";columnIndex++;}}} 8624turnIntoHeader(reference){const preserveSelection=this.dependencies.selection.preserveSelection();[...reference.children].forEach((td)=>{if(td.nodeName=="TD"){const th=this.document.createElement("th");if(td.style?.cssText.length){th.style.cssText=td.style?.cssText;} 8625th.classList.add("o_table_header");th.append(...td.childNodes);td.replaceWith(th);}});preserveSelection.restore();} 8626turnIntoRow(reference){const preserveSelection=this.dependencies.selection.preserveSelection();
8626[...reference.children].forEach((th)=>{if(th.nodeName=="TH"){const td=this.document.createElement("td");if(th.style?.cssText.length){td.style.cssText=th.style?.cssText;} 8627td.append(...th.childNodes);th.replaceWith(td);}});preserveSelection.restore();} 8628removeColumn(cell){const table=closestElement(cell,"table");const cells=[...closestElement(cell,"tr").querySelectorAll("th, td")];const index=cells.findIndex((td)=>td===cell);const siblingCell=cells[index-1]||cells[index+1];table.querySelectorAll(`tr :is(td, th):nth-of-type(${index + 1})`).forEach((td)=>td.remove());siblingCell?this.dependencies.selection.setCursorEnd(lastLeaf(siblingCell)):this.deleteTable(table);} 8629removeRow(row){const table=closestElement(row,"table");const siblingRow=row.previousElementSibling||row.nextElementSibling;row.remove();siblingRow?this.dependencies.selection.setCursorEnd(lastLeaf(siblingRow.cells[0])):this.deleteTable(table);} 8630moveColumn(position,cell){const columnIndex=getColumnIndex(cell);const nColumns=cell.parentElement.children.length;if(columnIndex<0||(position==="left"&&columnIndex===0)||(position!=="left"&&columnIndex===nColumns-1)){return;} 8631const trs=cell.parentElement.parentElement.children;const tdsToMove=[...trs].map((tr)=>tr.children[columnIndex]);const selectionToRestore=this.dependencies.selection.getEditableSelection();if(position==="left"){tdsToMove.forEach((td)=>td.previousElementSibling.before(td));}else{tdsToMove.forEach((td)=>td.nextElementSibling.after(td));} 8632this.dependencies.selection.setSelection(selectionToRestore);} 8633moveRow(position,row){const selectionToRestore=this.dependencies.selection.getEditableSelection();let adjustedRow;if(position==="up"){const isPreviousRowHeader=[...row.previousElementSibling.children][0].nodeName==="TH";row.previousElementSibling?.before(row);adjustedRow=row;if(isPreviousRowHeader){this.turnIntoHeader(row);this.turnIntoRow(row.nextElementSibling);}}else{const isRowHeader=[...row.children][0].nodeName==="TH";row.nextElementSibling?.after(row);adjustedRow=row.previousElementSibling;if(isRowHeader){this.turnIntoHeader(adjustedRow);this.turnIntoRow(row);}} 8634if(!adjustedRow.previousElementSibling){adjustedRow.childNodes.forEach((cell,index)=>{cell.style.width=adjustedRow.nextElementSibling.childNodes[index].style.width;});} 8635this.dependencies.selection.setSelection(selectionToRestore);} 8636normalizeRowHeight(table){const rows=[...table.rows];const referenceRow=rows.find((row)=>!row.style.height);const referenceRowHeight=parseFloat(getComputedStyle(referenceRow).height);rows.forEach((row)=>{if(row.style.height&&Math.abs(parseFloat(row.style.height)-referenceRowHeight)<=1){row.style.height="";}});} 8637resetRowHeight(row){const table=closestElement(row,"table");row.style.height="";this.normalizeRowHeight(table);} 8638normalizeColumnWidth(tBody){const rows=[...tBody.rows];const firstRowCells=[...rows[0].cells];const tBodyWidth=parseFloat(tBody.style.width);if(tBodyWidth){const expectedCellWidth=tBodyWidth/firstRowCells.length;firstRowCells.forEach((cell,i)=>{const cellWidth=parseFloat(cell.style.width);if(cellWidth&&Math.abs(cellWidth-expectedCellWidth)<=1){rows.forEach((row)=>(row.cells[i].style.width=""));}});}} 8639resetColumnWidth(cell){const currentCellWidth=parseFloat(cell.style.width);if(!currentCellWidth){return;} 8640const tBody=closestElement(cell,"tbody");const tBodyWidth=parseFloat(tBody.style.width);const currentRow=cell.parentElement;const currentRowCells=[...currentRow.cells];const rowCellCount=currentRowCells.length;const expectedCellWidth=tBodyWidth/rowCellCount;const widthDifference=currentCellWidth-expectedCellWidth;const currentColumnIndex=getColumnIndex(cell);let totalWidthLeftOfCell=0,totalWidthRightOfCell=0;currentRowCells.forEach((rowCell,i)=>{const cellWidth=parseFloat(rowCell.style.width)||rowCell.clientWidth;if(i<currentColumnIndex){totalWidthLeftOfCell+=cellWidth;}else if(i>currentColumnIndex){totalWidthRightOfCell+=cellWidth;}});let expectedWidthLeftOfCell=currentColumnIndex*expectedCellWidth;let expectedWidthRightOfCell=(rowCellCount-1-currentColumnIndex)*expectedCellWidth;let cellsToAdjust=[];for(let i=currentColumnIndex-1;i>=0&&Math.abs(expectedWidthLeftOfCell-totalWidthLeftOfCell)>1;i--){cellsToAdjust.push(currentRowCells[i]);totalWidthLeftOfCell-=parseFloat(currentRowCells[i].style.width)||currentRowCells[i].clientWidth;expectedWidthLeftOfCell-=expectedCellWidth;} 8641for(let j=currentColumnIndex+1;j<rowCellCount&&Math.abs(expectedWidthRightOfCell-totalWidthRightOfCell)>1;j++){cellsToAdjust.push(currentRowCells[j]);totalWidthRightOfCell-=parseFloat(currentRowCells[j].style.width)||currentRowCells[j].clientWidth;expectedWidthRightOfCell-=expectedCellWidth;} 8642cellsToAdjust=cellsToAdjust.filter((adjCell)=>{const cellWidth=parseFloat(adjCell.style.width)||adjCell.clientWidth;return widthDifference>0?cellWidth<expectedCellWidth:cellWidth>expectedCellWidth;});const totalWidthForAdjustment=cellsToAdjust.reduce((width,adjCell)=>{const cellWidth=parseFloat(adjCell.style.width)||adjCell.clientWidth;return width+Math.abs(expectedCellWidth-cellWidth);},0);cell.style.width=`${expectedCellWidth}px`;cellsToAdjust.forEach((adjCell)=>{const adjCellWidth=parseFloat(adjCell.style.width)||adjCell.clientWidth;const adjustmentWidth=(Math.abs(expectedCellWidth-adjCellWidth)/totalWidthForAdjustment)*Math.abs(widthDifference);adjCell.style.width=`${ 8643 adjCellWidth + (widthDifference > 0 ? adjustmentWidth : -adjustmentWidth) 8644 }px`;});this.normalizeColumnWidth(tBody);} 8645resetTableSize(tBody){tBody.removeAttribute("style");const cells=[...tBody.querySelectorAll("tr, td, th")];
8645cells.forEach((cell)=>{const cStyle=cell.style;if(cell.tagName==="TR"){cStyle.height="";}else{cStyle.width="";}});} 8646clearColumnContent(cell){const table=closestElement(cell,"table");const cells=[...closestElement(cell,"tr").querySelectorAll("th, td")];const index=cells.findIndex((td)=>td===cell);table.querySelectorAll(`tr :is(td, th):nth-of-type(${index + 1})`).forEach((td)=>{const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);td.replaceChildren(baseContainer);});} 8647clearRowContent(row){row.querySelectorAll("td, th").forEach((td)=>{const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);td.replaceChildren(baseContainer);});} 8648deleteTable(table){table=table||findInSelection(this.dependencies.selection.getEditableSelection(),"table");if(!table){return;} 8649const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));table.before(baseContainer);table.remove();this.dependencies.selection.setCursorStart(baseContainer);} 8650deleteTableCells(selectedTds){const rows=[...closestElement(selectedTds[0],"tr").parentElement.children].filter((child)=>child.nodeName==="TR");const firstRowCells=[...rows[0].children].filter((child)=>child.nodeName==="TD"||child.nodeName==="TH");const firstCellRowIndex=getRowIndex(selectedTds[0]);const firstCellColumnIndex=getColumnIndex(selectedTds[0]);const lastCellRowIndex=getRowIndex(selectedTds[selectedTds.length-1]);const lastCellColumnIndex=getColumnIndex(selectedTds[selectedTds.length-1]);const areFullColumnsSelected=firstCellRowIndex===0&&lastCellRowIndex===rows.length-1;const areFullRowsSelected=firstCellColumnIndex===0&&lastCellColumnIndex===firstRowCells.length-1;if(areFullColumnsSelected){for(let index=firstCellColumnIndex;index<=lastCellColumnIndex;index++){this.removeColumn(firstRowCells[index]);} 8651return;} 8652if(areFullRowsSelected){for(let index=firstCellRowIndex;index<=lastCellRowIndex;index++){this.removeRow(rows[index]);} 8653return;} 8654for(const td of selectedTds){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));td.replaceChildren(baseContainer);} 8655this.dependencies.selection.setCursorStart(selectedTds[0].firstChild);} 8656deleteRangeWithFullySelectedTables(range,fullySelectedTables){let{startContainer,startOffset,endContainer,endOffset}=range;const firstTable=fullySelectedTables[0];if(firstTable.contains(startContainer)){[startContainer,startOffset]=leftPos(firstTable);} 8657const lastTable=fullySelectedTables.at(-1);if(lastTable.contains(endContainer)){[endContainer,endOffset]=rightPos(lastTable);} 8658range={startContainer,startOffset,endContainer,endOffset};range=this.dependencies.delete.deleteRange(range);const[anchorNode,anchorOffset]=getDeepestPosition(range.startContainer,range.startOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset});} 8659handleDeleteRange(range){const fullySelectedTables=[...this.editable.querySelectorAll(".o_selected_table")].filter((table)=>[...table.querySelectorAll("td, th")].every((td)=>closestElement(td,"table")!==table||td.classList.contains("o_selected_td")));if(fullySelectedTables.length){this.deleteRangeWithFullySelectedTables(range,fullySelectedTables);return true;} 8660const selectedTds=this.editable.querySelectorAll(".o_selected_td");if(selectedTds.length){this.deleteTableCells(selectedTds);return true;} 8661return false;} 8662getTableSelectionRangeRect(){const selection=this.dependencies.selection.getEditableSelection();if(closestElement(selection.commonAncestorContainer,"table.o_selected_table")){let[startTd,endTd]=[closestElement(selection.anchorNode,isTableCell),closestElement(selection.focusNode,isTableCell),];if(selection.direction===DIRECTIONS.LEFT){[startTd,endTd]=[endTd,startTd];} 8663const startTdRect=startTd.getBoundingClientRect();const endTdRect=endTd.getBoundingClientRect();const{left,top}=startTdRect;const{bottom,right}=endTdRect;const rect=new DOMRect(left,top,right-left,bottom-top);return rect;}} 8664shiftCursorToTableCell(shiftIndex){const sel=this.dependencies.selection.getEditableSelection();const currentTd=closestElement(sel.anchorNode,isTableCell);const closestTable=closestElement(currentTd,"table");if(!currentTd||!closestTable){return false;} 8665const tds=[...closestTable.querySelectorAll("td, th")];const cursorDestination=tds[tds.findIndex((td)=>currentTd===td)+shiftIndex];if(!cursorDestination){return false;} 8666this.dependencies.selection.setCursorEnd(lastLeaf(cursorDestination));return true;} 8667hanldeFirefoxSelection(ev=null){const selection=this.document.getSelection();if(isBrowserFirefox()){if(!this.dependencies.selection.isSelectionInEditable(selection)){return false;} 8668if(selection.rangeCount>1||selection.anchorNode?.tagName==="TR"){let[anchorNode,anchorOffset]=getDeepestPosition(selection.getRangeAt(0).startContainer,selection.getRangeAt(0).startOffset);let[focusNode,focusOffset]=getDeepestPosition(selection.getRangeAt(selection.rangeCount-1).startContainer,selection.getRangeAt(selection.rangeCount-1).startOffset);if(this.selectionDirection==="backward"){[anchorNode,focusNode]=[focusNode,anchorNode];
8668[anchorOffset,focusOffset]=[focusOffset,anchorOffset];} 8669this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});return true;}else if(ev&&closestElement(ev.target,"table")===closestElement(selection.anchorNode,"table")&&closestElement(ev.target,isTableCell)!==closestElement(selection.focusNode,isTableCell)){this.dependencies.selection.setSelection({anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:ev.target,focusOffset:0,});this.selectionDirection=selection.direction;return true;}} 8670return false;} 8671updateTableKeyboardSelection(ev){const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;const startTable=closestElement(selection.anchorNode,"table");const endTable=closestElement(selection.focusNode,"table");if(!(startTable||endTable)){return;} 8672const[startTd,endTd]=[closestElement(selection.anchorNode,isTableCell),closestElement(selection.focusNode,isTableCell),];if(startTable!==endTable){if(endTable){const deselectingBackward=["ArrowLeft","ArrowUp"].includes(ev.key)&&selection.direction===DIRECTIONS.RIGHT;const deselectingForward=["ArrowRight","ArrowDown"].includes(ev.key)&&selection.direction===DIRECTIONS.LEFT;let targetNode;if(deselectingBackward){targetNode=endTable.previousElementSibling;}else if(deselectingForward){targetNode=endTable.nextElementSibling;} 8673if(targetNode){ev.preventDefault();this.dependencies.selection.setSelection({anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:targetNode,focusOffset:deselectingBackward?nodeSize(targetNode):0,});}} 8674return;} 8675if(startTd===endTd&&!startTd.classList.contains("o_selected_td")){const{focusNode}=selection;if(!(ev.ctrlKey&&["ArrowUp","ArrowDown"].includes(ev.key))&&(focusNode.nodeType===Node.TEXT_NODE||focusNode.matches("br, p, div.o-paragraph"))){const isAtTextBoundary=(key)=>{const actualSelection=this.document.getSelection();const preserveSelection=this.dependencies.selection.preserveSelection();actualSelection.modify("extend",["ArrowDown","ArrowRight"].includes(ev.key)?"forward":"backward",["ArrowUp","ArrowDown"].includes(key)?"line":"character");const reachedTd=closestElement(actualSelection.focusNode,"td");preserveSelection.restore();return startTd!==reachedTd;};if(isAtTextBoundary(ev.key)){ev.preventDefault();this.selectTableCells(this.dependencies.selection.getEditableSelection());}}else{ev.preventDefault();this.selectTableCells(this.dependencies.selection.getEditableSelection());this.dependencies.selection.setSelection(this.dependencies.selection.getEditableSelection());} 8676return;} 8677const endCellPosition={x:getRowIndex(endTd),y:getColumnIndex(endTd)};const tds=[...startTable.rows].map((row)=>[...row.cells]);let targetTd,targetNode;switch(ev.key){case"ArrowUp":{if(endCellPosition.x>0){targetTd=tds[endCellPosition.x-1][endCellPosition.y];}else{targetNode=previousLeaf(startTable,this.editable);} 8678break;} 8679case"ArrowDown":{if(endCellPosition.x<tds.length-1){targetTd=tds[endCellPosition.x+1][endCellPosition.y];}else{targetNode=nextLeaf(startTable,this.editable);} 8680break;} 8681case"ArrowRight":{if(endCellPosition.y<tds[0].length-1){targetTd=tds[endCellPosition.x][endCellPosition.y+1];} 8682break;} 8683case"ArrowLeft":{if(endCellPosition.y>0){targetTd=tds[endCellPosition.x][endCellPosition.y-1];} 8684break;}} 8685if(targetTd||targetNode){this.dependencies.selection.setSelection({anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:targetTd||targetNode,focusOffset:0,});} 8686ev.preventDefault();} 8687updateSelectionTable(selectionData){if(this.hanldeFirefoxSelection()||this._isFirefoxDoubleMousedown||this._isTripleClickInTable){delete this._isFirefoxDoubleMousedown;delete this._isTripleClickInTable;return;} 8688if(!selectionData.documentSelectionIsInEditable){this.deselectTable();return;} 8689const selection=selectionData.editableSelection;const startTd=closestElement(selection.startContainer,isTableCell);const endTd=closestElement(selection.endContainer,isTableCell);const selectSingleCell=startTd&&startTd===endTd&&startTd.classList.contains("o_selected_td")&&this.isShiftArrowKeyboardSelection;if(!(startTd&&startTd===endTd)||this._isKeyDown){delete this._isKeyDown;this.deselectTable();} 8690delete this.isShiftArrowKeyboardSelection;const startTable=ancestors(selection.startContainer,this.editable).filter((node)=>node.nodeName==="TABLE").pop();const endTable=ancestors(selection.endContainer,this.editable).filter((node)=>node.nodeName==="TABLE").pop();const targetedNodes=this.dependencies.selection.getTargetedNodes();if((startTd!==endTd||selectSingleCell)&&startTable===endTable){if(!isProtected(startTable)&&!isProtecting(startTable)){this.selectTableCells(selection);}}else if(!targetedNodes.every((node)=>closestElement(node.parentElement,"table"))){const startEdgeSelectionTable=closestElement(selection.startContainer,"table");const endEdgeSelectionTable=closestElement(selection.endContainer,"table");const startsInTable=!!startEdgeSelectionTable;const edgeSelectionTable=startEdgeSelectionTable||endEdgeSelectionTable;const edgeSelectionTableTds=edgeSelectionTable&&getTableCells(edgeSelectionTable);const targetedTds=new Set(targetedNodes.map((node)=>closestElement(node,isTableCell)));const isTableFullySelected=edgeSelectionTableTds?.every((td)=>targetedTds.has(td));if(edgeSelectionTable&&!isTableFullySelected){const targetTd=edgeSelectionTableTds[startsInTable?0:edgeSelectionTableTds.length-1];const targetOffset=startsInTable?0:nodeSize(targetTd);if(selection.direction===DIRECTIONS.RIGHT){this.dependencies.selection.setSelection({anchorNode:startsInTable?targetTd:selection.anchorNode,anchorOffset:startsInTable?targetOffset:selection.anchorOffset,focu
8690sNode:startsInTable?selection.focusNode:targetTd,focusOffset:startsInTable?selection.focusOffset:targetOffset,});}else{this.dependencies.selection.setSelection({anchorNode:startsInTable?selection.anchorNode:targetTd,anchorOffset:startsInTable?selection.anchorOffset:targetOffset,focusNode:startsInTable?targetTd:selection.focusNode,focusOffset:startsInTable?targetOffset:selection.focusOffset,});}} 8691const targetedTables=new Set(targetedNodes.map((node)=>closestElement(node,"table")).filter((node)=>node&&!isProtected(node)&&!isProtecting(node)));for(const table of targetedTables){if(!ancestors(table,this.editable).some((node)=>targetedTables.has(node))){table.classList.toggle("o_selected_table",true);for(const td of getTableCells(table)){td.classList.toggle("o_selected_td",true);this.dispatchTo("deselect_custom_selected_nodes_handlers",td);}}}}} 8692onMousedown(ev){this._currentMouseState=ev.type;this._lastMousedownPosition=[ev.x,ev.y];const isPointerInsideCell=this.isPointerInsideCell(ev);const td=closestElement(ev.target,isTableCell);if(isPointerInsideCell){if(!isProtected(td)&&!isProtecting(td)&&((isEmptyBlock(td)&&ev.detail===2)||ev.detail===3)){this.hanldeFirefoxSelection();this.selectTableCells(this.dependencies.selection.getEditableSelection());if(isBrowserFirefox()){this._isFirefoxDoubleMousedown=true;} 8693if(ev.detail===2){this.dependencies.selection.setSelection(this.dependencies.selection.getEditableSelection());} 8694if(ev.detail===3){this._isTripleClickInTable=true;}}else{this.editable.addEventListener("mousemove",this.onMousemove);const currentSelection=this.dependencies.selection.getEditableSelection();if(closestElement(ev.target,"td.o_selected_td")){this.dependencies.selection.setCursorStart(currentSelection.anchorNode);} 8695this.deselectTable();}}} 8696onMouseup(ev){delete this._mouseMovePositionWhenAllContentsSelected;this._currentMouseState=ev.type;this.editable.removeEventListener("mousemove",this.onMousemove);} 8697isPointerInsideCell(ev){const td=closestElement(ev.target,isTableCell);if(td){const targetRect=td.getBoundingClientRect();if(ev.clientX>targetRect.x+BORDER_SENSITIVITY&&ev.clientX<targetRect.x+td.clientWidth-BORDER_SENSITIVITY&&ev.clientY>targetRect.y+BORDER_SENSITIVITY&&ev.clientY<targetRect.y+td.clientHeight-BORDER_SENSITIVITY){return true;}} 8698return false;} 8699onMousemove(ev){if(this._currentMouseState!=="mousedown"){return;} 8700if(this.hanldeFirefoxSelection(ev)){return;} 8701const selection=this.dependencies.selection.getEditableSelection();const startTd=closestElement(selection.startContainer,isTableCell);const endTd=closestElement(selection.endContainer,isTableCell);if(startTd&&startTd===endTd&&!isProtected(startTd)&&!isProtecting(startTd)){const cellContents=descendants(startTd);const areCellContentsFullySelected=this.dependencies.selection.areNodeContentsFullySelected(startTd);if(areCellContentsFullySelected){const SENSITIVITY=5;if(!this._mouseMovePositionWhenAllContentsSelected){this._mouseMovePositionWhenAllContentsSelected=[ev.clientX,ev.clientY];} 8702const isMovingAwayFromSelection=Math.abs(ev.clientX-this._mouseMovePositionWhenAllContentsSelected[0])>=SENSITIVITY;if(isMovingAwayFromSelection){this.selectTableCells(selection);}}else if(cellContents.filter(isBlock).every(isEmptyBlock)&&Math.abs(ev.clientX- 8703(this._lastMousedownPosition?this._lastMousedownPosition[0]:ev.clientX))>=20){this.selectTableCells(selection);}}} 8704navigateCell(ev){const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;const focusNode=selection.focusNode;const currentCell=closestElement(focusNode,isTableCell);if(!currentCell){return;} 8705const currentTable=closestElement(currentCell,"table");const areCellsSelected=currentCell.classList.contains("o_selected_td");const isArrowUp=ev.key==="ArrowUp";if(!areCellsSelected){if(ev.ctrlKey){ev.preventDefault();this.dependencies.selection.setSelection({anchorNode:currentCell,anchorOffset:isArrowUp?0:currentCell.childNodes.length,});return;} 8706const actualSelection=this.document.getSelection();actualSelection.modify("move",isArrowUp?"backward":"forward","line");const reachedCell=closestElement(actualSelection.focusNode,"td");ev.preventDefault();if(currentCell===reachedCell){return;}}
8707const cellPosition={row:getRowIndex(currentCell),col:getColumnIndex(currentCell),};const tableRows=[...currentTable.rows].map((row)=>[...row.cells]);const shouldNavigateCell=(currentNode)=>{const siblingDirection=isArrowUp?"previousElementSibling":"nextElementSibling";const direction=isArrowUp?DIRECTIONS.LEFT:DIRECTIONS.RIGHT;const domPath=createDOMPathGenerator(direction,{stopTraverseFunction:(node)=>node===currentCell,stopFunction:(node)=>node===currentCell,});const domPathNode=domPath(currentNode);let node=domPathNode.next().value;while(node){if((isBlock(node)&&node[siblingDirection])||node.nodeName==="BR"){return false;} 8708node=domPathNode.next().value;} 8709return true;};const rowOffset=isArrowUp?-1:1;let targetNode=tableRows[cellPosition.row+rowOffset]?.[cellPosition.col];const siblingElement=isArrowUp?currentTable.previousElementSibling:currentTable.nextElementSibling;if(!targetNode&&siblingElement){targetNode=siblingElement;} 8710if(shouldNavigateCell(focusNode)){ev.preventDefault();if(targetNode){targetNode=isArrowUp?lastLeaf(targetNode):firstLeaf(targetNode);const targetOffset=isArrowUp?nodeSize(targetNode):0;this.dependencies.selection.setSelection({anchorNode:targetNode,anchorOffset:targetOffset,});}}} 8711selectTableCells(selection){const table=closestElement(selection.commonAncestorContainer,"table");if(!table){return;} 8712table.classList.toggle("o_selected_table",true);const columns=getTableCells(table);const startCol=[selection.startContainer,...ancestors(selection.startContainer,this.editable)].find((node)=>isTableCell(node)&&closestElement(node,"table")===table)||columns[0];const endCol=[selection.endContainer,...ancestors(selection.endContainer,this.editable)].find((node)=>isTableCell(node)&&closestElement(node,"table")===table)||columns[columns.length-1];const[startRow,endRow]=[closestElement(startCol,"tr"),closestElement(endCol,"tr")];const[startColIndex,endColIndex]=[getColumnIndex(startCol),getColumnIndex(endCol)];const[startRowIndex,endRowIndex]=[getRowIndex(startRow),getRowIndex(endRow)];const[minRowIndex,maxRowIndex]=[Math.min(startRowIndex,endRowIndex),Math.max(startRowIndex,endRowIndex),];const[minColIndex,maxColIndex]=[Math.min(startColIndex,endColIndex),Math.max(startColIndex,endColIndex),];const grid=[...table.querySelectorAll("tr")].filter((tr)=>closestElement(tr,"table")===table).map((tr)=>[...tr.children].filter(isTableCell));for(const tds of grid.filter((_,index)=>index>=minRowIndex&&index<=maxRowIndex)){for(const td of tds.filter((_,index)=>index>=minColIndex&&index<=maxColIndex)){td.classList.toggle("o_selected_td",true);this.dispatchTo("deselect_custom_selected_nodes_handlers",td);}}} 8713deselectTable(root=this.editable){let didDeselectTable=false;for(const table of root.querySelectorAll(".o_selected_table")){removeClass(table,"o_selected_table");for(const td of table.querySelectorAll(".o_selected_td")){removeClass(td,"o_selected_td");} 8714didDeselectTable=true;} 8715return didDeselectTable;} 8716applyTableColor(color,mode,previewMode){const selectedTds=[...this.editable.querySelectorAll(".o_selected_td")].filter((node)=>node.isContentEditable);if(selectedTds.length&&(mode==="backgroundColor"||(mode==="color"&&!color))){selectedTds.forEach((td)=>td.classList.toggle("o_selected_td_bg_color_preview",previewMode));for(const td of selectedTds){this.dependencies.color.colorElement(td,color,mode);if(color){td.style["color"]=getComputedStyle(td).color;}else{td.style["color"]="";}}}} 8717computeBackgroundColorForTable(){const selectedTds=Array.from(this.editable.querySelectorAll(".o_selected_td"));if(selectedTds.length===0){return null;} 8718const firstStyle=getComputedStyle(selectedTds[0]);const backgroundColor=firstStyle.backgroundColor;const backgroundImage=firstStyle.backgroundImage;if(backgroundImage==="none"&&backgroundColor==="rgba(0, 0, 0, 0)"){return null;} 8719const allSameStyle=selectedTds.slice(1).every((td)=>{const s=getComputedStyle(td);return s.backgroundColor===backgroundColor&&s.backgroundImage===backgroundImage;});if(!allSameStyle){return"#00000000";} 8720return backgroundImage!=="none"?backgroundImage:rgbaToHex(backgroundColor);}
8721adjustTargetedNodes(targetedNodes){const modifiedTargetedNodes=[];const visitedTables=new Set();for(const node of targetedNodes){const selectedTable=closestElement(node,".o_selected_table");if(selectedTable){if(visitedTables.has(selectedTable)){continue;} 8722visitedTables.add(selectedTable);for(const selectedTd of selectedTable.querySelectorAll(".o_selected_td")){modifiedTargetedNodes.push(selectedTd,...descendants(selectedTd));}}else{modifiedTargetedNodes.push(node);}} 8723return modifiedTargetedNodes;} 8724resetTableSelection(){const selection=this.dependencies.selection.getEditableSelection({deep:true});const anchorTD=closestElement(selection.anchorNode,".o_selected_td");if(!anchorTD){return;} 8725this.deselectTable();this.dependencies.selection.setSelection({anchorNode:anchorTD.firstChild,anchorOffset:0,focusNode:anchorTD.lastChild,focusOffset:nodeSize(anchorTD.lastChild),});} 8726normalizeTableStructure(container){container.querySelectorAll("table").forEach((table)=>{let tbody=table.tBodies[0];const thead=table.tHead;if(thead){const thChildren=thead.querySelectorAll("th");thChildren.forEach((th)=>th.classList.add("o_table_header"));if(tbody){tbody.prepend(...thead.rows);thead.remove();}else{tbody=this.dependencies.dom.setTagName(thead,"TBODY");}} 8727if(!tbody){tbody=table.ownerDocument.createElement("tbody");tbody.innerHTML=`<tr><td><div class="o-paragraph"><br></div></td></tr>`;table.append(tbody);}});return container;} 8728processContentForClipboard(clonedContents,selection){if(clonedContents.firstChild.nodeName==="TR"||isTableCell(clonedContents.firstChild)){const table=closestElement(selection.commonAncestorContainer,"table");const tableClone=table.cloneNode(true);const isTableFullySelected=(table.parentElement&&!!closestElement(table.parentElement,".o_selected_td"))||getTableCells(table).every((td)=>td.classList.contains("o_selected_td"));if(!isTableFullySelected){for(const td of tableClone.querySelectorAll(":is(td, th):not(.o_selected_td)")){if(closestElement(td,"table")===tableClone){td.remove();}} 8729const trsWithoutTd=Array.from(tableClone.querySelectorAll("tr")).filter((row)=>!row.querySelector("td, th"));for(const tr of trsWithoutTd){if(closestElement(tr,"table")===tableClone){tr.remove();}}} 8730clonedContents=tableClone;} 8731const startTable=closestElement(selection.startContainer,"table");if(clonedContents.firstChild.nodeName==="TABLE"&&startTable){clonedContents.firstChild.after(startTable.cloneNode(true));clonedContents.firstChild.remove();} 8732const endTable=closestElement(selection.endContainer,"table");if(clonedContents.lastChild.nodeName==="TABLE"&&endTable){clonedContents.lastChild.before(endTable.cloneNode(true));clonedContents.lastChild.remove();} 8733this.deselectTable(clonedContents);return clonedContents;} 8734populateTableSpans(root){for(const table of selectElements(root,"table")){const matrix=[];let width=0;for(let r=0;r<table.rows.length;r++){const row=table.rows[r];matrix[r]||=[];let c=0;for(const cell of row.cells){while(matrix[r][c]!==undefined){c++;} 8735const rowspan=cell.rowSpan;const colspan=cell.colSpan;for(let dr=0;dr<rowspan;dr++){matrix[r+dr]||=[];for(let dc=0;dc<colspan;dc++){matrix[r+dr][c+dc]=dr===0&&dc===0?cell:null;}} 8736cell.removeAttribute("rowspan");cell.removeAttribute("colspan");c+=colspan;width=Math.max(width,c);}} 8737for(let r=0;r<table.rows.length;r++){const row=table.rows[r];matrix[r]||=[];let domIndex=0;for(let c=0;c<width;c++){const entry=matrix[r][c];if(!entry){const cell=this.document.createElement("td");const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(this.document.createElement("br"));cell.append(baseContainer);row.insertBefore(cell,row.children[domIndex]??null);} 8738domIndex++;}}} 8739return root;}} 8740return __exports;});; 8741 8742/* /html_editor/static/src/main/table/table_resize_plugin.js */ 8743odoo.define('@html_editor/main/table/table_resize_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/utils/table','@html_editor/main/table/table_plugin','@html_editor/utils/dom_info'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement,getAdjacentNextSiblings,getAdjacentPreviousSiblings,}=require("@html_editor/utils/dom_traversal");const{getColumnIndex}=require("@html_editor/utils/table");const{BORDER_SENSITIVITY}=require("@html_editor/main/table/table_plugin");const{isTableCell}=require("@html_editor/utils/dom_info");const TableResizePlugin=__exports.TableResizePlugin=class TableResizePlugin extends Plugin{static id="tableResize";static dependencies=["table","history"];setup(){this.addDomListener(this.editable,"dblclick",this.fitToContent);this.addDomListener(this.editable,"mousedown",this.onMousedown);this.addDomListener(this.editable,"mousemove",this.onMousemove);} 8744isHoveringTdBorder(ev){const target=(ev.target);if(ev.target&&isTableCell(target)&&target.isContentEditable){const targetRect=target.getBoundingClientRect();if(ev.clientX<=targetRect.x+BORDER_SENSITIVITY){return"left";}
8744else if(ev.clientY<=targetRect.y+BORDER_SENSITIVITY){return"top";}else if(ev.clientX>=targetRect.x+target.clientWidth-BORDER_SENSITIVITY){return"right";}else if(ev.clientY>=targetRect.y+target.clientHeight-BORDER_SENSITIVITY){return"bottom";}} 8745return false;} 8746setTableResizeCursor(direction){const classList=this.editable.classList;if(classList.contains("o_col_resize")){classList.remove("o_col_resize");} 8747if(classList.contains("o_row_resize")){classList.remove("o_row_resize");} 8748if(direction==="col"){this.editable.classList.add("o_col_resize");}else if(direction==="row"){this.editable.classList.add("o_row_resize");}} 8749resizeTable(ev,direction,target1,target2){ev.preventDefault();const position=target1?(target2?"middle":"last"):"first";let[item,neighbor]=[target1||target2,target2];const tBody=closestElement(item,"tbody");const[sizeProp,positionProp,clientPositionProp]=direction==="col"?["width","x","clientX"]:["height","y","clientY"];const isRTL=this.config.direction==="rtl";if(sizeProp==="width"){const tBodyRect=tBody.getBoundingClientRect();tBody.style[sizeProp]=tBodyRect[sizeProp]+"px";} 8750const unsizedItemsSelector=`${ 8751 direction === "col" ? "td" : "tr" 8752 }:not([style*=${sizeProp}])`;for(const unsizedItem of tBody.querySelectorAll(unsizedItemsSelector)){unsizedItem.style[sizeProp]=unsizedItem.getBoundingClientRect()[sizeProp]+"px";} 8753if(direction==="col"){let hostCell=closestElement(tBody,isTableCell);const hostCells=[];while(hostCell){hostCells.push(hostCell);hostCell=closestElement(hostCell.parentElement,isTableCell);} 8754const nthColumn=getColumnIndex(item);const firstRow=[...tBody.querySelector("tr").children];[item,neighbor]=[firstRow[nthColumn],firstRow[nthColumn+1]];for(const td of hostCells){if(td!==item&&td!==neighbor&&closestElement(td,"tbody")===tBody&&getColumnIndex(td)!==0){td.style.removeProperty(sizeProp);}} 8755if(isRTL&&position=="middle"){[item,neighbor]=[neighbor,item];}} 8756const MIN_SIZE=33;switch(position){case"first":{const marginProp=direction==="col"?(isRTL?"marginRight":"marginLeft"):"marginTop";const itemRect=item.getBoundingClientRect();const tBodyStyle=getComputedStyle(tBody);const currentMargin=parseFloat(tBodyStyle[marginProp]);let sizeDelta=itemRect[positionProp]-ev[clientPositionProp];if(direction==="col"&&isRTL){sizeDelta=ev[clientPositionProp]-itemRect[positionProp]-itemRect[sizeProp];} 8757const newMargin=currentMargin-sizeDelta;const currentSize=itemRect[sizeProp];const newSize=currentSize+sizeDelta;if(newMargin>=0&&newSize>MIN_SIZE){const tBodyRect=tBody.getBoundingClientRect();const hostCell=closestElement(tBody,isTableCell);const childTable=item.querySelector("table");const endProp=isRTL?"left":"right";if(direction==="col"&&((hostCell&&tBodyRect[endProp]+sizeDelta>hostCell.getBoundingClientRect()[endProp]-5)||(childTable&&childTable.getBoundingClientRect()[endProp]>itemRect[endProp]+sizeDelta-5))){break;} 8758tBody.style[marginProp]=newMargin+"px";item.style[sizeProp]=newSize+"px";if(sizeProp==="width"){tBody.style[sizeProp]=tBodyRect[sizeProp]+sizeDelta+"px";}} 8759break;} 8760case"middle":{const[itemRect,neighborRect]=[item.getBoundingClientRect(),neighbor.getBoundingClientRect(),];const[currentSize,newSize]=[itemRect[sizeProp],ev[clientPositionProp]-itemRect[positionProp],];const editableStyle=getComputedStyle(this.editable);const sizeDelta=newSize-currentSize;const currentNeighborSize=neighborRect[sizeProp];const newNeighborSize=currentNeighborSize-sizeDelta;const enclosingCell=closestElement(tBody.parentElement,"td, th");const containerWidth=enclosingCell?.getBoundingClientRect().width||this.editable.clientWidth;const maxWidth=containerWidth- 8761parseFloat(editableStyle.paddingLeft)- 8762parseFloat(editableStyle.paddingRight);const tBodyRect=tBody.getBoundingClientRect();if(newSize>MIN_SIZE&&(direction==="row"||newNeighborSize>MIN_SIZE||tBodyRect[sizeProp]+sizeDelta<maxWidth)){const childTable=item.querySelector("table");if(direction==="col"&&childTable&&childTable.getBoundingClientRect().right>itemRect.right+sizeDelta-5){break;} 8763item.style[sizeProp]=newSize+"px";if(direction==="col"){neighbor.style[sizeProp]=(newNeighborSize>MIN_SIZE?newNeighborSize:currentNeighborSize)+"px";}else if(sizeProp==="width"){tBody.style[sizeProp]=tBodyRect[sizeProp]+sizeDelta+"px";}} 8764break;} 8765case"last":{const itemRect=item.getBoundingClientRect();let sizeDelta=ev[clientPositionProp]-(itemRect[positionProp]+itemRect[sizeProp]);if(direction==="col"&&isRTL){sizeDelta=itemRect[positionProp]-ev[clientPositionProp];} 8766const currentSize=itemRect[sizeProp];const newSize=currentSize+sizeDelta;if((newSize>=0||direction==="row")&&newSize>MIN_SIZE){const tBodyRect=tBody.getBoundingClientRect();const hostCell=closestElement(tBody.parentElement,isTableCell);const childTable=item.querySelector("table");const endProp=isRTL?"left":"right";if(direction==="col"&&((hostCell&&tBodyRect[endProp]+sizeDelta>hostCell.getBoundingClientRect()[endProp]-5)||(childTable&&childTable.getBoundingClientRect()[endProp]>itemRect[endProp]+sizeDelta-5))){break;} 8767if(sizeProp==="width"){tBody.style[sizeProp]=tBodyRect[sizeProp]+sizeDelta+"px";} 8768item.style[sizeProp]=newSize+"px";} 8769break;}}} 8770fitToContent(ev){const isHoveringTdBorder=this.isHoveringTdBorder(ev);if(!isHoveringTdBorder){return;} 8771const cell=ev.target;if(["left","right"].includes(isHoveringTdBorder)){const tBody=closestElement(cell,"tbody");const currentColumnIndex=getColumnIndex(cell);const currentColumnCells=tBody.querySelectorAll(`tr :is(td, th):nth-of-type(${currentColumnIndex + 1})`);this.dependencies.table.resetColumnWidth(currentColumnCells[0]);const isLeftSideClick=isHoveringTdBorder==="left";if((isLeftSideClick&¤tColumnIndex>0)||(!isLeftSideClick&¤tColumnIndex<tBody.rows[0].cells.length-1)){const siblingColumnIndex=isLeftSideClick?currentColumnIndex-1:currentColumnIndex+1;const siblingColumnCells=tBody.querySelectorAll(`tr :is(td, th):nth-of-type(${siblingColumnIndex + 1})`);this.dependencies.table.resetColumnWidth(siblingColumnCells[0]);}}else if(["top","bottom"].includes(isHoveringTdBorder)){const currentRow=cell.parentElement;this.dependencies.table.resetRowHeight(currentRow);const siblingRow=isHoveringTdBorder==="top"?currentRow.previousElementSibling:currentRow.nextElementSibling;if(siblingRow){this.dependencies.table.resetRowHeight(siblingRow);}}} 8772onMousedown(ev){if(ev.button!==0){return;} 8773const isHoveringTdBorder=this.isHoveringTdBorder(ev);const isRTL=this.config.direction==="rtl";if(isHoveringTdBorder){ev.preventDefault();const direction={top:"row",right:"col",bottom:"row",left:"col"}[isHoveringTdBorder]||false;let target1,target2;const column=closestElement(ev.target,"tr");if(isHoveringTdBorder==="top"&&column){target1=getAdjacentPreviousSiblings(column).find((node)=>node.nodeName==="TR");target2=closestElement(ev.target,"tr");}else if(isHoveringTdBorder==="right"){if(isRTL){target1=getAdjacentPreviousSiblings(ev.target).find(isTableCell);target2=ev.target;}else{target1=ev.target;target2=getAdjacentNextSiblings(ev.target).find(isTableCell);}}else if(isHoveringTdBorder==="bottom"&&column){target1=closestElement(ev.target,"tr");target2=getAdjacentNextSiblings(column).find((node)=>node.nodeName==="TR");}else if(isHoveringTdBorder==="left"){if(isRTL){target1=ev.target;target2=getAdjacentNextSiblings(ev.target).find(isTableCell);}else{target1=getAdjacentPreviousSiblings(ev.target).find(isTableCell);target2=ev.target;}} 8774this.isResizingTable=true;this.setTableResizeCursor(direction);const resizeTable=(ev)=>{if((target1&&!target1.isConnected)||(target2&&!target2.isConnected)){return stopResizing(ev);} 8775this.resizeTable(ev,direction,target1,target2);};const stopResizing=(ev)=>{ev.preventDefault();this.isResizingTable=false;this.setTableResizeCursor(false);this.dependencies.history.addStep();this.document.removeEventListener("mousemove",resizeTable);this.document.removeEventListener("mouseup",stopResizing);this.document.removeEventListener("mouseleave",stopResizing);};this.document.addEventListener("mousemove",resizeTable);this.document.addEventListener("mouseup",stopResizing);this.document.addEventListener("mouseleave",stopResizing);}} 8776onMousemove(ev){const direction={top:"row",right:"col",bottom:"row",left:"col"}[this.isHoveringTdBorder(ev)]||false;
8776if(direction||!this.isResizingTable){this.setTableResizeCursor(direction);}}} 8777return __exports;});; 8778 8779/* /html_editor/static/src/main/table/table_ui_plugin.js */ 8780odoo.define('@html_editor/main/table/table_ui_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@odoo/owl','@web/core/l10n/translation','@html_editor/main/table/table_menu','@html_editor/main/table/table_picker','@html_editor/core/selection_plugin','@web/core/registry'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const{reactive}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{TableMenu}=require("@html_editor/main/table/table_menu");const{TablePicker}=require("@html_editor/main/table/table_picker");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{registry}=require("@web/core/registry");const TableUIPlugin=__exports.TableUIPlugin=class TableUIPlugin extends Plugin{static id="tableUi";static dependencies=["history","overlay","table"];resources={user_commands:[{id:"openTablePicker",title:_t("Table"),description:_t("Insert a table"),icon:"fa-table",run:this.openPickerOrInsertTable.bind(this),isAvailable:isHtmlContentSupported,},],powerbox_items:[{categoryId:"structure",commandId:"openTablePicker",},],};setup(){this.picker=this.dependencies.overlay.createOverlay(TablePicker,{positionOptions:{updatePositionOnResize:false,onPositioned:(picker,position)=>{const popperRect=picker.getBoundingClientRect();const{left}=position;if(this.config.direction==="rtl"){picker.style.right=`${window.innerWidth - left - popperRect.width}px`;picker.style.removeProperty("left");}},},});this.columnMenuOverlayKey="table-column-menu";this.rowMenuOverlayKey="table-row-menu";this.activeTd=null;this.addDomListener(this.document,"pointermove",this.onMouseMove);const closeMenus=()=>{if(this.isMenuOpened){this.isMenuOpened=false;this.closeColumnMenu();this.closeRowMenu();}};this.addDomListener(this.document,"scroll",closeMenus,true);} 8781openPicker(){this.picker.open({props:{editable:this.editable,overlay:this.picker,direction:this.config.direction||"ltr",insertTable:(params)=>this.dependencies.table.insertTable(params),},});} 8782openPickerOrInsertTable(){if(this.services.ui.isSmall){this.dependencies.table.insertTable({cols:3,rows:3});}else{this.openPicker();}} 8783onMouseMove(ev){const target=ev.target;if(this.isMenuOpened){return;} 8784const targetCell=closestElement(target,"td, th");if(targetCell&&targetCell!==this.activeTd&&this.editable.contains(targetCell)){if(ev.target.isContentEditable&&closestElement(target,"table").isContentEditable){this.setActiveTd(targetCell);}}else if(this.activeTd){const isOverlay=target.closest(".o-we-table-menu");if(isOverlay){return;} 8785if(!targetCell){this.setActiveTd(null);}}} 8786createDropdownState(closeMenu){const dropdownState=reactive({isOpen:false,open:()=>{dropdownState.isOpen=true;closeMenu();this.isMenuOpened=true;},close:()=>{dropdownState.isOpen=false;this.isMenuOpened=false;},});return dropdownState;} 8787closeColumnMenu(){registry.category(this.config.localOverlayContainers.key).remove(this.columnMenuOverlayKey);} 8788closeRowMenu(){registry.category(this.config.localOverlayContainers.key).remove(this.rowMenuOverlayKey);} 8789setActiveTd(td){this.activeTd=td;this.closeColumnMenu();this.closeRowMenu();if(!td){return;} 8790const withAddStep=(fn)=>(...args)=>{fn(...args);this.dependencies.history.addStep();};const tableMethods={moveColumn:withAddStep(this.dependencies.table.moveColumn),addColumn:withAddStep(this.dependencies.table.addColumn),removeColumn:withAddStep(this.dependencies.table.removeColumn),moveRow:withAddStep(this.dependencies.table.moveRow),addRow:withAddStep(this.dependencies.table.addRow),removeRow:withAddStep(this.dependencies.table.removeRow),turnIntoHeader:withAddStep(this.dependencies.table.turnIntoHeader),turnIntoRow:withAddStep(this.dependencies.table.turnIntoRow),resetRowHeight:withAddStep(this.dependencies.table.resetRowHeight),resetColumnWidth:withAddStep(this.dependencies.table.resetColumnWidth),resetTableSize:withAddStep(this.dependencies.table.resetTableSize),clearColumnContent:withAddStep(this.dependencies.table.clearColumnContent),clearRowContent:withAddStep(this.dependencies.table.clearRowContent),};if(td.cellIndex===0){registry.category(this.config.localOverlayContainers.key).add(this.rowMenuOverlayKey,{Component:TableMenu,props:{document:this.document,type:"row",target:td,dropdownState:this.createDropdownState(this.closeColumnMenu.bind(this)),direction:this.config.direction||"ltr",close:()=>this.closeRowMenu(),...tableMethods,},});} 8791if(td.parentElement.rowIndex===0){registry.category(this.config.localOverlayContainers.key).add(this.columnMenuOverlayKey,{Component:TableMenu,props:{document:this.document,type:"column",target:td,dropdownState:this.createDropdownState(this.closeRowMenu.bind(this)),direction:this.config.direction||"ltr",close:()=>this.closeColumnMenu(),...tableMethods,},});}}} 8792return __exports;});; 8793 8794/* /html_editor/static/src/main/tabulation_plugin.js */ 8795odoo.define('@html_editor/main/tabulation_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/html','@html_editor/utils/position','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{splitTextNode}=require("@html_editor/utils/dom");const{isEditorTab,isParagraphRelatedElement,isTextNode,isZWS,}=require("@html_editor/utils/dom_info");const{descendants,getAdjacentPreviousSiblings,closestElement,firstLeaf,selectElements,}=require("@html_editor/utils/dom_traversal");const{parseHTML}=require("@html_editor/utils/html");const{DIRECTIONS,childNodeIndex}=require("@html_editor/utils/position");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const tabHtml='<span class="oe-tabs" contenteditable="false">\u0009</span>\u200B';const GRID_COLUMN_WIDTH=40;function isIndentationTab(tab){return!getAdjacentPreviousSiblings(tab).some((sibling)=>isTextNode(sibling)&&!/^[\u200B\s]*$/.test(sibling.textContent));} 8796const TabulationPlugin=__exports.TabulationPlugin=class TabulationPlugin extends Plugin{static id="tabulation";static dependencies=["dom","selection","history","delete"];static shared=["indentBlocks","outdentBlocks"];resources={user_commands:[{id:"tab",run:this.handleTab.bind(this),isAvailable:isHtmlContentSupported,},{id:"shiftTab",run:this.handleShiftTab.bind(this),isAvailable:isHtmlContentSupported,},],shortcuts:[{hotkey:"tab",commandId:"tab"},{hotkey:"shift+tab",commandId:"shiftTab"},],content_not_editable_providers:(rootEl)=>[...selectElements(rootEl,".oe-tabs")],contenteditable_to_remove_selector:"span.oe-tabs",normalize_handlers:this.normalize.bind(this),delete_forward_overrides:this.handleDeleteForward.bind(this),unsplittable_node_predicates:isEditorTab,};handleTab(){if(this.delegateTo("tab_overrides")){return;} 8797const selection=this.dependencies.selection.getEditableSelection();if(selection.isCollapsed){this.insertTab();}else{const targetedBlocks=this.dependencies.selection.getTargetedBlocks();this.indentBlocks(targetedBlocks);} 8798this.dependencies.history.addStep();} 8799handleShiftTab(){if(this.delegateTo("shift_tab_overrides")){return;} 8800const targetedBlocks=this.dependencies.selection.getTargetedBlocks();this.outdentBlocks(targetedBlocks);this.dependencies.history.addStep();} 8801insertTab(){const selection=this.dependencies.selection.getEditableSelection();const element=closestElement(selection.anchorNode);const isSelectionAtStart=firstLeaf(element)===selection.anchorNode&&(selection.anchorOffset===0||element.textContent==="\u200B");const tab=parseHTML(this.document,tabHtml);if(isSelectionAtStart&&!isBlock(element)){element.before(tab);}else{this.dependencies.dom.insert(tab);}} 8802indentBlocks(blocks){const selectionToRestore=this.dependencies.selection.getEditableSelection();const tab=parseHTML(this.document,tabHtml);const indentableBlocks=[...blocks].filter((block)=>block.isContentEditable&&(isParagraphRelatedElement(block)||block.tagName==="BLOCKQUOTE"));for(const block of indentableBlocks){block.prepend(tab.cloneNode(true));} 8803this.dependencies.selection.setSelection(selectionToRestore,{normalize:false});} 8804outdentBlocks(blocks){for(const block of blocks){const firstTab=descendants(block).find(isEditorTab);if(firstTab&&isIndentationTab(firstTab)){this.removeTrailingZWS(firstTab);firstTab.remove();}}} 8805removeTrailingZWS(tab){const selection=this.dependencies.selection.getEditableSelection();
8805const{anchorNode,anchorOffset,focusNode,focusOffset}=selection;const updateAnchor=anchorNode===tab.nextSibling;const updateFocus=focusNode===tab.nextSibling;let zwsRemoved=0;while(tab.nextSibling&&tab.nextSibling.nodeType===Node.TEXT_NODE&&tab.nextSibling.textContent.startsWith("\u200B")){splitTextNode(tab.nextSibling,1,DIRECTIONS.LEFT);tab.nextSibling.remove();zwsRemoved++;} 8806if(updateAnchor||updateFocus){this.dependencies.selection.setSelection({anchorNode:updateAnchor?tab.nextSibling:anchorNode,anchorOffset:updateAnchor?Math.max(0,anchorOffset-zwsRemoved):anchorOffset,focusNode:updateFocus?tab.nextSibling:focusNode,focusOffset:updateFocus?Math.max(0,focusOffset-zwsRemoved):focusOffset,});}} 8807adjustTabWidth(tabSpan){let tabPreviousSibling=tabSpan.previousSibling;while(isZWS(tabPreviousSibling)){tabPreviousSibling=tabPreviousSibling.previousSibling;} 8808if(isEditorTab(tabPreviousSibling)){tabSpan.style.width=`${GRID_COLUMN_WIDTH}px`;return;} 8809const spanRect=tabSpan.getBoundingClientRect();const referenceRect=this.editable.firstElementChild?.getBoundingClientRect();if(!referenceRect?.width||!spanRect.width){return;} 8810const relativePosition=spanRect.left-referenceRect.left;const distToNextGridLine=GRID_COLUMN_WIDTH-(relativePosition%GRID_COLUMN_WIDTH);const width=distToNextGridLine.toFixed(1);tabSpan.style.width=`${width}px`;} 8811alignTabs(root=this.editable){const block=closestBlock(root);if(!block){return;} 8812for(const tab of block.querySelectorAll("span.oe-tabs")){this.adjustTabWidth(tab);}} 8813expandRangeToIncludeZWS(tabElement){let previous=tabElement;let node=tabElement.nextSibling;while(node?.nodeType===Node.TEXT_NODE){for(let i=0;i<node.textContent.length;i++){if(node.textContent[i]!=="\u200B"){return[node,i];}} 8814previous=node;node=node.nextSibling;} 8815return[previous.parentElement,childNodeIndex(previous)+1];} 8816handleDeleteForward(range){let{endContainer,endOffset}=range;if(!(endContainer?.nodeType===Node.ELEMENT_NODE)||!endOffset){return;} 8817const nodeToDelete=endContainer.childNodes[endOffset-1];if(isEditorTab(nodeToDelete)){[endContainer,endOffset]=this.expandRangeToIncludeZWS(nodeToDelete);range=this.dependencies.delete.deleteRange({...range,endContainer,endOffset});this.dependencies.selection.setSelection({anchorNode:range.startContainer,anchorOffset:range.startOffset,});return true;}} 8818normalize(el){this.alignTabs(el);}} 8819return __exports;});; 8820 8821/* /html_editor/static/src/main/text_direction_plugin.js */ 8822odoo.define('@html_editor/main/text_direction_plugin',['@web/core/l10n/translation','@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_traversal','@html_editor/utils/dom_info','@html_editor/core/selection_plugin'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{Plugin}=require("@html_editor/plugin");const{closestBlock}=require("@html_editor/utils/blocks");const{closestElement}=require("@html_editor/utils/dom_traversal");const{isContentEditable,isDirectionSwitched}=require("@html_editor/utils/dom_info");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const TextDirectionPlugin=__exports.TextDirectionPlugin=class TextDirectionPlugin extends Plugin{static id="textDirection";static dependencies=["selection","history","split"];resources={user_commands:[{id:"switchDirection",title:_t("Switch direction"),description:_t("Switch the text's direction"),icon:"fa-exchange",run:this.switchDirection.bind(this),isAvailable:isHtmlContentSupported,},],powerbox_items:[{categoryId:"format",commandId:"switchDirection",},],};setup(){if(this.config.direction&&!this.editable.closest("[dir]")){this.editable.setAttribute("dir",this.config.direction);} 8823this.direction=this.config.direction||"ltr";} 8824switchDirection(){const targetedNodes=this.dependencies.selection.getTargetedNodes().filter(isContentEditable);const blocks=new Set(targetedNodes.map((node)=>closestElement(node,"ul,ol")||closestElement(node,"[data-embedded='toggleBlock']")||closestBlock(node)));if(!blocks.size){return;} 8825const shouldApplyStyle=![...blocks].every((block)=>isDirectionSwitched(block,this.editable));for(const block of blocks){for(const node of block.querySelectorAll("ul,ol")){blocks.add(node);}} 8826for(const block of blocks){if(!shouldApplyStyle){block.removeAttribute("dir");}else{block.setAttribute("dir",this.direction==="ltr"?"rtl":"ltr");}} 8827for(const element of blocks){const style=getComputedStyle(element);if(style.direction==="ltr"&&style.textAlign==="right"){element.style.setProperty("text-align","left");}else if(style.direction==="rtl"&&style.textAlign==="left"){element.style.setProperty("text-align","right");}} 8828this.dependencies.history.addStep();}} 8829return __exports;});; 8830 8831/* /html_editor/static/src/main/toolbar/mobile_toolbar.js */ 8832odoo.define('@html_editor/main/toolbar/mobile_toolbar',['@odoo/owl','@html_editor/main/toolbar/toolbar'],function(require){'use strict';let __exports={};const{Component,onMounted,useExternalListener,useRef}=require("@odoo/owl");const{Toolbar}=require("@html_editor/main/toolbar/toolbar");const ToolbarMobile=__exports.ToolbarMobile=class ToolbarMobile extends Component{static template="html_editor.MobileToolbar";static props={editable:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE},class:{type:String,optional:true},state:Object,getSelection:Function,focusEditable:Function,};
8832static components={Toolbar,};setup(){this.toolbar=useRef("toolbarWrapper");try{const innerWindow=this.props.editable.ownerDocument.defaultView;const frameElement=innerWindow.frameElement;this.targetWindow=frameElement?.ownerDocument.defaultView??window;}catch{this.targetWindow=window;} 8833useExternalListener(this.targetWindow.visualViewport,"resize",this.fixToolbarPosition);useExternalListener(this.targetWindow.visualViewport,"scroll",this.fixToolbarPosition);onMounted(()=>this.fixToolbarPosition());} 8834fixToolbarPosition(){const visualViewport=this.targetWindow.visualViewport;const keyboardHeight=Math.max(0,this.targetWindow.innerHeight-(visualViewport.height+visualViewport.offsetTop));this.toolbar.el.style.bottom=`${keyboardHeight}px`;}} 8835return __exports;});; 8836 8837/* /html_editor/static/src/main/toolbar/toolbar.js */ 8838odoo.define('@html_editor/main/toolbar/toolbar',['@odoo/owl','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{Component,useState,validate}=require("@odoo/owl");const{omit,pick}=require("@web/core/utils/objects");const Toolbar=__exports.Toolbar=class Toolbar extends Component{static template="html_editor.Toolbar";static props={class:{type:String,optional:true},getSelection:Function,focusEditable:Function,state:{type:Object,shape:{namespace:{type:String,optional:true},buttonGroups:{type:Array,element:{type:Object,shape:{id:String,buttons:{type:Array,element:{type:Object,validate:(button)=>{const base={id:String,description:String,isDisabled:Boolean,};if(button.Component){validate(button,{...base,Component:Function,props:{type:Object,optional:true},});}else{validate(button,{...base,run:Function,icon:{type:String,optional:true},text:{type:String,optional:true},isActive:Boolean,});} 8839return true;},},},},},},},},};setup(){this.state=useState(this.props.state);} 8840onButtonClick(button){button.run();this.props.focusEditable();}} 8841const toolbarButtonProps=__exports.toolbarButtonProps={title:[String,Function],getSelection:Function,isDisabled:Boolean,};__exports.composeToolbarButton=composeToolbarButton;function composeToolbarButton(userCommand,toolbarItem){const description=toolbarItem.description||userCommand.description;return{...pick(userCommand,"icon"),...omit(toolbarItem,"commandId","commandParams"),run:()=>userCommand.run(toolbarItem.commandParams),isAvailable:(selection)=>[userCommand.isAvailable,toolbarItem.isAvailable].filter(Boolean).every((predicate)=>predicate(selection)),description:description instanceof Function?description:()=>description,};} 8842return __exports;});; 8843 8844/* /html_editor/static/src/main/toolbar/toolbar_plugin.js */ 8845odoo.define('@html_editor/main/toolbar/toolbar_plugin',['@html_editor/plugin','@html_editor/utils/dom_info','@odoo/owl','@html_editor/main/toolbar/toolbar','@web/core/browser/feature_detection','@web/core/registry','@html_editor/main/toolbar/mobile_toolbar','@web/core/utils/timing','@web/core/utils/objects','@html_editor/utils/resource','@web/core/l10n/translation','@web/core/utils/functions','@html_editor/utils/dom_traversal','@web/core/ui/ui_service'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{isEmptyTextNode,isZWS}=require("@html_editor/utils/dom_info");const{reactive}=require("@odoo/owl");const{composeToolbarButton,Toolbar}=require("@html_editor/main/toolbar/toolbar");const{hasTouch,isMacOS,isIOS}=require("@web/core/browser/feature_detection");const{registry}=require("@web/core/registry");const{ToolbarMobile}=require("@html_editor/main/toolbar/mobile_toolbar");const{debounce}=require("@web/core/utils/timing");const{omit,pick}=require("@web/core/utils/objects");const{withSequence}=require("@html_editor/utils/resource");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{memoize}=require("@web/core/utils/functions");const{closestElement}=require("@html_editor/utils/dom_traversal");const{utils}=require("@web/core/ui/ui_service");const DELAY_TOOLBAR_OPEN=__exports.DELAY_TOOLBAR_OPEN=300;const MIN_SIZE_FOR_COMPACT=7;const DISABLED_NAMESPACE=__exports.DISABLED_NAMESPACE="disabled";const ToolbarPlugin=__exports.ToolbarPlugin=class ToolbarPlugin extends Plugin{static id="toolbar";static dependencies=["overlay","selection","userCommand"];static shared=["getToolbarInfo"];resources={selectionchange_handlers:this.handleSelectionChange.bind(this),selection_leave_handlers:()=>this.closeToolbar(null,{force:true}),selection_enter_handlers:()=>this.updateToolbar(),step_added_handlers:()=>this.updateToolbar(),user_commands:{id:"expandToolbar",run:()=>{this.isToolbarExpanded=true;this.updateToolbar();},},toolbar_groups:[withSequence(100,{id:"expand_toolbar",namespaces:["compact"]}),withSequence(30,{id:"layout"}),],toolbar_items:{id:"expand_toolbar",groupId:"expand_toolbar",commandId:"expandToolbar",description:_t("Expand toolbar"),icon:"oi-ellipsis-v",},toolbar_namespace_providers:[withSequence(100,(targetedNodes,editableSelection)=>this.isToolbarVisible(targetedNodes,editableSelection)?"compact":undefined),],};setup(){const groupIds=new Set();for(const group of this.getResource("toolbar_groups")){if(groupIds.has(group.id)){throw new Error(`Duplicate toolbar group id: ${group.id}`);} 8846groupIds.add(group.id);} 8847this.buttonGroups=this.getButtonGroups();this.buttonsByNamespace={DISABLED_NAMESPACE:[]};this.isMobileToolbar=(utils.isSmall()&&hasTouch()&&window.visualVie
8847wport)||isIOS();if(this.isMobileToolbar){this.overlay=new MobileToolbarOverlay(this.editable);}else{this.overlay=this.dependencies.overlay.createOverlay(Toolbar,{positionOptions:{position:"top-start",},closeOnPointerdown:false,});} 8848this.state=reactive({buttonGroups:[],namespace:undefined});this.onSelectionChangeActive=true;this.debouncedUpdateToolbar=debounce(()=>{this._updateToolbar();this.onSelectionChangeActive=true;},DELAY_TOOLBAR_OPEN);if(this.isMobileToolbar){this.addDomListener(this.editable,"pointerup",()=>{this.isToolbarExpanded=false;});}else{this.addDomListener(this.editable,"mousedown",(ev)=>{this.closeToolbar(this.dependencies.selection.getSelectionData());this.debouncedUpdateToolbar.cancel();this.onSelectionChangeActive=false;});this.addGlobalDomListener("mouseup",(ev)=>{if(ev.detail>=2){this.triggerDebouncedUpdateToolbar();}else{setTimeout(()=>{this.updateToolbar();this.onSelectionChangeActive=true;});}});this.addDomListener(this.editable,"keydown",(ev)=>{if(ev.key?.startsWith("Arrow")){this.closeToolbar(this.dependencies.selection.getSelectionData());this.onSelectionChangeActive=false;if(isMacOS()&&ev.metaKey){this.pendingArrowKey=true;}}});this.addDomListener(this.editable,"keyup",(ev)=>{if(ev.key?.startsWith("Arrow")){this.pendingArrowKey=false;this.triggerDebouncedUpdateToolbar();}});if(isMacOS()){this.addDomListener(this.document,"selectionchange",()=>{if(this.pendingArrowKey&&!this.isMouseDown){this.pendingArrowKey=false;this.triggerDebouncedUpdateToolbar();}});this.addDomListener(this.editable,"mousedown",()=>(this.isMouseDown=true));this.addDomListener(this.document,"mouseup",()=>(this.isMouseDown=false));}} 8849this.isToolbarExpanded=false;this.toolbarProps={class:"shadow rounded my-2",getSelection:()=>this.dependencies.selection.getSelectionData(),focusEditable:()=>this.dependencies.selection.focusEditable(),state:this.state,};} 8850destroy(){this.debouncedUpdateToolbar.cancel();this.updateToolbar.cancel();this.overlay.close();super.destroy();} 8851triggerDebouncedUpdateToolbar(){this.debouncedUpdateToolbar();} 8852getButtons(){const toolbarItems=this.getResource("toolbar_items");const commandItemToButton=(item)=>{const command=this.dependencies.userCommand.getCommand(item.commandId);return composeToolbarButton(command,item);};const componentItemToButton=(item)=>({isAvailable:()=>true,...item,description:item.description instanceof Function?item.description:()=>item.description,});return toolbarItems.map((item)=>"Component"in item?componentItemToButton(item):commandItemToButton(item));} 8853getButtonGroups(){const buttons=this.getButtons();const groups=this.getResource("toolbar_groups");return groups.map((group)=>({...omit(group,"namespaces"),buttons:buttons.filter((button)=>button.groupId===group.id).map((button)=>({...button,namespaces:button.namespaces||group.namespaces||["expanded"],})),}));} 8854getButtonsForNamespace(namespace){if(this.buttonsByNamespace[namespace]){return this.buttonsByNamespace[namespace];} 8855const button=this.buttonGroups.flatMap((group)=>group.buttons.filter((btn)=>btn.namespaces.includes(namespace)));this.buttonsByNamespace[namespace]=button;return button;} 8856getToolbarInfo(){return{buttonGroups:this.buttonGroups,};} 8857getIsToolbarOpen(){return this.overlay.isOpen;} 8858handleSelectionChange(selectionData){if(this.onSelectionChangeActive){this.updateToolbar(selectionData);}} 8859updateToolbar=debounce(this._updateToolbar,0,{trailing:true});_updateToolbar(selectionData=this.dependencies.selection.getSelectionData()){if(this.isDestroyed){return;} 8860if(!selectionData.currentSelectionIsInEditable||selectionData.documentSelectionIsProtected||selectionData.documentSelectionIsProtecting){this.closeToolbar();return;} 8861const targetedNodes=this.dependencies.selection.getTargetedNodes();if(targetedNodes.every((node)=>!this.dependencies.selection.isNodeEditable(node))){this.closeToolbar();return;} 8862let currentNamespace=null;let filteredtargetedNodes=[];filteredtargetedNodes=this.getFilteredTargetedNodes(targetedNodes);for(const fn of this.getResource("toolbar_namespace_providers")){currentNamespace=fn(filteredtargetedNodes,selectionData.editableSelection);if(currentNamespace){break;}} 8863if(currentNamespace===DISABLED_NAMESPACE){this.closeToolbar();return;} 8864if(currentNamespace==="compact"&&this.isToolbarExpanded){currentNamespace="expanded";} 8865if(currentNamespace){this.state.namespace=currentNamespace;if(!this.overlay.isOpen){this.overlay.open({props:this.toolbarProps}
8865);} 8866this.updateButtonsStates(selectionData.editableSelection,filteredtargetedNodes);}else{this.closeToolbar();}} 8867getFilteredTargetedNodes(targetedNodes){return targetedNodes.filter((node)=>this.dependencies.selection.isNodeEditable(node)&&(node.nodeType!==Node.TEXT_NODE||(!isEmptyTextNode(node)&&!isZWS(node)))).filter((node)=>{const element=closestElement(node);const style=this.document.defaultView.getComputedStyle(element);return style.display!=="none"&&style.visibility!=="hidden";});} 8868isToolbarVisible(targetedNodes,editableSelection){if(this.isMobileToolbar){return true;} 8869const isCollapsed=editableSelection.isCollapsed;if(isCollapsed){return false;} 8870const selectionText=editableSelection.textContent();const textCleaned=selectionText.replace(/(\r\n|\n|\r|\u200B|\uFEFF)/gm,"");if(textCleaned.length){return true;} 8871return targetedNodes.some((node)=>node.nodeType===Node.ELEMENT_NODE&&node.tagName==="BR");} 8872closeToolbar(selectionData=null,{force=false}={}){if(!this.overlay.isOpen){return;} 8873const anchor=selectionData?.documentSelectionIsInEditable?selectionData.editableSelection?.anchorNode:document.getSelection()?.anchorNode;const shouldPreventClosing=!force&&anchor?.closest?.("[data-prevent-closing-overlay]")?.dataset?.preventClosingOverlay==="true";if(!shouldPreventClosing){this.overlay.close();this.isToolbarExpanded=false;this.state.namespace=null;}} 8874updateButtonsStates(selection,targetedNodes){const availableButtons=this.getAvailableButtonsSet(selection);this.state.buttonGroups=this.buttonGroups.map((group)=>({id:group.id,buttons:group.buttons.filter((button)=>availableButtons.has(button)).map((button)=>({id:button.id,description:button.description(selection,targetedNodes),isDisabled:!!button.isDisabled?.(selection,targetedNodes),...(button.Component?pick(button,"Component","props"):{...pick(button,"run","icon","text"),isActive:!!button.isActive?.(selection,targetedNodes),}),})),})).filter((group)=>group.buttons.length>0);} 8875getAvailableButtonsSet(selection){if(this.state.namespace==="compact"){return this.getAvailableButtonsCompact(selection);} 8876const isAvailable=(button)=>button.isAvailable(selection);return new Set(this.getButtonsForNamespace(this.state.namespace).filter(isAvailable));} 8877getAvailableButtonsCompact(selection){const isAvailable=memoize((button)=>button.isAvailable(selection));const compact=this.getButtonsForNamespace("compact").filter(isAvailable);const expanded=this.getButtonsForNamespace("expanded").filter(isAvailable);const shouldDisplayCompactToolbar=expanded.length>=MIN_SIZE_FOR_COMPACT&&expanded.length>compact.length;if(shouldDisplayCompactToolbar){return new Set(compact);} 8878this.state.namespace="expanded";return new Set(expanded);}} 8879class MobileToolbarOverlay{constructor(editable){this.isOpen=false;this.overlayId=`mobile_toolbar_${Math.random().toString(16).slice(2)}`;this.editable=editable;} 8880open({props}){props.class="shadow";props.editable=this.editable;if(!this.isOpen){const modal=this.editable.closest(".o_modal_full");if(modal){modal.style.paddingBottom="40px";} 8881registry.category("main_components").add(this.overlayId,{Component:ToolbarMobile,props,});this.isOpen=true;}} 8882close(){const modal=this.editable.closest(".o_modal_full");if(modal){modal.style.paddingBottom="";} 8883registry.category("main_components").remove(this.overlayId,"MobileToolbar");this.isOpen=false;}} 8884return __exports;});; 8885 8886/* /html_editor/static/src/main/youtube_plugin.js */ 8887odoo.define('@html_editor/main/youtube_plugin',['@web/core/l10n/translation','@web/core/network/rpc','@html_editor/plugin','@html_editor/main/media/media_dialog/video_selector'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{rpc}=require("@web/core/network/rpc");const{Plugin}=require("@html_editor/plugin");const{VideoSelector}=require("@html_editor/main/media/media_dialog/video_selector");const YOUTUBE_URL_GET_VIDEO_ID=__exports.YOUTUBE_URL_GET_VIDEO_ID=/^(?:(?:https?:)?\/\/)?(?:(?:www|m)\.)?(?:youtube\.com|youtu\.be)(?:\/(?:[\w-]+\?v=|embed\/|v\/)?)([^\s?&#]+)(?:\S+)?$/i;const YoutubePlugin=__exports.YoutubePlugin=class YoutubePlugin extends Plugin{static id="youtube";static dependencies=["history","dom"];
8887mediaSpecificClasses=VideoSelector.mediaSpecificClasses;resources={...(this.config.allowVideo&&{paste_media_url_command_providers:this.getCommandForVideoUrlPaste.bind(this),}),};getCommandForVideoUrlPaste(url){const youtubeUrl=YOUTUBE_URL_GET_VIDEO_ID.exec(url);if(youtubeUrl){return{title:_t("Embed Youtube Video"),description:_t("Embed the youtube video in the document."),icon:"fa-youtube-play",run:async()=>{const videoElement=await this.getYoutubeVideoElement(youtubeUrl[0]);this.dependencies.dom.insert(videoElement);this.dependencies.history.addStep();},};}} 8888async getYoutubeVideoElement(url){if(!URL.canParse(url)){return;} 8889const parsedUrl=new URL(url);const urlParams=parsedUrl.searchParams;const start_from=urlParams.get("start")||urlParams.get("t");const autoplay=urlParams.get("autoplay")==="1";const loop=urlParams.get("loop")==="1";const hide_controls=urlParams.get("controls")==="0";const hide_fullscreen=urlParams.get("fs")==="0";const videoData=await rpc("/html_editor/video_url/data",{video_url:url,autoplay,loop,hide_controls,hide_fullscreen,start_from,});const savedVideo=this.createVideoElement(videoData);savedVideo.classList.add(...this.mediaSpecificClasses);return savedVideo;} 8890createVideoElement(videoData){return VideoSelector.createElements([{src:videoData.embed_url}])[0];}} 8891return __exports;});; 8892 8893/* /html_editor/static/src/others/collaboration/PeerToPeer.js */ 8894odoo.define('@html_editor/others/collaboration/PeerToPeer',[],function(require){'use strict';let __exports={};const urlParams=new URLSearchParams(window.location.search);const collaborationDebug=urlParams.get("collaborationDebug");const COLLABORATION_LOCALSTORAGE_KEY="odoo_editor_collaboration_debug";if(typeof collaborationDebug==="string"){if(collaborationDebug==="false"){localStorage.removeItem(COLLABORATION_LOCALSTORAGE_KEY,urlParams.get("collaborationDebug"));}else{localStorage.setItem(COLLABORATION_LOCALSTORAGE_KEY,urlParams.get("collaborationDebug"));}} 8895const debugValue=localStorage.getItem(COLLABORATION_LOCALSTORAGE_KEY);const debugShowLog=["","true","all"].includes(debugValue);const debugShowNotifications=debugValue==="all";const baseNotificationMethods={ptp_request:async function(notification){const{requestId,requestName,requestPayload,requestTransport}=notification.notificationPayload;this._onRequest(notification.fromPeerId,requestId,requestName,requestPayload,requestTransport);},ptp_request_result:function(notification){const{requestId,result}=notification.notificationPayload;if(this._pendingRequestResolver[requestId]){clearTimeout(this._pendingRequestResolver[requestId].rejectTimeout);this._pendingRequestResolver[requestId].resolve(result);delete this._pendingRequestResolver[requestId];}},ptp_join:async function(notification){const peerId=notification.fromPeerId;if(this.peersInfos[peerId]&&this.peersInfos[peerId].peerConnection){return this.peersInfos[peerId];} 8896this._createPeer(peerId);},rtc_signal_icecandidate:async function(notification){if(debugShowLog){console.log(`%creceive candidate`,"background: darkgreen; color: white;");} 8897const peerInfos=this.peersInfos[notification.fromPeerId];if(!peerInfos||!peerInfos.peerConnection||peerInfos.peerConnection.connectionState==="closed"){console.groupCollapsed("=== ERROR: Handle Ice Candidate from undefined|closed ===");console.trace(peerInfos);console.groupEnd();return;} 8898if(!peerInfos.peerConnection.remoteDescription){peerInfos.iceCandidateBuffer.push(notification.notificationPayload);}else{this._addIceCandidate(peerInfos,notification.notificationPayload);}},rtc_signal_description:async function(notification){const description=notification.notificationPayload;if(debugShowLog){console.log(`%cdescription received:`,"background: blueviolet; color: white;",description);} 8899const peerInfos=this.peersInfos[notification.fromPeerId]||this._createPeer(notification.fromPeerId);const pc=peerInfos.peerConnection;if(!pc||pc.connectionState==="closed"){if(debugShowLog){console.groupCollapsed("=== ERROR: handle offer ===");console.log("An offer has been received for a non-existent peer connection - peer: "+ 8900notification.fromPeerId);console.trace(pc&&pc.connectionState);console.groupEnd();} 8901return;} 8902if(pc.signalingState==="have-remote-offer"){return;} 8903const isPolite=(""+notification.fromPeerId).localeCompare(""+this._currentPeerId)===1;if(debugShowLog){console.log(`%cisPolite: %c${isPolite}`,"background: deepskyblue;",`background:${isPolite ? "green" : "red"}`);} 8904const isOfferRacing=description.type==="offer"&&(peerInfos.makingOffer||pc.signalingState!=="stable");if(isOfferRacing&&!isPolite){if(debugShowLog){console.log(`%creturn because isOfferRacing && !isPolite. pc.signalingState: ${pc.signalingState}`,"background: red;");} 8905return;} 8906if(debugShowLog){console.log(`%cisOfferRacing: ${isOfferRacing}`,"background: red;");console.log(`%c SETREMOTEDESCRIPTION`,"background: navy; color:white;");} 8907try{await pc.setRemoteDescription(description);}catch(e){if(e instanceof DOMException&&e.name==="InvalidStateError"){console.error(e);return;}else{throw e;}} 8908if(peerInfos.iceCandidateBuffer.length){for(const candidate of peerInfos.iceCandidateBuffer){await this._addIceCandidate(peerInfos,candidate);} 8909peerInfos.iceCandidateBuffer.splice(0);} 8910if(description.type==="offer"){const answerDescription=await pc.createAnswer();try{await pc.setLocalDescription(answerDescription);}catch(e){if(e instanceof DOMException&&e.name==="InvalidStateError"){console.error(e);return;}else{throw e;}} 8911this.notifyPeer(notification.fromPeerId,"rtc_signal_description",pc.localDescription);}},};const PeerToPeer=__exports.PeerToPeer=class PeerToPeer{constructor(options){this.options=options;this._currentPeerId=this.options.currentPeerId;if(debugShowLog){console.log(`%c currentPeerId:${this._currentPeerId}`,"background: blue; color: white;");} 8912this.peersInfos={};this._lastRequestId=-1;this._pendingRequestResolver={};this._stopped=false;} 8913stop(){this.closeAllConnections();this._stopped=true;} 8914getConnectedPeerIds(){return Object.entries(this.peersInfos).filter(([id,infos])=>infos.peerConnection&&infos.peerConnection.iceConnectionState==="connected"&&infos.dataChannel&&infos.dataChannel.readyState==="open").map(([id])=>id);} 8915removePeer(peerId){if(debugShowLog){console.log(`%c REMOVE PEER ${peerId}`,"background: chocolate;");} 8916this.notifySelf("ptp_remove",peerId);const peerInfos=this.peersInfos[peerId];if(!peerInfos){return;} 8917clearTimeout(peerInfos.fallbackTimeout);clearTimeout(peerInfos.zombieTimeout);peerInfos.dataChannel&&peerInfos.dataChannel.close();peerInfos.peerConnection&&peerInfos.peerConnection.close();delete this.peersInfos[peerId];} 8918closeAllConnections(){for(const peerId of Object.keys(this.peersInfos)){this.notifyAllPeers("ptp_disconnect");this.removePeer(peerId);}} 8919async notifyAllPeers(notificationName,notificationPayload,{transport="server"}={}){if(this._stopped){return;} 8920const transportPayload={fromPeerId:this._currentPeerId,notificationName,notificationPayload,};if(transport==="server"){await this.options.broadcastAll(transportPayload);}else if(transport==="rtc"){for(const cliendId of Object.keys(this.peersInfos)){this._channelNotify(cliendId,transportPayload);}}else{throw new Error(`Transport "${transport}" is not supported. Use "server" or "rtc" transport.`);}} 8921notifyPeer(peerId,notificationName,notificationPayload,{transport="server"}={}){if(this._stopped){return;} 8922if(debugShowNotifications){if(notificationName==="ptp_request_result"){console.log(`%c${Date.now()} - REQUEST RESULT SEND: %c${transport}:${ 8923 notificationPayload.requestId 8924 }:${this._currentPeerId.slice("-5")}:${peerId.slice("-5")}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}else if(notificationName==="ptp_request"){console.log(`%c${Date.now()} - REQUEST SEND: %c${transport}:${ 8925 notificationPayload.requestName 8926 }|${notificationPayload.requestId}:${this._currentPeerId.slice( 8927 "-5" 8928 )}:${peerId.slice("-5")}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}else{console.log(`%c${Date.now()} - NOTIFICATION SEND: %c${transport}:${notificationName}:${this._currentPeerId.slice( 8929 "-5" 8930 )}:${peerId.slice("-5")}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}} 8931const transportPayload={fromPeerId:this._currentPeerId,toPeerId:peerId,notificationName,notificationPayload,};if(transport==="server"){this.options.broadcastAll(transportPayload);}else if(transport==="rtc"){this._channelNotify(peerId,transportPayload);}else{throw new Error(`Transport "${transport}" is not supported. Use "server" or "rtc" transport.`);}} 8932notifySelf(notificationName,notificationPayload){if(this._stopped){return;} 8933return this.handleNotification({notificationName,notificationPayload});}
8934handleNotification(notification){if(this._stopped){return;} 8935const isInternalNotification=typeof notification.fromPeerId==="undefined"&&typeof notification.toPeerId==="undefined";if(isInternalNotification||(notification.fromPeerId!==this._currentPeerId&&!notification.toPeerId)||notification.toPeerId===this._currentPeerId){if(debugShowNotifications){if(notification.notificationName==="ptp_request_result"){console.log(`%c${Date.now()} - REQUEST RESULT RECEIVE: %c${ 8936 notification.notificationPayload.requestId 8937 }:${notification.fromPeerId.slice("-5")}:${notification.toPeerId.slice( 8938 "-5" 8939 )}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}else if(notification.notificationName==="ptp_request"){console.log(`%c${Date.now()} - REQUEST RECEIVE: %c${ 8940 notification.notificationPayload.requestName 8941 }|${ 8942 notification.notificationPayload.requestId 8943 }:${notification.fromPeerId.slice("-5")}:${notification.toPeerId.slice( 8944 "-5" 8945 )}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}else{console.log(`%c${Date.now()} - NOTIFICATION RECEIVE: %c${ 8946 notification.notificationName 8947 }:${notification.fromPeerId}:${notification.toPeerId}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}} 8948try{const baseMethod=baseNotificationMethods[notification.notificationName];if(baseMethod){return baseMethod.call(this,notification);} 8949if(this.options.onNotification){return this.options.onNotification(notification);}}catch(error){console.groupCollapsed("=== ERROR: On notification in collaboration ===");console.error(error);console.groupEnd();}}} 8950requestPeer(peerId,requestName,requestPayload,{transport="server"}={}){if(this._stopped){return;} 8951return new Promise((resolve,reject)=>{const requestId=this._getRequestId();const abort=(reason)=>{clearTimeout(rejectTimeout);delete this._pendingRequestResolver[requestId];reject(new RequestError(reason||"Request was aborted."));};const rejectTimeout=setTimeout(()=>abort("Request took too long (more than 10 seconds)."),10000);this._pendingRequestResolver[requestId]={resolve,rejectTimeout,abort,};this.notifyPeer(peerId,"ptp_request",{requestId,requestName,requestPayload,requestTransport:transport,},{transport});});} 8952abortCurrentRequests(){for(const{abort}of Object.values(this._pendingRequestResolver)){abort();}} 8953_createPeer(peerId,{makeOffer=true}={}){if(this._stopped){return;} 8954if(debugShowLog){console.log("CREATE CONNECTION with peer id:",peerId);} 8955this.peersInfos[peerId]={makingOffer:false,iceCandidateBuffer:[],backoffFactor:0,};if(!navigator.onLine){return this.peersInfos[peerId];} 8956const pc=new RTCPeerConnection(this.options.peerConnectionConfig);if(makeOffer){pc.onnegotiationneeded=async()=>{if(debugShowLog){console.log(`%c NEGONATION NEEDED: ${pc.connectionState}`,"background: deeppink;");} 8957try{this.peersInfos[peerId].makingOffer=true;if(debugShowLog){console.log(`%ccreating and sending an offer`,"background: darkmagenta; color: white;");} 8958const offer=await pc.createOffer();if(pc.signalingState!=="stable"){return;} 8959await pc.setLocalDescription(offer);this.notifyPeer(peerId,"rtc_signal_description",pc.localDescription);}catch(err){console.error(err);}finally{this.peersInfos[peerId].makingOffer=false;}};} 8960pc.onicecandidate=async(event)=>{if(event.candidate){this.notifyPeer(peerId,"rtc_signal_icecandidate",event.candidate);}};pc.oniceconnectionstatechange=async()=>{if(debugShowLog){console.log("ICE STATE UPDATE: "+pc.iceConnectionState);} 8961switch(pc.iceConnectionState){case"failed":case"closed":this.removePeer(peerId);break;case"disconnected":if(navigator.onLine){await this._recoverConnection(peerId,{delay:3000,reason:"ice connection disconnected",});} 8962break;case"connected":this.peersInfos[peerId].backoffFactor=0;break;}};pc.onconnectionstatechange=async()=>{if(debugShowLog){console.log("CONNECTION STATE UPDATE:"+pc.connectionState);} 8963switch(pc.connectionState){case"failed":case"closed":this.removePeer(peerId);break;case"disconnected":if(navigator.onLine){await this._recoverConnection(peerId,{delay:3000,reason:"connection disconnected",});} 8964break;case"connected":case"completed":this.peersInfos[peerId].backoffFactor=0;break;}};pc.onicecandidateerror=async(error)=>{if(debugShowLog){console.groupCollapsed("=== ERROR: onIceCandidate ===");console.log("connectionState: "+ 8965pc.connectionState+" - iceState: "+ 8966pc.iceConnectionState);console.trace(error);console.groupEnd();} 8967this._recoverConnection(peerId,{delay:3000,reason:"ice candidate error"});};
8967const dataChannel=pc.createDataChannel("notifications",{negotiated:true,id:1});let message=[];dataChannel.onmessage=(event)=>{if(event.data!=="-"){message.push(event.data);}else{this.handleNotification(JSON.parse(message.join("")));message=[];}};dataChannel.onopen=(event)=>{this.notifySelf("rtc_data_channel_open",{connectionPeerId:peerId,});};this.peersInfos[peerId].peerConnection=pc;this.peersInfos[peerId].dataChannel=dataChannel;return this.peersInfos[peerId];} 8968async _addIceCandidate(peerInfos,candidate){const rtcIceCandidate=new RTCIceCandidate(candidate);try{await peerInfos.peerConnection.addIceCandidate(rtcIceCandidate);}catch(error){console.groupCollapsed("=== ERROR: ADD ICE CANDIDATE ===");console.trace(error);console.groupEnd();}} 8969_channelNotify(peerId,transportPayload){if(this._stopped){return;} 8970const peerInfo=this.peersInfos[peerId];const dataChannel=peerInfo&&peerInfo.dataChannel;if(!dataChannel||dataChannel.readyState!=="open"){if(peerInfo&&!peerInfo.zombieTimeout){if(debugShowLog){console.warn(`Impossible to communicate with peer ${peerId}
8970. The connection will be killed in 10 seconds if the datachannel state has not changed.`);} 8971this._killPotentialZombie(peerId);}}else{const str=JSON.stringify(transportPayload);const size=str.length;const maxStringLength=5000;let from=0;let to=maxStringLength;while(from<size){dataChannel.send(str.slice(from,to));from=to;to=to+=maxStringLength;} 8972dataChannel.send("-");}} 8973_getRequestId(){this._lastRequestId++;return this._lastRequestId;} 8974async _onRequest(fromPeerId,requestId,requestName,requestPayload,requestTransport){if(this._stopped){return;} 8975const requestFunction=this.options.onRequest&&this.options.onRequest[requestName];const result=await requestFunction({fromPeerId,requestId,requestName,requestPayload,});this.notifyPeer(fromPeerId,"ptp_request_result",{requestId,result},{transport:requestTransport});} 8976_recoverConnection(peerId,{delay=0,reason=""}={}){if(this._stopped){this.removePeer(peerId);return;} 8977const peerInfos=this.peersInfos[peerId];if(!peerInfos||peerInfos.fallbackTimeout){return;} 8978const backoffFactor=this.peersInfos[peerId].backoffFactor;const backoffDelay=delay*Math.pow(2,backoffFactor);if(backoffFactor>10){if(debugShowLog){console.log(`%c STOP RTC RECOVERY: impossible to connect to peer ${peerId}: ${reason}`,"background: darkred; color: white;");} 8979return;} 8980peerInfos.fallbackTimeout=setTimeout(async()=>{peerInfos.fallbackTimeout=undefined;const pc=peerInfos.peerConnection;if(!pc||pc.iceConnectionState==="connected"){return;} 8981if(["connected","closed"].includes(pc.connectionState)){return;} 8982if(debugShowLog){console.log(`%c RTC RECOVERY: calling back peer ${peerId} to salvage the connection ${pc.iceConnectionState} after ${backoffDelay}ms, reason: ${reason}`,"background: darkorange; color: white;");} 8983this.removePeer(peerId);const newPeerInfos=this._createPeer(peerId);newPeerInfos.backoffFactor=backoffFactor+1;},backoffDelay);} 8984_killPotentialZombie(peerId){if(this._stopped){this.removePeer(peerId);return;} 8985const peerInfos=this.peersInfos[peerId];if(!peerInfos||peerInfos.zombieTimeout){return;} 8986peerInfos.zombieTimeout=setTimeout(()=>{if(peerInfos&&peerInfos.dataChannel&&peerInfos.dataChannel.readyState!=="open"){if(debugShowLog){console.log(`%c KILL ZOMBIE ${peerId}`,"background: red;");} 8987this.removePeer(peerId);}else{if(debugShowLog){console.log(`%c NOT A ZOMBIE ${peerId}`,"background: green;");}}},10000);}} 8988const RequestError=__exports.RequestError=class RequestError extends Error{constructor(message){super(message);this.name="RequestError";}} 8989return __exports;});; 8990 8991/* /html_editor/static/src/others/collaboration/collaboration_odoo_plugin.js */ 8992odoo.define('@html_editor/others/collaboration/collaboration_odoo_plugin',['@html_editor/plugin','@web/core/network/rpc','@web/core/user','@web/core/utils/concurrency','@web/core/utils/timing','@html_editor/others/collaboration/PeerToPeer','@html_editor/utils/dom_traversal','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{rpc}=require("@web/core/network/rpc");const{user}=require("@web/core/user");const{Mutex}=require("@web/core/utils/concurrency");const{debounce}=require("@web/core/utils/timing");const{PeerToPeer,RequestError}=require("@html_editor/others/collaboration/PeerToPeer");const{ancestors}=require("@html_editor/utils/dom_traversal");const{childNodeIndex}=require("@html_editor/utils/position");const PTP_MAX_RECOVERY_TIME=500;const REQUEST_ERROR=Symbol("REQUEST_ERROR");let ICE_SERVERS=null;const CollaborationOdooPlugin=__exports.CollaborationOdooPlugin=class CollaborationOdooPlugin extends Plugin{static id="collaborationOdoo";static dependencies=["baseContainer","history","collaboration","selection"];static shared=["getPeerMetadata"];resources={selectionchange_handlers:debounce(()=>{this.ptp?.notifyAllPeers("oe_history_set_selection",this.getCurrentCollaborativeSelection(),{transport:"rtc",});},50),clean_for_save_handlers:({root})=>this.attachHistoryIds(root),history_missing_parent_step_handlers:this.onHistoryMissingParentStep.bind(this),history_reset_handlers:this.onReset.bind(this),step_added_handlers:({step})=>this.ptp?.notifyAllPeers("oe_history_step",step,{transport:"rtc"}),};setup(){this.isDocumentStale=false;this.ptpJoined=false;this.lastCollaborationResetId=0;this.serverLastStepId=this.config.content&&this.getLastHistoryStepId(this.config.content);this.setupCollaboration(this.config.collaboration.collaborationChannel);const collaborativeTrigger=this.config.collaboration.collaborativeTrigger;this.joinPeerToPeer=this.joinPeerToPeer.bind(this);if(collaborativeTrigger==="start"){this.joinPeerToPeer();}else if(collaborativeTrigger==="focus"||typeof collaborativeTrigger==="undefined"){this.editable.addEventListener("focus",this.joinPeerToPeer);} 8993stripHistoryIds(this.editable);} 8994destroy(){this.collaborationStopBus&&this.collaborationStopBus();if(this.peerToPeerLoading){this.peerToPeerLoading.then(()=>{this.stopPeerToPeer();});} 8995super.destroy();} 8996stopPeerToPeer(){this.joiningPtp=false;this.ptpJoined=false;this.resetCollabRequests();this.ptp&&this.ptp.stop();} 8997getCurrentCollaborativeSelection(){const selection=this.dependencies.selection.getEditableSelection();return{selection:this.dependencies.history.serializeSelection(selection),peerId:this.config.collaboration.peerId,};} 8998setupCollaboration(collaborationChannel){const modelName=collaborationChannel.collaborationModelName;const fieldName=collaborationChannel.collaborationFieldName;const resId=collaborationChannel.collaborationResId;const channelName=`editor_collaboration:${modelName}:${fieldName}:${resId}`;if(!(modelName&&fieldName&&resId)){return;} 8999this.collaborationChannelName=channelName;this.historyStepsBuffer=[];const collaborationBusListener=(payload)=>{if(payload.model_name===modelName&&payload.field_name===fieldName&&payload.res_id===resId){if(payload.notificationName==="html_field_write"){this.onServerLastIdUpdate(payload.notificationPayload.last_step_id);}else if(this.ptpJoined){this.peerToPeerLoading.then(()=>this.ptp.handleNotification(payload));}}};const{busService}=this.config.collaboration;busService.subscribe("editor_collaboration",collaborationBusListener);busService.addChannel(this.collaborationChannelName);this.collaborationStopBus=()=>{busService.unsubscribe("editor_collaboration",collaborationBusListener);busService.deleteChannel(this.collaborationChannelName);};this.startCollaborationTime=new Date().getTime();const loadPeerToPeer=async()=>
8999{if(!ICE_SERVERS){ICE_SERVERS=await rpc("/html_editor/get_ice_servers");} 9000let iceServers=ICE_SERVERS;if(!iceServers.length){iceServers=[{urls:["stun:stun1.l.google.com:19302","stun:stun2.l.google.com:19302"],},];} 9001this.iceServers=iceServers;this.ptp=this.getNewPtp();};this.peerToPeerLoading=loadPeerToPeer();} 9002getNewPtp(){const rpcMutex=new Mutex();const{collaborationChannel}=this.config.collaboration;const modelName=collaborationChannel.collaborationModelName;const fieldName=collaborationChannel.collaborationFieldName;const resId=collaborationChannel.collaborationResId;this.historySyncAtLeastOnce=false;return new PeerToPeer({peerConnectionConfig:{iceServers:this.iceServers},currentPeerId:this.config.collaboration.peerId,broadcastAll:(rpcData)=>rpcMutex.exec(async()=>rpc("/html_editor/bus_broadcast",{model_name:modelName,field_name:fieldName,res_id:resId,bus_data:rpcData,})),onRequest:{get_peer_metadata:this.getMetadata.bind(this),get_missing_steps:(params)=>this.dependencies.collaboration.historyGetMissingSteps(params.requestPayload),get_history_from_snapshot:()=>this.getHistorySnapshot(),get_collaborative_selection:()=>this.getCurrentCollaborativeSelection(),recover_document:(params)=>{const{serverDocumentId,fromStepId}=params.requestPayload;if(!this.dependencies.collaboration.getBranchIds().includes(serverDocumentId)){return;} 9003return{missingSteps:this.dependencies.collaboration.historyGetMissingSteps({fromStepId,}),snapshot:this.getHistorySnapshot(),};},},onNotification:async(notification)=>{this.dispatchTo("collaboration_notification_handlers",notification);let{fromPeerId,notificationName,notificationPayload}=notification;switch(notificationName){case"ptp_remove":break;case"ptp_disconnect":this.ptp.removePeer(fromPeerId);break;case"rtc_data_channel_open":{fromPeerId=notificationPayload.connectionPeerId;const metadata=await this.requestPeer(fromPeerId,"get_peer_metadata",undefined,{transport:"rtc"});if(metadata===REQUEST_ERROR){return;} 9004this.ptp.peersInfos[fromPeerId].metadata=metadata;if(!this.historySyncAtLeastOnce){const localPeer={id:this.config.collaboration.peerId,startTime:this.startCollaborationTime,};const remotePeer={id:fromPeerId,startTime:metadata.startTime,};
9004if(isPeerFirst(localPeer,remotePeer)){this.historySyncAtLeastOnce=true;this.historySyncFinished=true;}else{this.resetCollabRequests();const response=await this.resetFromPeer(fromPeerId,this.lastCollaborationResetId);if(response===REQUEST_ERROR){return;}}}else{this.ptp.notifyAllPeers("oe_history_step",this.dependencies.history.getHistorySteps().at(-1),{transport:"rtc"});this.resetCollaborativeSelection(fromPeerId);} 9005break;} 9006case"oe_history_step":if(this.historySyncFinished){this.dependencies.collaboration.onExternalHistorySteps([notificationPayload,]);}else{this.historyStepsBuffer.push(notificationPayload);} 9007break;case"oe_history_set_selection":{const peer=this.ptp.peersInfos[fromPeerId];if(!peer){return;} 9008const selection=notificationPayload;this.onExternalMultiselectionUpdate(selection);break;}}},});} 9009getPeerMetadata(peerId){return this.ptp.peersInfos[peerId]?.metadata;} 9010onExternalMultiselectionUpdate(selection){this.dispatchTo("collaborative_selection_update_handlers",selection);} 9011async requestPeer(peerId,requestName,requestPayload,params){return this.ptp.requestPeer(peerId,requestName,requestPayload,params).catch((e)=>{if(e instanceof RequestError){return REQUEST_ERROR;}else{throw e;}});} 9012getMetadata(){const metadatas={startTime:this.startCollaborationTime,peerName:user.name,};for(const cb of this.getResource("collaboration_peer_metadata_providers")){Object.assign(metadatas,cb());} 9013return metadatas;} 9014onServerLastIdUpdate(last_step_id){this.serverLastStepId=last_step_id;this.isDocumentStale=this.isLastDocumentStale();if(this.isDocumentStale&&this.ptpJoined){return this.recoverFromStaleDocument();}else if(this.isDocumentStale&&this.joiningPtp){this.resetCollabRequests();this.joinPeerToPeer();}} 9015joinPeerToPeer(){this.editable.removeEventListener("focus",this.joinPeerToPeer);if(this.peerToPeerLoading){return this.peerToPeerLoading.then(async()=>{this.joiningPtp=true;if(this.isDocumentStale){const success=await this.resetFromServerAndResyncWithPeers();if(!success){return;}} 9016this.ptp.notifyAllPeers("ptp_join");this.joiningPtp=false;this.ptpJoined=true;});}} 9017isLastDocumentStale(){if(!this.serverLastStepId){return false;} 9018return!this.dependencies.collaboration.getBranchIds().includes(this.serverLastStepId);} 9019async recoverFromStaleDocument(){return new Promise((resolve)=>{const resetCollabCount=this.lastCollaborationResetId;const allPeers=this.getPtpPeers().map((peer)=>peer.id);if(allPeers.length===0){if(this.isDocumentStale){this.showConflictDialog();resolve();return this.resetFromServerAndResyncWithPeers();}} 9020let hasRetrievalBudgetTimeout=false;const snapshots=[];let nbPendingResponses=allPeers.length;const success=()=>{resolve();clearTimeout(timeout);};for(const peerId of allPeers){this.requestPeer(peerId,"recover_document",{serverDocumentId:this.serverLastStepId,fromStepId:this.dependencies.collaboration.getBranchIds().at(-1),},{transport:"rtc"}).then((response)=>{nbPendingResponses--;if(response===REQUEST_ERROR||resetCollabCount!==this.lastCollaborationResetId||hasRetrievalBudgetTimeout||!response||!this.isDocumentStale){if(nbPendingResponses<=0){processSnapshots();} 9021return;} 9022this.processMissingSteps(response.missingSteps);this.isDocumentStale=this.isLastDocumentStale();snapshots.push(response.snapshot);if(nbPendingResponses<1){processSnapshots();}});} 9023const processSnapshots=async()=>{this.isDocumentStale=this.isLastDocumentStale();if(!this.isDocumentStale){return success();} 9024if(snapshots[0]){this.showConflictDialog();} 9025for(const snapshot of snapshots){this.applySnapshot(snapshot);this.isDocumentStale=this.isLastDocumentStale();if(!this.isDocumentStale){return success();}} 9026if(this.isDocumentStale){this.showConflictDialog();await this.resetFromServerAndResyncWithPeers();} 9027success();};const timeout=setTimeout(()=>{if(resetCollabCount!==this.lastCollaborationResetId){return;} 9028hasRetrievalBudgetTimeout=true;this.onRecoveryPeerTimeout(processSnapshots);},PTP_MAX_RECOVERY_TIME);});} 9029getPtpPeers(){const peers=Object.entries(this.ptp.peersInfos).map(([peerId,peerInfo])=>({id:peerId,...peerInfo,}));return peers.sort((a,b)=>(isPeerFirst(a,b)?-1:1));} 9030getLastHistoryStepId(value){const matchId=value.match(/data-last-history-steps="[0-9,]*?([0-9]+)"/);
9030return matchId&&matchId[1];} 9031resetCollabRequests(){this.lastCollaborationResetId++;this.ptp&&this.ptp.abortCurrentRequests();} 9032async resetFromServerAndResyncWithPeers(){let collaborationResetId=this.lastCollaborationResetId;const record=await this.getCurrentRecord();if(collaborationResetId!==this.lastCollaborationResetId){return;} 9033const content=record[this.config.collaboration.collaborationChannel.collaborationFieldName];this.serverLastStepId=content&&this.getLastHistoryStepId(content);this.isDocumentStale=false;if(content){this.editable.innerHTML=content;}else{this.editable.replaceChildren(this.dependencies.baseContainer.createBaseContainer());} 9034stripHistoryIds(this.editable);this.dispatchTo("normalize_handlers",this.editable);this.dependencies.history.reset(content);this.historySyncAtLeastOnce=false;this.resetCollabRequests();collaborationResetId=this.lastCollaborationResetId;this.startCollaborationTime=new Date().getTime();await Promise.all(this.getPtpPeers().map((peer)=>this.resetFromPeer(peer.id,collaborationResetId)));return true;} 9035onReset(content){this.historyShareId=Math.floor(Math.random()*Math.pow(2,52)).toString();const lastStepId=content&&content.match(/data-last-history-steps="([\d,]+)"/)?.[1];if(lastStepId){this.dependencies.collaboration.setInitialBranchStepId(lastStepId);}} 9036async processMissingSteps(missingSteps){if(missingSteps===-1||!missingSteps.length){return false;} 9037this.dependencies.collaboration.onExternalHistorySteps(missingSteps);return true;} 9038applySnapshot(snapshot){const{steps,historyIds,historyShareId}=snapshot;const isStaleDocument=this.serverLastStepId&&!historyIds.includes(this.serverLastStepId);if(isStaleDocument){return;} 9039this.historyShareId=historyShareId;this.historySyncAtLeastOnce=true;this.dependencies.collaboration.resetFromSteps(steps,historyIds);return true;} 9040async onRecoveryPeerTimeout(processSnapshots){processSnapshots();} 9041showConflictDialog(){} 9042getHistorySnapshot(){return Object.assign({},this.dependencies.collaboration.getSnapshotSteps(),{historyShareId:this.historyShareId,});} 9043async resetFromPeer(fromPeerId,resetCollabCount){this.historySyncFinished=false;this.historyStepsBuffer=[];const snapshot=await this.requestPeer(fromPeerId,"get_history_from_snapshot",undefined,{transport:"rtc"});if(snapshot===REQUEST_ERROR){return REQUEST_ERROR;} 9044if(resetCollabCount!==this.lastCollaborationResetId){return;} 9045if(this.historySyncAtLeastOnce){return;} 9046const selection=this.dependencies.selection.getEditableSelection();let anchorNodeIndexPath=this._getNodeIndexPath(selection.anchorNode);let anchorOffset=selection.anchorOffset;if(selection.anchorNode===this.editable){anchorNodeIndexPath=this._getNodeIndexPath(this.editable.firstChild);anchorOffset=0;} 9047const applied=this.applySnapshot(snapshot);if(!applied){return;} 9048const anchorNode=this._getNodeFromIndexPath(anchorNodeIndexPath);if(this.dependencies.selection.isSelectionInEditable({anchorNode,focusNode:anchorNode})){this.dependencies.selection.setSelection({anchorNode,anchorOffset,});} 9049this.historySyncFinished=true;if(this.historyStepsBuffer.length){this.dependencies.collaboration.onExternalHistorySteps(this.historyStepsBuffer);this.historyStepsBuffer=[];} 9050this.editable.dispatchEvent(new CustomEvent("onHistoryResetFromPeer"));this.resetCollaborativeSelection(fromPeerId);} 9051async resetCollaborativeSelection(fromPeerId){const remoteSelection=await this.requestPeer(fromPeerId,"get_collaborative_selection",undefined,{transport:"rtc"});if(remoteSelection===REQUEST_ERROR){return;} 9052if(remoteSelection){this.onExternalMultiselectionUpdate(remoteSelection);}} 9053async onHistoryMissingParentStep({step,fromStepId}){if(!this.ptp){return;} 9054const missingSteps=await this.requestPeer(step.peerId,"get_missing_steps",{fromStepId:fromStepId,toStepId:step.id,},{transport:"rtc"});if(missingSteps===REQUEST_ERROR){return;} 9055this.processMissingSteps(Array.isArray(missingSteps)?missingSteps.concat(step):missingSteps);} 9056async getCurrentRecord(){const[record]=await this.config.collaboration.ormService.read(this.config.collaboration.collaborationChannel.collaborationModelName,[this.config.collaboration.collaborationChannel.collaborationResId],[this.config.collaboration.collaborationChannel.collaborationFieldName]);return record;} 9057attachHistoryIds(editable){const historyIds=this.dependencies.collaboration.getBranchIds().join(",");const firstChild=editable.children[0];if(firstChild){firstChild.setAttribute("data-last-history-steps",historyIds);}} 9058_getNodeIndexPath(node){return[node,...ancestors(node,this.editable)].map((ancestor)=>childNodeIndex(ancestor));} 9059_getNodeFromIndexPath(indexPath){return indexPath.reduceRight((node,index)=>node?.childNodes?.[index],this.editable.parentElement);}} 9060function isPeerFirst(peerA,peerB){if(peerA.startTime===peerB.startTime){return peerA.id.localeCompare(peerB.id)===-1;} 9061if(peerA.startTime===undefined||peerB.startTime===undefined){return Boolean(peerA.startTime);}else{return peerA.startTime<peerB.startTime;}} 9062__exports.stripHistoryIds=stripHistoryIds;function stripHistoryIds(element){element.querySelectorAll("[data-last-history-steps]").forEach((el)=>el.removeAttribute("data-last-history-steps"));} 9063return __exports;});; 9064 9065/* /html_editor/static/src/others/collaboration/collaboration_plugin.js */ 9066odoo.define('@html_editor/others/collaboration/collaboration_plugin',['@html_editor/plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const HISTORY_SNAPSHOT_INTERVAL=__exports.HISTORY_SNAPSHOT_INTERVAL=1000*60;const HISTORY_SNAPSHOT_BUFFER_TIME=1000*10;const CollaborationPlugin=__exports.CollaborationPlugin=class CollaborationPlugin extends Plugin{static id="collaboration";static dependencies=["history","selection","sanitize"];resources={history_cleaned_handlers:this.onHistoryClean.bind(this),history_reset_handlers:this.onHistoryReset.bind(this),step_added_handlers:({step})=>this.onStepAdded(step),set_attribute_overrides:this.setAttribute.bind(this),history_step_processors:this.processHistoryStep.bind(this),unreversible_step_predicates:this.isUnreversibleStep.bind(this),};static shared=["getBranchIds","getSnapshotSteps","historyGetMissingSteps","onExternalHistorySteps","resetFromSteps","setInitialBranchStepId",];peerId=null;setup(){this.peerId=this.config.collaboration.peerId;if(!this.peerId){throw new Error("The collaboration plugin requires a peerId");} 9067this._snapshotInterval=setInterval(()=>{this.makeSnapshot();},HISTORY_SNAPSHOT_INTERVAL);} 9068destroy(){super.destroy();clearInterval(this._snapshotInterval);this._snapshotInterval=false;} 9069onHistoryClean(){this.branchStepIds=[];} 9070onHistoryReset(){const firstStep=this.dependencies.history.getHistorySteps()[0];this.snapshots=[{step:firstStep}];} 9071isUnreversibleStep(step){return step.peerId!==this.peerId;} 9072setAttribute(node,attributeName,attributeValue){if(attributeValue){this.safeSetAttribute(node,attributeName,attributeValue);return true;}} 9073getBranchIds(){const steps=this.dependencies.history.getHistorySteps();return(this.initialBranchStepId||"").split(",").concat(this.branchStepIds).c
9073oncat(steps.map((s)=>s.id));} 9074safeSetAttribute(node,attributeName,attributeValue){const clone=this.document.createElement(node.tagName);clone.setAttribute(attributeName,attributeValue);this.dependencies.sanitize.sanitize(clone);if(clone.hasAttribute(attributeName)){node.setAttribute(attributeName,clone.getAttribute(attributeName));}else{node.removeAttribute(attributeName);}} 9075onExternalHistorySteps(newSteps){let stepIndex=0;const selectionData=this.dependencies.selection.getSelectionData();const steps=this.dependencies.history.getHistorySteps();for(const newStep of newSteps){const insertIndex=this.getInsertStepIndex(steps,newStep);if(typeof insertIndex==="undefined"){continue;} 9076this.dependencies.history.addExternalStep(newStep,insertIndex);stepIndex++;} 9077if(selectionData.documentSelectionIsInEditable){this.dependencies.selection.rectifySelection(selectionData.editableSelection);} 9078this.dispatchTo("external_history_step_handlers");if(stepIndex){this.config.onChange?.();}} 9079getInsertStepIndex(steps,newStep){let index=steps.length-1;while(index>=0&&steps[index].id!==newStep.previousStepId){if(steps[index].id===newStep.id){return;} 9080index--;} 9081if(index<0){const historySteps=steps;let index=historySteps.length-1;while(index!==0){if(historySteps[index].peerId===newStep.peerId){break;} 9082index--;} 9083const fromStepId=historySteps[index].id;this.dispatchTo("history_missing_parent_step_handlers",{step:newStep,fromStepId:fromStepId,});return;} 9084let concurentSteps=[];index++;while(index<steps.length){if(steps[index].previousStepId===newStep.previousStepId){if(steps[index].id.localeCompare(newStep.id)===1){break;}else{concurentSteps=[steps[index].id];}}else{if(concurentSteps.includes(steps[index].previousStepId)){concurentSteps.push(steps[index].id);}else{break;}} 9085index++;} 9086return index;} 9087historyGetMissingSteps({fromStepId,toStepId}){const steps=this.dependencies.history.getHistorySteps();const fromIndex=steps.findIndex((x)=>x.id===fromStepId);const toIndex=toStepId?steps.findIndex((x)=>x.id===toStepId):steps.length;if(fromIndex===-1||toIndex===-1){return-1;} 9088return steps.slice(fromIndex+1,toIndex);} 9089getSnapshotSteps(){const historySteps=this.dependencies.history.getHistorySteps();if(!this.snapshots[0].time){return{steps:historySteps,historyIds:this.getBranchIds()};} 9090const snapshotSteps=[];let snapshot;if(this.snapshots[0].time+HISTORY_SNAPSHOT_BUFFER_TIME<Date.now()){snapshot=this.snapshots[0];}else{snapshot=this.snapshots[1];} 9091let index=historySteps.length-1;while(historySteps[index].id!==snapshot.step.id){snapshotSteps.push(historySteps[index]);index--;} 9092snapshotSteps.push(snapshot.step);snapshotSteps.reverse();return{steps:snapshotSteps,historyIds:this.getBranchIds()};} 9093setInitialBranchStepId(stepId){this.initialBranchStepId=stepId;} 9094resetFromSteps(steps,branchStepIds){this.dependencies.selection.resetSelection();this.dependencies.history.resetFromSteps(steps);this.snapshots=[{step:steps[0]}];this.branchStepIds=branchStepIds;} 9095makeSnapshot(){const historyLength=this.dependencies.history.getHistorySteps().length;if(!this.lastSnapshotLength||this.lastSnapshotLength<historyLength){this.lastSnapshotLength=historyLength;const step=this.dependencies.history.makeSnapshotStep();const snapshot={time:Date.now(),step:step,};this.snapshots=[snapshot,this.snapshots[0]];}} 9096onStepAdded(step){step.peerId=this.peerId;this.dispatchTo("collaboration_step_added_handlers",step);} 9097processHistoryStep(step){step.peerId=this.peerId;return step;}} 9098return __exports;});; 9099 9100/* /html_editor/static/src/others/collaboration/collaboration_selection_avatar_plugin.js */ 9101odoo.define('@html_editor/others/collaboration/collaboration_selection_avatar_plugin',['@html_editor/plugin','@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@web/core/browser/browser','@web/core/l10n/translation','@web/core/user'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{isProtecting}=require("@html_editor/utils/dom_info");const{closestElement}=require("@html_editor/utils/dom_traversal");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{user}=require("@web/core/user");const AVATAR_SIZE=__exports.AVATAR_SIZE=25;const CollaborationSelectionAvatarPlugin=__exports.CollaborationSelectionAvatarPlugin=class CollaborationSelectionAvatarPlugin extends Plugin{static id="collaborationSelectionAvatar";static dependencies=["history","position","localOverlay","collaborationOdoo"];resources={collaboration_notification_handlers:this.handleCollaborationNotification.bind(this),external_history_step_handlers:this.refreshSelection.bind(this),layout_geometry_change_handlers:this.refreshSelection.bind(this),set_movable_element_handlers:this.disableAvatarForElement.bind(this),unset_movable_element_handlers:this.enableAvatars.bind(this),collaborative_selection_update_handlers:this.updateSelection.bind(this),collaboration_peer_metadata_providers:()=>({avatarUrl:this.avatarUrl}),};selectionInfos=new Map();setup(){this.avatarOverlay=this.dependencies.localOverlay.makeLocalOverlay("oe-avatars-overlay");this.avatarsCountersOverlay=this.dependencies.localOverlay.makeLocalOverlay("oe-avatars-counters-overlay");this.avatarUrl=`${ 9102 browser.location.origin 9103 }/web/image?model=res.users&field=avatar_128&id=${encodeURIComponent(user.userId)}`;} 9104handleCollaborationNotification({notificationName,notificationPayload}){switch(notificationName){case"ptp_remove":this.selectionInfos.delete(notificationPayload);this.refreshSelection();}} 9105updateSelection(selection){const savedSelection=this.selectionInfos.get(selection.peerId)||{};const newSelection=Object.assign(savedSelection,selection);this.selectionInfos.set(selection.peerId,newSelection);this.drawPeerAvatar(newSelection);this.updateAvatarCounters();} 9106drawPeerAvatar(selectionInfo){const{selection,peerId}=selectionInfo;const peerMetadata=this.dependencies.collaborationOdoo.getPeerMetadata(peerId);if(!peerMetadata){return;} 9107const{avatarUrl,peerName=_t("Anonymous")}=peerMetadata;const anchorNode=this.dependencies.history.getNodeById(selection.anchorNodeId);const focusNode=this.dependencies.history.getNodeById(selection.focusNodeId);if(!anchorNode||!focusNode||!anchorNode.isConnected||!focusNode.isConnected){return;} 9108let anchorBlock=closestBlock(anchorNode);
9108if(!anchorBlock){return;} 9109if(isProtecting(anchorBlock)){const rootAnchorBlock=closestElement(anchorNode,(el)=>isBlock(el)&&el.parentElement===this.editable);if(rootAnchorBlock){anchorBlock=rootAnchorBlock;}} 9110const containerRect=this.avatarOverlay.getBoundingClientRect();let avatarElement=selectionInfo.avatarElement;if(!avatarElement){avatarElement=this.document.createElement("div");avatarElement.className="oe-collaboration-caret-avatar";avatarElement.style.display="none";const image=this.document.createElement("img");avatarElement.append(image);image.onload=()=>avatarElement.style.removeProperty("display");image.setAttribute("src",avatarUrl);image.classList.add("object-fit-cover");} 9111if(!avatarElement.parentElement){this.avatarOverlay.append(avatarElement);} 9112selectionInfo.avatarElement=avatarElement;selectionInfo.peerName=peerName;selectionInfo.avatarTargetElement=anchorBlock;this.selectionInfos.set(peerId,selectionInfo);const anchorBlockRect=anchorBlock.getBoundingClientRect();const top=anchorBlockRect.y-containerRect.y;avatarElement.style.top=top+"px";const closestList=closestElement(anchorNode,"ul, ol");const anchorX=closestList?closestList.getBoundingClientRect().x:anchorBlockRect.x;const left=anchorX-containerRect.x-AVATAR_SIZE;avatarElement.style.left=left+"px";selectionInfo.avatarPositionKey=`${left}|${top}`;} 9113updateAvatarCounters(){const avatarsOverlaps={};for(const info of this.selectionInfos.values()){const key=info.avatarPositionKey;avatarsOverlaps[key]=avatarsOverlaps[key]||new Set();avatarsOverlaps[key].add(info);} 9114this.avatarsCountersOverlay.replaceChildren();for(const[overlapKey,infos]of Object.entries(avatarsOverlaps)){const size=infos.size;if(size>1){const[left,top]=overlapKey.split("|").map((n)=>parseInt(n,10));const div=document.createElement("div");div.className="oe-overlapping-counter";div.style.left=left+10+"px";div.style.top=top+10+"px";div.innerText=size;this.avatarsCountersOverlay.append(div);}}} 9115refreshSelection(){if(!this.selectionInfos.size){this.avatarOverlay.replaceChildren();} 9116this.avatarsCountersOverlay.replaceChildren();for(const selection of this.selectionInfos.values()){this.drawPeerAvatar(selection);} 9117this.updateAvatarCounters();} 9118disableAvatarForElement(element){this.enableAvatars();for(const info of this.selectionInfos.values()){if(info.avatarTargetElement===element){if(!info.avatarElement.classList.contains("invisible")){info.avatarElement.classList.add("invisible");}}}} 9119enableAvatars(){for(const element of this.avatarOverlay.querySelectorAll(".oe-collaboration-caret-avatar.invisible")){element.classList.remove("invisible");}}} 9120return __exports;});; 9121 9122/* /html_editor/static/src/others/collaboration/collaboration_selection_plugin.js */ 9123odoo.define('@html_editor/others/collaboration/collaboration_selection_plugin',['@html_editor/plugin','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/utils/selection','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{getDeepestPosition,isProtected,isProtecting,isUnprotecting,}=require("@html_editor/utils/dom_info");const{childNodes}=require("@html_editor/utils/dom_traversal");const{DIRECTIONS}=require("@html_editor/utils/position");const{getCursorDirection}=require("@html_editor/utils/selection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const CollaborationSelectionPlugin=__exports.CollaborationSelectionPlugin=class CollaborationSelectionPlugin extends Plugin{static id="collaborationSelection";static dependencies=["history","collaborationOdoo","position","localOverlay"];resources={collaboration_notification_handlers:this.handleCollaborationNotification.bind(this),layout_geometry_change_handlers:this.refreshSelection.bind(this),collaborative_selection_update_handlers:this.updateSelection.bind(this),collaboration_peer_metadata_providers:()=>({selectionColor:this.selectionColor}),};selectionInfos=new Map();setup(){this.selectionOverlay=this.dependencies.localOverlay.makeLocalOverlay("oe-selections-container");this.selectionColor=`hsl(${(Math.random() * 360).toFixed(0)}, 75%, 50%)`;} 9124handleCollaborationNotification({notificationName,notificationPayload}){switch(notificationName){case"ptp_remove":this.multiselectionRemove(notificationPayload);this.selectionInfos.delete(notificationPayload);break;}} 9125updateSelection(selection){this.selectionInfos.set(selection.peerId,selection);this.drawPeerSelection(selection);} 9126drawPeerSelection({selection,peerId}){const peerMetadata=this.dependencies.collaborationOdoo.getPeerMetadata(peerId);if(!peerMetadata){return;} 9127const{selectionColor,peerName=_t("Anonymous")}=peerMetadata;this.multiselectionRemove(peerId);let clientRects;let anchorNode=this.dependencies.history.getNodeById(selection.anchorNodeId);let focusNode=this.dependencies.history.getNodeById(selection.focusNodeId);let anchorOffset=selection.anchorOffset;let focusOffset=selection.focusOffset;if(!anchorNode||!focusNode){anchorNode=this.editable.children[0];focusNode=this.editable.children[0];anchorOffset=0;focusOffset=0;} 9128const anchorTarget=childNodes(anchorNode).at(anchorOffset);const focusTarget=childNodes(focusNode).at(focusOffset);const protectionCheck=(node)=>isProtecting(node)||(isProtected(node)&&!isUnprotecting(node));if(protectionCheck(anchorTarget)||protectionCheck(focusTarget)){return;} 9129if(anchorNode.isConnected&&focusNode.isConnected){[anchorNode,anchorOffset]=getDeepestPosition(anchorNode,anchorOffset);[focusNode,focusOffset]=getDeepestPosition(focusNode,focusOffset);}else{anchorNode=this.editable.children[0];focusNode=this.editable.children[0];anchorOffset=0;focusOffset=0;}
9130const direction=getCursorDirection(anchorNode,anchorOffset,focusNode,focusOffset);const range=new Range();try{if(direction===DIRECTIONS.RIGHT){range.setStart(anchorNode,anchorOffset);range.setEnd(focusNode,focusOffset);}else{range.setStart(focusNode,focusOffset);range.setEnd(anchorNode,anchorOffset);} 9131clientRects=Array.from(range.getClientRects());}catch{clientRects=[];} 9132if(!clientRects.length){return;} 9133const containerRect=this.selectionOverlay.getBoundingClientRect();const indicators=clientRects.map(({x,y,width,height})=>{const rectElement=this.document.createElement("div");rectElement.style=` 9134 position: absolute; 9135 top: ${y - containerRect.y}px; 9136 left: ${x - containerRect.x}px; 9137 width: ${width}px; 9138 height: ${height}px; 9139 background-color: ${selectionColor}; 9140 opacity: 0.25; 9141 pointer-events: none; 9142 `;rectElement.setAttribute("data-selection-peer-id",peerId);return rectElement;});const caretElement=this.document.createElement("div");caretElement.style=`border-left: 2px solid ${selectionColor}; position: absolute;`;
9142caretElement.setAttribute("data-selection-peer-id",peerId);caretElement.className="oe-collaboration-caret";const caretTopSquare=this.document.createElement("div");caretTopSquare.className="oe-collaboration-caret-top-square";caretTopSquare.style["background-color"]=selectionColor;caretTopSquare.setAttribute("data-peer-name",peerName);caretElement.append(caretTopSquare);if(direction===DIRECTIONS.LEFT){const rect=clientRects[0];caretElement.style.height=`${rect.height * 1.2}px`;caretElement.style.top=`${rect.y - containerRect.y}px`;caretElement.style.left=`${rect.x - containerRect.x}px`;}else{const rect=clientRects.at(-1);caretElement.style.height=`${rect.height * 1.2}px`;caretElement.style.top=`${rect.y - containerRect.y}px`;caretElement.style.left=`${rect.right - containerRect.x}px`;} 9143this.selectionOverlay.append(caretElement,...indicators);} 9144multiselectionRemove(peerId){const elements=this.selectionOverlay.querySelectorAll(`[data-selection-peer-id="${peerId}"]`);for(const element of elements){element.remove();}} 9145refreshSelection(){this.selectionOverlay.replaceChildren();for(const selection of this.selectionInfos.values()){this.drawPeerSelection(selection);}}} 9146return __exports;});; 9147 9148/* /html_editor/static/src/others/embedded_components/backend/caption/caption.js */ 9149odoo.define('@html_editor/others/embedded_components/backend/caption/caption',[],function(require){'use strict';let __exports={};return __exports;});; 9150 9151/* /html_editor/static/src/others/embedded_components/backend/file/file.js */ 9152odoo.define('@html_editor/others/embedded_components/backend/file/file',['@html_editor/others/embedded_component_utils','@odoo/owl','@html_editor/others/embedded_components/core/file/readonly_file'],function(require){'use strict';let __exports={};const{applyObjectPropertyDifference,getEmbeddedProps,StateChangeManager,useEmbeddedState,}=require("@html_editor/others/embedded_component_utils");const{useEffect,useRef,useState}=require("@odoo/owl");const{ReadonlyEmbeddedFileComponent}=require("@html_editor/others/embedded_components/core/file/readonly_file");const EmbeddedFileComponent=__exports.EmbeddedFileComponent=class EmbeddedFileComponent extends ReadonlyEmbeddedFileComponent{static template="html_editor.EmbeddedFile";setup(){super.setup();this.state=useEmbeddedState(this.props.host);this.fileModel.state=this.state;this.localState=useState({editFileName:false,});this.nameInput=useRef("nameInput");useEffect(()=>{if(this.localState.editFileName){this.nameInput.el.focus();this.nameInput.el.select();}},()=>[this.localState.editFileName]);} 9153onBlurNameInput(ev){this.localState.editFileName=false;this.renameFile();} 9154onFocusFileName(ev){this.localState.editFileName=true;} 9155onKeydownNameInput(ev){if(ev.key!=="Enter"){return;}else{ev.preventDefault();} 9156if(this.renameFile()){this.localState.editFileName=false;this.env.editorShared?.setSelectionAfter(this.props.host);}} 9157renameFile(){let newName=this.nameInput.el.value;if(!newName.length){return false;} 9158if(newName===this.fileModel.filename){return true;} 9159this.fileModel.filename=newName;if(this.fileModel.extension){const pattern=new RegExp(`\\.${this.fileModel.extension}$`,"i");if(!newName.match(pattern)){newName+=`.${this.fileModel.extension}`;}} 9160this.fileModel.name=newName;return true;}} 9161const fileEmbedding=__exports.fileEmbedding={name:"file",Component:EmbeddedFileComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),getStateChangeManager:(config)=>new StateChangeManager(Object.assign(config,{propertyUpdater:{fileData:(state,previous,next)=>{applyObjectPropertyDifference(state,"fileData",previous.fileData,next.fileData);},},})),};return __exports;});; 9162 9163/* /html_editor/static/src/others/embedded_components/backend/syntax_highlighting/code_toolbar.js */ 9164odoo.define('@html_editor/others/embedded_components/backend/syntax_highlighting/code_toolbar',['@odoo/owl','@web/core/copy_button/copy_button','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{CopyButton}=require("@web/core/copy_button/copy_button");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const LANGUAGES=__exports.LANGUAGES={plaintext:"Plain Text",markdown:"Markdown",javascript:"Javascript",typescript:"Typescript",jsdoc:"JSDoc",java:"Java",python:"Python",html:"HTML",xml:"XML",svg:"SVG",json:"JSON",css:"CSS",sass:"SASS",scss:"SCSS",sql:"SQL",diff:"Diff",};const CodeToolbar=__exports.CodeToolbar=class CodeToolbar extends Component{static template="html_editor.CodeToolbar";static props={target:{validate:(el)=>el.nodeType===Node.ELEMENT_NODE},getContent:{type:Function},onLanguageChange:{type:Function},currentLanguage:{type:String},convertToParagraph:{type:Function},};static components={Dropdown,DropdownItem,CopyButton};setup(){super.setup();this.languages=LANGUAGES;}} 9165return __exports;});; 9166 9167/* /html_editor/static/src/others/embedded_components/backend/syntax_highlighting/syntax_highlighting.js */ 9168odoo.define('@html_editor/others/embedded_components/backend/syntax_highlighting/syntax_highlighting',['@html_editor/others/embedded_component_utils','@odoo/owl','@web/core/assets','@web/core/browser/cookie','@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils','@html_editor/others/embedded_components/backend/syntax_highlighting/code_toolbar','@html_editor/utils/position'],function(require){'use strict';let __exports={};const{getEmbeddedProps,StateChangeManager,useEmbeddedState,}=require("@html_editor/others/embedded_component_utils");const{Component,onMounted,onWillStart,useEffect,useRef,useState}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const{cookie}=require("@web/core/browser/cookie");const{getPreValue,highlightPre,}=require("@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils");const{CodeToolbar}=require("@html_editor/others/embedded_components/backend/syntax_highlighting/code_toolbar");const{nodeSize}=require("@html_editor/utils/position");const EmbeddedSyntaxHighlightingComponent=__exports.EmbeddedSyntaxHighlightingComponent=class EmbeddedSyntaxHighlightingComponent extends Component{static template="html_editor.EmbeddedSyntaxHighlighting";static components={CodeToolbar};static props={value:{type:String},languageId:{type:String},onTextareaFocus:{type:Function},convertToParagraph:{type:Function},setSelection:{type:Function},host:{type:Object},};setup(){super.setup();this.state=useState({host:this.props.host,highlightedValue:"",});this.embeddedState=useEmbeddedState(this.props.host);this.preRef=useRef("pre");this.textareaRef=useRef("textarea");onWillStart(()=>this.loadPrism());onMounted(()=>{this.pre=this.preRef.el;this.textarea=this.textareaRef.el;this.document=this.textarea.ownerDocument;this.highlight();});useEffect(this.highlight.bind(this),()=>[this.embeddedState.value,this.embeddedState.languageId,]);} 9169loadPrism(){return loadBundle(`html_editor.assets_prism${cookie.get("
9169color_scheme") === "dark" ? "_dark" : ""}`,{targetDoc:this.props.host.ownerDocument});} 9170highlight(){const focus=this.document.activeElement===this.textarea;highlightPre(this.pre,this.embeddedState.value,this.embeddedState.languageId);const preValue=getPreValue(this.pre);if(this.textarea.value!==preValue){this.textarea.value=preValue;} 9171if(focus){this.textarea.focus({preventScroll:true});this.props.onTextareaFocus();} 9172this.embeddedState.value=this.textarea.value;} 9173onInput(){this.textarea.focus();this.props.onTextareaFocus();this.embeddedState.value=this.textarea.value;} 9174onKeydown(ev){if(ev.key==="Tab"){ev.preventDefault();const tabSize=+getComputedStyle(this.textarea).tabSize||4;const tab=" ".repeat(tabSize);const{selectionStart,selectionEnd}=this.textarea;const collapsed=selectionStart===selectionEnd;let start=this.textarea.value.slice(0,selectionStart).lastIndexOf("\n");start=start===-1?0:start;let newValue="";let spacesRemovedAtStart=0;if(ev.shiftKey){let end=this.textarea.value.slice(selectionEnd,this.textarea.value.length).indexOf("\n");end=end===-1?0:end;end=selectionEnd+end;newValue=this.textarea.value.slice(0,start);const regex=new RegExp(`(\n|^)( |\u00A0){1,${tabSize}}`,"g");const startSlice=this.textarea.value.slice(start,selectionStart);const cleanStartSlice=startSlice.replace(regex,"$1");spacesRemovedAtStart=startSlice.length-cleanStartSlice.length;newValue+=cleanStartSlice;newValue+=this.textarea.value.slice(selectionStart,selectionEnd).replace(regex,"$1");newValue+=this.textarea.value.slice(selectionEnd,end).replace(regex,"$1");newValue+=this.textarea.value.slice(end,this.textarea.value.length);}else{if(collapsed&&/\S/.test(this.textarea.value.slice(start,selectionStart))){newValue=this.textarea.value.slice(0,selectionStart)+ 9175tab+ 9176this.textarea.value.slice(selectionStart,this.textarea.value.length);}else{newValue=start?this.textarea.value.slice(0,start):tab;newValue+=this.textarea.value.slice(start,selectionEnd).replaceAll("\n",`\n${tab}`);newValue+=this.textarea.value.slice(selectionEnd,this.textarea.value.length);}} 9177const insertedChars=newValue.length-this.textarea.value.length;this.textarea.value=newValue;const newStart=selectionStart+(ev.shiftKey?-spacesRemovedAtStart:tabSize);const newEnd=collapsed?newStart:selectionEnd+insertedChars;this.textarea.setSelectionRange(newStart,newEnd,this.textarea.selectionDirection);this.embeddedState.value=this.textarea.value;}else if(ev.key==="Backspace"){if(this.textarea.value===""){ev.preventDefault();this.props.convertToParagraph({target:this.pre});}}else if(ev.key==="ArrowUp"||ev.key==="ArrowDown"){const{value,selectionStart,selectionEnd}=this.textarea;if(selectionStart!==selectionEnd){return;} 9178const isArrowUp=ev.key==="ArrowUp";const isCursorAtBoundary=isArrowUp?value.slice(0,selectionStart).lastIndexOf("\n")===-1:value.indexOf("\n",selectionEnd)===-1;if(!isCursorAtBoundary){return;} 9179ev.preventDefault();this.textarea.blur();const node=isArrowUp?this.props.host.previousElementSibling:this.props.host.nextElementSibling;this.props.setSelection({anchorNode:node,anchorOffset:isArrowUp?nodeSize(node):0,});}} 9180onScroll(){this.pre.scrollTop=this.textarea.scrollTop;this.pre.scrollLeft=this.textarea.scrollLeft;} 9181onLanguageChange(languageId){if(languageId&&this.embeddedState.languageId!==languageId){this.textarea.focus();this.props.onTextareaFocus();this.embeddedState.languageId=languageId;}}} 9182const syntaxHighlightingEmbedding=__exports.syntaxHighlightingEmbedding={name:"syntaxHighlighting",Component:EmbeddedSyntaxHighlightingComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),getStateChangeManager:(config)=>new StateChangeManager(config),};return __exports;});; 9183 9184/* /html_editor/static/src/others/embedded_components/backend/video/video.js */ 9185odoo.define('@html_editor/others/embedded_components/backend/video/video',['@html_editor/others/embedded_component_utils','@html_editor/utils/url','@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/dropdown/dropdown_item','@html_editor/others/embedded_components/core/video/readonly_video'],function(require){'use strict';let __exports={};const{getEmbeddedProps,StateChangeManager,useEmbeddedState,}=require("@html_editor/others/embedded_component_utils");const{getVideoUrl}=require("@html_editor/utils/url");const{Component,onMounted,onWillDestroy,onWillUnmount,useExternalListener,useRef,}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{ReadonlyEmbeddedVideoComponent}=require("@html_editor/others/embedded_components/core/video/readonly_video");const EmbeddedVideoComponent=__exports.EmbeddedVideoComponent=class EmbeddedVideoComponent extends ReadonlyEmbeddedVideoComponent{static template="html_editor.EmbeddedVideo";static props={platform:{type:String},videoId:{type:String},params:{type:Object,optional:true},host:{type:HTMLElement},createOverlay:{type:Function,optional:true},focusEditable:{type:Function,optional:true},addStep:{type:Function,optional:true},openVideoSelectorDialog:{type:Function,optional:true},};setup(){super.setup();this.videoBlock=this.props.host;this.state=useEmbeddedState(this.videoBlock);this.dropdown=useDropdownState();this.videoSettingsOverlay=this.props.createOverlay(VideoSettings,{positionOptions:{position:"right-start",},className:"video-overlay",closeOnPointerdown:false,});this.iframeRef=useRef("iframeRef");useExternalListener(this.videoBlock,"pointerenter",()=>{this.videoSettingsOverlay.open({target:this.videoBlock,props:{videoBlock:this.videoBlock,overlay:this.videoSettingsOverlay,replaceVideo:()=>{this.props.openVideoSelectorDialog((media)=>{this.replaceVideo(media);},this.iframeRef.el);},removeVideo:()=>{this.videoBlock.remove();this.props.addStep();},focusEditable:this.props.focusEditable,dropdown:this.dropdown,},});});useExternalListener(this.videoBlock,"pointerleave",(e)=>{if(this.dropdown.isOpen||e.relatedTarget?.closest(".video-overlay")){return;} 9186this.videoSettingsOverlay.close();});onWillDestroy(()=>{this.videoSettingsOverlay?.close();});} 9187get url(){return getVideoUrl(this.state.platform,this.state.videoId,this.state.params).toString();} 9188replaceVideo(media){this.state.videoId=media.videoId;this.state.platform=media.platform;this.state.params=media.params;this.props.focusEditable();}} 9189const videoEmbedding=__exports.videoEmbedding={name:"video",Component:EmbeddedVideoComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),getStateChangeManager:(config)=>new StateChangeManager(config),};const VideoSettings=__exports.VideoSettings=class VideoSettings extends Component{static template="html_editor.VideoSettings";static components={Dropdown,DropdownItem};static props={videoBlock:{type:HTMLElement},overlay:{type:Object},replaceVideo:{type:Function},removeVideo:{type:Function},focusEditable:{type:Function},dropdown:{type:Object},};setup(){this.menuRef=useRef("menuRef");onMounted(()=>{this.menuRef.el.addEventListener("pointerleave",()=>{if(!this.props.dropdown.isOpen){this.props.overlay.close();}});});useExternalListener(document,"pointerdown",(ev)=>{if(this.props.dropdown.isOpen){return;} 9190this.props.overlay.close();});onWillUnmount(()=>{if(!this.props.videoBlock.isConnected){this.props.focusEditable();}});}} 9191return __exports;});; 9192 9193/* /html_editor/static/src/others/embedded_components/embedding_sets.js */ 9194odoo.define('@html_editor/others/embedded_components/embedding_sets',['@html_editor/others/embedded_components/backend/file/file','@html_editor/others/embedded_components/core/file/readonly_file','@html_editor/others/embedded_components/core/table_of_content/table_of_content','@html_editor/others/embedded_components/core/toggle_block/toggle_block','@html_editor/others/embedded_components/backend/video/video','@html_editor/others/embedded_components/core/video/readonly_video','@html_editor/others/embedded_components/backend/syntax_highlighting/syntax_highlighting','@html_editor/others/embedded_components/core/syntax_highlighting/readonly_syntax_highlighting'],function(require){'use strict';let __exports={};const{fileEmbedding}=require("@html_editor/others/embedded_components/backend/file/file");const{readonlyFileEmbedding}=require("@html_editor/others/embedded_components/core/file/readonly_file");const{readonlyTableOfContentEmbedding,tableOfContentEmbedding,}=require("@html_editor/others/embedded_components/core/table_of_content/table_of_content");const{toggleBlockEmbedding}=require("@html_editor/others/embedded_components/core/toggle_block/toggle_block");const{videoEmbedding}=require("@html_editor/others/embedded_components/backend/video/video");const{readonlyVideoEmbedding}=require("@html_editor/others/embedded_components/core/video/readonly_video");const{syntaxHighlightingEmbedding}=require("@html_editor/others/embedded_components/backend/syntax_highlighting/syntax_highlighting");const{readonlySyntaxHighlightingEmbedding}=require("@html_editor/others/embedded_components/core/syntax_highlighting/readonly_syntax_highlighting");const MAIN_EMBEDDINGS=__exports.MAIN_EMBEDDINGS=[fileEmbedding,tableOfContentEmbedding,toggleBlockEmbedding,videoEmbedding,syntaxHighlightingEmbedding,];const READONLY_MAIN_EMBEDDINGS=__exports.READONLY_MAIN_EMBEDDINGS=[readonlyFileEmbedding,readonlyTableOfContentEmbedding,toggleBlockEmbedding,readonlyVideoEmbedding,readonlySyntaxHighlightingEmbedding,];return __exports;});; 9195 9196/* /html_editor/static/src/others/embedded_components/plugins/caption_plugin/caption_plugin.js */ 9197odoo.define('@html_editor/others/embedded_components/plugins/caption_plugin/caption_plugin',['@html_editor/plugin','@web/core/l10n/translation','@html_editor/utils/blocks','@web/core/utils/render','@html_editor/utils/dom','@html_editor/utils/dom_traversal','@html_editor/utils/dom_info','@html_editor/utils/position','@html_editor/utils/selection','@html_editor/core/selection_plugin','@html_editor/utils/resource','@html_editor/main/toolbar/toolbar_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{closestBlock,isBlock}=require("@html_editor/utils/blocks");const{renderToElement}=require("@web/core/utils/render");const{unwrapContents}=require("@html_editor/utils/dom");const{closestElement}=require("@html_editor/utils/dom_traversal");const{EDITABLE_MEDIA_CLASS,isParagraphRelatedElement,isVisible,}=require("@html_editor/utils/dom_info");const{boundariesOut,rightPos}=require("@html_editor/utils/position");const{findInSelection}=require("@html_editor/utils/selection");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{withSequence}=require("@html_editor/utils/resource");const{DISABLED_NAMESPACE}=require("@html_editor/main/toolbar/toolbar_plugin");const CAPTION_SPAN_SELECTOR="span.o_caption_editable";const CaptionPlugin=__exports.CaptionPlugin=class CaptionPlugin extends Plugin{static id="caption";static dependencies=["image","split","history","selection","baseContainer","clipboard"];resources={user_commands:[{id:"toggleImageCaption",title:_t("Add/remove a caption"),run:this.toggleImageCaption.bind(this),isAvailable:isHtmlContentSupported,},],toolbar_items:[{id:"image_caption",description:_t("Add/remove a caption"),groupId:"image_description",commandId:"toggleImageCaption",text:_t("Caption"),isActive:()=>this.hasImageCaption(this.dependencies.image.getTargetedImage()),},],clean_for_save_handlers:this.cleanForSave.bind(this),delete_handlers:this.afterDelete.bind(this),before_cut_handlers:this.expandSelectionToCaption.bind(this),before_drag_handlers:this.expandSelectionToCaption.bind(this),delete_image_overrides:this.handleDeleteImage.bind(this),after_save_media_dialog_handlers:this.onImageReplaced.bind(this),hints:[{selector:"FIGCAPTION > .o_caption_editable",text:_t("Write a caption...")}],hint_targets_providers:(selectionData)=>{const captionSpan=closestElement(selectionData.editableSelection.anchorNode,CAPTION_SPAN_SELECTOR);if(captionSpan){return[captionSpan];} 9198return[];},is_formattable_node_predicates:(node)=>{if(closestElement(node,CAPTION_SPAN_SELECTOR)){return false;}},unsplittable_node_predicates:[(node)=>["FIGURE","FIGCAPTION"].includes(node.nodeName),],image_name_predicates:[this.getImageName.bind(this)],link_compatible_selection_predicates:this.isLinkAllowedOnSelection.bind(this),toolbar_namespace_providers:withSequence(70,(targetedNodes
9198)=>{if(targetedNodes.length&&targetedNodes.every((node)=>closestElement(node,CAPTION_SPAN_SELECTOR))){return DISABLED_NAMESPACE;}}),html_drop_overrides:this.onPaste.bind(this),paste_overrides:this.onPaste.bind(this),normalize_handlers:(root)=>{let figures=[];if(root.matches(CAPTION_SPAN_SELECTOR)){figures=[closestElement(root,"figure")];}else{figures=[...root.querySelectorAll("figure")].filter(figure=>figure.querySelectorAll("img").length===1);} 9199figures.forEach((figure)=>{const captionSpan=figure.querySelector(CAPTION_SPAN_SELECTOR);const image=figure.querySelector("IMG");if(image&&image.getAttribute("data-caption")!==captionSpan.textContent){image.setAttribute("data-caption",captionSpan.textContent);} 9200if(captionSpan.textContent){const figcaption=figure.querySelector("figcaption");figcaption.setAttribute("placeholder",captionSpan.textContent);}});},split_element_block_overrides:(params)=>{if(closestElement(params.targetNode,CAPTION_SPAN_SELECTOR)){return true;}},powerbox_blacklist_selectors:CAPTION_SPAN_SELECTOR,are_inlines_allowed_at_root_predicates:(node)=>node.matches(CAPTION_SPAN_SELECTOR),empty_node_predicates:(el)=>el.matches?.("figure")&&el.children.length===1&&el.children[0].matches("figcaption"),move_node_whitelist_selectors:"figure",clipboard_content_processors:this.processContentForClipboard.bind(this),};setup(){const figures=[...this.editable.querySelectorAll("figure")].filter(figure=>figure.querySelectorAll("img").length===1);for(const figure of figures){const image=figure.querySelector("img");figure.before(image);const caption=figure.querySelector("figcaption")?.textContent;figure.remove();this.addImageCaption(image,caption,false);this.dependencies.history.addStep();}} 9201onPaste(selection,clipboardData){const captionSpan=closestElement(selection.anchorNode,CAPTION_SPAN_SELECTOR);if(captionSpan){const pastedTextContent=clipboardData.getData("text/plain");this.dependencies.clipboard.pasteText(pastedTextContent.replace(/\r?\n|\r/g,""));return true;}} 9202getCaptionId(){return""+Math.floor(Math.random()*Date.now());} 9203hasImageCaption(image){if(!image){return;} 9204const block=closestBlock(image.parentElement);return block.nodeName==="FIGURE"&&!!block.querySelector(CAPTION_SPAN_SELECTOR);} 9205toggleImageCaption(image=this.dependencies.image.getTargetedImage()){if(!image){return;} 9206if(this.hasImageCaption(image)){this.removeImageCaption(image);}else{this.addImageCaption(image,image.getAttribute("data-caption")||"");this.dependencies.history.addStep();}} 9207addImageCaption(image,captionText=""){const figure=this.document.createElement("figure");const link=image.parentElement.nodeName==="A"&&image.parentElement;const target=link||image;const blockEl=closestBlock(target.parentElement);if((target.nextSibling||target.previousSibling)&&isParagraphRelatedElement(blockEl)){const block=this.dependencies.split.splitAroundUntil(target,blockEl);if(isBlock(block.previousSibling)&&!isVisible(block.previousSibling)){block.previousSibling.remove();} 9208if(isBlock(block.nextSibling)&&!isVisible(block.nextSibling)){block.nextSibling.remove();}} 9209image.before(figure);figure.append(image);if(!link&&isParagraphRelatedElement(figure.parentElement)){unwrapContents(figure.parentElement);} 9210const captionId=this.getCaptionId();image.setAttribute("data-caption-id",captionId);image.setAttribute("data-caption",captionText||"");figure.setAttribute("contenteditable","false");image.classList.add(EDITABLE_MEDIA_CLASS);const figcaptionEl=renderToElement("html_editor.EmbeddedCaptionBlueprint",{captionId,});figure.append(figcaptionEl);this.setupCaption(figcaptionEl,image);} 9211setupCaption(figcaption,image){const span=figcaption.querySelector(CAPTION_SPAN_SELECTOR);if(span){const captionText=image.getAttribute("data-caption")||"";if(captionText){span.textContent=captionText;figcaption.setAttribute("placeholder",captionText);} 9212this.dependencies.selection.setCursorEnd(span);}} 9213removeImageCaption(image){const figure=closestElement(image,"figure");
9213if(figure){figure.querySelector("figcaption").remove();if(!isParagraphRelatedElement(closestBlock(figure.parentElement))){const baseContainer=this.dependencies.baseContainer.createBaseContainer();if(figure.parentElement.nodeName==="A"){figure.parentElement.before(baseContainer);baseContainer.append(figure.parentElement);}else{figure.before(baseContainer);baseContainer.append(figure);}} 9214unwrapContents(figure);image.removeAttribute("data-caption-id");image.classList.remove(EDITABLE_MEDIA_CLASS);const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesOut(image);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});this.dependencies.history.addStep();}} 9215cleanForSave({root}){const figures=[...root.querySelectorAll("figure")].filter(figure=>figure.querySelectorAll("img").length===1);for(const figure of figures){figure.removeAttribute("contenteditable");const image=figure.querySelector("img");const span=figure.querySelector(CAPTION_SPAN_SELECTOR);const captionText=span?.textContent||image.getAttribute("data-caption")||"";figure.querySelector("figcaption").remove();const newFigcaption=root.ownerDocument.createElement("figcaption");newFigcaption.textContent=captionText;image.removeAttribute("data-caption");image.removeAttribute("data-caption-id");image.classList.remove(EDITABLE_MEDIA_CLASS);image.after(newFigcaption);}} 9216getImageName(image){if(closestElement(image,"figure")){return image.getAttribute("data-caption");}} 9217isLinkAllowedOnSelection(){const figure=findInSelection(this.dependencies.selection.getSelectionData().deepEditableSelection,"figure");
9217if(figure&&this.dependencies.selection.getTargetedNodes().every((node)=>closestElement(node,"figure")===figure)){return true;}} 9218onImageReplaced(media){const figure=closestElement(media,"figure");let anchorNode,anchorOffset;if(figure){if(media.nodeName==="IMG"){[anchorNode,anchorOffset]=rightPos(figure);const span=figure.querySelector(CAPTION_SPAN_SELECTOR);const caption=span?.textContent||"";figure.before(media);figure.remove();this.addImageCaption(media,caption,false);}else{this.removeImageCaption(media);[anchorNode,anchorOffset]=rightPos(media);} 9219this.dependencies.selection.setSelection({anchorNode,anchorOffset});}} 9220afterDelete(){const{anchorNode}=this.dependencies.selection.getEditableSelection();const targetedNodes=this.dependencies.selection.getTargetedNodes();for(const figure of this.editable.querySelectorAll("figure:not(:has(img))")){const isSelectionInFigure=targetedNodes.some((node)=>figure.contains(node))||anchorNode===figure;const sibling=figure.nextSibling||figure.previousSibling;figure.remove();if(isSelectionInFigure){this.dependencies.selection.setSelection({anchorNode:sibling,anchorOffset:0,});}}} 9221handleDeleteImage(image){const figure=closestElement(image,"figure");
9221if(figure){const sibling=figure.nextSibling||figure.previousSibling;figure.remove();this.dependencies.selection.setSelection({anchorNode:sibling,anchorOffset:0,});this.dependencies.history.addStep();return true;}} 9222expandSelectionToCaption(selection){const startFigure=closestElement(selection.anchorNode,"figure");const endFigure=closestElement(selection.focusNode,"figure");if(startFigure&&startFigure===endFigure){const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesOut(startFigure);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset},{normalize:false});}} 9223processContentForClipboard(clonedContents,selection){if(clonedContents.firstChild.nodeName==="IMG"){clonedContents=selection.commonAncestorContainer.cloneNode(true);} 9224return clonedContents;}} 9225return __exports;});; 9226 9227/* /html_editor/static/src/others/embedded_components/plugins/embedded_file_plugin/embedded_file_documents_selector.js */ 9228odoo.define('@html_editor/others/embedded_components/plugins/embedded_file_plugin/embedded_file_documents_selector',['@html_editor/main/media/media_dialog/document_selector','@web/core/utils/render'],function(require){'use strict';let __exports={};const{DocumentSelector}=require("@html_editor/main/media/media_dialog/document_selector");const{renderToElement}=require("@web/core/utils/render");const EmbeddedFileDocumentsSelector=__exports.EmbeddedFileDocumentsSelector=class EmbeddedFileDocumentsSelector extends DocumentSelector{static mediaSpecificClasses=[];static async renderFileElement(attachment){return renderEmbeddedFileBox(attachment);}} 9229__exports.renderEmbeddedFileBox=renderEmbeddedFileBox;function renderEmbeddedFileBox(attachment){const dotSplit=attachment.name.split(".");const extension=dotSplit.length>1?dotSplit.pop():undefined;const fileData={access_token:attachment.access_token,checksum:attachment.checksum,extension,filename:attachment.name,id:attachment.id,mimetype:attachment.mimetype,name:attachment.name,type:attachment.type,url:attachment.url||"",};return renderToElement("html_editor.EmbeddedFileBlueprint",{embeddedProps:JSON.stringify({fileData}),});} 9230return __exports;});; 9231 9232/* /html_editor/static/src/others/embedded_components/plugins/embedded_file_plugin/embedded_file_plugin.js */ 9233odoo.define('@html_editor/others/embedded_components/plugins/embedded_file_plugin/embedded_file_plugin',['@html_editor/utils/dom_info','@html_editor/utils/blocks','@html_editor/others/embedded_components/plugins/embedded_file_plugin/embedded_file_documents_selector','@html_editor/main/media/file_plugin','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{nextLeaf}=require("@html_editor/utils/dom_info");const{isBlock}=require("@html_editor/utils/blocks");const{EmbeddedFileDocumentsSelector,renderEmbeddedFileBox,}=require("@html_editor/others/embedded_components/plugins/embedded_file_plugin/embedded_file_documents_selector");const{FilePlugin}=require("@html_editor/main/media/file_plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const EmbeddedFilePlugin=__exports.EmbeddedFilePlugin=class EmbeddedFilePlugin extends FilePlugin{static id="embeddedFile";static dependencies=[...super.dependencies,"embeddedComponents","selection"];resources={...this.resources,mount_component_handlers:this.setupNewFile.bind(this),};renderDownloadBox(attachment){return renderEmbeddedFileBox(attachment);} 9234isUploadCommandAvailable({anchorNode}){return(super.isUploadCommandAvailable()&&!closestElement(anchorNode,"[data-embedded='clipboard']"));} 9235get componentForMediaDialog(){return EmbeddedFileDocumentsSelector;} 9236setupNewFile({name,env}){if(name==="file"){Object.assign(env.editorShared,{setSelectionAfter:(host)=>{try{const leaf=nextLeaf(host,this.editable);if(!leaf){return;} 9237const leafEl=isBlock(leaf)?leaf:leaf.parentElement;if(isBlock(leafEl)&&leafEl.isContentEditable){this.dependencies.selection.setSelection({anchorNode:leafEl,anchorOffset:0,});}}catch{return;}},});}}} 9238return __exports;});; 9239 9240/* /html_editor/static/src/others/embedded_components/plugins/syntax_highlighting_plugin/syntax_highlighting_plugin.js */ 9241odoo.define('@html_editor/others/embedded_components/plugins/syntax_highlighting_plugin/syntax_highlighting_plugin',['@html_editor/plugin','@html_editor/utils/resource','@html_editor/others/embedded_component_utils','@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils','@html_editor/utils/dom','@web/core/h
9241otkeys/hotkey_service','@html_editor/utils/blocks','@html_editor/main/toolbar/toolbar_plugin','@html_editor/utils/dom_traversal'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{withSequence}=require("@html_editor/utils/resource");const{getEmbeddedProps}=require("@html_editor/others/embedded_component_utils");const{DEFAULT_LANGUAGE_ID,getPreValue,newlinesToLineBreaks,}=require("@html_editor/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils");const{removeInvisibleWhitespace}=require("@html_editor/utils/dom");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{closestBlock}=require("@html_editor/utils/blocks");const{DISABLED_NAMESPACE}=require("@html_editor/main/toolbar/toolbar_plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const CODE_BLOCK_CLASS="o_syntax_highlighting";const CODE_BLOCK_SELECTOR=`div.${CODE_BLOCK_CLASS}`;const SyntaxHighlightingPlugin=__exports.SyntaxHighlightingPlugin=class SyntaxHighlightingPlugin extends Plugin{static id="syntaxHighlighting";static dependencies=["baseContainer","overlay","history","selection","protectedNode","embeddedComponents",];resources={is_node_editable_predicates:(node)=>{if(node?.classList?.contains("o_prism_source")){return true;}},system_attributes:"data-syntax-highlighting-autofocus",mount_component_handlers:this.setupNewCodeBlock.bind(this),normalize_handlers:(root)=>this.addCodeBlocks(root,true),post_undo_handlers:()=>this.addCodeBlocks(this.editable,true),post_redo_handlers:()=>this.addCodeBlocks(this.editable,true),clean_for_save_handlers:withSequence(0,({root})=>this.cleanForSave(root)),before_set_tag_handlers:(el,newTagName,cursors)=>{if(newTagName.toLowerCase()==="pre"){removeInvisibleWhitespace(el,cursors);}},toolbar_namespace_providers:withSequence(70,(targetedNodes)=>{if(targetedNodes.length&&targetedNodes.every((node)=>closestElement(node,".o_syntax_highlighting"))){return DISABLED_NAMESPACE;}}),clipboard_content_processors:(clonedContent)=>this.cleanForSave(clonedContent),link_compatible_selection_predicates:()=>{if(this.document.activeElement.matches("textarea.o_prism_source")){return false;}},};setup(){this.addCodeBlocks();this.addDomListener(this.editable,"keydown",(ev)=>{const arrowHandled=["arrowup","control+arrowup","arrowdown","control+arrowdown"];if(arrowHandled.includes(getActiveHotkey(ev))){this.navigateAroundCodeBlock(ev);}});} 9242navigateAroundCodeBlock(ev){const isArrowUp=ev.key==="ArrowUp";const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!selection.isCollapsed){return;} 9243const anchorNode=selection.anchorNode;const currentBlock=closestBlock(anchorNode);const adjacentBlock=isArrowUp?currentBlock.previousElementSibling:currentBlock.nextElementSibling;if(!adjacentBlock?.matches(CODE_BLOCK_SELECTOR)){return;} 9244const actualSelection=this.document.getSelection();const preserveSelection=this.dependencies.selection.preserveSelection();actualSelection.modify("extend",isArrowUp?"backward":"forward","line");const reachedBlock=closestBlock(actualSelection.focusNode);preserveSelection.restore();if(currentBlock!==reachedBlock){ev.preventDefault();const textarea=adjacentBlock.querySelector("textarea");const position=isArrowUp?textarea.value.length:0;textarea.focus({preventScroll:true});textarea.setSelectionRange(position,position);}} 9245cleanForSave(root){for(const codeBlock of root.querySelectorAll("div.o_syntax_highlighting")){const pre=codeBlock.querySelector("pre");pre.dataset.embedded="readonlySyntaxHighlighting";const embeddedProps=getEmbeddedProps(codeBlock);const value=embeddedProps.value;pre.dataset.languageId=embeddedProps.languageId;codeBlock.before(pre);codeBlock.remove();pre.textContent=value;newlinesToLineBreaks(pre);}} 9246addCodeBlocks(root=this.editable,preserveFocus=false){const targetedNodes=this.dependencies.selection.getTargetedNodes();const nonEmbeddedPres=[...root.querySelectorAll("pre")].filter((pre)=>!pre.closest(CODE_BLOCK_SELECTOR));for(const pre of nonEmbeddedPres){const isPreInSelection=!targetedNodes.some((node)=>!pre.contains(node));const embeddedProps=JSON.stringify({value:getPreValue(pre),languageId:pre.dataset.languageId||DEFAULT_LANGUAGE_ID,});const codeBlock=this.dependencies.embeddedComponents.renderBlueprintToElement("html_editor.EmbeddedSyntaxHighlightingBlueprint",{embeddedProps},()=>{if(preserveFocus&&isPreInSelection){const textarea=codeBlock.querySelector("textarea");if(textarea!==codeBlock.ownerDocument.activeElement){textarea.focus();this.dependencies.history.stageFocus();}}});pre.before(codeBlock);if(isPreInSelection){this.document.getSelection().removeAllRanges();} 9247pre.remove();}} 9248setupNewCodeBlock({name,props}){if(name==="syntaxHighlighting"){Object.assign(props,{onTextareaFocus:()=>this.dependencies.history.stageFocus(),convertToParagraph:({target})=>{this.dependencies.history.stageSelection();const component=target.closest(`[data-embedded='${name}']`);const embeddedProps=getEmbeddedProps(component);const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.textContent=embeddedProps.value;component.replaceWith(baseContainer);newlinesToLineBreaks(baseContainer);this.dependencies.selection.setCursorStart(baseContainer);this.dependencies.history.addStep();},setSelection:(selection)=>this.dependencies.selection.setSelection(selection),});props.host.removeAttribute("data-syntax-highlighting-autofocus");}}} 9249return __exports;});; 9250 9251/* /html_editor/static/src/others/embedded_components/plugins/table_of_content_plugin/table_of_content_plugin.js */ 9252odoo.define('@html_editor/others/embedded_components/plugins/table_of_content_plugin/table_of_content_plugin',['@html_editor/plugin','@web/core/l10n/translation','@web/core/utils/render','@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager','@html_editor/core/selection_plugin','@html_editor/utils/resource','@html_editor/utils/dom_traversal','@html_editor/main/toolbar/toolbar_plugin'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{renderToElement}=require("@web/core/utils/render");const{HEADINGS,TableOfContentManager,}=require("@html_editor/others/embedded_components/core/table_of_content/table_of_content_manager");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{withSequence}=require("@html_editor/utils/resource");const{closestElement}=require("@html_editor/utils/dom_traversal");const{DISABLED_NAMESPACE}=require("@html_editor/main/toolbar/toolbar_plugin");const TableOfContentPlugin=__exports.TableOfContentPlugin=class TableOfContentPlugin extends Plugin{static id="tableOfContent";static dependencies=["dom","selection","embeddedComponents","link","history"];resources={user_commands:[{id:"insertTableOfContent",title:_t("Table of Contents"),description:_t("Highlight the structure (headings)"),icon:"fa-bookmark",run:this.insertTableOfContent.bind(this),isAvailable:isHtmlContentSupported,},],powerbox_items:[{categoryId:"navigation",commandId:"insertTableOfContent",},],restore_savepoint_handlers:()=>this.delayedUpdateTableOfContents(this.editable),history_reset_handlers:()=>this.delayedUpdateTableOfContents(this.editable),history_reset_from_steps_handlers:()=>this.delayedUpdateTableOfContents(this.editable),step_added_handlers:({stepCommonAncestor})=>this.delayedUpdateTableOfContents(stepCommonAncestor),external_step_added_handlers:this.delayedUpdateTableOfContents.bind(this,this.editable),clean_for_save_handlers:this.cleanForSave.bind(this),mount_component_handlers:this.setupNewToc.bind(this),toolbar_namespace_providers:withSequence(70,(targetedNodes
9252)=>{if(targetedNodes.length&&targetedNodes.every((node)=>closestElement(node,`[data-embedded="tableOfContent"]`))){return DISABLED_NAMESPACE;}}),system_classes:["o_embedded_toc_header_highlight"],};setup(){this.manager=new TableOfContentManager({el:this.editable,});this.alive=true;} 9253insertTableOfContent(){const tableOfContentBlueprint=renderToElement("html_editor.TableOfContentBlueprint");this.dependencies.dom.insert(tableOfContentBlueprint);this.dependencies.history.addStep();} 9254cleanForSave({root}){for(const el of root.querySelectorAll(".o_embedded_toc_header_highlight")){el.classList.remove("o_embedded_toc_header_highlight");}} 9255destroy(){super.destroy();this.alive=false;} 9256delayedUpdateTableOfContents(element){const selector=HEADINGS.join(",");if(!(!element||this.manager.structure.headings.length||element.querySelector(selector)||element.closest(selector))){return;} 9257if(this.updateTimeout){window.clearTimeout(this.updateTimeout);} 9258this.updateTimeout=window.setTimeout(()=>{if(!this.alive){return;} 9259this.manager.updateStructure();},500);} 9260setupNewToc({name,props}){if(name==="tableOfContent"){Object.assign(props,{manager:this.manager,});}}} 9261return __exports;});; 9262 9263/* /html_editor/static/src/others/embedded_components/plugins/toggle_block_plugin/toggle_block_plugin.js */ 9264odoo.define('@html_editor/others/embedded_components/plugins/toggle_block_plugin/toggle_block_plugin',['@html_editor/others/embedded_component_utils','@html_editor/plugin','@html_editor/core/selection_plugin','@html_editor/utils/base_container','@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/html','@html_editor/utils/position','@html_editor/utils/resource','@web/core/l10n/translation','@web/core/utils/render','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{getEmbeddedProps}=require("@html_editor/others/embedded_component_utils");const{Plugin}=require("@html_editor/plugin");const{isHtmlContentSupported}=require("@html_editor/core/selection_plugin");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{closestBlock}=require("@html_editor/utils/blocks");const{isEmptyBlock,isParagraphRelatedElement,isTextNode}=require("@html_editor/utils/dom_info");const{childNodes,children,closestElement,firstLeaf,lastLeaf,selectElements,}=require("@html_editor/utils/dom_traversal");const{parseHTML}=require("@html_editor/utils/html");const{childNodeIndex,nodeSize}=require("@html_editor/utils/position");const{withSequence}=require("@html_editor/utils/resource");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"html_editor",...args);const{renderToString}=require("@web/core/utils/render");const{uuid}=require("@web/core/utils/strings");const toggleSelector="[data-embedded='toggleBlock']";const titleSelector="[data-embedded-editable='title']";const contentSelector="[data-embedded-editable='content']";const ToggleBlockPlugin=__exports.ToggleBlockPlugin=class ToggleBlockPlugin extends Plugin{static id="toggleBlock";static dependencies=["baseContainer","delete","dom","embeddedComponents","history","selection","split",];resources={hints:[withSequence(20,{selector:`${toggleSelector} ${titleSelector} > *`,text:_t("Toggle title"),}),withSequence(10,{selector:`${toggleSelector} ${contentSelector}:not(:focus) > ${baseContainerGlobalSelector}:only-child`,text:_t("Add something inside this toggle"),}),],hint_targets_providers:(selectionData,editable)=>[...editable.querySelectorAll(`${toggleSelector} ${contentSelector} > ${baseContainerGlobalSelector}:only-child`),],move_node_blacklist_selectors:`${toggleSelector} ${titleSelector} *`,powerbox_items:[{commandId:"insertToggleBlock",categoryId:"structure",},],shortcuts:[{hotkey:"control+enter",commandId:"switchToggleBlockState"}],user_commands:[{id:"insertToggleBlock",title:_t("Toggle list"),description:_t("Hide Text under foldable toggles"),icon:"fa-caret-square-o-right",isAvailable:(selection)=>isHtmlContentSupported(selection)&&!closestElement(selection.anchorNode,`${toggleSelector} ${titleSelector}`),run:()=>{this.insertToggleBlock();},},{id:"switchToggleBlockState",run:this.manageToggleFromTitle.bind(this),},],normalize_handlers:withSequence(Infinity,this.normalize.bind(this)),delete_backward_overrides:this.handleDeleteBackward.bind(this),delete_forward_overrides:this.handleDeleteForward.bind(this),shift_tab_overrides:this.handleShiftTab.bind(this),split_element_block_overrides:withSequence(1,this.handleSplitElementBlock.bind(this)),tab_overrides:this.handleTab.bind(this),power_buttons_visibility_predicates:this.showPowerButtons.bind(this),before_insert_processors:this.handleInsert.bind(this),};setup(){this.preventDeleteBackwardContentEnd=false;this.selectedToggleEmptyContentSet=new Set();} 9265explodeToggle(toggle){const title=toggle.querySelector(titleSelector);const content=toggle.querySelector(contentSelector);let contentChildren=children(content);if(contentChildren.length===1&&isEmptyBlock(contentChildren[0])){contentChildren=[];} 9266toggle.replaceWith(...children(title),...contentChildren);} 9267forceToggle(toggle,{showContent,restoreSelection}={}){toggle.dispatchEvent(new CustomEvent("forceToggle",{detail:{showContent,restoreSelection}}));} 9268generateUniqueIds(toggles){for(const toggle of toggles){const props=getEmbeddedProps(toggle);props.toggleBlockId=this.getUniqueIdentifier();toggle.dataset.embeddedProps=JSON.stringify(props);}} 9269getClosestToggleContentInfo(node){const toggle=closestElement(node,toggleSelector);const title=toggle?.querySelector(titleSelector);const content=toggle?.querySelector(contentSelector);return content?.contains(node)?{content,title,toggle}:{};} 9270getClosestToggleTitleInfo(node){const toggle=closestElement(node,toggleSelector);const title=toggle?.querySelector(titleSelector);const content=toggle?.querySelector(contentSelector);return title?.contains(node)?{content,title,toggle}:{};} 9271getToggleFromTitleSelection(){const selection=this.dependencies.selection.getEditableSelection();if(!selection.anchorNode){return;} 9272const{toggle}=this.getClosestToggleTitleInfo(selection.anchorNode);return toggle;} 9273getUniqueIdentifier(){return uuid();} 9274getAdjacentToggleBlock(node,direction){const systemNodeSelectors=this.getResource("system_node_selectors").join(",");let sibling=node[`${direction}ElementSibling`];if(systemNodeSelectors&&sibling?.matches(systemNodeSelectors)){sibling.remove();sibling=node[`${direction}ElementSibling`];} 9275return sibling?.matches(toggleSelector)?sibling:null;} 9276handleDeleteBackward(range){for(const handler of[this.handleDeleteBackwardTitleStart,this.handleDeleteBackwardContentEnd,this.handleDeleteBackwardContentStart,this.handleDeleteBackwardAfterToggle,]){if(handler.call(this,range)){return true;}}} 9277handleDeleteBackwardContentEnd({endContainer,endOffset}){const block=closestBlock(endContainer);const isEmptyContainer=isEmptyBlock(endContainer);const leaf=isEmptyContainer?endContainer:firstLeaf(block);const{toggle,content}=this.getClosestToggleContentInfo(endContainer);if(!content||endOffset!==0||childNodeIndex(block)===0||block.nextElementSibling||leaf!==endContainer||!isParagraphRelatedElement(block)||this.preventDeleteBackwardContentEnd||closestBlock(block.parentElement)!==content){return;} 9278toggle.after(block);this.dependencies.selection.setCursorStart(block);return true;} 9279handleDeleteBackwardContentStart({endContainer,endOffset}){const block=closestBlock(endContainer);const leaf=isEmptyBlock(endContainer)?endContainer:firstLeaf(block);const{title,content}=this.getClosestToggleContentInfo(endContainer);if(!content||endOffset!==0||childNodeIndex(block)!==0||leaf!==endContainer||!isParagraphRelatedElement(block)){return;} 9280title.append(block);this.dependencies.selection.setCursorStart(block);this.dependencies.delete.deleteBackward(this.dependencies.selection.getEditableSelection(),"character");return true;} 9281handleDeleteBackwardTitleStart({endContainer,endOffset}){const block=closestBlock(endContainer);const leaf=isEmptyBlock(endContainer)?endContainer:firstLeaf(block);const{toggle,title}=this.getClosestToggleTitleInfo(endContainer);if(!title||endOffset!==0||childNodeIndex(block)!==0||leaf!==endContainer){return;} 9282const cursors=this.dependencies.selection.preserveSelection();this.explodeToggle(toggle);
9282cursors.restore();return true;} 9283handleDeleteBackwardAfterToggle({endContainer,endOffset}){const block=closestBlock(endContainer);const leaf=isEmptyBlock(endContainer)?endContainer:firstLeaf(block);const toggle=this.getAdjacentToggleBlock(block,"previous");if(!toggle||endOffset!==0||leaf!==endContainer){return;} 9284let target=toggle.querySelector(contentSelector);if(target.parentElement.matches(".d-none")){if(!isParagraphRelatedElement(block)){return;} 9285const title=toggle.querySelector(titleSelector);target=title;} 9286target.append(block);this.dependencies.selection.setCursorStart(block);this.preventDeleteBackwardContentEnd=true;this.dependencies.delete.deleteBackward(this.dependencies.selection.getEditableSelection(),"character");this.preventDeleteBackwardContentEnd=false;return true;} 9287handleDeleteForward(range){for(const handler of[this.handleDeleteForwardTitleEnd,this.handleDeleteForwardContentEnd,this.handleDeleteForwardBeforeToggle,]){if(handler.call(this,range)){return true;}}} 9288handleDeleteForwardContentEnd({startContainer,startOffset}){const block=closestBlock(startContainer);const isEmptyContainer=isEmptyBlock(startContainer);const leaf=isEmptyContainer?startContainer:lastLeaf(block);const{toggle,content}=this.getClosestToggleContentInfo(startContainer);if(!content||!((isEmptyContainer&&startOffset===0)||startOffset===nodeSize(startContainer))||block===this.editable||block.nextElementSibling||leaf!==startContainer||!isParagraphRelatedElement(block)){return;} 9289let nextEl=this.getAdjacentToggleBlock(toggle,"next");if(nextEl){this.explodeToggle(nextEl);nextEl=toggle.nextSibling;} 9290if(!isParagraphRelatedElement(nextEl)){return;} 9291content.append(nextEl);this.dependencies.selection.setCursorEnd(block);this.dependencies.delete.deleteForward(this.dependencies.selection.getEditableSelection(),"character");return true;} 9292handleDeleteForwardTitleEnd({startContainer,startOffset}){const block=closestBlock(startContainer);const isEmptyContainer=isEmptyBlock(startContainer);const leaf=isEmptyContainer?startContainer:lastLeaf(block);const{toggle,title,content}=this.getClosestToggleTitleInfo(startContainer);if(!title||!((isEmptyContainer&&startOffset===0)||startOffset===nodeSize(startContainer))||block===this.editable||block.nextElementSibling||leaf!==startContainer){return;} 9293let nextEl;if(content.parentElement.matches(".d-none")){nextEl=this.getAdjacentToggleBlock(toggle,"next");if(nextEl){this.explodeToggle(nextEl);nextEl=toggle.nextSibling;}}else{const systemNodeSelectors=this.getResource("system_node_selectors").join(",");nextEl=content.firstChild;if(systemNodeSelectors&&nextEl?.matches?.(systemNodeSelectors)){nextEl.remove();nextEl=content.firstChild;} 9294if(nextEl?.matches?.(toggleSelector)){this.explodeToggle(nextEl);nextEl=content.firstChild;}} 9295if(nextEl&&(isTextNode(nextEl)||isParagraphRelatedElement(nextEl))){title.append(nextEl);this.dependencies.selection.setCursorEnd(block);this.dependencies.delete.deleteForward(this.dependencies.selection.getEditableSelection(),"character");return true;}} 9296handleDeleteForwardBeforeToggle({startContainer,startOffset}){const block=closestBlock(startContainer);const isEmptyContainer=isEmptyBlock(startContainer);const leaf=isEmptyContainer?startContainer:lastLeaf(block);const toggle=block.nextSibling;if(!toggle?.matches?.(toggleSelector)||!((isEmptyContainer&&startOffset===0)||startOffset===nodeSize(startContainer))||leaf!==startContainer){return;} 9297if(isEmptyBlock(block)){block.remove();const title=toggle.querySelector(titleSelector);this.dependencies.selection.setCursorStart(title.firstElementChild);}else{this.explodeToggle(toggle);this.dependencies.selection.setCursorEnd(block);this.dependencies.delete.deleteForward(this.dependencies.selection.getEditableSelection(),"character");} 9298return true;} 9299handleInsert(insertContainer){const insertedToggles=insertContainer.querySelectorAll(toggleSelector);this.generateUniqueIds(insertedToggles);return insertContainer;} 9300handleShiftTab(){const toggle=this.getToggleFromTitleSelection();if(toggle){const closestToggleAncestor=closestElement(toggle.parentElement,toggleSelector);if(closestToggleAncestor){const cursors=this.dependencies.selection.preserveSelection();const ancestorContent=closestToggleAncestor.querySelector(contentSelector);const containerContent=toggle.querySelector(contentSelector);const siblings=childNodes(ancestorContent).filter((node)=>toggle.compareDocumentPosition(node)&Node.DOCUMENT_POSITION_FOLLOWING);if(isEmptyBlock(containerContent.lastElementChild)){containerContent.lastElementChild.remove();} 9301containerContent.append(...siblings);closestToggleAncestor.after(toggle);this.forceToggle(toggle,{showContent:true,restoreSelection:cursors.restore});this.dependencies.history.addStep();} 9302return true;}} 9303handleSplitElementBlock({targetNode,targetOffset,blockToSplit}){const{toggle,title,content}=this.getClosestToggleTitleInfo(targetNode);
9303if(title){const selection=this.dependencies.selection.getEditableSelection();if(isEmptyBlock(closestBlock(selection.anchorNode))){const contentChildren=children(content);if(contentChildren.length!==1||!isEmptyBlock(contentChildren[0])){toggle.after(...children(content));} 9304const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));toggle.replaceWith(baseContainer);const dir=toggle.getAttribute("dir");if(dir){baseContainer.setAttribute("dir",dir);} 9305this.dependencies.selection.setCursorStart(baseContainer);return true;} 9306const insertBefore=targetOffset===0&&blockToSplit.parentElement===title;const[beforeSplit,afterSplit]=this.dependencies.split.splitElementBlock({targetNode,targetOffset,blockToSplit,});if(beforeSplit&&afterSplit){if(content.parentElement.matches(".d-none")||insertBefore){const newToggle=this.renderToggleBlock();const newToggleBlock=newToggle.querySelector(toggleSelector);const newTitleEl=newToggle.querySelector(titleSelector);const dir=toggle.getAttribute("dir");if(dir){newToggleBlock.setAttribute("dir",dir);} 9307if(insertBefore){toggle.before(newToggle);newTitleEl.replaceChildren(beforeSplit);}else{toggle.after(newToggle);newTitleEl.replaceChildren(afterSplit);}}else{const firstChild=content.firstElementChild;if(isEmptyBlock(firstChild)){firstChild.replaceWith(afterSplit);}else{content.prepend(afterSplit);}} 9308this.dependencies.selection.setCursorStart(afterSplit);} 9309return true;}} 9310handleTab(){const toggle=this.getToggleFromTitleSelection();if(toggle){const previousToggleBlock=this.getAdjacentToggleBlock(toggle,"previous");if(previousToggleBlock){const cursors=this.dependencies.selection.preserveSelection();const previousToggleContent=previousToggleBlock.querySelector(contentSelector);if(children(previousToggleContent).length===1&&isEmptyBlock(previousToggleContent.firstElementChild)){previousToggleContent.replaceChildren(toggle);}else{previousToggleContent.append(toggle);} 9311const content=toggle.querySelector(contentSelector);if(!content.parentElement.matches(".d-none")){toggle.after(...children(content));} 9312this.forceToggle(previousToggleBlock,{showContent:true,restoreSelection:cursors.restore,});this.dependencies.history.addStep();} 9313return true;}} 9314insertToggleBlock(){const block=this.renderToggleBlock();const target=block.querySelector(`${titleSelector} > ${baseContainerGlobalSelector}`);this.dependencies.dom.insert(block);this.dependencies.selection.setCursorStart(target);this.dependencies.history.addStep();} 9315manageToggleFromTitle(){const toggle=this.getToggleFromTitleSelection();if(!toggle){return;} 9316this.forceToggle(toggle);} 9317normalize(element){const cursors=this.dependencies.selection.preserveSelection();let shouldRestoreCursor=false;for(const titleChild of selectElements(element,`${toggleSelector} ${titleSelector} > *:first-child`)){const title=titleChild.parentElement;const toggle=closestElement(title,toggleSelector);if(titleChild.nextElementSibling){const nodes=children(titleChild.parentElement);title.replaceChildren(nodes.shift());toggle.after(...nodes);shouldRestoreCursor=true;} 9318if(!isParagraphRelatedElement(titleChild)){toggle.after(titleChild);shouldRestoreCursor=true;}} 9319if(shouldRestoreCursor){cursors.restore();} 9320for(const emptyToggleNode of selectElements(element,`${toggleSelector} [data-embedded-editable]:empty`)){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));emptyToggleNode.replaceChildren(baseContainer);}} 9321renderToggleBlock(){const baseContainer=this.dependencies.baseContainer.createBaseContainer();return parseHTML(this.document,renderToString("html_editor.EmbeddedToggleBlockBlueprint",{baseContainerNodeName:baseContainer.nodeName,baseContainerAttributes:{class:baseContainer.className,},embeddedProps:JSON.stringify({toggleBlockId:this.getUniqueIdentifier()}),}));} 9322showPowerButtons(selection){return(selection.isCollapsed&&!closestElement(selection.anchorNode,`${toggleSelector} ${titleSelector}`));}} 9323return __exports;});; 9324 9325/* /html_editor/static/src/others/embedded_components/plugins/video_plugin/embedded_video_plugin.js */ 9326odoo.define('@html_editor/others/embedded_components/plugins/video_plugin/embedded_video_plugin',['@html_editor/main/media/video_plugin','@html_editor/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector'],function(require){'use strict';let __exports={};const{VideoPlugin}=require("@html_editor/main/media/video_plugin");const{EmbeddedVideoSelector}=require("@html_editor/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector");const EmbeddedVideoPlugin=__exports.EmbeddedVideoPlugin=class EmbeddedVideoPlugin extends VideoPlugin{static id="embeddedVideo";static dependencies=["embeddedComponents","selection","history","overlay","media"];
9326resources={...this.resources,mount_component_handlers:this.extendEmbeddedVideoProps.bind(this),};get componentForMediaDialog(){return EmbeddedVideoSelector;} 9327extendEmbeddedVideoProps({name,props}){if(name==="video"){Object.assign(props,{createOverlay:(Component,props={},options)=>this.dependencies.overlay.createOverlay(Component,props,options),focusEditable:()=>this.dependencies.selection.focusEditable(),addStep:()=>this.dependencies.history.addStep(),openVideoSelectorDialog:(save,media)=>{this.openVideoSelectorDialog(save,media);},});}} 9328openVideoSelectorDialog(save,iframe){this.dependencies.media.openMediaDialog({node:iframe,save:(elements,[media])=>{if(media.src){save(media);}},visibleTabs:["VIDEOS"],});}} 9329return __exports;});; 9330 9331/* /html_editor/static/src/others/embedded_components/plugins/video_plugin/embedded_youtube_plugin.js */ 9332odoo.define('@html_editor/others/embedded_components/plugins/video_plugin/embedded_youtube_plugin',['@html_editor/main/youtube_plugin','@html_editor/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector'],function(require){'use strict';let __exports={};const{YoutubePlugin}=require("@html_editor/main/youtube_plugin");const{EmbeddedVideoSelector}=require("@html_editor/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector");const EmbeddedYoutubePlugin=__exports.EmbeddedYoutubePlugin=class EmbeddedYoutubePlugin extends YoutubePlugin{static id="embeddedYoutube";static dependencies=[...super.dependencies,"embeddedComponents"];mediaSpecificClasses=EmbeddedVideoSelector.mediaSpecificClasses;createVideoElement(videoData){const{video_id:videoId,platform,params}=videoData;return EmbeddedVideoSelector.createElements([{videoId,platform,params}])[0];}} 9333return __exports;});; 9334 9335/* /html_editor/static/src/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector.js */ 9336odoo.define('@html_editor/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector',['@html_editor/main/media/media_dialog/video_selector','@web/core/utils/render'],function(require){'use strict';let __exports={};const{VideoSelector}=require("@html_editor/main/media/media_dialog/video_selector");const{renderToElement}=require("@web/core/utils/render");const EmbeddedVideoSelector=__exports.EmbeddedVideoSelector=class EmbeddedVideoSelector extends VideoSelector{static mediaSpecificClasses=[];static createElements(selectedMedia){return selectedMedia.map((media)=>renderToElement("html_editor.EmbeddedVideoBlueprint",{embeddedProps:JSON.stringify({videoId:media.videoId,platform:media.platform,params:media.params||{},}),}));}} 9337return __exports;});; 9338 9339/* /html_editor/static/src/others/embedded_component_plugin.js */ 9340odoo.define('@html_editor/others/embedded_component_plugin',['@html_editor/core/history_plugin','@html_editor/plugin','@html_editor/utils/resource','@html_editor/utils/dom_traversal','@web/core/utils/functions','@web/core/utils/render'],function(require){'use strict';let __exports={};const{nodeToTree}=require("@html_editor/core/history_plugin");const{Plugin}=require("@html_editor/plugin");const{withSequence}=require("@html_editor/utils/resource");const{selectElements}=require("@html_editor/utils/dom_traversal");const{memoize}=require("@web/core/utils/functions");const{renderToElement}=require("@web/core/utils/render");const EmbeddedComponentPlugin=__exports.EmbeddedComponentPlugin=class EmbeddedComponentPlugin extends Plugin{static id="embeddedComponents";static dependencies=["history","protectedNode","selection"];static shared=["renderBlueprintToElement"];resources={normalize_handlers:withSequence(0,this.normalize.bind(this)),clean_for_save_handlers:({root})=>this.cleanForSave(root),attribute_change_handlers:this.onChangeAttribute.bind(this),restore_savepoint_handlers:()=>this.handleComponents(this.editable),history_reset_handlers:()=>this.handleComponents(this.editable),history_reset_from_steps_handlers:()=>this.handleComponents(this.editable),step_added_handlers:({stepCommonAncestor})=>this.handleComponents(stepCommonAncestor),external_step_added_handlers:()=>this.handleComponents(this.editable),before_sanitize_processors:this.preProcessSanitizedElem.bind(this),after_sanitize_processors:this.postProcessSanitizedElem.bind(this),serializable_descendants_processors:this.processDescendantsToSerialize.bind(this),attribute_change_processors:this.onChangeAttribute.bind(this),savable_mutation_record_predicates:this.isMutationRecordSavable.bind(this),move_node_whitelist_selectors:"[data-embedded]",};setup(){this.components=new Set();this.nodeMap=new WeakMap();this.app=this.config.embeddedComponentInfo.app;this.env=this.config.embeddedComponentInfo.env??{};this.hostToStateChangeManagerMap=new WeakMap();this.hostToOnComponentInsertedMap=new WeakMap();this.embeddedComponents=memoize((embeddedComponents=[])=>{const result={};for(const embedding of embeddedComponents){result[embedding.name]=embedding;} 9341return result;});} 9342isMutationRecordSavable(record){const info=this.nodeMap.get(record.target);if(info&&record.type==="attributes"&&record.attributeName==="data-embedded-props"){return false;} 9343return true;} 9344processDescendantsToSerialize(elem,serializableDescendants){const embedding=this.getEmbedding(elem);if(!embedding){return serializableDescendants;} 9345return Object.values(embedding.getEditableDescendants?.(elem)||{}).map(nodeToTree);} 9346handleComponents(elem){this.destroyRemovedComponents([...this.components]);this.forEachEmbeddedComponentHost(elem,(host,embedding)=>{const info=this.nodeMap.get(host);if(!info){this.mountComponent(host,embedding);}});} 9347forEachEmbeddedComponentHost(elem,callback){const selector=`[data-embedded]`;const targets=[...elem.querySelectorAll(selector)];if(elem.matches(selector)){targets.unshift(elem);} 9348for(const host of targets){const embedding=this.getEmbedding(host);if(!embedding){continue;} 9349callback(host,embedding);}} 9350getEmbedding(host){return this.embeddedComponents(this.getResource("embedded_components"))[host.dataset.embedded];} 9351onChangeAttribute(attributeChange,{forNewStep=false}={}){const attributeValue=attributeChange.value;let newAttributeValue;if(attributeChange.attributeName==="data-embedded-state"){const attrState=attributeChange.reverse?attributeChange.oldValue:attributeChange.value;const stateChangeManager=this.getStateChangeManager(attributeChange.target);if(stateChangeManager){newAttributeValue=stateChangeManager.onStateChanged(attrState,{reverse:attributeChange.reverse,forNewStep,});}} 9352return newAttributeValue||attributeValue;} 9353getStateChangeManager(host){const embedding=this.getEmbedding(host);if(!("getStateChangeManager"in embedding)){return null;} 9354if(!this.hostToStateChangeManagerMap.has(host)){const config={host,commitStateChanges:()=>this.dependencies.history.addStep(),};const stateChangeManager=embedding.getStateChangeManager(config);stateChangeManager.setup();this.hostToStateChangeManagerMap.set(host,stateChangeManager);} 9355return this.hostToStateChangeManagerMap.get(host);} 9356mountComponent(host,{Component,getEditableDescendants,getProps,name,getStateChangeManager}){const props=getProps?.(host)||{};const env=Object.create(this.env);env.editorShared={};if(getStateChangeManager){env.getStateChangeManager=this.getStateChangeManager.bind(this);} 9357if(getEditableDescendants){env.getEditableDescendants=getEditableDescendants;Object.assign(env.editorShared,{selection:{...this.dependencies.selection},});} 9358this.dispatchTo("mount_component_handlers",{name,env,props});const root=this.app.createRoot(Component,{props,env,});root.mount(host);const fiber=root.node.fiber;const fiberComplete=fiber.complete;fiber.complete=()=>{host.replaceChildren();fiberComplete.call(fiber);this.dispatchTo("post_mount_component_handlers");};const onComponentInserted=this.extractOnComponentInserted(host);if(onComponentInserted){root.node.mounted.push(onComponentInserted);} 9359const info={root,host,};this.components.add(info);this.nodeMap.set(host,info);} 9360destroyRemovedComponents(infos){this.dependencies.history.ignoreDOMMutations(()=>{for(const info of infos){if(!this.editable.contains(info.host)){const host=info.host;const display=host.style.display;const parentNode=host.parentNode;const clone=host.cloneNode(false);
9360if(parentNode){parentNode.replaceChild(clone,host);} 9361host.style.display="none";this.editable.after(host);this.destroyComponent(info);if(parentNode){parentNode.replaceChild(host,clone);}else{host.remove();} 9362host.style.display=display;if(!host.getAttribute("style")){host.removeAttribute("style");}}}});} 9363deepDestroyComponent({host}){const removed=[];this.forEachEmbeddedComponentHost(host,(containedHost)=>{const info=this.nodeMap.get(containedHost);if(info){if(this.editable.contains(containedHost)){this.destroyComponent(info);}else{removed.push(info);}}});this.destroyRemovedComponents(removed);} 9364destroyComponent({root,host}){const{getEditableDescendants}=this.getEmbedding(host);const editableDescendants=getEditableDescendants?.(host)||{};root.destroy();this.components.delete(arguments[0]);this.nodeMap.delete(host);host.append(...Object.values(editableDescendants));} 9365destroy(){super.destroy();for(const info of[...this.components]){if(this.components.has(info)){this.deepDestroyComponent(info);}}} 9366renderBlueprintToElement(template,context={},onComponentInserted=undefined){const host=renderToElement(template,context);if(onComponentInserted){this.hostToOnComponentInsertedMap.set(host,onComponentInserted);} 9367return host;} 9368extractOnComponentInserted(host){const onComponentInserted=this.hostToOnComponentInsertedMap.get(host);this.hostToOnComponentInsertedMap.delete(host);return onComponentInserted;} 9369normalize(elem){this.forEachEmbeddedComponentHost(elem,(host,{getEditableDescendants})=>{this.dependencies.protectedNode.setProtectingNode(host,true);const editableDescendants=getEditableDescendants?.(host)||{};for(const editableDescendant of Object.values(editableDescendants)){this.dependencies.protectedNode.setProtectingNode(editableDescendant,false);}});} 9370cleanForSave(clone){this.forEachEmbeddedComponentHost(clone,(host,{getEditableDescendants})=>{const editableDescendants=getEditableDescendants?.(host)||{};host.replaceChildren();for(const editableDescendant of Object.values(editableDescendants)){delete editableDescendant.dataset.oeProtected;host.append(editableDescendant);} 9371delete host.dataset.oeProtected;delete host.dataset.embeddedState;});} 9372preProcessSanitizedElem(elem){if(elem?.nodeType!==Node.ELEMENT_NODE){return elem;} 9373for(const host of selectElements(elem,"[data-embedded-props], [data-embedded-state]")){if(host.dataset.embeddedProps){host.dataset.embeddedProps=encodeURIComponent(host.dataset.embeddedProps);} 9374if(host.dataset.embeddedState){host.dataset.embeddedState=encodeURIComponent(host.dataset.embeddedState);}} 9375return elem;}
9376postProcessSanitizedElem(elem){if(elem?.nodeType!==Node.ELEMENT_NODE){return elem;} 9377for(const host of selectElements(elem,"[data-embedded-props], [data-embedded-state]")){if(host.dataset.embeddedProps){host.dataset.embeddedProps=decodeURIComponent(host.dataset.embeddedProps);} 9378if(host.dataset.embeddedState){host.dataset.embeddedState=decodeURIComponent(host.dataset.embeddedState);}} 9379return elem;}} 9380return __exports;});; 9381 9382/* /html_editor/static/src/others/qweb_picker.js */ 9383odoo.define('@html_editor/others/qweb_picker',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const QWebPicker=__exports.QWebPicker=class QWebPicker extends Component{static template="html_editor.QWebPicker";static props=["groups","select"];setup(){this.state=useState({groups:this.props.groups});} 9384onChange(ev){const[groupIndex,elementIndex]=ev.target.value.split(",");this.props.select(this.state.groups[groupIndex][elementIndex].node);}} 9385return __exports;});; 9386 9387/* /html_editor/static/src/others/qweb_plugin.js */ 9388odoo.define('@html_editor/others/qweb_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@html_editor/utils/position','@html_editor/others/qweb_picker','@html_editor/utils/dom_info','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement,selectElements}=require("@html_editor/utils/dom_traversal");const{leftPos,rightPos}=require("@html_editor/utils/position");const{QWebPicker}=require("@html_editor/others/qweb_picker");const{isElement,PROTECTED_QWEB_SELECTOR}=require("@html_editor/utils/dom_info");const{withSequence}=require("@html_editor/utils/resource");const isUnsplittableQWebElement=(node)=>isElement(node)&&(node.tagName==="T"||["t-field","t-if","t-elif","t-else","t-foreach","t-value","t-esc","t-out","t-raw",].some((attr)=>node.getAttribute(attr)));const QWEB_DATA_ATTRIBUTES=["data-oe-t-group","data-oe-t-inline","data-oe-t-selectable","data-oe-t-group-active",];const dataAttributesSelector=QWEB_DATA_ATTRIBUTES.map((attr)=>`[${attr}]`).join(", ");const isUnremovableQWebElement=__exports.isUnremovableQWebElement=(node)=>node.getAttribute?.("t-set")||node.getAttribute?.("t-call");const QWebPlugin=__exports.QWebPlugin=class QWebPlugin extends Plugin{static id="qweb";static dependencies=["overlay","protectedNode","selection"];resources={selectionchange_handlers:withSequence(8,this.onSelectionChange.bind(this)),clean_for_save_handlers:({root})=>{this.clearDataAttributes(root);for(const element of root.querySelectorAll(PROTECTED_QWEB_SELECTOR)){element.removeAttribute("contenteditable");delete element.dataset.oeProtected;}},normalize_handlers:withSequence(0,this.normalize.bind(this)),system_attributes:QWEB_DATA_ATTRIBUTES,unremovable_node_predicates:isUnremovableQWebElement,unsplittable_node_predicates:isUnsplittableQWebElement,clipboard_content_processors:this.clearDataAttributes.bind(this),legit_empty_link_predicates:(linkEl)=>linkEl.getAttributeNames().some((name)=>name.startsWith("t-")),};setup(){this.editable.classList.add("odoo-editor-qweb");this.picker=this.dependencies.overlay.createOverlay(QWebPicker,{positionOptions:{position:"top-start"},});this.addDomListener(this.editable,"click",this.onClick);this.groupIndex=0;} 9389isValidTargetForDomListener(ev){if(ev.type==="click"&&ev.target&&closestElement(ev.target,PROTECTED_QWEB_SELECTOR)){return true;} 9390return super.isValidTargetForDomListener(ev);} 9391onSelectionChange(){if(this.picker.isOpen){this.picker.close();}} 9392normalize(root){this.normalizeInline(root);for(const element of selectElements(root,PROTECTED_QWEB_SELECTOR)){this.dependencies.protectedNode.setProtectingNode(element,true);} 9393this.applyGroupQwebBranching(root);} 9394checkAllInline(el){return[...el.children].every((child)=>{if(child.tagName==="T"){return this.checkAllInline(child);}else{return(child.nodeType!==Node.ELEMENT_NODE||this.window.getComputedStyle(child).display==="inline");}});} 9395normalizeInline(root){const targets=[...root.querySelectorAll("t")];if(root.matches("t")){targets.unshift(root);} 9396for(const el of targets.filter((el)=>this.checkAllInline(el))){el.setAttribute("data-oe-t-inline","true");}} 9397getNodeGroups(node){const branchNode=node.closest("[data-oe-t-group]");if(!branchNode){return[];} 9398const groupId=branchNode.getAttribute("data-oe-t-group");const group=[];for(const node of branchNode.parentElement.querySelectorAll(`[data-oe-t-group='${groupId}']`)){let label="";if(node.hasAttribute("t-if")){label=`if: ${node.getAttribute("t-if")}`;}else if(node.hasAttribute("t-elif")){label=`elif: ${node.getAttribute("t-elif")}`;}else if(node.hasAttribute("t-else")){label="else";} 9399group.push({groupId,node,label,isActive:node.getAttribute("data-oe-t-group-active")==="true",});} 9400return this.getNodeGroups(branchNode.parentElement).concat([group]);} 9401onClick(ev){if(this.picker.isOpen){this.picker.close();} 9402if(ev.detail>1){const selectionData=this.dependencies.selection.getSelectionData();const selection=selectionData.documentSelection;const qwebNode=selection&&selection.anchorNode&&closestElement(selection.anchorNode,PROTECTED_QWEB_SELECTOR);if(qwebNode&&this.editable.contains(qwebNode)){const[anchorNode,anchorOffset]=leftPos(qwebNode);const[focusNode,focusOffset]=rightPos(qwebNode);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focu
9402sNode,focusOffset,});}} 9403const targetNode=ev.target;if(targetNode.closest("[data-oe-t-group]")){this.selectNode(targetNode);}} 9404selectNode(node){const editableSelection=this.dependencies.selection.getSelectionData().editableSelection;if(!editableSelection.isCollapsed){return;} 9405this.selectedNode=node;this.picker.open({target:node,props:{groups:this.getNodeGroups(node),select:this.select.bind(this),},});} 9406applyGroupQwebBranching(root){const tNodes=selectElements(root,"[t-if], [t-elif], [t-else]");const groupsEncounter=new Set();for(const node of tNodes){const prevNode=node.previousElementSibling;let groupId;if(prevNode&&!node.hasAttribute("t-if")){prevNode.setAttribute("data-oe-t-selectable","true");groupId=parseInt(prevNode.getAttribute("data-oe-t-group"));node.setAttribute("data-oe-t-selectable","true");}else{groupId=this.groupIndex++;} 9407groupsEncounter.add(groupId);node.setAttribute("data-oe-t-group",groupId);} 9408for(const groupId of groupsEncounter){const isOneElementActive=root.querySelector(`[data-oe-t-group='${groupId}'][data-oe-t-group-active]`);if(!isOneElementActive){const firstElementToActivate=selectElements(root,`[data-oe-t-group='${groupId}']`).next().value;firstElementToActivate.setAttribute("data-oe-t-group-active","true");}}} 9409select(node){const groupId=node.getAttribute("data-oe-t-group");const activeElement=node.parentElement.querySelector(`[data-oe-t-group='${groupId}'][data-oe-t-group-active]`);if(activeElement===node){return;} 9410activeElement.removeAttribute("data-oe-t-group-active");node.setAttribute("data-oe-t-group-active","true");this.selectedNode=node;this.picker.close();this.selectNode(node);const selection=this.document.getSelection();selection.removeAllRanges();} 9411clearDataAttributes(root){for(const node of root.querySelectorAll(dataAttributesSelector)){QWEB_DATA_ATTRIBUTES.forEach((attr)=>node.removeAttribute(attr));}}} 9412return __exports;});; 9413 9414/* /html_editor/static/src/services/upload_local_files_service.js */ 9415odoo.define('@html_editor/services/upload_local_files_service',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const uploadLocalFileService=__exports.uploadLocalFileService={dependencies:["upload","orm"],start(env,{upload:uploadService,orm}){const input=document.createElement("input");input.type="file";async function selectLocalFiles({multiple,accept}){input.multiple=multiple;input.accept=accept;input.value="";input.click();await new Promise((resolve)=>{const resolveAndClear=()=>{resolve();input.removeEventListener("change",resolveAndClear);input.removeEventListener("cancel",resolveAndClear);};input.addEventListener("change",resolveAndClear);input.addEventListener("cancel",resolveAndClear);});return input.files;} 9416async function filesToAttachments(files,{resModel,resId},setAbortCallback){const attachments=[];await uploadService.uploadFiles(files,{resModel,resId},(attachment)=>{attachments.push(attachment);},setAbortCallback);return attachments;} 9417async function upload({resId,resModel},{accept="*/*",multiple=false,accessToken=false,setAbortCallback=()=>{},}={}){try{const files=await selectLocalFiles({multiple,accept});const attachments=await filesToAttachments(files,{resModel,resId},setAbortCallback);if(accessToken&&attachments.length&&!attachments[0].public){await addAccessToken(attachments);} 9418return attachments;}catch{return[];}} 9419async function addAccessToken(attachments){const accessTokens=await orm.call("ir.attachment","generate_access_token",[attachments.map((a)=>a.id),]);attachments.forEach((attachment,index)=>{attachment.access_token=accessTokens[index];});return attachments;} 9420function getURL(attachment,{unique,download,accessToken}={}){let url=`/web/content/${attachment.id}`;const queryParams=[];if(unique){queryParams.push(`unique=${encodeURIComponent(attachment.checksum)}`);} 9421if(download){queryParams.push("download=true");} 9422if(accessToken&&attachment.access_token){queryParams.push(`access_token=${attachment.access_token}`);} 9423if(queryParams.length){url+=`?${queryParams.join("&")}`;} 9424return url;} 9425return{upload,addAccessToken,getURL};},};registry.category("services").add("uploadLocalFiles",uploadLocalFileService);return __exports;});; 9426 9427/* /mail/static/src/model/export.js */ 9428odoo.define('@mail/model/export',['@mail/model/store','@mail/model/record','@mail/model/make_store','@mail/model/misc'],function(require){'use strict';let __exports={};Object.assign(__exports,require("@mail/model/store"));Object.assign(__exports,require("@mail/model/record"));Object.assign(__exports,require("@mail/model/make_store"));{const{AND,OR,fields}=require("@mail/model/misc");Object.assign(__exports,{AND,OR,fields})};return __exports;});; 9429 9430/* /mail/static/src/model/make_store.js */ 9431odoo.define('@mail/model/make_store',['@odoo/owl','@mail/model/store','@mail/model/misc','@mail/model/record','@mail/model/store_internal','@mail/model/model_internal','@mail/model/record_internal'],function(require){'use strict';let __exports={};const{markRaw,reactive,toRaw}
9431=require("@odoo/owl");const{Store}=require("@mail/model/store");const{STORE_SYM,isFieldDefinition,isMany,isRelation,modelRegistry}=require("@mail/model/misc");const{Record}=require("@mail/model/record");const{StoreInternal}=require("@mail/model/store_internal");const{ModelInternal}=require("@mail/model/model_internal");const{RecordInternal}=require("@mail/model/record_internal");__exports.makeStore=makeStore;function makeStore(env,{localRegistry}={}){const recordByLocalId=reactive(new Map());let store=new Store();store.env=env;store.Model=Store;store._=markRaw(new StoreInternal());store._raw=store;store._proxyInternal=store;store._proxy=store;store.recordByLocalId=recordByLocalId;Record.store=store;const Models={};const chosenModelRegistry=localRegistry??modelRegistry;for(const[,_OgClass]of chosenModelRegistry.getEntries()){const OgClass=_OgClass;if(store[OgClass.getName()]){throw new Error(`There must be no duplicated Model Names (duplicate found: ${OgClass.getName()})`);} 9432const Model=Object.create(OgClass);const Class={[OgClass.getName()]:class extends OgClass{constructor(){super();this.setup();const record=this;record._raw=record;record.Model=Model;record._=markRaw(record[STORE_SYM]?new StoreInternal():new RecordInternal());const recordProxyInternal=new Proxy(record,{get(record,name,recordFullProxy){recordFullProxy=record._.downgradeProxy(record,recordFullProxy);if(record._.gettingField||!Model._.fields.get(name)){let res=Reflect.get(...arguments);if(typeof res==="function"){res=res.bind(recordFullProxy);} 9433return res;} 9434if(Model._.fieldsCompute.get(name)&&!Model._.fieldsEager.get(name)){record._.fieldsComputeInNeed.set(name,true);if(record._.fieldsComputeOnNeed.get(name)){record._.compute(record,name);}} 9435if(Model._.fieldsSort.get(name)&&!Model._.fieldsEager.get(name)){record._.fieldsSortInNeed.set(name,true);if(record._.fieldsSortOnNeed.get(name)){record._.sort(record,name);}} 9436record._.gettingField=true;const val=recordFullProxy[name];record._.gettingField=false;if(isRelation(Model,name)){const recordListFullProxy=val._proxy;if(isMany(Model,name)){return recordListFullProxy;} 9437return recordListFullProxy[0];} 9438return Reflect.get(record,name,recordFullProxy);},deleteProperty(record,name){return store.MAKE_UPDATE(function recordDeleteProperty(){if(isRelation(Model,name)){const recordList=record[name];recordList.clear();return true;} 9439return Reflect.deleteProperty(record,name);});},set(record,name,val,receiver){if(record._.updatingAttrs.has(name)){record[name]=val;return true;} 9440return store.MAKE_UPDATE(function recordSet(){const reactiveSet=receiver!==record._proxyInternal;if(reactiveSet){record._.proxyUsed.set(name,true);} 9441store._.updateFields(record,{[name]:val});if(reactiveSet){record._.proxyUsed.delete(name);} 9442return true;});},});record._proxyInternal=recordProxyInternal;const recordProxy=reactive(recordProxyInternal);record._proxy=recordProxy;if(record?.[STORE_SYM]){record.recordByLocalId=store.recordByLocalId;record._=markRaw(toRaw(store._));store=record;Record.store=store;} 9443for(const name of Model._.fields.keys()){record._.prepareField(record,name,recordProxy);} 9444return recordProxy;}},}[OgClass.getName()];Model._=markRaw(new ModelInternal());Object.assign(Model,{Class,records:reactive({}),});Models[Model.getName()]=Model;store[Model.getName()]=Model;const obj=new OgClass();obj.setup();for(const[name,val]of Object.entries(obj)){if(isFieldDefinition(val)){Model._.prepareField(name,val);}}} 9445for(const Model of Object.values(Models)){for(const name of Model._.fields.keys()){if(!isRelation(Model,name)){continue;} 9446const targetModel=Model._.fieldsTargetModel.get(name);const inverse=Model._.fieldsInverse.get(name);if(targetModel&&!Models[targetModel]){throw new Error(`No target model ${targetModel} exists`);} 9447if(inverse){const OtherModel=Models[targetModel];const rel2TargetModel=OtherModel._.fieldsTargetModel.get(inverse);const rel2Inverse=OtherModel._.fieldsInverse.get(inverse);if(rel2TargetModel&&rel2TargetModel!==Model.getName()){throw new Error(`Fields ${Models[ 9448 targetModel 9449 ].getName()}.${inverse} has wrong targetModel. Expected: "${Model.getName()}" Actual: "${rel2TargetModel}"`);} 9450if(rel2Inverse&&rel2Inverse!==name){throw new Error(`Fields ${Models[ 9451 targetModel 9452 ].getName()}.${inverse} has wrong inverse. Expected: "${name}" Actual: "${rel2Inverse}"`);} 9453OtherModel._.fieldsTargetModel.set(inverse,Model.getName());OtherModel._.fieldsInverse.set(inverse,name);Model._.fieldsEager.set(name,true);OtherModel._.fieldsEager.set(inverse,true);}}} 9454Object.assign(store.Store,{store,_rawStore:store});
9454store=toRaw(store.Store.insert())._raw;for(const Model of Object.values(Models)){Model._rawStore=store;Model.store=store._proxy;store._proxy[Model.getName()]=Model;} 9455Object.assign(store,{Models,storeReady:true});return store._proxy;} 9456return __exports;});; 9457 9458/* /mail/static/src/model/misc.js */ 9459odoo.define('@mail/model/misc',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const modelRegistry=__exports.modelRegistry=registry.category("discuss.model");const FIELD_DEFINITION_SYM=__exports.FIELD_DEFINITION_SYM=Symbol("field_definition");const ATTR_SYM=__exports.ATTR_SYM=Symbol("attr");const MANY_SYM=__exports.MANY_SYM=Symbol("many");const ONE_SYM=__exports.ONE_SYM=Symbol("one");const OR_SYM=__exports.OR_SYM=Symbol("or");const AND_SYM=Symbol("and");const IS_RECORD_SYM=__exports.IS_RECORD_SYM=Symbol("isRecord");const IS_FIELD_SYM=__exports.IS_FIELD_SYM=Symbol("isField");const IS_DELETING_SYM=__exports.IS_DELETING_SYM=Symbol("isDeleting");const IS_DELETED_SYM=__exports.IS_DELETED_SYM=Symbol("isDeleted");const STORE_SYM=__exports.STORE_SYM=Symbol("store");__exports.AND=AND;function AND(...args){return[AND_SYM,...args];} 9460__exports.OR=OR;function OR(...args){return[OR_SYM,...args];} 9461__exports.isCommand=isCommand;function isCommand(data){return["ADD","DELETE","ADD.noinv","DELETE.noinv"].includes(data?.[0]?.[0]);} 9462__exports.isOne=isOne;function isOne(Model,fieldName){return Model._.fieldsOne.get(fieldName);} 9463__exports.isMany=isMany;function isMany(Model,fieldName){return Model._.fieldsMany.get(fieldName);} 9464__exports.isRecord=isRecord;function isRecord(record){return Boolean(record?._?.[IS_RECORD_SYM]);} 9465__exports.isRelation=isRelation;function isRelation(Model,fieldName){return isMany(Model,fieldName)||isOne(Model,fieldName);} 9466__exports.isFieldDefinition=isFieldDefinition;function isFieldDefinition(val){return val?.[FIELD_DEFINITION_SYM];} 9467const fields=__exports.fields={One(targetModel,param1){return{...param1,targetModel,[FIELD_DEFINITION_SYM]:true,[ONE_SYM]:true};},Many(targetModel,param1){return{...param1,targetModel,[FIELD_DEFINITION_SYM]:true,[MANY_SYM]:true};},Attr(def,param1){return{...param1,[FIELD_DEFINITION_SYM]:true,[ATTR_SYM]:true,default:def};},Html(def,param1){const definition={...param1,[FIELD_DEFINITION_SYM]:true,[ATTR_SYM]:true,default:def,};definition.html=true;return definition;},Date(param0){return{...param0,[FIELD_DEFINITION_SYM]:true,[ATTR_SYM]:true,type:"date",};},Datetime(param0){return{...param0,[FIELD_DEFINITION_SYM]:true,[ATTR_SYM]:true,type:"datetime",};},};return __exports;});; 9468 9469/* /mail/static/src/model/model_internal.js */ 9470odoo.define('@mail/model/model_internal',['@mail/model/misc'],function(require){'use strict';let __exports={};const{ATTR_SYM,MANY_SYM,ONE_SYM}=require("@mail/model/misc");const ModelInternal=__exports.ModelInternal=class ModelInternal{fields=new Map();fieldsAttr=new Map();fieldsOne=new Map();fieldsMany=new Map();fieldsHtml=new Map();fieldsTargetModel=new Map();fieldsCompute=new Map();fieldsEager=new Map();fieldsInverse=new Map();fieldsOnAdd=new Map();fieldsOnDelete=new Map();fieldsOnUpdate=new Map();fieldsSort=new Map();fieldsType=new Map();prepareField(fieldName,data){this.fields.set(fieldName,true);if(data[ATTR_SYM]){this.fieldsAttr.set(fieldName,true);} 9471if(data[ONE_SYM]){this.fieldsOne.set(fieldName,true);} 9472if(data[MANY_SYM]){this.fieldsMany.set(fieldName,true);} 9473for(const key in data){const value=data[key];switch(key){case"html":{if(!value){break;} 9474this.fieldsHtml.set(fieldName,value);break;} 9475case"targetModel":{this.fieldsTargetModel.set(fieldName,value);break;} 9476case"compute":{this.fieldsCompute.set(fieldName,value);break;} 9477case"eager":{if(!value){break;} 9478this.fieldsEager.set(fieldName,value);break;} 9479case"sort":{this.fieldsSort.set(fieldName,value);break;} 9480case"inverse":{this.fieldsInverse.set(fieldName,value);break;} 9481case"onAdd":{this.fieldsOnAdd.set(fieldName,value);break;} 9482case"onDelete":{this.fieldsOnDelete.set(fieldName,value);break;} 9483case"onUpdate":{this.fieldsOnUpdate.set(fieldName,value);break;} 9484case"type":{this.fieldsType.set(fieldName,value);break;}}}}} 9485return __exports;});; 9486 9487/* /mail/static/src/model/record.js */ 9488odoo.define('@mail/model/record',['@odoo/owl','@mail/model/misc','@web/core/l10n/dates'],function(require){'use strict';let __exports={};const{markup,toRaw}=require("@odoo/owl");const{IS_DELETED_SYM,OR_SYM,isCommand,isMany,isOne,isRecord,isRelation,modelRegistry,}=require("@mail/model/misc");const{serializeDate,serializeDateTime}=require("@web/core/l10n/dates");const Markup=markup().constructor;const Record=__exports.Record=class Record{static _;_;static id;static env;env;static records;static store;static MAKE_UPDATE(fn){return this.store.MAKE_UPDATE(...arguments);} 9489static onChange(record,name,cb){return this.store.onChange(...arguments);} 9490static get(data){const Model=toRaw(this);return this.records[Model.localId(data)];} 9491static getName(){return this._name||this.name;} 9492static register(localRegistry){if(localRegistry){localRegistry.add(this.getName(),this);}else{modelRegistry.add(this.getName(),this);}} 9493static localId(data){const Model=toRaw(this);let idStr;if(typeof data==="object"&&data!==null){idStr=Model._localId(Model.id,data);}else{idStr=data;} 9494return`${Model.getName()},${idStr}`;} 9495get localId(){return toRaw(this)._.localId;} 9496static _localId(expr,data,{brackets=false}={}){const Model=toRaw(this);if(!Array.isArray(expr)){if(Model._.fields.get(expr)){if(Model._.fieldsMany.get(expr)){throw new Error("Using a fields.Many() as id is not (yet) supported");} 9497if(!isRelation(Model,expr)){return data[expr];} 9498if(isCommand(data[expr])){const[cmd,data2]=data[expr].at(-1);if(cmd==="DELETE"){return undefined;}else{return`(${data2?.localId})`;}} 9499if(isRecord(data[expr])){return`(${data[expr]?.localId})`;} 9500const TargetModelName=Model._.fieldsTargetModel.get(expr);return`(${Model.store[TargetModelName].get(data[expr])?.localId})`;} 9501return data[expr];} 9502const vals=[];for(let i=1;i<expr.length;i++){vals.push(Model._localId(expr[i],data,{brackets:true}));} 9503let res=vals.join(expr[0]===OR_SYM?" OR ":" AND ");if(brackets){res=`(${res})`;} 9504return res;} 9505static _retrieveIdFromData(data){const Model=toRaw(this);const res={};function _deepRetrieve(expr2){if(typeof expr2==="string"){if(isCommand(data[expr2])){const[cmd,data2]=data[expr2].at(-1);return Object.assign(res,{[expr2]:cmd==="DELETE"?undefined:cmd==="DELETE.noinv"?[["DELETE.noinv",data2]]:cmd==="ADD.noinv"?[["ADD.noinv",data2]]:data2,});} 9506return Object.assign(res,{[expr2]:data[expr2]});} 9507if(expr2 instanceof Array){for(const expr of this.id){if(typeof expr==="symbol"){continue;} 9508_deepRetrieve(expr);}}}
9509if(Model.id===undefined){return res;} 9510if(typeof Model.id==="string"){if(typeof data!=="object"||data===null){return{[Model.id]:data};} 9511if(isCommand(data[Model.id])){const[cmd,data2]=data[Model.id].at(-1);return Object.assign(res,{[Model.id]:cmd==="DELETE"?undefined:cmd==="DELETE.noinv"?[["DELETE.noinv",data2]]:cmd==="ADD.noinv"?[["ADD.noinv",data2]]:data2,});} 9512return{[Model.id]:data[Model.id]};} 9513for(const expr of Model.id){if(typeof expr==="symbol"){continue;} 9514_deepRetrieve(expr);} 9515return res;} 9516static Class;static new(data,ids){const Model=toRaw(this);const store=Model._rawStore;return store.MAKE_UPDATE(function RecordNew(){const recordProxy=new Model.Class();const record=toRaw(recordProxy)._raw;Object.assign(record._,{localId:Model.localId(ids)});Object.assign(recordProxy,{...ids});Model.records[record.localId]=recordProxy;if(record.Model.getName()==="Store"){Object.assign(record,{env:Model._rawStore.env,recordByLocalId:Model._rawStore.recordByLocalId,});} 9517Model._rawStore.recordByLocalId.set(record.localId,recordProxy);for(const fieldName of record.Model._.fields.keys()){record._.requestCompute?.(record,fieldName);record._.requestSort?.(record,fieldName);} 9518return recordProxy;});} 9519static insert(data,options={}){const ModelFullProxy=this;const Model=toRaw(ModelFullProxy);const store=Model._rawStore;return store.MAKE_UPDATE(function RecordInsert(){const isMulti=Array.isArray(data);if(!isMulti){data=[data];} 9520const res=data.map(function RecordInsertMap(d){return Model._insert.call(ModelFullProxy,d,options);});if(!isMulti){return res[0];} 9521return res;});} 9522static _insert(data){const ModelFullProxy=this;const Model=toRaw(ModelFullProxy);const recordFullProxy=Model.preinsert.call(ModelFullProxy,data);const record=toRaw(recordFullProxy)._raw;record.update.call(record._proxy,data);return recordFullProxy;} 9523static preinsert(data){const ModelFullProxy=this;const Model=toRaw(ModelFullProxy);const ids=Model._retrieveIdFromData(data);for(const name in ids){if(ids[name]&&!isRecord(ids[name])&&!isCommand(ids[name])&&isRelation(Model,name)){ids[name]=Model._rawStore[Model._.fieldsTargetModel.get(name)].preinsert(ids[name]);}} 9524return Model.get.call(ModelFullProxy,data)??Model.new(data,ids);} 9525get store(){return toRaw(this)._raw.Model._rawStore._proxy;} 9526get _rawStore(){return toRaw(this)._raw.Model._rawStore;} 9527Model;_raw;_proxyInternal;_proxy;setup(){} 9528update(data){const record=toRaw(this)._raw;const store=record._rawStore;return store.MAKE_UPDATE(function recordUpdate(){if(typeof data==="object"&&data!==null){store._.updateFields(record,data);}else{if(Array.isArray(record.Model.id)){throw new Error(`Cannot insert "${data}" on model "${record.Model.getName()}": this model doesn't support single-id data!`);} 9529store._.updateFields(record,{[record.Model.id]:data});}});} 9530delete(){const record=toRaw(this)._raw;const store=record._rawStore;return store.MAKE_UPDATE(function recordDelete(){store._.ADD_QUEUE("delete",record);});} 9531exists(){return!this[IS_DELETED_SYM];} 9532eq(record){return toRaw(this)._raw===toRaw(record)?._raw;} 9533notEq(record){return!this.eq(record);} 9534in(collection){if(!collection){return false;} 9535return collection.some((record)=>toRaw(record)._raw.eq(this));} 9536notIn(collection){return!this.in(collection);} 9537toData(options={depth:false}){const prefix=this._getActualModelName();const ongoing={seenRecords:new Set(),storeData:{},depth:options.depth,fields:undefined,};if(Array.isArray(options)){ongoing.fields=options.map((field)=>`${prefix}.${field}`);} 9538this._toData(ongoing,prefix);return ongoing.storeData;} 9539_cleanupData(data){const fieldsToDelete=["_","_fieldsValue","_proxy","_proxyInternal","_raw","env","Model",];fieldsToDelete.forEach((field)=>delete data[field]);} 9540_getActualModelName(){return this.Model.getName();} 9541_toData(ongoing,prefix=undefined){if(ongoing.depth&&ongoing.seenRecords.has(this.localId)){return;} 9542ongoing.seenRecords.add(this.localId);const recordProxy=this;const record=toRaw(recordProxy)._raw;const Model=record.Model;const data={...recordProxy};for(const name of Model._.fields.keys()){if(Model._.fieldsCompute.has(name)){delete data[name];continue;} 9543const fullFieldName=prefix?`${prefix}.${name}`:name;if(isMany(Model,name)){data[name]=record._proxyInternal[name].map((recordProxy)=>{const record=toRaw(recordProxy)._raw;return record._toDataRelationalRecord.call(record._proxyInternal,ongoing,fullFieldName);});}else if(isOne(Model,name)){const otherRecord=toRaw(record._proxyInternal[name])?._raw;data[name]=otherRecord?._toDataRelationalRecord.call(otherRecord._proxyInternal,ongoing,fullFieldName);}else{const value=recordProxy[name];if(Model._.fieldsType.get(name)==="datetime"&&value){data[name]=serializeDateTime(value);}else if(Model._.fieldsType.get(name)==="date"&&value){data[name]=serializeDate(value);}else if(Model._.fieldsHtml.get(name)&&value instanceof Markup){data[name]=["markup",value.toString()];}else{data[name]=value;}}} 9544this._cleanupData(data);const pyModelName=record._getActualModelName();ongoing.storeData[pyModelName]||=[];ongoing.storeData[pyModelName].push(data);} 9545_toDataRelationalRecord(ongoing,prefix=undefined){const data=this.Model._retrieveIdFromData(this);if(ongoing.depth||ongoing.fields?.some((field)=>field.startsWith(prefix))){this._toData(ongoing,prefix);}
9546for(const[name,val]of Object.entries(data)){if(isRecord(val)){data[name]=val._toDataRelationalRecord(ongoing,prefix);}} 9547return data;}} 9548Record.register();return __exports;});; 9549 9550/* /mail/static/src/model/record_internal.js */ 9551odoo.define('@mail/model/record_internal',['@mail/utils/common/misc','@mail/model/misc','@mail/model/record_list','@odoo/owl','@mail/model/record_uses'],function(require){'use strict';let __exports={};const{onChange}=require("@mail/utils/common/misc");const{IS_DELETED_SYM,IS_RECORD_SYM,isRelation}=require("@mail/model/misc");const{RecordList}=require("@mail/model/record_list");const{reactive,toRaw}=require("@odoo/owl");const{RecordUses}=require("@mail/model/record_uses");const RecordInternal=__exports.RecordInternal=class RecordInternal{[IS_RECORD_SYM]=true;fieldsComputing=new Map();fieldsSortOnNeed=new Map();fieldsSortInNeed=new Map();fieldsSorting=new Map();fieldsComputeInNeed=new Map();fieldsComputeOnNeed=new Map();fieldsOnUpdateObserves=new Map();fieldsSortProxy2=new Map();fieldsComputeProxy2=new Map();uses=new RecordUses();updatingAttrs=new Map();proxyUsed=new Map();localId;gettingField=false;prepareField(record,fieldName,recordProxy){const self=this;const Model=toRaw(record).Model;if(isRelation(Model,fieldName)){const recordList=new RecordList();Object.assign(recordList._,{name:fieldName,owner:record,});Object.assign(recordList,{_raw:recordList,_store:record.store,});record[fieldName]=recordList;}else{record[fieldName]=record[fieldName].default;} 9552if(Model._.fieldsCompute.get(fieldName)){if(!Model._.fieldsEager.get(fieldName)){onChange(recordProxy,fieldName,()=>{if(this.fieldsComputing.get(fieldName)){this.fieldsComputeInNeed.delete(fieldName);}});this.fieldsComputeInNeed.delete(fieldName);this.fieldsSortInNeed.delete(fieldName);} 9553const cb=function computeObserver(){self.requestCompute(record,fieldName);};const computeProxy2=reactive(recordProxy,cb);this.fieldsComputeProxy2.set(fieldName,computeProxy2);} 9554if(Model._.fieldsSort.get(fieldName)){if(!Model._.fieldsEager.get(fieldName)){onChange(recordProxy,fieldName,()=>{if(this.fieldsSorting.get(fieldName)){this.fieldsSortInNeed.delete(fieldName);}});this.fieldsComputeInNeed.delete(fieldName);this.fieldsSortInNeed.delete(fieldName);} 9555const sortProxy2=reactive(recordProxy,function sortObserver(){self.requestSort(record,fieldName);});this.fieldsSortProxy2.set(fieldName,sortProxy2);} 9556if(Model._.fieldsOnUpdate.get(fieldName)){const store=Model.store;store._onChange(recordProxy,fieldName,(obs)=>{this.fieldsOnUpdateObserves.set(fieldName,obs);if(store._.UPDATE!==0){store._.ADD_QUEUE("onUpdate",record,fieldName);}else{this.onUpdate(record,fieldName);}});}} 9557requestCompute(record,fieldName,{force=false}={}){if(record[IS_DELETED_SYM]){return;} 9558const Model=record.Model;if(!Model._.fieldsCompute.get(fieldName)){return;} 9559const store=record._rawStore;if(store._.UPDATE!==0&&!force){store._.ADD_QUEUE("compute",record,fieldName);}else{if(Model._.fieldsEager.get(fieldName)||this.fieldsComputeInNeed.get(fieldName)){this.compute(record,fieldName);}else{this.fieldsComputeOnNeed.set(fieldName,true);}}} 9560requestSort(record,fieldName,{force}={}){if(record[IS_DELETED_SYM]){return;} 9561const Model=record.Model;if(!Model._.fieldsSort.get(fieldName)){return;} 9562const store=record._rawStore;if(store._.UPDATE!==0&&!force){store._.ADD_QUEUE("sort",record,fieldName);}else{if(Model._.fieldsEager.get(fieldName)||this.fieldsSortInNeed.get(fieldName)){this.sort(record,fieldName);}else{this.fieldsSortOnNeed.set(fieldName,true);}}} 9563compute(record,fieldName){const Model=record.Model;const store=record._rawStore;this.fieldsComputing.set(fieldName,true);this.fieldsComputeOnNeed.delete(fieldName);let computedValue;try{computedValue=Model._.fieldsCompute.get(fieldName).call(this.fieldsComputeProxy2.get(fieldName));}catch(err){store.handleError(err);} 9564store._.updateFields(record,{[fieldName]:computedValue,});this.fieldsComputing.delete(fieldName);} 9565sort(record,fieldName){const Model=record.Model;if(!Model._.fieldsSort.get(fieldName)){return;} 9566const store=record._rawStore;this.fieldsSortOnNeed.delete(fieldName);this.fieldsSorting.set(fieldName,true);const proxy2Sort=this.fieldsSortProxy2.get(fieldName);const func=Model._.fieldsSort.get(fieldName).bind(proxy2Sort);
9566if(isRelation(Model,fieldName)){try{store._.sortRecordList(proxy2Sort[fieldName]._proxy,func);}catch(err){store.handleError(err);}}else{const copy=[...proxy2Sort[fieldName]];copy.sort(func);const hasChanged=copy.some((item,index)=>item!==record[fieldName][index]);if(hasChanged){proxy2Sort[fieldName]=copy;}} 9567this.fieldsSorting.delete(fieldName);} 9568onUpdate(record,fieldName){const store=record._rawStore;const Model=record.Model;if(!Model._.fieldsOnUpdate.get(fieldName)){return;} 9569try{Model._.fieldsOnUpdate.get(fieldName).call(record._proxyInternal);}catch(err){store.handleError(err);} 9570this.fieldsOnUpdateObserves.get(fieldName)?.();} 9571downgradeProxy(record,fullProxy){return record._proxy===fullProxy?record._proxyInternal:fullProxy;}} 9572return __exports;});; 9573 9574/* /mail/static/src/model/record_list.js */ 9575odoo.define('@mail/model/record_list',['@odoo/owl','@mail/model/misc'],function(require){'use strict';let __exports={};const{markRaw,reactive,toRaw}=require("@odoo/owl");const{isRecord}=require("@mail/model/misc");function getInverse(reclist){return reclist._.owner.Model._.fieldsInverse.get(reclist._.name);} 9576function getTargetModel(reclist){return reclist._.owner.Model._.fieldsTargetModel.get(reclist._.name);} 9577function isComputeField(reclist){return reclist._.owner.Model._.fieldsCompute.get(reclist._.name);} 9578function isSortField(reclist){return reclist._.owner.Model._.fieldsSort.get(reclist._.name);} 9579function isEager(reclist){return reclist._.owner.Model._.fieldsEager.get(reclist._.name);} 9580function setComputeInNeed(reclist){reclist._.owner._.fieldsComputeInNeed.set(reclist._.name,true);} 9581function setSortInNeed(reclist){reclist._.owner._.fieldsSortInNeed.set(reclist._.name,true);} 9582function isComputeOnNeed(reclist){return reclist._.owner._.fieldsComputeOnNeed.get(reclist._.name);} 9583function isSortOnNeed(reclist){return reclist._.owner._.fieldsSortOnNeed.get(reclist._.name);} 9584function computeField(reclist){reclist._.owner._.compute(reclist._.owner,reclist._.name);} 9585function sortField(reclist){reclist._.owner._.sort(reclist._.owner,reclist._.name);} 9586function isOne(reclist){return reclist._.owner.Model._.fieldsOne.get(reclist._.name);} 9587const RecordListInternal=__exports.RecordListInternal=class RecordListInternal{name;owner;addNoinv(recordList,...records){const self=this;const store=recordList._store;if(isOne(recordList)){const last=records.at(-1);if(isRecord(last)&&last.in(recordList)){return;} 9588const record=self.insert(recordList,last,function recordList_AddNoInvOneInsert(record){if(record.localId!==recordList.data[0]){const old=recordList._proxy.at(-1);recordList._proxy.data.pop();old?._.uses.delete(recordList);recordList._proxy.data.push(record.localId);self.syncLength(recordList);record._.uses.add(recordList);}},{inv:false});store._.ADD_QUEUE("onAdd",self.owner,self.name,record);return;} 9589for(const val of records){if(isRecord(val)&&val.in(recordList)){continue;} 9590const record=self.insert(recordList,val,function recordList_AddNoInvManyInsert(record){if(recordList.data.indexOf(record.localId)===-1){recordList._proxy.data.push(record.localId);self.syncLength(recordList);record._.uses.add(recordList);}},{inv:false});store._.ADD_QUEUE("onAdd",self.owner,self.name,record);}} 9591assign(recordList,data){const self=this;const store=recordList._store;return store.MAKE_UPDATE(function recordListAssign(){const collection=isRecord(data)?[data]:data;const vals=[...collection];const oldRecords=recordList._proxyInternal.slice.call(recordList._proxy).map((recordProxy)=>toRaw(recordProxy)._raw);const newRecords=vals.map((val)=>self.insert(recordList,val,function recordListAssignInsert(record){if(record.notIn(oldRecords)){record._.uses.add(recordList);store._.ADD_QUEUE("onAdd",self.owner,self.name,record);}}));const inverse=getInverse(recordList);for(const oldRecord of oldRecords){if(oldRecord.notIn(newRecords)){oldRecord._.uses.delete(recordList);store._.ADD_QUEUE("onDelete",self.owner,self.name,oldRecord);if(inverse){oldRecord[inverse].delete(self.owner);}}} 9592recordList._proxy.data=newRecords.map((newRecord)=>newRecord.localId);recordList._.syncLength(recordList);});} 9593deleteNoinv(recordList,...records){const self=this;const store=recordList._store;for(const val of records){const record=this.insert(recordList,val,function recordList_DeleteNoInv_Insert(record){const index=recordList.data.indexOf(record.localId);if(index!==-1){recordList.splice.call(recordList._proxy,index,1);self.syncLength(recordList);}},{inv:false});store._.ADD_QUEUE("onDelete",self.owner,self.name,record);}} 9594downgradeProxy(recordList,fullProxy){return recordList._proxy===fullProxy?recordList._proxyInternal:fullProxy;} 9595insert(recordList,val,fn,{inv=true,mode="ADD"}={}){const inverse=getInverse(recordList);const targetModel=getTargetModel(recordList);if(typeof val!=="object"){if(Array.isArray(recordList._store[targetModel].id)){throw new Error(`Cannot insert "${val}" on relational field "${recordList._.owner.Model.getName()}/${ 9596 recordList._.name 9597 }": target model "${targetModel}" doesn't support single-id data!`);} 9598val={[recordList._store[targetModel].id]:val};} 9599if(inverse&&inv){const target=isRecord(val)&&val._raw===val?val._proxy:val;target[inverse]=[[mode==="ADD"?"ADD.noinv":"DELETE.noinv",recordList._.owner]];} 9600let newRecordProxy;if(!isRecord(val)){newRecordProxy=recordList._store[targetModel].preinsert(val);}else{newRecordProxy=val;} 9601const newRecord=toRaw(newRecordProxy)._raw;fn?.(newRecord);if(!isRecord(val)){recordList._store[targetModel].insert(val);} 9602return newRecord;} 9603syncLength(reclist){reclist.length=reclist.data.length;}} 9604const RecordList=__exports.RecordList=class RecordList extends Array{_store;data=[];_raw;_proxyInternal;_proxy;_=markRaw(new RecordListInternal());constructor(){super();const recordList=this;recordList._raw=recordList;const recordListProxyInternal=new Proxy(recordList,{get(recordList,name,recordListFullProxy){recordListFullProxy=recordList._.downgradeProxy(recordList,recordListFullProxy);if(typeof name==="symbol"||Object.keys(recordList).includes(name)||Object.prototype.hasOwnProperty.call(recordList.constructor.prototype,name)){let res=Reflect.get(...arguments);if(typeof res==="function"){res=res.bind(recordListFullProxy);} 9605return res;} 9606if(isComputeField(recordList)&&!isEager(recordList)){setComputeInNeed(recordList);if(isComputeOnNeed(recordList)){computeField(recordList);}} 9607if(name==="length"){return recordListFullProxy.data.length;} 9608if(isSortField(recordList)&&!isEager(recordList)){setSortInNeed(recordList);if(isSortOnNeed(recordList)){sortField(recordList);}} 9609if(typeof name!=="symbol"&&!window.isNaN(parseInt(name))){const index=
9609parseInt(name);return recordListFullProxy._store.recordByLocalId.get(recordListFullProxy.data[index]);} 9610const array=[...recordList[Symbol.iterator].call(recordListFullProxy)];return array[name]?.bind(array);},set(recordList,name,val,recordListProxy){const store=recordList._store;return store.MAKE_UPDATE(function recordListSet(){if(typeof name!=="symbol"&&!window.isNaN(parseInt(name))){const index=parseInt(name);recordList._.insert(recordList,val,function recordListSet_Insert(newRecord){const oldRecord=toRaw(toRaw(recordList._store.recordByLocalId).get(recordList.data[index]))._raw;recordListProxy.data[index]=newRecord?.localId;if(oldRecord&&oldRecord.notEq(newRecord)){oldRecord._.uses.delete(recordList);} 9611store._.ADD_QUEUE("onDelete",recordList._.owner,recordList._.name,oldRecord);const inverse=getInverse(recordList);if(inverse){oldRecord[inverse].delete(recordList._.owner);} 9612if(newRecord){newRecord._.uses.add(recordList);store._.ADD_QUEUE("onAdd",recordList._.owner,recordList._.name,newRecord);if(inverse){newRecord[inverse].add?.(recordList._.owner);}}});}else if(name==="length"){const newLength=parseInt(val);if(newLength!==recordList.data.length){if(newLength<recordList.data.length){recordList.splice.call(recordListProxy,newLength,recordList.length-newLength);} 9613recordListProxy.data.length=newLength;recordList._.syncLength(recordList);}}else{return Reflect.set(recordList,name,val,recordListProxy);} 9614return true;});},});recordList._proxyInternal=recordListProxyInternal;recordList._proxy=reactive(recordListProxyInternal);return recordList;} 9615push(...records){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);const store=recordList._store;return store.MAKE_UPDATE(function recordListPush(){for(const val of records){const record=recordList._.insert(recordList,val,function recordListPushInsert(record){recordList._proxy.data.push(record.localId);recordList._.syncLength(recordList);record._.uses.add(recordList);});store._.ADD_QUEUE("onAdd",recordList._.owner,recordList._.name,record);const inverse=getInverse(recordList);if(inverse){record[inverse].add(recordList._.owner);}} 9616return recordListFullProxy.data.length;});} 9617pop(){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);const store=recordList._store;return store.MAKE_UPDATE(function recordListPop(){const oldRecordProxy=recordListFullProxy.at(-1);if(oldRecordProxy){recordList.splice.call(recordListFullProxy,recordListFullProxy.length-1,1);} 9618return oldRecordProxy;});} 9619shift(){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);const store=recordList._store;return store.MAKE_UPDATE(function recordListShift(){const recordProxy=recordListFullProxy._store.recordByLocalId.get(recordListFullProxy.data.shift());recordList._.syncLength(recordList);if(!recordProxy){return;} 9620const record=toRaw(recordProxy)._raw;record._.uses.delete(recordList);store._.ADD_QUEUE("onDelete",recordList._.owner,recordList._.name,record);const inverse=getInverse(recordList);if(inverse){record[inverse].delete(recordList._.owner);} 9621return recordProxy;});} 9622unshift(...records){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);const store=recordList._store;return store.MAKE_UPDATE(function recordListUnshift(){for(let i=records.length-1;i>=0;i--){const record=recordList._.insert(recordList,records[i],(record)=>{recordList._proxy.data.unshift(record.localId);recordList._.syncLength(recordList);record._.uses.add(recordList);});store._.ADD_QUEUE("onAdd",recordList._.owner,recordList._.name,record);const inverse=getInverse(recordList);if(inverse){record[inverse].add(recordList._.owner);}} 9623return recordListFullProxy.data.length;});} 9624indexOf(recordProxy){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);return recordListFullProxy.data.indexOf(toRaw(recordProxy)?._raw.localId);} 9625splice(start,deleteCount,...newRecordsProxy){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);const store=recordList._store;return store.MAKE_UPDATE(function recordListSplice(){const oldRecordLocalIds=rec
9625ordList.data.slice(start,start+deleteCount);const oldRecords=oldRecordLocalIds.map((localId)=>toRaw(toRaw(recordList._store.recordByLocalId).get(localId))._raw);const list=recordListFullProxy.data.slice();list.splice(start,deleteCount,...newRecordsProxy.map((newRecordProxy)=>toRaw(newRecordProxy)._raw.localId));if(isOne(recordList)&&start===0&&deleteCount===1){if(list.length===0){recordList._proxy.data.pop();}else{recordList._proxy.data[0]=list[0];}}else{recordList._proxy.data=list;} 9626recordList._.syncLength(recordList);for(const oldRecord of oldRecords){oldRecord._.uses.delete(recordList);store._.ADD_QUEUE("onDelete",recordList._.owner,recordList._.name,oldRecord);const inverse=getInverse(recordList);if(inverse){oldRecord[inverse].delete(recordList._.owner);}} 9627for(const newRecordProxy of newRecordsProxy){const newRecord=toRaw(newRecordProxy)._raw;newRecord._.uses.add(recordList);store._.ADD_QUEUE("onAdd",recordList._.owner,recordList._.name,newRecord);const inverse=getInverse(recordList);if(inverse){newRecord[inverse].add(recordList._.owner);}}});} 9628sort(func){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);const store=recordList._store;return store.MAKE_UPDATE(function recordListSort(){recordList._store._.sortRecordList(recordListFullProxy,func);return recordListFullProxy;});} 9629concat(...collections){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);return recordListFullProxy.data.map((localId)=>recordListFullProxy._store.recordByLocalId.get(localId)).concat(...collections.map((c)=>[...c]));} 9630add(...records){const recordList=toRaw(this)._raw;const store=recordList._store;return store.MAKE_UPDATE(function recordListAdd(){if(isOne(recordList)){const last=records.at(-1);if(isRecord(last)&&recordList.data.includes(toRaw(last)._raw.localId)){return last;} 9631return recordList._.insert(recordList,last,function recordListAddInsertOne(record){if(record.localId!==recordList.data[0]){recordList.splice.call(recordList._proxy,0,1,record);}});} 9632const res=[];for(const val of records){if(isRecord(val)&&recordList.data.includes(val.localId)){continue;} 9633const rec=recordList._.insert(recordList,val,function recordListAddInsertMany(record){if(recordList.data.indexOf(record.localId)===-1){recordList.push.call(recordList._proxy,record);}});res.push(rec);} 9634return res.length===1?res[0]:res;});} 9635delete(...records){const recordList=toRaw(this)._raw;const store=recordList._store;return store.MAKE_UPDATE(function recordListDelete(){for(const val of records){recordList._.insert(recordList,val,function recordListDelete_Insert(record){const index=recordList.data.indexOf(record.localId);if(index!==-1){recordList.splice.call(recordList._proxy,index,1);}},{mode:"DELETE"});}});} 9636clear(){const recordList=toRaw(this)._raw;const store=recordList._store;return store.MAKE_UPDATE(function recordListClear(){while(recordList.data.length>0){recordList.pop.call(recordList._proxy);}});}*[Symbol.iterator](){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);for(const localId of recordListFullProxy.data){yield recordListFullProxy._store.recordByLocalId.get(localId);}}
9636 9637at(index){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);return recordListFullProxy._store.recordByLocalId.get(recordListFullProxy.data.at(index));}} 9638return __exports;});; 9639 9640/* /mail/static/src/model/record_uses.js */ 9641odoo.define('@mail/model/record_uses',[],function(require){'use strict';let __exports={};const RecordUses=__exports.RecordUses=class RecordUses{data=new Map();add(list){const record=list._.owner;if(!this.data.has(record.localId)){this.data.set(record.localId,new Map());} 9642const use=this.data.get(record.localId);if(!use.get(list._.name)){use.set(list._.name,0);} 9643use.set(list._.name,use.get(list._.name)+1);} 9644delete(list){const record=list._.owner;if(!this.data.has(record.localId)){return;} 9645const use=this.data.get(record.localId);if(!use.get(list._.name)){return;} 9646use.set(list._.name,use.get(list._.name)-1);if(use.get(list._.name)===0){use.delete(list._.name);}}} 9647return __exports;});; 9648 9649/* /mail/static/src/model/store.js */ 9650odoo.define('@mail/model/store',['@mail/model/record','@mail/model/misc','@odoo/owl'],function(require){'use strict';let __exports={};const{Record}=require("@mail/model/record");const{IS_DELETED_SYM,IS_DELETING_SYM,STORE_SYM,modelRegistry}=require("@mail/model/misc");const{reactive,toRaw}=require("@odoo/owl");const storeInsertFns=__exports.storeInsertFns={makeContext(store){},getActualModelName(store,ctx,pyOrJsModelName){return pyOrJsModelName;},getExtraFieldsFromModel(store){},};const Store=__exports.Store=class Store extends Record{_;[STORE_SYM]=true;recordByLocalId;storeReady=false;get(localId){return this.recordByLocalId.get(localId);} 9651handleError(err){this._.ERRORS.push(err);} 9652warnErrors=true;MAKE_UPDATE(fn){this._.UPDATE++;let res;try{res=fn();}catch(err){this.handleError(err);} 9653this._.UPDATE--;if(this._.UPDATE===0){const deletingRecordsByLocalId=new Map();this._.UPDATE++;while(this._.FC_QUEUE.size>0||this._.FS_QUEUE.size>0||this._.FA_QUEUE.size>0||this._.FD_QUEUE.size>0||this._.FU_QUEUE.size>0||this._.RO_QUEUE.size>0||this._.RD_QUEUE.size>0){const FC_QUEUE=new Map(this._.FC_QUEUE);const FS_QUEUE=new Map(this._.FS_QUEUE);const FA_QUEUE=new Map(this._.FA_QUEUE);const FD_QUEUE=new Map(this._.FD_QUEUE);const FU_QUEUE=new Map(this._.FU_QUEUE);const RO_QUEUE=new Map(this._.RO_QUEUE);const RD_QUEUE=new Map(this._.RD_QUEUE);this._.FC_QUEUE.clear();this._.FS_QUEUE.clear();this._.FA_QUEUE.clear();this._.FD_QUEUE.clear();this._.FU_QUEUE.clear();this._.RO_QUEUE.clear();this._.RD_QUEUE.clear();while(FC_QUEUE.size>0){const[record,recMap]=FC_QUEUE.entries().next().value;FC_QUEUE.delete(record);for(const fieldName of recMap.keys()){record._.requestCompute(record,fieldName,{force:true});}} 9654while(FS_QUEUE.size>0){const[record,recMap]=FS_QUEUE.entries().next().value;FS_QUEUE.delete(record);for(const fieldName of recMap.keys()){record._.requestSort(record,fieldName,{force:true});}} 9655while(FA_QUEUE.size>0){const[record,recMap]=FA_QUEUE.entries().next().value;FA_QUEUE.delete(record);while(recMap.size>0){const[fieldName,fieldMap]=recMap.entries().next().value;recMap.delete(fieldName);const onAdd=record.Model._.fieldsOnAdd.get(fieldName);for(const addedRec of fieldMap.keys()){try{onAdd?.call(record._proxy,addedRec._proxy);}catch(err){this.handleError(err);}}}} 9656while(FD_QUEUE.size>0){const[record,recMap]=FD_QUEUE.entries().next().value;FD_QUEUE.delete(record);while(recMap.size>0){const[fieldName,fieldMap]=recMap.entries().next().value;recMap.delete(fieldName);const onDelete=record.Model._.fieldsOnDelete.get(fieldName);for(const removedRec of fieldMap.keys()){try{onDelete?.call(record._proxy,removedRec._proxy);}catch(err){this.handleError(err);}}}} 9657while(FU_QUEUE.size>0){const[record,map]=FU_QUEUE.entries().next().value;FU_QUEUE.delete(record);for(const fieldName of map.keys()){record._.onUpdate(record,fieldName);}} 9658while(RO_QUEUE.size>0){const cb=RO_QUEUE.keys().next().value;RO_QUEUE.delete(cb);try{cb();}catch(err){this.handleError(err);}} 9659while(RD_QUEUE.size>0){const record=RD_QUEUE.keys().next().value;RD_QUEUE.delete(record);for(const[localId,names]of record._.uses.data.entries()){for(const[name2,count]of names.entries()){const existingRecordProxyInternal=toRaw(this.recordByLocalId).get(localId);const usingRecord=(existingRecordProxyInternal&&toRaw(existingRecordProxyInternal)?._raw)||deletingRecordsByLocalId.get(localId);if(!usingRecord){record._.uses.data.delete(localId);continue;} 9660for(let c=0;c<count;c++){usingRecord[name2].delete(record);}}} 9661deletingRecordsByLocalId.set(record.localId,record);this.recordByLocalId.delete(record.localId);record._[IS_DELETING_SYM]=true;record._proxy[IS_DELETED_SYM]=true;delete record.Model.records[record.localId];}} 9662this._.UPDATE--;if(this._.ERRORS.length){if(this.warnErrors){console.warn("Store data insert aborted due to following errors:");for(const err of this._.ERRORS){console.warn(err);}} 9663const[error1]=this._.ERRORS;
9663this._.ERRORS=[];throw error1;}} 9664return res;} 9665insert(dataByModelName={},options={}){const store=this;const ctx=storeInsertFns.makeContext(store);Record.MAKE_UPDATE(function storeInsert(){const recordsDataToDelete=[];for(const[pyOrJsModelName,data]of Object.entries(dataByModelName)){const modelName=storeInsertFns.getActualModelName(store,ctx,pyOrJsModelName);if(!store[modelName]){console.warn(`store.insert() received data for unknown model â${modelName}â.`);continue;} 9666const insertData=[];for(const vals of Array.isArray(data)?data:[data]){const extraFields=storeInsertFns.getExtraFieldsFromModel(store,pyOrJsModelName);if(extraFields){Object.assign(vals,extraFields);} 9667if(vals._DELETE){delete vals._DELETE;recordsDataToDelete.push([modelName,vals]);}else{insertData.push(vals);}} 9668store[modelName].insert(insertData,options);} 9669for(const[modelName,vals]of recordsDataToDelete){store[modelName].get(vals)?.delete();}});} 9670onChange(record,name,cb){return this._onChange(record,name,(observe)=>{const fn=()=>{observe();try{cb();}catch(err){this.handleError(err);}};if(this._.UPDATE!==0){if(!this._.RO_QUEUE.has(fn)){this._.RO_QUEUE.set(fn,true);}}else{fn();}});} 9671_onChange(record,key,callback){let proxy;function _observe(){const val=proxy[key];if(typeof val==="object"&&val!==null){void Object.keys(val);} 9672if(Array.isArray(val)){void val.length;void toRaw(val).forEach.call(val,(i)=>i);}} 9673if(Array.isArray(key)){for(const k of key){this._onChange(record,k,callback);} 9674return;} 9675let ready=true;proxy=reactive(record,()=>{if(ready){callback(_observe);}});_observe();return()=>{ready=false;};} 9676_cleanupData(data){super._cleanupData(data);if(this._getActualModelName()==="Store"){delete data.Models;for(const[name]of modelRegistry.getEntries()){delete data[name];}}}} 9677return __exports;});; 9678 9679/* /mail/static/src/model/store_internal.js */ 9680odoo.define('@mail/model/store_internal',['@odoo/owl','@mail/model/record_internal','@web/core/l10n/dates','@mail/model/misc'],function(require){'use strict';let __exports={};const{htmlEscape,markup,toRaw}=require("@odoo/owl");const{RecordInternal}=require("@mail/model/record_internal");const{deserializeDate,deserializeDateTime}=require("@web/core/l10n/dates");const{isCommand,isMany}=require("@mail/model/misc");const Markup=markup().constructor;const StoreInternal=__exports.StoreInternal=class StoreInternal extends RecordInternal{FC_QUEUE=new Map();FS_QUEUE=new Map();FA_QUEUE=new Map();FD_QUEUE=new Map();FU_QUEUE=new Map();RO_QUEUE=new Map();RD_QUEUE=new Map();ERRORS=[];UPDATE=0;ADD_QUEUE(type,...params){switch(type){case"delete":{const[record]=params;if(!this.RD_QUEUE.has(record)){this.RD_QUEUE.set(record,true);} 9681break;} 9682case"compute":{const[record,fieldName]=params;let recMap=this.FC_QUEUE.get(record);if(!recMap){recMap=new Map();this.FC_QUEUE.set(record,recMap);} 9683recMap.set(fieldName,true);break;} 9684case"sort":{const[record,fieldName]=params;let recMap=this.FS_QUEUE.get(record);if(!recMap){recMap=new Map();this.FS_QUEUE.set(record,recMap);} 9685recMap.set(fieldName,true);break;} 9686case"onAdd":{const[record,fieldName,addedRec]=params;const Model=record.Model;if(Model._.fieldsSort.get(fieldName)){this.ADD_QUEUE("sort",record,fieldName);} 9687if(!Model._.fieldsOnAdd.get(fieldName)){return;} 9688let recMap=this.FA_QUEUE.get(record);if(!recMap){recMap=new Map();this.FA_QUEUE.set(record,recMap);} 9689let fieldMap=recMap.get(fieldName);if(!fieldMap){fieldMap=new Map();recMap.set(fieldName,fieldMap);} 9690fieldMap.set(addedRec,true);break;} 9691case"onDelete":{const[record,fieldName,removedRec]=params;const Model=record.Model;if(!Model._.fieldsOnDelete.get(fieldName)){return;} 9692let recMap=this.FD_QUEUE.get(record);if(!recMap){recMap=new Map();this.FD_QUEUE.set(record,recMap);} 9693let fieldMap=recMap.get(fieldName);if(!fieldMap){fieldMap=new Map();recMap.set(fieldName,fieldMap);} 9694fieldMap.set(removedRec,true);break;} 9695case"onUpdate":{const[record,fieldName]=params;let recMap=this.FU_QUEUE.get(record);if(!recMap){recMap=new Map();this.FU_QUEUE.set(record,recMap);} 9696recMap.set(fieldName,true);break;}}} 9697sortRecordList(recordListFullProxy,func){const recordList=toRaw(recordListFullProxy)._raw;const recordsFullProxy=recordListFullProxy.data.map((localId)=>recordListFullProxy._store.recordByLocalId.get(localId));recordsFullProxy.sort(func);const data=recordsFullProxy.map((recordFullProxy)=>toRaw(recordFullProxy)._raw.localId);
9697const hasChanged=recordList.data.some((localId,i)=>localId!==data[i]);if(hasChanged){recordListFullProxy.data=data;}} 9698updateAttr(record,fieldName,value){const Model=record.Model;const fieldType=Model._.fieldsType.get(fieldName);const fieldHtml=Model._.fieldsHtml.get(fieldName);const targetRecord=record._.proxyUsed.has(fieldName)?record:record._proxy;let shouldChange=record[fieldName]!==value;if(fieldType==="datetime"&&value){if(!(value instanceof luxon.DateTime)){value=deserializeDateTime(value);} 9699shouldChange=!record[fieldName]||!value.equals(record[fieldName]);} 9700if(fieldType==="date"&&value){if(!(value instanceof luxon.DateTime)){value=deserializeDate(value);} 9701shouldChange=!record[fieldName]||!value.equals(record[fieldName]);} 9702let newValue=value;if(fieldHtml){newValue=Array.isArray(value)&&value[0]==="markup"?value[1]?markup(value[1]):"":value?htmlEscape(value):"";shouldChange=record[fieldName]?.toString()!==newValue?.toString()||record[fieldName]instanceof Markup!=newValue instanceof Markup;} 9703if(shouldChange){record._.updatingAttrs.set(fieldName,true);targetRecord[fieldName]=newValue;record._.updatingAttrs.delete(fieldName);}} 9704updateFields(record,vals){const fieldEntries=Object.entries(vals).concat(Object.getOwnPropertySymbols(vals).map((sym)=>[sym,vals[sym]]));for(const[fieldName,value]of fieldEntries){if(!record.Model._.fields.get(fieldName)||record.Model._.fieldsAttr.get(fieldName)){this.updateAttr(record,fieldName,value);}else{this.updateRelation(record,fieldName,value);}}} 9705updateRelation(record,fieldName,value){const recordList=record[fieldName];if(isMany(record.Model,fieldName)){this.updateRelationMany(recordList,value);}else{this.updateRelationOne(recordList,value);}} 9706updateRelationMany(recordList,value){if(isCommand(value)){for(const[cmd,cmdData]of value){if(Array.isArray(cmdData)){for(const item of cmdData){if(cmd==="ADD"){recordList.add(item);}else if(cmd==="ADD.noinv"){recordList._.addNoinv(recordList,item);}else if(cmd==="DELETE.noinv"){recordList._.deleteNoinv(recordList,item);}else{recordList.delete(item);}}}else{if(cmd==="ADD"){recordList.add(cmdData);}else if(cmd==="ADD.noinv"){recordList._.addNoinv(recordList,cmdData);}else if(cmd==="DELETE.noinv"){recordList._.deleteNoinv(recordList,cmdData);}else{recordList.delete(cmdData);}}}}else if([null,false,undefined].includes(value)){recordList.clear();}else if(!Array.isArray(value)){recordList._.assign(recordList,[value]);}else{recordList._.assign(recordList,value);}} 9707updateRelationOne(recordList,value){if(isCommand(value)){const[cmd,cmdData]=value.at(-1);if(cmd==="ADD"){recordList.add(cmdData);}else if(cmd==="ADD.noinv"){recordList._.addNoinv(recordList,cmdData);}else if(cmd==="DELETE.noinv"){recordList._.deleteNoinv(recordList,cmdData);}else{recordList.delete(cmdData);}}else if([null,false,undefined].includes(value)){recordList.clear();}else{recordList.add(value);}}} 9708return __exports;});; 9709 9710/* /mail/static/src/core/common/action.js */ 9711odoo.define('@mail/core/common/action',['@mail/model/misc','@odoo/owl','@web/core/dropdown/dropdown_hooks','@web/core/utils/hooks','@web/core/utils/reactive'],function(require){'use strict';let __exports={};const{isRecord,STORE_SYM}=require("@mail/model/misc");const{Component,toRaw}=require("@odoo/owl");const{DropdownState}=require("@web/core/dropdown/dropdown_hooks");const{useService}=require("@web/core/utils/hooks");const{Reactive}=require("@web/core/utils/reactive");const ACTION_TAGS=__exports.ACTION_TAGS=Object.freeze({DANGER:"DANGER",SUCCESS:"SUCCESS",PRIMARY:"PRIMARY",IMPORTANT_BADGE:"IMPORTANT_BADGE",WARNING_BADGE:"WARNING_BADGE",CALL_LAYOUT:"CALL_LAYOUT",JOIN_LEAVE_CALL:"JOIN_LEAVE_CALL",});const Action=__exports.Action=class Action{definition;owner;id;store;constructor({owner,id,definition,store}){this.definition=definition;this.id=id;this.owner=owner;const rawOwner=toRaw(owner);this.store=store??(rawOwner[STORE_SYM]?owner:isRecord(owner)?owner.store:useService("mail.store"));} 9712get params(){return{action:this,store:this.store,owner:this.owner};} 9713_badge(action){} 9714get badge(){return(this._badge(this.params)??(typeof this.definition.badge==="function"?this.definition.badge.call(this,this.params):this.definition.badge));} 9715_badgeIcon(action){} 9716get badgeIcon(){return(this._badgeIcon(this.params)??(typeof this.definition.badgeIcon==="function"?this.definition.badgeIcon.call(this,this.params):this.definition.badgeIcon));} 9717_badgeText(action){} 9718get badgeText(){return(this._badgeText(this.params)??(typeof this.definition.badgeText==="function"?this.definition.badgeText.call(this,this.params):this.definition.badgeText));} 9719_btnAttrs(action){} 9720get btnAttrs(){return(this._btnAttrs(this.params)??(typeof this.definition.btnAttrs==="function"?this.definition.btnAttrs.call(this,this.params):this.definition.btnAttrs));} 9721_btnClass(action){} 9722get btnClass(){return(this._btnClass(this.params)??(typeof this.definition.btnClass==="function"?this.definition.btnClass.call(this,this.params):this.definition.btnClass));} 9723_component(action){} 9724get component(){return this._component(this.params)??this.definition.component;} 9725_componentCondition(action){} 9726get componentCondition(){return(this._componentCondition(this.params)??(typeof this.definition.componentCondition==="function"?this.definition.componentCondition.call(this,this.params):this.definition.componentCondition??true));} 9727_componentProps(action){} 9728get componentProps(){return(this._componentProps(this.params)??this.definition.componentProps?.call(this,this.params));} 9729_condition(action){} 9730get condition(){return(this._condition(this.params)??(typeof this.definition.condition==="function"?this.definition.condition.call(this,this.params):this.definition.condition??true));} 9731_disabledCondition(action){} 9732get disabledCondition(){return Boolean(this._disabledCondition(this.params)??this.definition.disabledCondition?.call(this,this.params));} 9733_dropdown(action){} 9734get dropdown(){return this._dropdown(this.params)??this.definition.dropdown;} 9735_dropdownComponent(action){} 9736get dropdownComponent(){return(this._dropdownComponent(this.params)??(typeof this.definition.dropdownComponent==="function"&&Object.getPrototypeOf(this.definition.dropdownComponent)!==Component?this.definition.dropdownComponent.call(this,this.params):this.definition.dropdownComponent));} 9737_dropdownComponentProps(action){} 9738get dropdownComponentProps(){return(this._dropdownComponentProps(this.params)??(typeof this.definition.dropdownComponentProps==="function"?this.definition.dropdownComponentProps.call(this,this.params):this.definition.dropdownComponentProps));} 9739_dropdownMenuClass(action){} 9740get dropdownMenuClass(){return(this._dropdownMenuClass(this.params)??(typeof this.definition.dropdownMenuClass==="function"?this.definition.dropdownMenuClass.call(this,this.params):this.definition.dropdownMenuClass));} 9741_dropdownPosition(action){} 9742get dropdownPosition(){return(this._dropdownPosition(this.params)??(typeof this.definition.dropdownPosition==="function"?this.definition.dropdownPosition.call(this,this.params):this.definition.dropdownPosition));} 9743_dropdownState(action){} 9744get dropdownState(){return(this._dropdownState(this.params)??(typeof this.definition.dropdownState==="function"?this.definition.dropdownState.call(this,this.params):this.definition.dropdownState));} 9745_dropdownTemplate(action){} 9746get dropdownTemplate(){return(this._dropdownTemplate(this.params)??(typeof this.definition.dropdownTemplate==="function"?this.definition.dropdownTemplate.call(this,this.params):this.definition.dropdownTemplate));} 9747_dropdownTemplateParams(action){} 9748get dropdownTemplateParams(){return(this._dropdownTemplateParams(this.params)??(typeof this.definition.dropdownTemplateParams==="function"?this.definition.dropdownTemplateParams.call(this,this.params):this.definition.dropdownTemplateParams));} 9749_hasBtnBg(action){} 9750get hasBtnBg(){return(this._hasBtnBg(this.params)??(typeof this.definition.hasBtnBg==="function"?this.definition.hasBtnBg.call(this,this.params):this.definition.hasBtnBg));} 9751_hotkey(action){} 9752get hotkey(){return(this._hotkey(this.params)??(typeof this.definition.hotkey==="function"?this.definition.hotkey.call(this,this.params):this.definition.hotkey));} 9753_icon(action){} 9754get icon(){return(this._icon(this.params)??(typeof this.definition.icon==="function"?this.definition.icon.call(this,this.params):this.definition.icon));} 9755_inlineName(action){} 9756get inlineName(){return(this._inlineName(this.params)??(typeof this.definition.inlineName==="function"?this.definition.inlineName.call(this,this.params):this.definition.inlineName)??false);} 9757_isActive(action){} 9758get isActive(){return(this._isActive(this.params)??(typeof this.definition.isActive==="function"?this.definition.isActive.call(this,this.params):this.definition.isActive));} 9759_name(action){} 9760get name(){return(this._name(this.params)??(typeof this.definition.name==="function"?this.definition.name.call(this,this.params):this.definition.name));} 9761_onSelected(action,ev){} 9762onSelected(ev){return(this._onSelected(this.params,ev)??this.definition.onSelected?.call(this,this.params,ev));} 9763_sequence(action){} 9764get sequence(){return(this._sequence(this.params)??(typeof this.definition.sequence==="function"?this.definition.sequence.call(this,this.params):this.definition.sequence));} 9765_sequenceGroup(action){} 9766get sequenceGroup(){return(this._sequenceGroup(this.params)??(typeof this.definition.sequenceGroup==="function"?this.definition.sequenceGroup.call(this,this.params):this.definition.sequenceGroup));} 9767_sequenceQuick(action){} 9768get sequenceQuick(){return(this._sequenceQuick(this.params)??(typeof this.definition.sequenceQuick==="function"?this.definition.sequenceQuick.call(this,this.params):this.definition.sequenceQuick));} 9769_setup(action){} 9770setup(){return this._setup(this.params)??this.definition.setup?.call(this,this.params);} 9771_tags(action){} 9772get tags(){const res=this._tags(this.params)??(typeof this.definition.tags==="function"?this.definition.tags.call(this,this.params):this.definition.tags);return Array.isArray(res)?res:[res];} 9773get tagClassNames(){return this.tags.map((tag)=>`o-tag-${tag}`).join(" ");}} 9774const UseActions=__exports.UseActions=class UseActions extends Reactive{ActionClass=Action;component;moreActions=new Map();transformedActions;store;constructor(component,transformedActions,store){super();this.component=component;this.transformedActions=transformedActions;this.store=store;} 9775more(data={}
9775,id){let moreAction=toRaw(this).moreActions.get(id);if(moreAction){moreAction=this.moreActions.get(id);moreAction.definition.actions=data.actions;}else{moreAction=new this.ActionClass({owner:this.component,id:`more-action:${id}`,definition:{...data,dropdown:true,dropdownState:new DropdownState(),icon:data?.icon??"oi oi-ellipsis-v",isActive:({action})=>action.dropdownState.isOpen,isMoreAction:true,sequence:data.sequence??1000,},store:this.store,});toRaw(this).moreActions.set(data.id,moreAction);} 9776return moreAction;} 9777get actions(){const actions=this.transformedActions.filter((action)=>action.condition).sort((a1,a2)=>a1.sequence-a2.sequence);return actions;} 9778get partition(){const actions=this.transformedActions.filter((action)=>action.condition);const quick=actions.filter((a)=>a.sequenceQuick).sort((a1,a2)=>a1.sequenceQuick-a2.sequenceQuick);const grouped=actions.filter((a)=>a.sequenceGroup);const groups={};for(const a of grouped){if(!(a.sequenceGroup in groups)){groups[a.sequenceGroup]=[];} 9779groups[a.sequenceGroup].push(a);} 9780const sortedGroups=Object.entries(groups).sort(([groupId1],[groupId2])=>groupId1-groupId2);for(const[,actions]of sortedGroups){actions.sort((a1,a2)=>a1.sequence-a2.sequence);} 9781const group=sortedGroups.map(([groupId,actions])=>actions);const other=actions.filter((a)=>!a.sequenceQuick&&!a.sequenceGroup).sort((a1,a2)=>a1.sequence-a2.sequence);return{quick,group,other};}} 9782return __exports;});; 9783 9784/* /mail/static/src/core/common/action_list.js */ 9785odoo.define('@mail/core/common/action_list',['@mail/discuss/call/common/call_dropdown','@mail/utils/common/format','@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{CallDropdown}=require("@mail/discuss/call/common/call_dropdown");const{attClassObjectToString}=require("@mail/utils/common/format");const{Component,onWillUnmount}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{useService}=require("@web/core/utils/hooks");const actionListProps=["inline?","dropdown?","fw?","hasBtnBg?","odooControlPanelSwitchStyle?","thread?",];class Action extends Component{static props=["action","group?","isFirstInGroup?","isLastInGroup?","style?",...actionListProps,];static defaultProps={fw:true};static components={Action,DropdownItem};static template="mail.Action";get ActionList(){return ActionList;} 9786get Dropdown(){if(this.env.inDiscussCallView?.isPip){return CallDropdown;} 9787return Dropdown;} 9788setup(){super.setup();this.store=useService("mail.store");this.ui=useService("ui");this.attClassObjectToString=attClassObjectToString;if(this.props.action.definition?.isMoreAction){onWillUnmount(()=>{this.props.action.dropdownState.close();});}} 9789get action(){return this.props.action;} 9790get hasBtnBg(){return(this.props.odooControlPanelSwitchStyle||this.props.hasBtnBg||this.props.action.hasBtnBg);} 9791onSelected(action,ev){action.onSelected?.(ev);this.env.inCallDropdown?.close();}} 9792const ActionList=__exports.ActionList=class ActionList extends Component{static components={Action};static props=["actions","groupClass?",...actionListProps];static template="mail.ActionList";getActionProps(action,group,{index,isFirstInGroup,isLastInGroup}={}){return{action,group,isFirstInGroup,isLastInGroup,...Object.fromEntries(actionListProps.map((propName)=>{const actualPropName=propName.endsWith("?")?propName.substring(0,propName.length-1):propName;return[actualPropName,this.props[actualPropName]];})),style:`z-index: ${group.length - index}`,};} 9793setup(){super.setup();this.store=useService("mail.store");this.ui=useService("ui");this.actionListProps=actionListProps;} 9794get groups(){let groups;if(this.props.actions.find((i)=>Array.isArray(i))){groups=this.props.actions;}else{groups=[this.props.actions];} 9795return groups.filter((group)=>group.length);} 9796get hasBtnBg(){return this.props.odooControlPanelSwitchStyle||this.props.hasBtnBg;}} 9797return __exports;});; 9798 9799/* /mail/static/src/core/common/activity_model.js */ 9800odoo.define('@mail/core/common/activity_model',['@mail/core/common/record','@mail/utils/common/misc'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{assignDefined}=require("@mail/utils/common/misc");const Activity=__exports.Activity=class Activity extends Record{static _name="mail.activity";static id="id";static _insert(data,{broadcast=true}={}){const activity=this.preinsert(data);assignDefined(activity,data);if(broadcast){this.store.activityBroadcastChannel?.postMessage({type:"INSERT",payload:activity.serialize(),});} 9801return activity;} 9802id;active;activity_category;activity_type_id=fields.One("mail.activity.type");activity_decoration;attachment_ids;can_write;chaining_type;create_date=fields.Datetime();create_uid=fields.One("res.users");date_deadline=fields.Date();date_done=fields.Date();display_name;has_recommended_activities;feedback;icon="fa-tasks";mail_template_ids=fields.Many("mail.template");note=fields.Html("");res_model;res_model_id;res_id;res_name;state;summary;user_id=fields.One("res.users");write_date;write_uid;serialize(){return JSON.parse(JSON.stringify(this.toData(["user_id"])));}} 9803Activity.register();return __exports;});; 9804 9805/* /mail/static/src/core/common/attachment_list.js */ 9806odoo.define('@mail/core/common/attachment_list',['@mail/core/common/gif','@odoo/owl','@web/core/browser/feature_detection','@web/core/confirmation_dialog/confirmation_dialog','@web/core/network/download','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/dropdown/dropdown_item','@web/core/file_viewer/file_viewer_hook','@web/core/l10n/translation','@web/core/utils/hooks','@web/core/utils/urls','@mail/utils/common/format'],function(require){'use strict';let __exports={};const{Gif}=require("@mail/core/common/gif");const{Component}=require("@odoo/owl");const{isMobileOS}=require("@web/core/browser/feature_detection");const{ConfirmationDialog}=require("@web/core/confirmation_dialog/confirmation_dialog");const{downloadFile}=require("@web/core/network/download");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{useFileViewer}=require("@web/core/file_viewer/file_viewer_hook");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{url}=require("@web/core/utils/urls");const{attClassObjectToString}=require("@mail/utils/common/format");class Actions extends Component{static components={Dropdown,DropdownItem};static props=["actions"];static template="mail.Actions";setup(){super.setup();this.actionsMenuState=useDropdownState();}} 9807const AttachmentList=__exports.AttachmentList=class AttachmentList extends Component{static components={Actions,Gif};static props=["attachments","unlinkAttachment","messageSearch?"];static template="mail.AttachmentList";attClassObjectToString=attClassObjectToString;setup(){super.setup();this.ui=useService("ui");this.dialog=useService("dialog");this.fileViewer=useFileViewer();this.actionsMenuState=useDropdownState();this.isMobileOS=isMobileOS();} 9808getImageUrl(attachment){if(attachment.uploading&&attachment.tmpUrl){return attachment.tmpUrl;} 9809return url(attachment.urlRoute,{...attachment.urlQueryParams,});} 9810canDownload(attachment){return!attachment.uploading&&!this.env.inComposer;} 9811onClickDownload(attachment){downloadFile(attachment.downloadUrl);} 9812onClickUnlink(attachment){if(this.env.inComposer){return this.props.unlinkAttachment(attachment);} 9813this.dialog.add(ConfirmationDialog,{body:_t('Do you really want to delete "%s"?',attachment.name),cancel:()=>{},confirm:()=>this.onConfirmUnlink(attachment),});} 9814onClickAttachment(attachment){this.fileViewer.open(attachment,this.props.attachments);} 9815onConfirmUnlink(attachment){this.props.unlinkAttachment(attachment);} 9816onImageLoaded(){this.env.onImageLoaded?.();} 9817get isInChatWindowAndIsAlignedRight(){return this.env.inChatWindow&&this.env.alignedRight;} 9818get isInChatWindowAndIsAlignedLeft(){return this.env.inChatWindow&&!this.env.alignedRight;} 9819getActions(attachment){const res=[];if(this.showDelete){res.push({label:_t("Remove"),icon:"fa fa-tras
9819h",onSelect:()=>this.onClickUnlink(attachment),});} 9820if(this.canDownload(attachment)){res.push({label:_t("Download"),icon:"fa fa-download",onSelect:()=>this.onClickDownload(attachment),});} 9821return res;} 9822get showDelete(){if(this.env.inComposer){return true;} 9823if(!this.attachment.isDeletable){return false;} 9824return(!this.env.message||this.env.message.hasTextContent||(this.env.message&&this.props.attachments.length>1));} 9825showUploaded(attachment){return!attachment.isImage&&!attachment.uploading&&this.env.inComposer;}} 9826return __exports;});; 9827 9828/* /mail/static/src/core/common/attachment_model.js */ 9829odoo.define('@mail/core/common/attachment_model',['@mail/core/common/record','@mail/utils/common/misc','@mail/utils/common/pdf_thumbnail','@web/core/file_viewer/file_model','@web/core/l10n/translation','@web/core/network/rpc','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{assignDefined}=require("@mail/utils/common/misc");const{generatePdfThumbnail}=require("@mail/utils/common/pdf_thumbnail");const{FileModelMixin}=require("@web/core/file_viewer/file_model");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{rpc}=require("@web/core/network/rpc");const{imageUrl,url}=require("@web/core/utils/urls");const Attachment=__exports.Attachment=class Attachment extends FileModelMixin(Record){static _name="ir.attachment";static id="id";static new(){const attachment=super.new(...arguments);Record.onChange(attachment,["extension","name"],()=>{if(!attachment.extension&&attachment.name){attachment.extension=attachment.name.split(".").pop();}});return attachment;} 9830composer=fields.One("Composer",{inverse:"attachments"});thread=fields.One("Thread",{inverse:"attachments"});raw_access_token;res_name;thumbnail_access_token;message=fields.One("mail.message",{inverse:"attachment_ids"});ownership_token;create_date=fields.Datetime();has_thumbnail=fields.Attr(undefined,{onUpdate(){if(this.isPdf&&!this.has_thumbnail&&(this.ownership_token||((!this.thread||this.thread.hasWriteAccess)&&this.store.self.main_user_id?.share===false))){this.setPdfThumbnail();}},});get thumbnailUrl(){return imageUrl("ir.attachment",this.id,"thumbnail",assignDefined({},{access_token:this.thumbnail_access_token,crop:"top",height:110,unique:this.checksum,width:180,}));} 9831get gifPaused(){return this.thread?!this.thread.isFocused:!this.composer?.isFocused;} 9832get isDeletable(){if(this.message&&this.store.self.main_user_id?.share!==false){return this.message.editable;} 9833return true;} 9834get monthYear(){if(!this.create_date){return undefined;} 9835return`${this.create_date.monthLong}, ${this.create_date.year}`;} 9836get uploading(){return this.id<0;} 9837delete(){if(this.tmpUrl){URL.revokeObjectURL(this.tmpUrl);} 9838super.delete();} 9839async remove(){if(this.id>0){await rpc("/mail/attachment/delete",assignDefined({attachment_id:this.id},{access_token:this.ownership_token}));} 9840this.delete();} 9841get previewName(){return this.voice?_t("Voice Message"):this.name||"";} 9842async setPdfThumbnail(){const{isPdfValid,thumbnail}=await generatePdfThumbnail(url(`/mail/attachment/pdf_first_page/${this.id}`,assignDefined({},{access_token:this.ownership_token})));if(isPdfValid){rpc(`/mail/attachment/update_thumbnail`,assignDefined({attachment_id:this.id,thumbnail},{access_token:this.ownership_token}));}}} 9843Attachment.register();return __exports;});; 9844 9845/* /mail/static/src/core/common/attachment_upload_service.js */ 9846odoo.define('@mail/core/common/attachment_upload_service',['@odoo/owl','@web/core/l10n/translation','@web/core/registry','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{EventBus}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const{Deferred}=require("@web/core/utils/concurrency");const AttachmentUploadService=__exports.AttachmentUploadService=class AttachmentUploadService{constructor(env,services){this.setup(env,services);} 9847setup(env,services){this.env=env;this.fileUploadService=services["file_upload"];this.store=services["mail.store"];this.notificationService=services["notification"];this.nextId=-1;this.abortByAttachmentId=new Map();this.deferredByAttachmentId=new Map();this.deletingAttachmentIds=new Set();this.uploadingAttachmentIds=new Set();this._fileUploadBus=new EventBus();this.targetsByTmpId=new Map();this.fileUploadService.bus.addEventListener("FILE_UPLOAD_ADDED",({detail
9847:{upload}})=>{const tmpId=parseInt(upload.data.get("temporary_id"));if(!this.uploadingAttachmentIds.has(tmpId)){return;} 9848const{thread,composer}=this.targetsByTmpId.get(tmpId);const tmpUrl=upload.data.get("tmp_url");this.abortByAttachmentId.set(tmpId,upload.xhr.abort.bind(upload.xhr));const attachment=this.store["ir.attachment"].insert(this._makeAttachmentData(upload,tmpId,composer?undefined:thread,tmpUrl));composer?.attachments.push(attachment);});this.fileUploadService.bus.addEventListener("FILE_UPLOAD_LOADED",({detail:{upload}})=>{const tmpId=parseInt(upload.data.get("temporary_id"));if(!this.uploadingAttachmentIds.has(tmpId)){return;} 9849const def=this.deferredByAttachmentId.get(tmpId);if(upload.xhr.status===413){this.notificationService.add(_t("File too large"),{type:"danger"});def.resolve();this._cleanupUploading(tmpId);return;} 9850if(upload.xhr.status!==200){this.notificationService.add(_t("Server error"),{type:"danger"});def.resolve();this._cleanupUploading(tmpId);return;} 9851const response=JSON.parse(upload.xhr.response);if(response.error){this.notificationService.add(response.error,{type:"danger"});def.resolve();this._cleanupUploading(tmpId);return;} 9852const{thread,composer}=this.targetsByTmpId.get(tmpId);this._processLoaded(thread,composer,response,tmpId,def);});this.fileUploadService.bus.addEventListener("FILE_UPLOAD_ERROR",({detail
9852:{upload}})=>{const tmpId=parseInt(upload.data.get("temporary_id"));if(!this.uploadingAttachmentIds.has(tmpId)){return;} 9853this.deferredByAttachmentId.get(tmpId).resolve();this._cleanupUploading(tmpId);});} 9854_processLoaded(thread,composer,{data},tmpId,def){const{store_data,attachment_id}=data;this.store.insert(store_data);const attachment=this.store["ir.attachment"].get(attachment_id);if(composer){const index=composer.attachments.findIndex(({id})=>id===tmpId);if(index>=0){composer.attachments[index]=attachment;}else{composer.attachments.push(attachment);}} 9855def.resolve(attachment);this._fileUploadBus.trigger("UPLOAD",thread);this._cleanupUploading(tmpId);} 9856_cleanupUploading(tmpId){this.abortByAttachmentId.delete(tmpId);this.deferredByAttachmentId.delete(tmpId);this.uploadingAttachmentIds.delete(tmpId);this.targetsByTmpId.delete(tmpId);this.store["ir.attachment"].get(tmpId)?.remove();} 9857getUploadURL(thread){return"/mail/attachment/upload";} 9858async unlink(attachment){if(this.uploadingAttachmentIds.has(attachment.id)){const deferred=this.deferredByAttachmentId.get(attachment.id);const abort=this.abortByAttachmentId.get(attachment.id);this._cleanupUploading(attachment.id);deferred.resolve();abort();return;} 9859if(this.deletingAttachmentIds.has(attachment.id)){return;} 9860this.deletingAttachmentIds.add(attachment.id);try{await attachment.remove();}finally{this.deletingAttachmentIds.delete(attachment.id);}} 9861async upload(thread,composer,file,options){const tmpId=this.nextId--;const tmpURL=URL.createObjectURL(file);return this._upload(thread,composer,file,options,tmpId,tmpURL);} 9862async _upload(thread,composer,file,options,tmpId,tmpURL){this.targetsByTmpId.set(tmpId,{composer,thread});this.uploadingAttachmentIds.add(tmpId);await this.fileUploadService.upload(this.getUploadURL(thread),[file],{buildFormData:(formData)=>{this._buildFormData(formData,tmpURL,thread,composer,tmpId,options);},}).catch((e)=>{if(e.name!=="AbortError"){throw e;}});const uploadDoneDeferred=new Deferred();this.deferredByAttachmentId.set(tmpId,uploadDoneDeferred);return uploadDoneDeferred;} 9863onFileUploaded(thread,onFileUploaded){this._fileUploadBus.addEventListener("UPLOAD",({detail})=>{if(thread.eq(detail)){onFileUploaded();}});} 9864_buildFormData(formData,tmpURL,thread,composer,tmpId,options){formData.append("thread_id",thread.id);formData.append("tmp_url",tmpURL);formData.append("thread_model",thread.model);formData.append("is_pending",Boolean(composer));formData.append("temporary_id",tmpId);if(options?.activity){formData.append("activity_id",options.activity.id);} 9865return formData;} 9866_makeAttachmentData(upload,tmpId,thread,tmpUrl){const attachmentData={id:tmpId,mimetype:upload.type,name:upload.title,resModel:upload.res_model,thread,extension:upload.title.split(".").pop(),uploading:true,tmpUrl,};return attachmentData;}} 9867const attachmentUploadService=__exports.attachmentUploadService={dependencies:["file_upload","mail.store","notification"],start(env,services){return new AttachmentUploadService(env,services);},};registry.category("services").add("mail.attachment_upload",attachmentUploadService);return __exports;});; 9868 9869/* /mail/static/src/core/common/attachment_uploader_hook.js */ 9870odoo.define('@mail/core/common/attachment_uploader_hook',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{useState}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");__exports.dataUrlToBlob=dataUrlToBlob;function dataUrlToBlob(data,type){const binData=window.atob(data);const uiArr=new Uint8Array(binData.length);uiArr.forEach((_,index)=>(uiArr[index]=binData.charCodeAt(index)));return new Blob([uiArr],{type});} 9871const AttachmentUploader=__exports.AttachmentUploader=class AttachmentUploader{constructor(thread,{composer}={}){this.attachmentUploadService=useService("mail.attachment_upload");Object.assign(this,{thread,composer});} 9872uploadData({data,name,type},options){const file=new File([dataUrlToBlob(data,type)],name,{type});return this.uploadFile(file,options);} 9873async uploadFile(file,options){const thread=options?.thread||this.thread;return this.attachmentUploadService.upload(thread,this.composer,file,options);} 9874async unlink(attachment){await this.attachmentUploadService.unlink(attachment);}} 9875__exports.useAttachmentUploader=useAttachmentUploader;function useAttachmentUploader(thread,{composer,onFileUploaded}={}){return useState(new AttachmentUploader(...arguments));} 9876return __exports;});; 9877 9878/* /mail/static/src/core/common/attachment_view.js */ 9879odoo.define('@mail/core/common/attachment_view',['@odoo/owl','@web/core/utils/hooks','@web/core/utils/objects','@web/core/utils/pdfjs'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillUnmount,onWillUpdateProps,useComponent,useEffect,useRef,useState,}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{deepEqual}=require("@web/core/utils/objects");const{hidePDFJSButtons}=require("@web/core/utils/pdfjs");class AbstractAttachmentView extends Component{static template="mail.AttachmentView";static components={};static props=["threadId","threadModel"];setup(){super.setup();this.store=useService("mail.store");this.uiService=useService("ui");this.iframeViewerPdfRef=useRef("iframeViewerPdf");this.state=useState({thread:undefined,});useEffect((el)=>{if(el){hidePDFJSButtons(this.iframeViewerPdfRef.el);}},()=>[this.iframeViewerPdfRef.el]);this.updateFromProps(this.props);onWillUpdateProps((props)=>this.updateFromProps(props));} 9880onClickNext(){const index=this.state.thread.attachmentsInWebClientView.findIndex((attachment)=>attachment.eq(this.state.thread.message_main_attachment_id));this.state.thread.setMainAttachmentFromIndex(index>=this.state.thread.attachmentsInWebClientView.length-1?0:index+1);} 9881onClickPrevious(){const index=this.state.thread.attachmentsInWebClientView.findIndex((attachment)=>attachment.eq(this.state.thread.message_main_attachment_id));this.state.thread.setMainAttachmentFromIndex(index<=0?this.state.thread.attachmentsInWebClientView.length-1:index-1);} 9882updateFromProps(props){this.state.thread=this.store.Thread.insert({id:props.threadId,model:props.threadModel,});} 9883get displayName(){return this.state.thread.message_main_attachment_id.name;} 9884onClickPopout(){}} 9885const PopoutAttachmentView=__exports.PopoutAttachmentView=class PopoutAttachmentView extends AbstractAttachmentView{static template="mail.PopoutAttachmentView";} 9886__exports.usePopoutAttachment=usePopoutAttachment;function usePopoutAttachment(){const component=useComponent();const uiService=useService("ui");const mailPopoutService=useService("mail.popout");function attachmentViewParentElementClassList(){const attachmentViewEl=document.querySelector(".o-mail-Attachment");let parentElementClassList;if((parentElementClassList=attachmentViewEl?.parentElement?.classList)){return parentElementClassList;} 9887return null;} 9888function showAttachmentView(){const parentElementClassList=attachmentViewParentElementClassList();const hiddenClass="d-none";if(parentElementClassList?.contains(hiddenClass)){parentElementClassList.remove(hiddenClass);}} 9889function hideAttachmentView(){const parentElementClassList=attachmentViewParentElementClassList();const hiddenClass="d-none";if(!parentElementClassList?.contains(hiddenClass)){parentElementClassList?.add(hiddenClass);}} 9890function extractPopoutProps(props){return{threadId:props.threadId,threadModel:props.threadModel,};} 9891function popout(){mailPopoutService.addHooks(()=>{hideAttachmentView();uiService.bus.trigger("resize");},()=>{showAttachmentView();uiService.bus.trigger("resize");});mailPopoutService.popout(PopoutAttachmentView,extractPopoutProps(component.props));} 9892function updatePopout(newProps=component.props){if(mailPopoutService.externalWindow){hideAttachmentView();mailPopoutService.popout(PopoutAttachmentView,extractPopoutProps(newProps));}} 9893function resetPopout(){mailPopoutService.reset();} 9894onMounted(updatePopout);onWillUpdateProps((props)=>{const oldProps=extractPopoutProps(component.props);const newProps=extractPopoutProps(props);if(!deepEqual(oldProps,newProps)){updatePopout(newProps);}});onWillUnmount(resetPopout);return{popout,updatePopout,resetPopout,};} 9895const AttachmentView=__exports.AttachmentView=class AttachmentView extends AbstractAttachmentView{setup(){super.setup();this.attachmentPopout=usePopoutAttachment();} 9896onClickPopout(){this.attachmentPopout.popout();}} 9897return __exports;});; 9898 9899/* /mail/static/src/core/common/autoresize_input.js */ 9900odoo.define('@mail/core/common/autoresize_input',['@odoo/owl','@web/core/utils/autoresize'],function(require){'use strict';let __exports={};const{Component,useRef,useState,onWillUpdateProps,onMounted}=require("@odoo/owl");const{useAutoresize}=require("@web/core/utils/autoresize");const AutoresizeInput=__exports.AutoresizeInput=class AutoresizeInput extends Component{static template="mail.AutoresizeInput";static props={autofocus:{type:Boolean,optional:true},className:{type:String,optional:true},enabled:{optional:true},onValidate:{type:Function,optional:true},placeholder:{type:String,optional:true},value:{type:String,optional:true},};static defaultProps={autofocus:false,className:"",enabled:true,onValidate:()=>{},placeholder:"",};setup(){super.setup();this.state=useState({value:this.props.value,isFocused:false,});this.inputRef=useRef("input");onWillUpdateProps((nextProps)=>
9900{if(this.props.value!==nextProps.value){this.state.value=nextProps.value;}});useAutoresize(this.inputRef);onMounted(()=>{if(this.props.autofocus){this.inputRef.el.focus();this.inputRef.el.setSelectionRange(-1,-1);}});} 9901onKeydownInput(ev){switch(ev.key){case"Enter":this.inputRef.el.blur();break;case"Escape":ev.stopPropagation();this.state.value=this.props.value;this.inputRef.el.blur();break;}} 9902onBlurInput(){this.state.isFocused=false;this.props.onValidate(this.state.value);}} 9903return __exports;});; 9904 9905/* /mail/static/src/core/common/canned_response_model.js */ 9906odoo.define('@mail/core/common/canned_response_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const CannedResponse=__exports.CannedResponse=class CannedResponse extends Record{static _name="mail.canned.response";static id="id";id;source;substitution;} 9907CannedResponse.register();return __exports;});; 9908 9909/* /mail/static/src/core/common/chat_bubble.js */ 9910odoo.define('@mail/core/common/chat_bubble',['@mail/core/common/im_status','@odoo/owl','@web/core/utils/hooks','@mail/utils/common/hooks','@web/core/popover/popover_hook','@mail/core/common/country_flag','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{ImStatus}=require("@mail/core/common/im_status");const{Component,useEffect,useRef,useState,useSubEnv}=require("@odoo/owl");const{useChildRef,useService}=require("@web/core/utils/hooks");const{useHover}=require("@mail/utils/common/hooks");const{usePopover}=require("@web/core/popover/popover_hook");const{CountryFlag}=require("@mail/core/common/country_flag");const{isMobileOS}=require("@web/core/browser/feature_detection");class ChatBubblePreview extends Component{static props=["chatWindow","close"];static template="mail.ChatBubblePreview";get thread(){return this.props.chatWindow.thread;} 9911get previewText(){const lastMessage=this.thread?.newestPersistentOfAllMessage;if(!lastMessage){return false;} 9912return lastMessage.previewText;}} 9913const ChatBubble=__exports.ChatBubble=class ChatBubble extends Component{static components={CountryFlag,ImStatus};static props=["chatWindow"];static template="mail.ChatBubble";setup(){super.setup();this.store=useService("mail.store");const popoverRef=useChildRef();this.isMobileOS=isMobileOS();this.popover=usePopover(ChatBubblePreview,{animation:false,position:"left-middle",popoverClass:"dropdown-menu bg-view border-0 p-0 overflow-visible o-rounded-bubble mx-1",ref:popoverRef,});this.env.bus.addEventListener("ChatBubble:preview-will-open",({detail})=>{if(detail===this){return;} 9914this.popover.close();});this.hover=useHover(["root",popoverRef],{onHover:()=>{this.env.bus.trigger("ChatBubble:preview-will-open",this);this.popover.open(this.rootRef.el,{chatWindow:this.props.chatWindow});},onAway:()=>this.popover.close(),});this.rootRef=useRef("root");this.state=useState({bouncing:false});useEffect((importantCounter)=>{this.state.bouncing=Boolean(importantCounter);},()=>[this.thread?.importantCounter]);useSubEnv({inChatBubble:true});} 9915get thread(){return this.props.chatWindow.thread;} 9916get showImStatus(){return(this.thread?.correspondent?.im_status&&this.thread.correspondent.im_status!=="offline");}} 9917return __exports;});; 9918 9919/* /mail/static/src/core/common/chat_hub.js */ 9920odoo.define('@mail/core/common/chat_hub',['@mail/core/common/chat_hub_model','@mail/core/common/chat_window','@mail/core/common/action_list','@mail/utils/common/hooks','@odoo/owl','@web/core/browser/browser','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/registry','@web/core/utils/hooks','@mail/core/common/chat_bubble','@web/core/browser/feature_detection','@web/core/l10n/translation','@mail/core/common/action'],function(require){'use strict';let __exports={};const{CHAT_HUB_COMPACT_LS}=require("@mail/core/common/chat_hub_model");const{ChatWindow}=require("@mail/core/common/chat_window");const{ActionList}=require("@mail/core/common/action_list");const{useHover,useMovable}=require("@mail/utils/common/hooks");const{Component,useEffect,useExternalListener,useRef,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{registry}=require("@web/core/registry");const{useService}=require("@web/core/utils/hooks");const{ChatBubble}=require("@mail/core/common/chat_bubble");const{isMobileOS}=require("@web/core/browser/feature_detection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{Action}=require("@mail/core/common/action");const ChatHub=__exports.ChatHub=class ChatHub extends Component{static components={ActionList,ChatBubble,ChatWindow,Dropdown};static props=[];static template="mail.ChatHub";get chatHub(){return this.store.chatHub;} 9921setup(){super.setup();this.store=useService("mail.store");this.ui=useService("ui");this.busMonitoring=useService("bus.monitoring_service");this.bubblesHover=useHover("bubbles");this.moreHover=useHover(["more-button","more-menu"],{onHover:()=>(this.more.isOpen=true),onAway:()=>(this.more.isOpen=false),});this.options=useDropdownState();this.more=useDropdownState();this.ref=useRef("bubbles");this.position=useState({dragged:false,isDragging:false,top:"unset",left:"unset",bottom:`${this.chatHub.BUBBLE_OUTER}px;`,right:`${this.chatHub.BUBBLE_OUTER + this.chatHub.BUBBLE_START}px;`,});this.onResize();useExternalListener(browser,"resize",this.onResize);useEffect(()=>{if(this.chatHub.folded.length&&this.store.channels?.status==="not_fetched"){this.store.channels.fetch();}});useMovable({enable:()=>this.chatHub.compact||!this.chatHub.opened.length,cursor:"grabbing",ref:this.ref,elements:".o-mail-ChatHub-bubbles",onDragStart:()=>{this.more.close();this.options.close();this.position.isDragging=true;this.position.dragged=true;},onDragEnd:()=>(this.position.isDragging=false),onDrop:this.onDrop.bind(this),});this.env.bus.addEventListener("ChatWindow:will-open",()=>{this.resetPosition();});} 9922get optionActions(){const actions=[];if(this.chatHub.showConversations&&!this.chatHub.compact){actions.push(new Action({owner:this,id:"hide-all",definition:{name:_t("Hide all conversations"),icon:"fa fa-eye-slash",onSelected:()=>this.chatHub.hideAll(),},store:this.store,}),new Action({owner:this,id:"close-all",definition:{name:_t("Close all conversations"),icon:"oi oi-close",onSelected:()=>this.chatHub.closeAll(),},store:this.store,}));} 9923if(this.position.dragged){actions.push(new Action({owner:this,id:"reset-position",definition:{name:_t("Reset initial position"),icon:"fa fa-undo",onSelected:()=>this.resetPosition(),},store:this.store,}));} 9924return actions;} 9925get isMobileOS(){return isMobileOS();} 9926onDrop({top,left}){this.position.bottom="unset";this.position.right="unset";this.position.top=`${top}px`;
9926this.position.left=`${left}px`;} 9927onResize(){this.chatHub.onRecompute();} 9928resetPosition(){this.position.top="unset";this.position.left="unset";this.position.bottom=`${this.chatHub.BUBBLE_OUTER}px;`;this.position.right=`${this.chatHub.BUBBLE_OUTER + this.chatHub.BUBBLE_START}px;`;this.position.dragged=false;this.options.close();} 9929get compactCounter(){let counter=0;const cws=this.chatHub.opened.concat(this.chatHub.folded);for(const chatWindow of cws){counter+=chatWindow.thread.importantCounter>0?1:0;} 9930return counter;} 9931get hiddenCounter(){let counter=0;for(const chatWindow of this.chatHub.folded.slice(this.chatHub.maxFolded)){counter+=chatWindow.thread.importantCounter>0?1:0;} 9932return counter;} 9933get displayConversations(){return this.chatHub.showConversations&&!this.chatHub.compact;} 9934get isShown(){return true;} 9935shouldDisplayChatWindow(cw){return cw.canShow;} 9936expand(){browser.localStorage.removeItem(CHAT_HUB_COMPACT_LS);this.chatHub._recomputeCompact++;this.more.isOpen=this.chatHub.folded.length>this.chatHub.maxFolded;if(this.chatHub.opened.length>0){this.resetPosition();}}} 9937const chatHubService=__exports.chatHubService={dependencies:["bus.monitoring_service","mail.store","ui"],start(){registry.category("main_components").add("mail.ChatHub",{Component:ChatHub});},};registry.category("services").add("mail.chat_hub",chatHubService);return __exports;});; 9938 9939/* /mail/static/src/core/common/chat_hub_model.js */ 9940odoo.define('@mail/core/common/chat_hub_model',['@web/core/browser/browser','@mail/core/common/record','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{fields,Record}=require("@mail/core/common/record");const{Deferred,Mutex}=require("@web/core/utils/concurrency");const CHAT_HUB_KEY=__exports.CHAT_HUB_KEY="mail.ChatHub";const CHAT_HUB_COMPACT_LS=__exports.CHAT_HUB_COMPACT_LS="mail.user_setting.chathub_compact";const ChatHub=__exports.ChatHub=class ChatHub extends Record{BUBBLE=56;BUBBLE_START=15;BUBBLE_LIMIT=7;BUBBLE_OUTER=10;WINDOW_GAP=10;WINDOW_INBETWEEN=5;WINDOW=380;static new(){const chatHub=super.new(...arguments);browser.addEventListener("storage",(ev)=>{if(ev.key===CHAT_HUB_KEY){chatHub.load(ev.newValue||undefined);}else if(ev.key===null){chatHub.load();} 9941if(ev.key===CHAT_HUB_COMPACT_LS){chatHub._recomputeCompact++;}});chatHub.load(browser.localStorage.getItem(CHAT_HUB_KEY)??undefined).then(()=>chatHub.initPromise.resolve());return chatHub;} 9942_recomputeCompact=0;compact=fields.Attr(false,{compute(){void this._recomputeCompact;return browser.localStorage.getItem(CHAT_HUB_COMPACT_LS)==="true";},});canShowOpened=fields.Many("ChatWindow");canShowFolded=fields.Many("ChatWindow");opened=fields.Many("ChatWindow",{inverse:"hubAsOpened",onAdd(r){this.onRecompute();},});folded=fields.Many("ChatWindow",{inverse:"hubAsFolded"});initPromise=new Deferred();preFirstFetchPromise=new Deferred();loadMutex=new Mutex();async closeAll(){await this.initPromise;const promises=[];for(const cw of[...this.opened,...this.folded]){promises.push(cw.close({notifyState:false}));} 9943await Promise.all(promises);this.save();} 9944hideAll(){for(const cw of this.opened){cw.bypassCompact=false;} 9945browser.localStorage.setItem(CHAT_HUB_COMPACT_LS,true);this._recomputeCompact++;} 9946onRecompute(){while(this.opened.length>this.maxOpened){const cw=this.opened.pop();this.folded.unshift(cw);}} 9947async load(str="{}"){await this.loadMutex.exec(()=>this._load(str));} 9948async _load(str){const{opened=[],folded=[]}=JSON.parse(str);const hasInvalidData=opened.some((data)=>!data.id||!data.model)||folded.some((data)=>!data.id||!data.model);if(hasInvalidData){opened.length=0;folded.length=0;browser.localStorage.removeItem(CHAT_HUB_KEY);} 9949const getThread=(data)=>this.store.Thread.getOrFetch(data,["display_name"]);const openPromises=opened.map(getThread);const foldPromises=folded.map(getThread);this.preFirstFetchPromise.resolve();const foldThreads=await Promise.all(foldPromises);const openThreads=await Promise.all(openPromises);const insertChatWindows=(threads)=>threads.filter((thread)=>thread?.model==="discuss.channel").map((thread)=>this.store.ChatWindow.insert({thread}));const toFold=insertChatWindows(foldThreads);const toOpen=insertChatWindows(openThreads);for(const chatWindow of[...this.opened,...this.folded]){if(chatWindow.notIn(toOpen)&&chatWindow.notIn(toFold)){chatWindow.close({force:true,notifyState:false});}} 9950this.folded=toFold;this.opened=toOpen;} 9951get maxOpened(){const chatBubblesWidth=this.BUBBLE_START+this.BUBBLE+this.BUBBLE_OUTER*2;const startGap=this.store.env.services.ui.isSmall?0:this.WINDOW_GAP;const endGap=this.store.env.services.ui.isSmall?0:this.WINDOW_GAP;const available=browser.innerWidth-startGap-endGap-chatBubblesWidth;const maxAmountWithoutHidden=Math.max(1,Math.floor(available/(this.WINDOW+this.WINDOW_INBETWEEN)));return maxAmountWithoutHidden;} 9952get maxFolded(){const chatBubbleSpace=this.BUBBLE_START+this.BUBBLE+this.BUBBLE_OUTER*2;
9952return Math.min(this.BUBBLE_LIMIT,Math.floor(browser.innerHeight/chatBubbleSpace));} 9953save(){browser.localStorage.setItem(CHAT_HUB_KEY,JSON.stringify({opened:this.opened.map((cw)=>({id:cw.thread.id,model:cw.thread.model})),folded:this.folded.map((cw)=>({id:cw.thread.id,model:cw.thread.model})),}));} 9954showConversations=fields.Attr(false,{compute(){return this.canShowOpened.length+this.canShowFolded.length>0;},});} 9955ChatHub.register();return __exports;});; 9956 9957/* /mail/static/src/core/common/chat_window.js */ 9958odoo.define('@mail/core/common/chat_window',['@mail/core/common/action_list','@mail/core/common/composer','@mail/core/common/im_status','@mail/core/common/thread','@mail/core/common/autoresize_input','@mail/core/common/country_flag','@mail/core/common/thread_actions','@mail/core/common/thread_icon','@mail/utils/common/hooks','@web/core/utils/misc','@odoo/owl','@web/core/dropdown/dropdown','@web/core/l10n/localization','@web/core/l10n/translation','@web/core/utils/hooks','@mail/discuss/typing/common/typing','@web/core/hotkeys/hotkey_service','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{ActionList}=require("@mail/core/common/action_list");const{Composer}=require("@mail/core/common/composer");const{ImStatus}=require("@mail/core/common/im_status");const{Thread}=require("@mail/core/common/thread");const{AutoresizeInput}=require("@mail/core/common/autoresize_input");const{CountryFlag}=require("@mail/core/common/country_flag");const{useThreadActions}=require("@mail/core/common/thread_actions");const{ThreadIcon}=require("@mail/core/common/thread_icon");const{useHover,useMessageScrolling}=require("@mail/utils/common/hooks");const{isEventHandled}=require("@web/core/utils/misc");const{Component,toRaw,useChildSubEnv,useRef,useState,useSubEnv}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{localization}=require("@web/core/l10n/localization");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{Typing}=require("@mail/discuss/typing/common/typing");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{isMobileOS}=require("@web/core/browser/feature_detection");const ChatWindow=__exports.ChatWindow=class ChatWindow extends Component{static components={ActionList,CountryFlag,Dropdown,Thread,Composer,ThreadIcon,ImStatus,AutoresizeInput,Typing,};static props=["chatWindow","right?"];static template="mail.ChatWindow";setup(){super.setup();useSubEnv({inChatWindow:true});this.store=useService("mail.store");this.messageHighlight=useMessageScrolling();this.state=useState({actionsMenuOpened:false,jumpThreadPresent:0,editingGuestName:false,editingName:false,});this.ui=useService("ui");this.contentRef=useRef("content");this.threadActions=useThreadActions({thread:()=>this.thread});this.actionsMenuButtonHover=useHover("actionsMenuButton");this.parentChannelHover=useHover("parentChannel");this.isMobileOS=isMobileOS();useChildSubEnv({closeActionPanel:()=>this.threadActions.activeAction?.close(),messageHighlight:this.messageHighlight,});} 9959get autofocusComposer(){if(this.isMobileOS||this.thread.composerDisabled){return undefined;} 9960return this.props.chatWindow.autofocus;} 9961get autofocusThread(){if(this.isMobileOS||this.thread.composerDisabled){return this.props.chatWindow.autofocus;} 9962return undefined;}
9963get composerType(){if(this.thread.model!=="discuss.channel"){return"note";} 9964return undefined;} 9965get hasActionsMenu(){return(this.partitionedActions.group.length>0||this.partitionedActions.other.length>0||(this.ui.isSmall&&this.partitionedActions.quick.length>2)||(!this.ui.isSmall&&this.partitionedActions.quick.length>3));} 9966get thread(){return this.props.chatWindow.thread;} 9967get showImStatus(){return this.thread?.channel_type==="chat"&&this.thread.correspondent;} 9968get attClass(){return{"w-100 h-100 o-mobile":this.ui.isSmall,"o-rounded-bubble border border-dark mb-2":!this.ui.isSmall,};} 9969get style(){const textDirection=localization.direction;const offsetFrom=textDirection==="rtl"?"left":"right";const visibleOffset=this.ui.isSmall?0:this.props.right;const oppositeFrom=offsetFrom==="right"?"left":"right";return`${offsetFrom}: ${visibleOffset}px; ${oppositeFrom}: auto;`;} 9970onKeydown(ev){const chatWindow=toRaw(this.props.chatWindow);if(ev.key==="Escape"&&this.threadActions.activeAction){this.threadActions.activeAction.close();ev.stopPropagation();return;} 9971if(ev.target.closest(".o-dropdown")||ev.target.closest(".o-dropdown--menu")){return;} 9972ev.stopPropagation();switch(getActiveHotkey(ev)){case"escape":if(isEventHandled(ev,"NavigableList.close")||isEventHandled(ev,"Composer.discard")){return;} 9973if(this.state.editingName){this.state.editingName=false;return;} 9974this.close({escape:true});break;case"tab":{const index=this.store.chatHub.opened.findIndex((cw)=>cw.eq(chatWindow));if(index===this.store.chatHub.opened.length-1){this.store.chatHub.opened[0].focus({jumpToNewMessage:true});}else{this.store.chatHub.opened[index+1].focus({jumpToNewMessage:true});} 9975break;} 9976case"control+k":this.store.env.services.command.openMainPalette({searchValue:"@"});ev.preventDefault();break;}} 9977onClickHeader(ev){if(this.ui.isSmall||this.state.editingName||this.props.chatWindow.actionsDisabled||isEventHandled(ev,"ThreadAction.onSelected")){return;} 9978this.toggleFold();} 9979toggleFold(){const chatWindow=toRaw(this.props.chatWindow);if(this.state.actionsMenuOpened){return;} 9980chatWindow.fold();} 9981close(options){const chatWindow=toRaw(this.props.chatWindow);chatWindow.close(options);} 9982get actionsMenuTitleText(){return _t("Open Actions Menu");} 9983async renameThread(name){const thread=toRaw(this.thread);await thread.rename(name);this.state.editingName=false;} 9984async renameGuest(name){const newName=name.trim();if(this.store.self.name!==newName){await this.store.self.updateGuestName(newName);} 9985this.state.editingGuestName=false;} 9986async onActionsMenuStateChanged(isOpen){this.state.actionsMenuOpened=isOpen;}} 9987return __exports;});; 9988 9989/* /mail/static/src/core/common/chat_window_model.js */ 9990odoo.define('@mail/core/common/chat_window_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const ChatWindow=__exports.ChatWindow=class ChatWindow extends Record{static id="thread";actionsDisabled=false;bypassCompact=false;thread=fields.One("Thread",{inverse:"chat_window"});autofocus=0;jumpToNewMessage=0;hidden=false;fromMessagingMenu=false;hubAsOpened=fields.One("ChatHub",{inverse:"opened"});hubAsFolded=fields.One("ChatHub",{inverse:"folded"});hubAsCanShowOpened=fields.One("ChatHub",{inverse:"canShowOpened",compute(){if(this.canShow&&this.hubAsOpened){return this.store.chatHub;}},});hubAsCanShowFolded=fields.One("ChatHub",{inverse:"canShowFolded",compute(){if(this.canShow&&this.hubAsFolded){return this.store.chatHub;}},});get displayName(){return this.thread?.displayName;} 9991get isOpen(){return Boolean(this.hubAsOpened);} 9992canShow=fields.Attr(true,{compute(){return this.computeCanShow();},});computeCanShow(){if(this.store.env.services.ui.isSmall){return!this.hubAsFolded||!this.store.discuss?.isActive;} 9993return!this.store.discuss?.isActive;} 9994async close(options={}){await this.store.chatHub.initPromise;const{escape=false}=options;options.notifyState??=true;const chatHub=this.store.chatHub;const indexAsOpened=chatHub.opened.findIndex((w)=>w.eq(this));this.store.chatHub.opened.delete(this);this.store.chatHub.folded.delete(this);if(options.notifyState){this.store.chatHub.save();} 9995if(escape&&indexAsOpened!==-1&&chatHub.opened.length>0){chatHub.opened[indexAsOpened===0?0:indexAsOpened-1].focus();} 9996this._onClose(options);this.delete();} 9997focus({jumpToNewMessage=false}={}){this.autofocus++;if(jumpToNewMessage){this.jumpToNewMessage++;}} 9998async fold(){await this.store.chatHub.initPromise;this.store.chatHub.opened.delete(this);this.store.chatHub.folded.delete(this);this.store.chatHub.folded.unshift(this);this.store.chatHub.save();this.bypassCompact=false;} 9999async open({focus=false,notifyState=true,jumpToNewMessage=false,swapOpened=true,}={}){await this.store.chatHub.initPromise;this.store.env.bus.trigger("ChatWindow:will-open");this.store.chatHub.folded.delete(this);if(swapOpened||!this.store.chatHub.opened.includes(this)){this.store.chatHub.opened.delete(this);this.store.chatHub.opened.unshift(this);} 10000if(notifyState){this.store.chatHub.save();} 10001if(focus){this.focus({jumpToNewMessage});}} 10002_onClose(){}}
10003ChatWindow.register();return __exports;});; 10004 10005/* /mail/static/src/core/common/composer.js */ 10006odoo.define('@mail/core/common/composer',['@mail/core/common/attachment_list','@mail/core/common/attachment_uploader_hook','@web/core/dropzone/dropzone_hook','@mail/core/common/mail_attachment_dropzone','@mail/core/common/message_confirm_dialog','@mail/core/common/navigable_list','@mail/core/common/plugin/plugin_sets','@mail/core/common/suggestion_hook','@mail/utils/common/hooks','@mail/utils/common/format','@mail/utils/common/misc','@html_editor/wysiwyg','@web/core/network/rpc','@web/core/utils/misc','@web/core/browser/browser','@web/core/utils/timing','@odoo/owl','@web/core/l10n/translation','@web/core/utils/hooks','@web/core/utils/html','@web/views/fields/file_handler','@web/core/utils/strings','@web/core/browser/feature_detection','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@mail/core/common/composer_actions','@mail/core/common/action_list','@html_editor/utils/dom_traversal','@html_editor/utils/position','@web/core/popover/popover_hook'],function(require){'use strict';let __exports={};const{AttachmentList}=require("@mail/core/common/attachment_list");const{useAttachmentUploader}=require("@mail/core/common/attachment_uploader_hook");const{useCustomDropzone}=require("@web/core/dropzone/dropzone_hook");const{MailAttachmentDropzone}=require("@mail/core/common/mail_attachment_dropzone");const{MessageConfirmDialog}=require("@mail/core/common/message_confirm_dialog");const{NavigableList}=require("@mail/core/common/navigable_list");
10006const{MAIL_PLUGINS,MAIL_SMALL_UI_PLUGINS}=require("@mail/core/common/plugin/plugin_sets");const{mapSuggestionsToOptions,useSuggestion}=require("@mail/core/common/suggestion_hook");const{useSelection}=require("@mail/utils/common/hooks");const{trimEmptyBlocksAround}=require("@mail/utils/common/format");const{isDragSourceExternalFile}=require("@mail/utils/common/misc");const{Wysiwyg}=require("@html_editor/wysiwyg");const{rpc}=require("@web/core/network/rpc");const{isEventHandled,markEventHandled}=require("@web/core/utils/misc");const{browser}=require("@web/core/browser/browser");const{useDebounced}=require("@web/core/utils/timing");const{Component,markup,onMounted,onWillUnmount,useChildSubEnv,useEffect,useRef,useState,useExternalListener,toRaw,EventBus,reactive,}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{htmlJoin,isHtmlEmpty,isMarkup,setElementContent}=require("@web/core/utils/html");const{FileUploader}=require("@web/views/fields/file_handler");const{isEmail}=require("@web/core/utils/strings");const{isDisplayStandalone,isIOS,isMobileOS}=require("@web/core/browser/feature_detection");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{useComposerActions}=require("@mail/core/common/composer_actions");const{ActionList}=require("@mail/core/common/action_list");const{closestElement,lastLeaf}=require("@html_editor/utils/dom_traversal");const{rightPos}=require("@html_editor/utils/position");const{usePopover}=require("@web/core/popover/popover_hook");const EDIT_CLICK_TYPE={CANCEL:"cancel",SAVE:"save",};class FullComposerRecoveryPopover extends Component{static props=["composer","onClickFullRecover","onClickTextRecover","close?"];static template="mail.FullComposerRecoveryPopover";onClickFullRecover(){this.props.onClickFullRecover();this.props.close();} 10007onClickTextRecover(){this.props.onClickTextRecover();this.props.close();}} 10008const Composer=__exports.Composer=class Composer extends Component{static components={ActionList,AttachmentList,Dropdown,DropdownItem,FileUploader,NavigableList,Wysiwyg,};static defaultProps={autofocus:0,mode:"normal",className:"",sidebar:true,showFullComposer:true,allowUpload:true,};static props=["composer","autofocus?","onCloseFullComposerCallback?","onDiscardCallback?","onPostCallback?","mode?","placeholder?","dropzoneRef?","className?","sidebar?","type?","showFullComposer?","allowUpload?",];static template="mail.Composer";setup(){super.setup();this.dialogService=useService("dialog");this.editor=undefined;this.isMobileOS=isMobileOS();this.isIosPwa=isIOS()&&isDisplayStandalone();this.store=useService("mail.store");this.composerActions=useComposerActions({composer:()=>this.props.composer});this.EDIT_CLICK_TYPE=EDIT_CLICK_TYPE;this.OR_PRESS_SEND_KEYBIND=_t("or press %(send_keybind)s",{send_keybind:htmlJoin(this.sendKeybinds.map((key)=>markup`<samp>${key}</samp>`)," + "),});this.attachmentUploader=useAttachmentUploader(this.thread??this.props.composer.message.thread,{composer:this.props.composer});this.ui=useService("ui");this.composerService=useService("mail.composer");this.ref=useRef("textarea");this.fakeTextarea=useRef("fakeTextarea");this.inputContainerRef=useRef("input-container");this.pickerContainerRef=useRef("picker-container");this.state=useState({active:true,isFullComposerOpen:false,});this.root=useRef("root");this.fullComposerRecoveryPopover=usePopover(FullComposerRecoveryPopover,{closeOnClickAway:false,closeOnEscape:false,position:"top-end",popoverClass:"dropdown-menu o-dropdown--menu bg-view overflow-visible o-rounded-bubble mx-1",});this.fullComposerBus=new EventBus();this.selection=useSelection({refName:"textarea",model:this.props.composer.selection,preserveOnClickAwayPredicate:async(ev)=>{await new Promise(setTimeout);return(!this.isEventTrusted(ev)||isEventHandled(ev,"sidebar.openThread")||isEventHandled(ev,"emoji.selectEmoji")||isEventHandled(ev,"Composer.onClickAddEmoji")||isEventHandled(ev,"composer.clickOnAddAttachment")||isEventHandled(ev,"composer.selectSuggestion")||isEventHandled(ev,"composer.clickInsertCannedResponse"));},});this.suggestion=useSuggestion();this.markEventHandled=markEventHandled;this.onDropFile=this.onDropFile.bind(this);this.saveContentDebounced=useDebounced(this.saveContent,5000,{execBeforeUnmount:true,});this.updateFromEditor=false;useExternalListener(window,"beforeunload",this.saveContent.bind(this));useExternalListener(window,"click",(ev)=>{const target=ev.composedPath()[0];if(this.ui.isSmall&&this.composerActions.activePicker&&this.pickerContainerRef.el&&target!==this.pickerContainerRef.el&&!this.pickerContainerRef.el.contains(target)){this.composerActions.activePicker.close?.();}},{capture:true});if(this.props.dropzoneRef){useCustomDropzone(this.props.dropzoneRef,MailAttachmentDropzone,{extraClass:"o-mail-Composer-dropzone",onDrop:this.onDropFile,},()=>this.props.allowUpload&&(!this.store.rtc.state.isFullscreen||this.env.inMeetingView)&&(this.props.composer.message||!this.thread?.messageInEdition));} 10009useChildSubEnv({inComposer:true});useEffect((focus)=>
10009{if(focus&&this.ref.el){this.selection.restore();this.ref.el.focus();} 10010if(focus&&this.editor){this.editor.shared.selection.focusEditable();this.editor.shared.selection.selectAroundNonEditable();}},()=>[this.props.autofocus+this.props.composer.autofocus,this.props.placeholder]);useEffect(()=>{if(this.props.composer.replyToMessage){this.props.composer.autofocus++;}},()=>[this.props.composer.replyToMessage]);useEffect(()=>{if(this.fakeTextarea.el?.scrollHeight){let wasEmpty=false;if(!this.fakeTextarea.el.value){wasEmpty=true;this.fakeTextarea.el.value="0";} 10011this.ref.el.style.height=this.fakeTextarea.el.scrollHeight+"px";if(wasEmpty){this.fakeTextarea.el.value="";}} 10012this.saveContentDebounced();},()=>[this.props.composer.composerText,this.ref.el]);useEffect(()=>{if(!this.props.composer.forceCursorMove){return;} 10013this.selection.restore();this.props.composer.forceCursorMove=false;},()=>[this.props.composer.forceCursorMove]);useEffect((isFullComposerOpen,restoredFromFullComposer,fullComposerButtonEl)=>{if(isFullComposerOpen||!restoredFromFullComposer||!fullComposerButtonEl){this.fullComposerRecoveryPopover.close();return;} 10014if(this.fullComposerRecoveryPopover.isOpen){return;} 10015this.fullComposerRecoveryPopover.open(fullComposerButtonEl,{composer:this.props.composer,onClickFullRecover:()=>{this.onClickFullComposer();this.props.composer.restoredFromFullComposer=false;},onClickTextRecover:()=>{this.props.composer.restoredFromFullComposer=false;},});},()=>[this.state.isFullComposerOpen,this.props.composer.restoredFromFullComposer,this.root.el?.querySelector("button[name='open-full-composer']"),]);onMounted(()=>{this.ref.el?.scrollTo({top:0,behavior:"instant"});if(!this.props.composer.composerText){this.restoreContent();}});onWillUnmount(()=>{this.props.composer.isFocused=false;});const composerProxy=reactive(this.props.composer,()=>{if(this.status===2){return;} 10016const composerHtml=composerProxy.composerHtml;if(this.updateFromEditor){return;} 10017if(!this.editor?.editable){return;} 10018setElementContent(this.editor.editable,composerHtml);this.setEditorCursorEnd();this.editor.shared.history.addStep();});void composerProxy.composerHtml;} 10019setEditorCursorEnd(){const lastNode=lastLeaf(this.editor?.editable);if(!lastNode){return;} 10020const nonEditableAncestor=closestElement(lastNode,(el)=>!el.isContentEditable);if(nonEditableAncestor&&this.editor.editable.contains(nonEditableAncestor)){const[anchorNode,anchorOffset]=rightPos(nonEditableAncestor);this.editor.shared.selection.setSelection({anchorNode,anchorOffset});}else{this.editor.shared.selection.setCursorEnd(lastNode);} 10021this.editor.shared.selection.selectAroundNonEditable();} 10022get areAllActionsDisabled(){return false;} 10023get isMultiUpload(){return true;} 10024get placeholder(){if(this.props.placeholder){return this.props.placeholder;} 10025if(this.thread){if(this.thread.channel_type==="channel"){const threadName=this.thread.displayName;if(this.thread.parent_channel_id){return _t('Message "%(subChannelName)s"',{subChannelName:threadName,});} 10026return _t("Message #%(threadName)sâ¦",{threadName});} 10027return _t("Message %(thread name)sâ¦",{"thread name":this.thread.displayName});} 10028return"";} 10029get wysiwygConfig(){return{content:this.props.composer.composerHtml,placeholder:this.placeholder,Plugins:this.ui.isSmall?MAIL_SMALL_UI_P
10029LUGINS:MAIL_PLUGINS,composerPluginDependencies:{onBeforePaste:(selection,ev)=>this.onPaste(ev),onFocusin:this.onFocusin.bind(this),onFocusout:this.onFocusout.bind(this),onInput:this.onInput.bind(this),onKeydown:this.onKeydown.bind(this),},classList:["o-mail-Composer-html"],onChange:()=>this.onChangeWysiwygContent(),onEditorReady:()=>{this.setEditorCursorEnd();this.editor.shared.history.addStep();},};} 10030onClickCancelOrSaveEditText(ev){const composer=toRaw(this.props.composer);if(composer.message&&ev.target.dataset?.type===EDIT_CLICK_TYPE.CANCEL){this.props.onDiscardCallback(ev);} 10031if(composer.message&&ev.target.dataset?.type===EDIT_CLICK_TYPE.SAVE){this.editMessage(ev);}} 10032get CANCEL_OR_SAVE_EDIT_TEXT(){const tags={open_samp:markup`<samp>`,close_samp:markup`</samp>`,open_em:markup`<em>`,close_em:markup`</em>`,open_cancel:markup`<button class="btn btn-link fst-italic p-0 align-baseline" data-type="${EDIT_CLICK_TYPE.CANCEL}">`,close_cancel:markup`</button>`,open_save:markup`<button class="btn btn-link fst-italic p-0 align-baseline" data-type="${EDIT_CLICK_TYPE.SAVE}">`,close_save:markup`</button>`,};return this.env.inChatter?_t("%(open_samp)sEscape%(close_samp)s %(open_em)sto %(open_cancel)scancel%(close_cancel)s%(close_em)s, %(open_samp)sCTRL-Enter%(close_samp)s %(open_em)sto %(open_save)ssave%(close_save)s%(close_em)s",tags):_t("%(open_samp)sEscape%(close_samp)s %(open_em)sto %(open_cancel)scancel%(close_cancel)s%(close_em)s, %(open_samp)sEnter%(close_samp)s %(open_em)sto %(open_save)ssave%(close_save)s%(close_em)s",tags);} 10033get SEND_TEXT(){if(this.props.composer.message){return _t("Save editing");} 10034return this.props.type==="note"?_t("Log"):_t("Send");} 10035get sendKeybinds(){return this.env.inChatter?[_t("CTRL"),_t("Enter")]:[_t("Enter")];} 10036get showComposerAvatar(){return!this.compact&&this.props.sidebar;} 10037get thread(){return this.props.composer.targetThread;} 10038get allowUpload(){return this.props.allowUpload;} 10039get message(){return this.props.composer.message??null;} 10040get extraData(){return this.thread.rpcParams;} 10041get isSendButtonDisabled(){const attachments=this.props.composer.attachments;return(!this.state.active||(isHtmlEmpty(this.props.composer.composerHtml)&&attachments.length===0)||attachments.some(({uploading})=>Boolean(uploading)));} 10042get hasSuggestions(){return Boolean(this.suggestion?.state.items);} 10043get navigableListProps(){const props={anchorRef:this.inputContainerRef.el,position:this.env.inChatter?"bottom-fit":"top-fit",onSelect:(ev,option)=>{this.suggestion.insert(option);markEventHandled(ev,"composer.selectSuggestion");},isLoading:!!this.suggestion.search.term&&this.suggestion.state.isFetching,options:[],};if(!this.hasSuggestions){return props;} 10044return{...props,...mapSuggestionsToOptions(this.suggestion.state.items.type,this.suggestion.state.items.suggestions,{thread:this.thread}),};} 10045onDropFile(ev){if(isDragSourceExternalFile(ev.dataTransfer)){for(const file of ev.dataTransfer.files){this.attachmentUploader.uploadFile(file);}}} 10046onCloseFullComposerCallback(isDiscard){if(this.props.onCloseFullComposerCallback){this.props.onCloseFullComposerCallback(isDiscard);}else{this.thread?.fetchNewMessages();}} 10047onInput(ev){if(!this.props.composer.isDirty){this.props.composer.isDirty=true;}} 10048onPaste(ev){if(!this.allowUpload){return;} 10049if(!ev.clipboardData?.items){return;} 10050if(ev.clipboardData.files.length===0){return;} 10051ev.preventDefault();for(const file of ev.clipboardData.files){this.attachmentUploader.uploadFile(file);}} 10052onKeydown(ev){const composer=toRaw(this.props.composer);switch(ev.key){case"ArrowUp":if(!this.env.inChatter&&composer.composerText===""&&composer.thread){const messageToEdit=composer.thread.lastEditableMessageOfSelf;if(messageToEdit){messageToEdit.enterEditMode(this.props.composer.thread);}} 10053break;case"Enter":{if(isEventHandled(ev,"NavigableList.select")||!this.state.active){ev.preventDefault();return;} 10054if(this.isMobileOS||ev.isComposing){return;} 10055const shouldPost=this.env.inChatter?ev.ctrlKey:!ev.shiftKey;if(!shouldPost){return;} 10056ev.preventDefault();if(composer.message){this.editMessage();}else{this.sendMessage();} 10057break;} 10058case"Escape":if(isEventHandled(ev,"NavigableList.close")){return;} 10059if(this.props.onDiscardCallback){this.props.onDiscardCallback();markEventHandled(ev,"Composer.discard");} 10060break;}} 10061get fullComposerAdditionalContext(){return{};} 10062async onClickFullComposer(ev){this.props.composer.restoredFromFullComposer=false;const allRecipients=[...this.thread.suggestedRecipients];if(this.props.type!=="note"){allRecipients.push(...this.thread.additionalRecipients);const newPartners=allRecipients.filter((recipient)=>!recipient.partner_id);if(newPartners.length!==0){const recipientEmails=[];
10062newPartners.forEach((recipient)=>{recipientEmails.push(recipient.email);});const partners=await rpc("/mail/partner/from_email",{thread_model:this.thread.model,thread_id:this.thread.id,emails:recipientEmails,});for(const index in partners){const partnerData=partners[index];const partner=this.store["res.partner"].insert(partnerData);const email=recipientEmails[index];const recipient=allRecipients.find((recipient)=>recipient.email===email);recipient.partner_id=partner.id;}}} 10063const attachmentIds=this.props.composer.attachments.map((attachment)=>attachment.id);let default_body=this.props.composer.composerHtml;if(isHtmlEmpty(default_body)){const composer=toRaw(this.props.composer);composer.emailAddSignature=true;} 10064const signature=this.thread.effectiveSelf.main_user_id?.getSignatureBlock();default_body=this.formatDefaultBodyForFullComposer(default_body,this.props.composer.emailAddSignature?signature:"");const context={default_attachment_ids:attachmentIds,default_body,default_email_add_signature:false,default_model:this.thread.model,default_partner_ids:this.props.type==="note"?[]:allRecipients.filter((recipient)=>recipient.partner_id).map((recipient)=>recipient.partner_id),default_res_ids:[this.thread.id],default_subtype_xmlid:this.props.type==="note"?"mail.mt_note":"mail.mt_comment",clicked_on_full_composer:true,body_contains_signature_only:!this.props.composer.composerText||this.props.composer.composerText.trim().length===0,is_thread_composer:true,...this.fullComposerAdditionalContext,};const action={name:this.props.type==="note"?_t("Log note"):_t("Compose Email"),type:"ir.actions.act_window",res_model:"mail.compose.message",view_mode:"form",views:[[false,"form"]],target:"new",context:context,};const options={onClose:(args)=>{const accidentalDiscard=args?.dismiss;const isDiscard=accidentalDiscard||args?.special;if(accidentalDiscard){this.fullComposerBus.trigger("ACCIDENTAL_DISCARD",{onAccidentalDiscard:(isEmpty)=>{if(!isEmpty){this.state.isFullComposerOpen=true;this.saveContent();this.restoreContent();this.state.isFullComposerOpen=false;}},});}else{this.clear();} 10065this.props.composer.replyToMessage=undefined;this.onCloseFullComposerCallback(isDiscard);this.state.isFullComposerOpen=false;this.fullComposerBus=new EventBus();},props:{fullComposerBus:this.fullComposerBus,},};await this.env.services.action.doAction(action,options);this.state.isFullComposerOpen=true;} 10066formatDefaultBodyForFullComposer(defaultBody,signature=""){if(signature){defaultBody=markup`${defaultBody}<br>${signature}`;} 10067return markup`<div>${defaultBody}</div>`;} 10068clear(){this.props.composer.clear();browser.localStorage.removeItem(this.props.composer.localId);} 10069notifySendFromMailbox(){this.store.notifySendFromMailbox(this.thread.displayName);} 10070isEventTrusted(ev){return ev.isTrusted;} 10071async processMessage(cb){if(this.props.composer.attachments.some(({uploading})=>uploading)){this.env.services.notification.add(_t("Please wait while the file is uploading."),{type:"warning",});}else if(this.canProcessMessage){if(!this.state.active){return;} 10072this.state.active=false;await cb(trimEmptyBlocksAround(this.props.composer.composerHtml));if(this.props.onPostCallback){this.props.onPostCallback();} 10073this.clear();this.state.active=true;this.ref.el?.focus();}} 10074get canProcessMessage(){return(!isHtmlEmpty(this.props.composer.composerHtml)||this.props.composer.attachments.length>0||(this.message&&this.message.attachment_ids.length>0));} 10075async sendMessage(){const composer=toRaw(this.props.composer);this.composerActions.activePicker?.close?.();if(composer.message){this.editMessage();return;} 10076if(this.props.type!=="note"){const allRecipients=[...composer.thread.suggestedRecipients,...composer.thread.additionalRecipients,];if(allRecipients.some((recipient)=>!recipient.email||!isEmail(recipient.email))){return;}} 10077await this.processMessage(async(value)=>{await this._sendMessage(value,this.postData,this.extraData);});} 10078get postData(){const composer=toRaw(this.props.composer);return{attachments:composer.attachments||[],emailAddSignature:composer.emailAddSignature,isNote:this.props.type==="note",mentionedChannels:composer.mentionedChannels||[],mentionedPartners:composer.mentionedPartners||[],mentionedRoles:composer.mentionedRoles||[],cannedResponseIds:composer.cannedResponses.map((c)=>c.id),parentId:this.props.composer.replyToMessage?.id,};} 10079async _sendMessage(value,postData,extraData){const thread=toRaw(this.props.composer.thread);const postThread=toRaw(this.thread);const post=postThread.post.bind(postThread,value,postData,extraData);let message;if(postThread.model==="discuss.channel"){post();}else{message=await post();} 10080if(thread.model==="mail.box"){this.notifySendFromMailbox();} 10081this.suggestion?.clearRawMentions();this.suggestion?.clearCannedResponses();this.props.composer.replyToMessage=undefined;this.props.composer.emailAddSignature=true;this.props.composer.thread.additionalRecipients=[];return message;} 10082async editMessage(){const composer=toRaw(this.props.composer);
10082if(!this.askDeleteFromEdit){await this.processMessage(async(value)=>composer.message.edit(value,composer.attachments,{mentionedChannels:composer.mentionedChannels,mentionedPartners:composer.mentionedPartners,mentionedRoles:composer.mentionedRoles,}));}else{this.env.services.dialog.add(MessageConfirmDialog,{message:composer.message,onConfirm:()=>this.message.remove({removeFromThread:this.shouldHideFromMessageListOnDelete,}),prompt:_t("Are you sure you want to bid farewell to this message forever?"),},{context:this});} 10083this.suggestion?.clearRawMentions();} 10084get askDeleteFromEdit(){const composer=toRaw(this.props.composer);return!composer.composerText&&composer.message.attachment_ids.length===0;} 10085onClickInsertCannedResponse(ev){markEventHandled(ev,"composer.clickInsertCannedResponse");const composer=toRaw(this.props.composer);if(this.editor){if(!isHtmlEmpty(this.props.composer.composerHtml)){this.editor.shared.dom.insert(" ");} 10086this.editor.shared.dom.insert("::");this.editor.shared.history.addStep();}else{const composerText=composer.composerText;const firstPart=composerText.slice(0,composer.selection.start);const secondPart=composerText.slice(composer.selection.end,composerText.length);const toInsertPart=firstPart.length===0||firstPart.at(-1)===" "?"::":" ::";composer.composerText=firstPart+toInsertPart+secondPart;this.selection.moveCursor((firstPart+toInsertPart).length);} 10087if(!this.ui.isSmall||!this.env.inChatter){composer.autofocus++;}} 10088onChangeWysiwygContent(){this.updateFromEditor=true;this.props.composer.composerHtml=markup(this.editor.getContent());if(!this.props.composer.isDirty){this.props.composer.isDirty=true;} 10089this.updateFromEditor=false;} 10090onLoadWysiwyg(editor){this.editor=editor;} 10091addEmoji(str){const composer=toRaw(this.props.composer);if(this.editor){this.editor.shared.dom.insert(str);this.editor.shared.history.addStep();}else{const composerText=composer.composerText;const firstPart=composerText.slice(0,composer.selection.start);const secondPart=composerText.slice(composer.selection.end,composerText.length);composer.composerText=firstPart+str+secondPart;this.selection.moveCursor((firstPart+str).length);} 10092if(this.ui.isSmall&&!this.env.inChatter){return false;}else{composer.autofocus++;}} 10093onFocusin(ev){ev.stopPropagation();const composer=toRaw(this.props.composer);composer.isFocused=true;if(composer.thread?.scrollTop==="bottom"&&!composer.thread.scrollUnread&&!composer.thread.markedAsUnread){composer.thread?.markAsRead();}} 10094onFocusout(ev){if([EDIT_CLICK_TYPE.CANCEL,EDIT_CLICK_TYPE.SAVE].includes(ev.relatedTarget?.dataset?.type)){return;} 10095this.props.composer.isFocused=false;} 10096saveContent(){const composer=toRaw(this.props.composer);if(composer.restoredFromFullComposer&&!this.state.isFullComposerOpen){return;} 10097const saveContentToLocalStorage=({composerHtml,emailAddSignature,replyToMessageId,fromFullComposer=composer.restoredFromFullComposer,})=>{if(isHtmlEmpty(composerHtml)){browser.localStorage.removeItem(composer.localId);}else{browser.localStorage.setItem(composer.localId,JSON.stringify({emailAddSignature,replyToMessageId,composerHtml:isMarkup(composerHtml)?["markup",composerHtml]:composerHtml,fromFullComposer,}));}};if(this.state.isFullComposerOpen){this.fullComposerBus.trigger("SAVE_CONTENT",{onSaveContent:(...args)=>saveContentToLocalStorage({...args[0],fromFullComposer:true}),});}else{saveContentToLocalStorage({composerHtml:composer.composerHtml,emailAddSignature:true,replyToMessageId:composer.replyToMessage?.id,fromFullComposer:false,});}} 10098restoreContent(){const composer=toRaw(this.props.composer);let config;try{config=JSON.parse(browser.localStorage.getItem(composer.localId));}catch{browser.localStorage.removeItem(composer.localId);} 10099if(!config){return;} 10100if(!isHtmlEmpty(config.composerHtml)){if(composer.thread&&composer.thread?.model!=="discuss.channel"){composer.restoredFromFullComposer=config.fromFullComposer;} 10101composer.emailAddSignature=config.emailAddSignature;composer.composerHtml=config.composerHtml;} 10102if(Number.isInteger(config.replyToMessageId)){composer.replyToMessage=this.store["mail.message"].insert(config.replyToMessageId);}} 10103get shouldHideFromMessageListOnDelete(){return false;}} 10104return __exports;});; 10105 10106/* /mail/static/src/core/common/composer_actions.js */ 10107odoo.define('@mail/core/common/composer_actions',['@odoo/owl','@web/core/emoji_picker/emoji_picker','@web/core/l10n/translation','@web/core/registry','@web/core/utils/misc','@mail/core/common/action','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{toRaw,useComponent,useEffect,useRef,useState}=require("@odoo/owl");const{useEmojiPicker}=require("@web/core/emoji_picker/emoji_picker");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const{markEventHandled}=require("@web/core/utils/misc");const{Action,ACTION_TAGS,UseActions}=require("@mail/core/common/action");const{useService}=require("@web/core/utils/hooks");const composerActionsRegistry=__exports.composerActionsRegistry=registry.category("mail.composer/actions");__exports.registerComposerAction=registerComposerAction;function registerComposerAction(id,definition){composerActionsRegistry.add(id,definition);} 10108__exports.pickerOnClick=pickerOnClick;function pickerOnClick(component,action,ev){let anchorEl;if(component.ui.isSmall){anchorEl=component.pickerTargetRef.el;}else if(!anchorEl){if(action.sequenceQuick){anchorEl=component.quickActionsRef.el;}else{anchorEl=component.moreActionsRef.el??component.extraActionsRef.el;}} 10109const previousPicker=component.getActivePicker();previousPicker?.close();if(toRaw(previousPicker)===toRaw(action.picker)){component.setActivePicker(null);}else{component.setActivePicker(action.picker);component.getActivePicker().open({el:anchorEl});}} 10110__exports.pickerSetup=pickerSetup;function pickerSetup(action,func){const component=useComponent();component.pickerTargetRef=useRef("picker-target");component.quickActionsRef=useRef("quick-actions");component.moreActionsRef=useRef("more-actions");component.extraActionsRef=useRef("extra-actions");action.ref=useRef(action.id);action.picker=func();} 10111registerComposerAction("send-message",{btnClass:({action})=>(action.isActive?"o-sendMessageActive o-text-white shadow-sm":""),condition:({composer,owner,store})=>(store.env.isSmall&&composer.message)||(!owner.env.inChatter&&!composer.message),disabledCondition:({owner})=>owner.isSendButtonDisabled,icon:"fa fa-paper-plane-o",isActive:({owner})=>owner.sendMessageState.active,name:({composer,owner})=>composer.message?_t("Save editing"):composer.targetThread?.model==="discuss.channel"?_t("Send"):owner.props.type==="note"?_t("Log"):_t("Send"),onSelected:({owner})=>owner.sendMessage(),setup:({owner})=>{owner.sendMessageState=useState({active:false});useEffect(()=>{owner.sendMessageState.active=!owner.isSendButtonDisabled;},()=>[owner.isSendButtonDisabled]);},sequenceQuick:30,});registerComposerAction("add-emoji",{icon:"fa fa-smile-o",isPicker:true,pickerName:_t("Emoji"),name:_t("Add Emojis"),onSelected({owner},ev){pickerOnClick(owner,this,ev);markEventHandled(ev,"Composer.onClickAddEmoji");},setup({owner}){pickerSetup(this,()=>useEmojiPicker(undefined,{onSelect:(emoji)=>owner.addEmoji(emoji),onClose:()=>owner.setActivePicker(null),},{arrow:false}));},sequenceQuick:20,});registerComposerAction("upload-files",{condition:({owner})=>owner.allowUpload,icon:"fa fa-paperclip",name:_t("Attach Files"),onSelected:({composer:comp,owner},ev)=>{owner.fileUploaderRef.el?.click();const composer=toRaw(comp);markEventHandled(ev,"composer.clickOnAddAttachment");composer.autofocus++;},setup:({owner})=>(owner.fileUploaderRef=useRef("file-uploader")),sequence:20,});registerComposerAction("open-full-composer",{condition:({composer,owner})=>!composer.message&&owner.props.showFullComposer&&composer.targetThread&&composer.targetThread.model!=="discuss.channel"&&!owner.env.inFrontendPortalChatter,hasBtnBg:({composer,owner})=>(composer.restoredFromFullComposer&&!owner.state.isFullComposerOpen)||undefined,hotkey:"shift+c",icon:"fa fa-expand",isActive:({composer,owner})=>(composer.restoredFromFullComposer&&!owner.state.isFullComposerOpen)||undefined,name:_t("Open Full Composer"),onSelected:({owner})=>owner.onClickFullComposer(),sequence:30,tags:({composer,owner})=>composer.restoredFromFullComposer&&!owner.state.isFullComposerOpen?[ACTION_TAGS.PRIMARY]:undefined,});registerComposerAction("add-canned-response",{condition:({composer,store})=>store.hasCannedResponses&&composer.targetThread&&store.env.services["mail.suggestion"].getSupportedDelimiters(composer.targetThread).find(([delimiter])=>delimiter==="::"),icon:"fa fa-file-text-o",name:_t("Insert a Canned response"),onSelected:({owner},ev)=>owner.onClickInsertCannedResponse(ev),sequence:5,});const ComposerAction=__exports.ComposerAction=class ComposerAction extends Action{composerFn;constructor({composer}){super(...arguments);this.composerFn=typeof composer==="function"?composer:()=>composer;} 10112_disabledCondition({composer}){if(composer.restoredFromFullComposer&&this.id!=="open-full-composer"){return true;} 10113return super._disabledCondition(...arguments);} 10114get params(){return Object.assign(super.params,{composer:this.composerFn()});} 10115get isPicker(){return this.definition.isPicker;} 10116get pickerName(){return typeof this.definition.pickerName==="function"?this.definition.pickerName(this._component):this.definition.pickerName;}} 10117class UseComposerActions extends UseActions{get partition(){const res=super.partition;const actions=this.transformedActions.filter((action)=>action.condition);const groupedPickers=Object.groupBy(actions.filter((a)=>a.isPicker),(a)=>(a.sequenceQuick?"quick":"other"));groupedPickers.quick?.sort((a1,a2)=>
10117a1.sequenceQuick-a2.sequenceQuick);groupedPickers.other?.sort((a1,a2)=>a1.sequence-a2.sequence);const pickers=(groupedPickers.other??[]).concat(groupedPickers.quick??[]);return Object.assign(res,{pickers});}} 10118__exports.useComposerActions=useComposerActions;function useComposerActions({composer}={}){const component=useComponent();const transformedActions=composerActionsRegistry.getEntries().map(([id,definition])=>new ComposerAction({owner:component,id,definition,composer}));for(const action of transformedActions){action.setup();} 10119const state=useState(new UseComposerActions(component,transformedActions,useService("mail.store")));component.getActivePicker=()=>state.activePicker;component.setActivePicker=(newActivePicker)=>(state.activePicker=newActivePicker);return state;} 10120return __exports;});; 10121 10122/* /mail/static/src/core/common/composer_model.js */ 10123odoo.define('@mail/core/common/composer_model',['@mail/core/common/record','@mail/utils/common/format','@odoo/owl','@web/core/utils/html','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{fields,OR,Record}=require("@mail/core/common/record");const{convertBrToLineBreak,generatePartnerMentionElement,getNonEditableMentions,prettifyMessageText,}=require("@mail/utils/common/format");const{markup}=require("@odoo/owl");const{createDocumentFragmentFromContent,isHtmlEmpty}=require("@web/core/utils/html");const{nbsp}=require("@web/core/utils/strings");const Composer=__exports.Composer=class Composer extends Record{static id=OR("thread","message");clear(){this.attachments.length=0;this.replyToMessage=undefined;this.restoredFromFullComposer=false;this.composerHtml=markup("<div class='o-paragraph'><br></div>");Object.assign(this.selection,{start:0,end:0,direction:"none",});} 10124insertText(text,position,{moveCursorToEnd=false}={}){const before=this.composerText.substring(0,position);const after=this.composerText.substring(position);this.composerText=before+text+after;this.selection.start=before.length+text.length;if(moveCursorToEnd){this.selection.start=this.composerText.length;} 10125this.selection.end=this.selection.start;this.forceCursorMove=true;} 10126attachments=fields.Many("ir.attachment");emailAddSignature=true;message=fields.One("mail.message");mentionedPartners=fields.Many("res.partner");mentionedRoles=fields.Many("res.role");mentionedChannels=fields.Many("Thread");cannedResponses=fields.Many("mail.canned.response");isDirty=false;composerText=fields.Attr("",{onUpdate(){if(this.updateFrom==="html"){this.updateFrom=undefined;return;} 10127const validMentions=this.store.getMentionsFromText(this.composerText,{mentionedChannels:this.mentionedChannels,mentionedPartners:this.mentionedPartners,mentionedRoles:this.mentionedRoles,thread:this.targetThread,});const prettifiedHtml=prettifyMessageText(this.composerText,{validMentions,thread:this.targetThread,});if(this.composerHtml.toString()!==prettifiedHtml.toString()){this.updateFrom="text";this.composerHtml=prettifiedHtml;}},});composerHtml=fields.Html(markup("<div class='o-paragraph'><br></div>"),{compute(){if(this.syncHtmlWithMessage){return(getNonEditableMentions(this.message.body)||markup("<div class='o-paragraph'><br></div>"));} 10128return this.composerHtml;},onUpdate(){if(this.updateFrom==="text"){this.updateFrom=undefined;return;} 10129const prettifiedText=isHtmlEmpty(this.composerHtml)?"":convertBrToLineBreak(this.composerHtml);if(this.composerText!==prettifiedText){this.updateFrom="html";this.composerText=prettifiedText;}},});thread=fields.One("Thread");selection={start:0,end:0,direction:"none",};forceCursorMove;isFocused=fields.Attr(false,{onUpdate(){if(this.thread){if(this.isFocused){this.thread.isFocusedCounter++;}else{this.thread.isFocusedCounter--;}}},});autofocus=0;restoredFromFullComposer=false;replyToMessage=fields.One("mail.message",{inverse:"composerAsReplyToMessage"});updateFrom=undefined;get syncHtmlWithMessage(){return this.message&&!this.isDirty;} 10130get targetThread(){return this.replyToMessage?.thread??this.thread??this.message?.thread??null;} 10131insertReplyFromNote(message){this.mentionedPartners.add(message.author);if(!this.store.env.services["mail.composer"].htmlEnabled){const mentionText=`@${message.authorName} `;if(!this.composerText.includes(mentionText)){this.insertText(mentionText,0,{moveCursorToEnd:true});} 10132return;} 10133const composerBody=createDocumentFragmentFromContent(this.composerHtml).body;if(composerBody.querySelector(`a.o_mail_redirect[data-oe-model="res.partner"][data-oe-id="${message.author.id}"]`)){return;} 10134composerBody.firstElementChild.prepend(generatePartnerMentionElement(message.author,this.thread),nbsp);this.composerHtml=markup(composerBody.innerHTML);}} 10135Composer.register();return __exports;});; 10136 10137/* /mail/static/src/core/common/composer_service.js */ 10138odoo.define('@mail/core/common/composer_service',['@odoo/owl','@web/core/registry'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{registry}=require("@web/core/registry");const composerService=__exports.composerService={dependencies:["mail.store","legacy_multi_tab"],start(env,{legacy_multi_tab}){const state=reactive({htmlEnabled:legacy_multi_tab.getSharedValue("mail.html_composer.enabled",fal
10138se),setHtmlComposer(){if(state.htmlEnabled){return;} 10139state.htmlEnabled=true;legacy_multi_tab.setSharedValue("mail.html_composer.enabled",true);},setTextComposer(){if(!state.htmlEnabled){return;} 10140state.htmlEnabled=false;legacy_multi_tab.setSharedValue("mail.html_composer.enabled",false);},});legacy_multi_tab.bus.addEventListener("shared_value_updated",({detail})=>{if(detail.key==="mail.html_composer.enabled"){state.htmlEnabled=JSON.parse(detail.newValue);}});return state;},};registry.category("services").add("mail.composer",composerService);return __exports;});; 10141 10142/* /mail/static/src/core/common/country_flag.js */ 10143odoo.define('@mail/core/common/country_flag',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const CountryFlag=__exports.CountryFlag=class CountryFlag extends Component{static props=["country","class?"];static template="mail.CountryFlag";} 10144return __exports;});; 10145 10146/* /mail/static/src/core/common/country_model.js */ 10147odoo.define('@mail/core/common/country_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const Country=__exports.Country=class Country extends Record{static id="id";static _name="res.country";code;id;name;get flagUrl(){if(!this.code){return false;} 10148return`/base/static/img/country_flags/${encodeURIComponent(this.code.toLowerCase())}.png`;}} 10149Country.register();return __exports;});; 10150 10151/* /mail/static/src/core/common/data_response_model.js */ 10152odoo.define('@mail/core/common/data_response_model',['@mail/core/common/record','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{Deferred}=require("@web/core/utils/concurrency");const DataResponse=__exports.DataResponse=class DataResponse extends Record{static id="id";static _lastId=0;static createRequest(){return this.insert({id:++this._lastId});} 10153id;_autoResolve=false;_resultDef=new Deferred();_resolve=fields.Attr(undefined,{onUpdate(){if(this._resolve){this._resultDef.resolve({...this});this.delete();}},});attachments=fields.Many("ir.attachment");channel=fields.One("Thread");channels=fields.Many("Thread");count;message=fields.One("mail.message");partners=fields.Many("res.partner");} 10154DataResponse.register();return __exports;});; 10155 10156/* /mail/static/src/core/common/date_section.js */ 10157odoo.define('@mail/core/common/date_section',['@odoo/owl','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{isMobileOS}=require("@web/core/browser/feature_detection");const DateSection=__exports.DateSection=class DateSection extends Component{static template="mail.DateSection";static props=["date","className?"];get isMobileOS(){return isMobileOS();}} 10158return __exports;});; 10159 10160/* /mail/static/src/core/common/discuss_call_history_model.js */ 10161odoo.define('@mail/core/common/discuss_call_history_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const DiscussCallHistory=__exports.DiscussCallHistory=class DiscussCallHistory extends Record{static id="id";static _name="discuss.call.history";id;end_dt=fields.Datetime();duration_hour;} 10162DiscussCallHistory.register();return __exports;});; 10163 10164/* /mail/static/src/core/common/discuss_component_registry.js */ 10165odoo.define('@mail/core/common/discuss_component_registry',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const discussComponentRegistry=__exports.discussComponentRegistry=registry.category("discuss.component");return __exports;});; 10166 10167/* /mail/static/src/core/common/failure_model.js */ 10168odoo.define('@mail/core/common/failure_model',['@mail/core/common/record','@odoo/owl','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{markRaw}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const Failure=__exports.Failure=class Failure extends Record{static nextId=markRaw({value:1});static id="id";notifications=fields.Many("mail.notification",{onUpdate(){if(this.notifications.length===0){this.delete();}else{this.store.failures.add(this);}},});get modelName(){return this.notifications?.[0]?.mail_message_id?.thread?.modelName;} 10169get resModel(){return this.notifications?.[0]?.mail_message_id?.thread?.model;} 10170get resIds(){return new Set([...this.notifications.map((notif)=>notif.mail_message_id?.thread?.id).filter((id)=>!!id),]);} 10171lastMessage=fields.One("mail.message",{compute(){let lastMsg=this.notifications[0]?.mail_message_id;for(const notification of this.notifications){if(lastMsg?.id<notification.mail_message_id?.id){lastMsg=notification.mail_message_id;}} 10172return lastMsg;},});get type(){return this.notifications?.[0]?.notification_type;} 10173get status(){return this.notifications?.[0]?.notification_status;} 10174get iconSrc(){return"/mail/static/src/img/smiley/mailfailure.svg";} 10175get body(){if(this.notifications.length===1&&this.lastMessage?.thread){return _t("An error occurred when sending an email on â%(record_name)sâ",{record_name:this.lastMessage.thread.display_name,});} 10176return _t("An error occurred when sending an email");} 10177get datetime(){return this.lastMessage?.datetime;}} 10178Failure.register();return __exports;});; 10179 10180/* /mail/static/src/core/common/follower_model.js */ 10181odoo.define('@mail/core/common/follower_model',['@mail/core/common/record','@web/core/network/rpc','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{rpc}=require("@web/core/network/rpc");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const Follower=__exports.Follower=class Follower extends Record{static _name="mail.followers";static id="id";thread=fields.One("Thread");id;is_active;partner_id=fields.One("res.partner");subtype_ids=fields.Many("mail.message.subtype");get displayName(){return this.partner_id.name||this.display_name||_t("Unnamed");} 10182get isEditable(){const hasWriteAccess=this.thread?this.thread.hasWriteAccess:false;return this.partner_id.eq(this.store.self_partner)?this.thread.hasReadAccess:hasWriteAccess;} 10183async remove(){const data=await rpc("/mail/thread/unsubscribe",{res_model:this.thread.model,res_id:this.thread.id,partner_ids:[this.partner_id.id],});this.store.insert(data);} 10184removeRecipient(){this.thread.recipients.delete(this);}} 10185Follower.register();return __exports;});; 10186 10187/* /mail/static/src/core/common/gif.js */ 10188odoo.define('@mail/core/common/gif',['@odoo/owl','@web/core/utils/concurrency','@web/core/utils/functions'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{Deferred,KeepLast}=require("@web/core/utils/concurrency");const{memoize}=require("@web/core/utils/functions");const Gif=__exports.Gif=class Gif extends Component{static template="mail.Gif";static props={src:String,alt:{type:String,optional:true},class:{type:String,optional:true},loading:{type:String,optional:true},onLoad:{type:Function,optional:true},onClick:{type:Function,optional:true},paused:{type:Boolean,optional:true},style:{type:String,optional:true},};static components={};generateGifSnapshot=memoize(async(src)=>{const deferred=new Deferred();const image=document.createElement("img");
10188if(new URL(src).origin!==location.origin){image.crossOrigin="anonymous";} 10189image.src=src;image.onload=()=>{const canvas=document.createElement("canvas");canvas.width=image.width;canvas.height=image.height;canvas.getContext("2d").drawImage(image,0,0,image.width,image.height);deferred.resolve(canvas.toDataURL("image/gif"));};return deferred;});setup(){this.state=useState({snapshot:null});this.keepLast=new KeepLast();} 10190onLoad(){this.props.onLoad?.(...arguments);this.keepLast.add(this.generateGifSnapshot(this.props.src)).then((snapshot)=>(this.state.snapshot=snapshot));}} 10191return __exports;});; 10192 10193/* /mail/static/src/core/common/im_status.js */ 10194odoo.define('@mail/core/common/im_status',['@odoo/owl','@mail/discuss/typing/common/typing'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Typing}=require("@mail/discuss/typing/common/typing");const ImStatus=__exports.ImStatus=class ImStatus extends Component{static props=["persona?","className?","style?","member?","slots?","size?"];static template="mail.ImStatus";static defaultProps={className:"",style:"",size:"lg"};static components={Typing};get persona(){return this.props.persona??this.props.member?.persona;}} 10195return __exports;});; 10196 10197/* /mail/static/src/core/common/im_status_dropdown.js */ 10198odoo.define('@mail/core/common/im_status_dropdown',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@mail/core/common/im_status','@web/core/l10n/translation','@web/core/registry','@web/core/utils/hooks','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{ImStatus}=require("@mail/core/common/im_status");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const{useService}=require("@web/core/utils/hooks");const{rpc}=require("@web/core/network/rpc");const ImStatusDropdown=__exports.ImStatusDropdown=class ImStatusDropdown extends Component{static components={Dropdown,DropdownItem,ImStatus};static props=[];static template="mail.ImStatusDropdown";setup(){this.store=useService("mail.store");this.readableImStatusByCode={online:_t("Online"),away:_t("Away"),busy:_t("Do Not Disturb"),offline:_t("Offline"),};} 10199setManualImStatus(status){rpc("/mail/set_manual_im_status",{status});} 10200get readableImStatus(){const imStatus=this.store.self.im_status||"offline";for(const status in this.readableImStatusByCode){if(imStatus.includes(status)){return this.readableImStatusByCode[status];}} 10201return _t("Unknown Status");}} 10202__exports.imStatusItem=imStatusItem;function imStatusItem(env){return{type:"component",contentComponent:ImStatusDropdown,sequence:45,};} 10203registry.category("user_menuitems").add("im_status",imStatusItem);return __exports;});; 10204 10205/* /mail/static/src/core/common/im_status_service.js */ 10206odoo.define('@mail/core/common/im_status_service',['@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const AWAY_DELAY=__exports.AWAY_DELAY=30*60*1000;const imStatusService=__exports.imStatusService={dependencies:["bus_service","presence"],start(env,{bus_service,presence}){let lastSentInactivity;let becomeAwayTimeout;const updateBusPresence=()=>{lastSentInactivity=presence.getInactivityPeriod();startAwayTimeout();bus_service.send("update_presence",{inactivity_period:lastSentInactivity});};const startAwayTimeout=()=>{clearTimeout(becomeAwayTimeout);const awayTime=AWAY_DELAY-presence.getInactivityPeriod();if(awayTime>0){becomeAwayTimeout=browser.setTimeout(()=>updateBusPresence(),awayTime);}};bus_service.addEventListener("BUS:CONNECT",()=>updateBusPresence(),{once:true});bus_service.subscribe("bus.bus/im_status_updated",async({presence_status,im_status,partner_id,guest_id,debounce=true})=>{const store=env.services["mail.store"];const partner=store["res.partner"].get(partner_id);const guest=store["mail.guest"].get(guest_id);if(!partner&&!guest){return;} 10207if(debounce){partner?.debouncedSetImStatus(im_status);guest?.debouncedSetImStatus(im_status);}else{partner?.updateImStatus(im_status);guest?.updateImStatus(im_status);} 10208if(partner?.eq(store.self_partner)||guest?.eq(store.self_guest)){const isOnline=presence.getInactivityPeriod()<AWAY_DELAY;if((presence_status==="away"&&isOnline)||presence_status==="offline"){updateBusPresence();}}});presence.bus.addEventListener("presence",()=>{if(!lastSentInactivity||lastSentInactivity>=AWAY_DELAY){updateBusPresence();} 10209startAwayTimeout();});return{updateBusPresence};},};registry.category("services").add("im_status",imStatusService);return __exports;});; 10210 10211/* /mail/static/src/core/common/link_preview.js */ 10212odoo.define('@mail/core/common/link_preview',['@mail/core/common/gif','@mail/core/common/link_preview_confirm_delete','@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Gif}=require("@mail/core/common/gif");const{LinkPreviewConfirmDelete}=require("@mail/core/common/link_preview_confirm_delete");const{Component,useEffect,useRef,useState}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const LinkPreview=__exports.LinkPreview=class LinkPreview extends Component{static template="mail.LinkPreview";static props=["linkPreview","delete?","deleteAll?","gifPaused?","message?"];static components={Gif};setup(){super.setup();this.dialogService=useService("dialog");this.state=useState({startVideo:false,videoLoaded:false});this.videoRef=useRef("video");useEffect((el)=>{if(el){el.onload=()=>(this.state.videoLoaded=true);}},()=>[this.videoRef.el]);} 10213onClick(){this.dialogService.add(LinkPreviewConfirmDelete,{linkPreview:this.props.linkPreview,delete:this.props.delete,deleteAll:this.props.deleteAll,LinkPreview,});} 10214onImageLoaded(){this.env.onImageLoaded?.();}} 10215return __exports;});; 10216 10217/* /mail/static/src/core/common/link_preview_confirm_delete.js */ 10218odoo.define('@mail/core/common/link_preview_confirm_delete',['@odoo/owl','@web/core/dialog/dialog','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{useService}=require("@web/core/utils/hooks");const LinkPreviewConfirmDelete=__exports.LinkPreviewConfirmDelete=class LinkPreviewConfirmDelete extends Component{static components={Dialog};static props=["linkPreview","delete","deleteAll?","close","LinkPreview"];static template="mail.LinkPreviewConfirmDelete";setup(){super.setup();this.store=useService("mail.store");} 10219get message(){return this.props.linkPreview.message_id;} 10220onClickOk(){this.props.delete();this.props.close();} 10221onClickDeleteAll(){this.props.deleteAll?.();this.props.close();} 10222onClickCancel(){this.props.close();}} 10223return __exports;});; 10224 10225/* /mail/static/src/core/common/link_preview_model.js */ 10226odoo.define('@mail/core/common/link_preview_model',['@mail/core/common/record','@mail/utils/common/misc'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{convertToEmbedURL}=require("@mail/utils/common/misc");const VIDEO_EXTENSIONS=new Set(["mp4","mov","avi","mkv","webm","mpeg","mpg","ogv","3gp"]);const LinkPreview=__exports.LinkPreview=class LinkPreview extends Record{static _name="mail.link.preview";static id="id";id;message_link_preview_ids=fields.Many("mail.message.link.preview",{inverse:"link_preview_id",});image_mimetype;og_description;og_image;og_mimetype;og_title;og_type;og_site_name;source_url;get isGif(){return[this.og_mimetype,this.image_mimetype].includes("image/gif");} 10227get imageUrl(){return this.og_image?this.og_image:this.source_url;} 10228get isImage(){return Boolean(this.image_mimetype||this.og_mimetype==="image/gif");} 10229get isVideo(){let fileExt;if(this.og_title){fileExt=this.og_title.split(".").pop();} 10230return(VIDEO_EXTENSIONS.has(fileExt)||Boolean(!this.isImage&&this.og_type&&this.og_type.startsWith("video")));} 10231get isCard(){return!this.isImage&&!this.isVideo;} 10232get videoURL(){const{url}=convertToEmbedURL(this.source_url);return url;} 10233get videoProvider(){const{provider}=convertToEmbedURL(this.source_url);return provider;}} 10234LinkPreview.register();return __exports;});; 10235 10236/* /mail/static/src/core/common/mail_activity_type_model.js */ 10237odoo.define('@mail/core/common/mail_activity_type_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const MailActivityType=__exports.MailActivityType=class MailActivityType extends Record{static _name="mail.activity.type";static id="id";id;name;} 10238MailActivityType.register();return __exports;});; 10239 10240/* /mail/static/src/core/common/mail_attachment_dropzone.js */ 10241odoo.define('@mail/core/common/mail_attachment_dropzone',['@odoo/owl','@web/core/dropzone/dropzone'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dropzone}=require("@web/core/dropzone/dropzone");const MailAttachmentDropzone=__exports.MailAttachmentDropzone=class MailAttachmentDropzone extends Component{static template="mail.MailAttachmentDropzone";static components={Dropzone};static props=Dropzone.props;} 10242return __exports;});; 10243 10244/* /mail/static/src/core/common/mail_core_common_service.js */ 10245odoo.define('@mail/core/common/mail_core_common_service',['@odoo/owl','@web/core/registry'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{registry}=require("@web/core/registry");const MailCoreCommon=__exports.MailCoreCommon=class MailCoreCommon{constructor(env,services){this.env=env;this.busService=services.bus_service;this.store=services["mail.store"];} 10246setup(){this.busService.subscribe("ir.attachment/delete",(payload)=>{const{id:attachmentId,message:messageData}=payload;if(messageData){this.store["mail.message"].insert(messageData);} 10247const attachment=this.store["ir.attachment"].get(attachmentId);attachment?.delete();});this.busService.subscribe("mail.message/delete",(payload,{id:notifId})=>{for(const messageId of payload.message_ids){const message=this.store["mail.message"].get(messageId);if(!message){continue;} 10248this.env.bus.trigger("mail.message/delete",{message,notifId});message.delete();}});this.busService.subscribe("mail.message/toggle_star",(payload,metadata)=>this._handleNotificationToggleStar(payload,metadata));this.busService.subscribe("res.users.settings",(payload)=>{if(payload){this.store.settings.update(payload);}});this.busService.subscribe("mail.record/insert",(payload)=>{this.store.insert(payload);});} 10249_handleNotificationToggleStar(payload,metadata){const{message_ids:messageIds,starred}=payload;this.store["mail.message"].insert(messageIds.map((id)=>({id,starred})));}} 10250const mailCoreCommon=__exports.mailCoreCommon={dependencies:["bus_service","mail.store"],start(env,services){const mailCoreCommon=reactive(new MailCoreCommon(env,services));mailCoreCommon.setup();return mailCoreCommon;},};registry.category("services").add("mail.core.common",mailCoreCommon);return __exports;});; 10251 10252/* /mail/static/src/core/common/mail_fullscreen.js */ 10253odoo.define('@mail/core/common/mail_fullscreen',['@odoo/owl','@web/core/utils/hooks','@web/core/registry'],function(require){'use strict';let __exports={};const{Component,reactive}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const DEFAULT_ID=Symbol("default");const MailFullscreen=__exports.MailFullscreen=class MailFullscreen extends Component{static props=["component","props?"];static template="mail.Fullscreen";setup(){super.setup();this.fullscreen=useService("mail.fullscreen");}} 10254const fullscreenService=__exports.fullscreenService={start(env){const state=reactive({enter,exit,id:undefined,closeOverlay:undefined});async function exit(id=state.id){if(!id||id!==state.id){return;} 10255state.closeOverlay?.();state.id=undefined;state.closeOverlay=undefined;const fullscreenElement=document.webkitFullscreenElement||document.fullscreenElement;if(fullscreenElement){if(document.exitFullscreen){await document.exitFullscreen();}else if(document.mozCancelFullScreen){await document.mozCancelFullScreen();}else if(document.webkitCancelFullScreen){await document.webkitCancelFullScreen();}}} 10256async function enter(component,{keepBrowserHeader=false,props,rootId,id=DEFAULT_ID}={}){state.closeOverlay?.();state.id=id;state.closeOverlay=env.services.overlay.add(MailFullscreen,{component,props},{rootId});const el=document.body;if(keepBrowserHeader){return;} 10257try{if(el.requestFullscreen){await el.requestFullscreen();}else if(el.mozRequestFullScreen){await el.mozRequestFullScreen();}else if(el.webkitRequestFullscreen){await el.webkitRequestFullscreen();}}catch{}} 10258window.addEventListener("fullscreenchange",()=>{const isFullscreen=Boolean(document.webkitFullscreenElement||document.fullscreenElement);if(!isFullscreen){state.exit();}});return state;},};registry.category("services").add("mail.fullscreen",fullscreenService);return __exports;});; 10259 10260/* /mail/static/src/core/common/mail_guest_model.js */ 10261odoo.define('@mail/core/common/mail_guest_model',['@mail/core/common/record','@web/core/utils/urls','@web/core/network/rpc','@web/core/utils/timing','@mail/core/common/store_service'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{imageUrl}=require("@web/core/utils/urls");const{rpc}=require("@web/core/network/rpc");const{debounce}=require("@web/core/utils/timing");const{Store}=require("@mail/core/common/store_service");const TRANSPARENT_AVATAR="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAQAAABpN6lAAAAAqElEQVR42u3QMQEAAAwCoNm/9GJ4CBHIjYsAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDQ9+KgAIHd5IbMAAAAAElFTkSuQmCC";const{DateTime}=luxon;const MailGuest=__exports.MailGuest=class MailGuest extends Record{static id="id";static _name="mail.guest";static new(){const record=super.new(...arguments);record.debouncedSetImStatus=debounce((newStatus)=>record.updateImStatus(newStatus),Store.IM_STATUS_DEBOUNCE_DELAY);return record;} 10262avatar_128_access_token;id;debouncedSetImStatus;monitorPresence=fields.Attr(false,{compute(){return this.store.env.services.bus_service.isActive&&this.id>0;},});_triggerPresenceSubscription=fields.Attr(null,{compute(){return this.monitorPresence&&this.presenceChannel;},onUpdate(){if(this.previousPresencechannel){this.store.env.services.bus_service.deleteChannel(this.previousPresencechannel);} 10263if(this._triggerPresenceSubscription){this.store.env.services.bus_service.addChannel(this.presenceChannel);} 10264this.previousPresencechannel=this.presenceChannel;},eager:true,});name;country_id=fields.One("res.country");email;im_status=fields.Attr(null,{onUpdate(){if(this.eq(this.store.self_guest)&&this.im_status==="offline"&&this.id<0){this.store.env.services.im_status.updateBusPresence();}},});im_status_access_token;offline_since=fields.Datetime();previousPresencechannel;presenceChannel=fields.Attr(null,{compute(){const channel=`odoo-presence-mail.guest_${this.id}`;if(this.im_status_access_token){return`${channel}-${this.im_status_access_token}`;} 10265return channel;},});write_date=fields.Datetime();get avatarUrl(){const accessTokenParam={};if(this.store.self.main_user_id?.share!==false){accessTokenParam.access_token=this.avatar_128_access_token;} 10266if(this.id===-1){return TRANSPARENT_AVATAR;} 10267return imageUrl("mail.guest",this.id,"avatar_128",{...accessTokenParam,unique:this.write_date,});} 10268async updateGuestName(name){await rpc("/mail/guest/update_name",{guest_id:this.id,name,});} 10269updateImStatus(newStatus){if(newStatus==="offline"){this.offline_since=DateTime.now();} 10270this.im_status=newStatus;}} 10271MailGuest.register();return __exports;});; 10272 10273/* /mail/static/src/core/common/mail_message_subtype_model.js */ 10274odoo.define('@mail/core/common/mail_message_subtype_model',['@mail/model/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/model/record");const MailMessageSubtype=__exports.MailMessageSubtype=class MailMessageSubtype extends Rec
10274ord{static id="id";static _name="mail.message.subtype";description;id;name;} 10275MailMessageSubtype.register();return __exports;});; 10276 10277/* /mail/static/src/core/common/mail_popout_service.js */ 10278odoo.define('@mail/core/common/mail_popout_service',['@odoo/owl','@web/core/browser/browser','@web/core/l10n/translation','@web/core/registry','@web/core/templates'],function(require){'use strict';let __exports={};const{App}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{getTemplate}=require("@web/core/templates");const DEFAULT_ID=Symbol("default");const mailPopoutService=__exports.mailPopoutService={async addAssets(window){},start(env){const popouts=new Map();async function reset(id,{useAlternativeAssets}={}){const popout=popouts.get(id);if(!popout){return;} 10279const doc=popout.externalWindow?.document;if(doc){doc.head.textContent="";if(useAlternativeAssets){await mailPopoutService.addAssets(popout.externalWindow);}else{doc.write(window.document.head.outerHTML);} 10280doc.body=doc.createElement("body");} 10281if(popout.app){popout.app.destroy();popout.app=null;}} 10282async function pollClosedWindow(id){while(popouts.get(id)?.externalWindow){const popout=popouts.get(id);await new Promise((r)=>setTimeout(r,1000));if(popout.externalWindow?.closed){const hooks=popout.hooks;hooks?.afterPopoutClosed?.();popout.externalWindow=null;}}} 10283async function pip(id,component,{props,options:{width,height,aspectRatio=16/9,useAlternativeAssets=false}={},}={}){const popout=popouts.get(id);let externalWindow=popout.externalWindow;if(!externalWindow||externalWindow.closed){const hooks=popout.hooks;hooks?.beforePopout?.();height=height||(width?width/aspectRatio:Math.min(240,window.innerHeight));width=width||height*aspectRatio;if(window.documentPictureInPicture){externalWindow=await window.documentPictureInPicture.requestWindow({width,height,});}else{externalWindow=browser.open("about:blank","_blank",`popup=yes,width=${width},height=${height}`);} 10284popout.externalWindow=externalWindow;pollClosedWindow(id);} 10285await reset(id,{useAlternativeAssets});popout.app=new App(component,{name:"Popout",env:Object.assign({},env,{pipWindow:externalWindow,}),props,getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,});popout.app.mount(externalWindow.document.body);return externalWindow;} 10286function popout(id,component,props){const popout=popouts.get(id);let externalWindow=popout.externalWindow;if(!externalWindow||externalWindow.closed){const hooks=popout.hooks;hooks?.beforePopout?.();externalWindow=browser.open("about:blank","_blank","popup=yes");window.addEventListener("beforeunload",()=>{if(externalWindow&&!externalWindow.closed){externalWindow.close();}});popout.externalWindow=externalWindow;pollClosedWindow(id);} 10287reset(id);popout.app=new App(component,{name:"Popout",env,props,getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,});popout.app.mount(externalWindow.document.body);return externalWindow;} 10288function getExternalWindow(id){const externalWindow=popouts.get(id)?.externalWindow;return externalWindow&&!externalWindow.closed?externalWindow:null;} 10289function addHooks(id,hooks){const popout=popouts.get(id);popout.hooks=hooks;}
10290function createManager(id=DEFAULT_ID){popouts.set(id,{externalWindow:null,hooks:{},});return{addHooks(beforePopout=()=>{},afterPopoutClosed=()=>{}){addHooks(id,{beforePopout,afterPopoutClosed});},async pip(component,props){return pip(id,component,props);},popout(component,props){return popout(id,component,props);},reset(){reset(id);},get externalWindow(){return getExternalWindow(id);},get id(){return id;},};} 10291return Object.assign(createManager(),{createManager});},};registry.category("services").add("mail.popout",mailPopoutService);return __exports;});; 10292 10293/* /mail/static/src/core/common/mail_template_model.js */ 10294odoo.define('@mail/core/common/mail_template_model',['@mail/model/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/model/record");const MailTemplate=__exports.MailTemplate=class MailTemplate extends Record{static id="id";static _name="mail.template";id;name;} 10295MailTemplate.register();return __exports;});; 10296 10297/* /mail/static/src/core/common/message.js */ 10298odoo.define('@mail/core/common/message',['@mail/core/common/attachment_list','@mail/core/common/composer','@mail/core/common/im_status','@mail/core/common/message_in_reply','@mail/core/common/message_link_preview_list','@mail/core/common/message_notification_popover','@mail/core/common/message_reaction_menu','@mail/core/common/message_reactions','@mail/core/common/relative_time','@mail/utils/common/format','@web/core/utils/misc','@web/core/utils/render','@odoo/owl','@web/core/action_swiper/action_swiper','@web/core/browser/feature_detection','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/l10n/translation','@web/core/popover/popover_hook','@web/core/utils/hooks','@web/core/utils/html','@web/core/utils/urls','@mail/core/common/message_actions','@mail/core/common/discuss_component_registry','@mail/core/common/notification_message','@mail/utils/common/hooks','@mail/core/common/action_list','@mail/utils/common/misc'],function(require){'use strict';let __exports={};const{AttachmentList}=require("@mail/core/common/attachment_list");const{Composer}=require("@mail/core/common/composer");const{ImStatus}=require("@mail/core/common/im_status");const{MessageInReply}=require("@mail/core/common/message_in_reply");const{MessageLinkPreviewList}=require("@mail/core/common/message_link_preview_list");const{MessageNotificationPopover}=require("@mail/core/common/message_notification_popover");const{MessageReactionMenu}=require("@mail/core/common/message_reaction_menu");const{MessageReactions}=require("@mail/core/common/message_reactions");const{RelativeTime}=require("@mail/core/common/relative_time");const{htmlToTextContentInline}=require("@mail/utils/common/format");const{isEventHandled,markEventHandled}=require("@web/core/utils/misc");const{renderToElement}=require("@web/core/utils/render");const{Component,onMounted,onPatched,onWillDestroy,onWillUpdateProps,toRaw,useChildSubEnv,useEffect,useRef,useState,useSubEnv,}=require("@odoo/owl");const{ActionSwiper}=require("@web/core/action_swiper/action_swiper");const{hasTouch,isMobileOS}=require("@web/core/browser/feature_detection");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{usePopover}=require("@web/core/popover/popover_hook");const{useService}=require("@web/core/utils/hooks");const{createElementWithContent}=require("@web/core/utils/html");const{getOrigin,url}=require("@web/core/utils/urls");const{useMessageActions}=require("@mail/core/common/message_actions");const{discussComponentRegistry}=require("@mail/core/common/discuss_component_registry");const{NotificationMessage}=require("@mail/core/common/notification_message");const{useLongPress}=require("@mail/utils/common/hooks");const{ActionList}=require("@mail/core/common/action_list");const{loadCssFromBundle}=require("@mail/utils/common/misc");class MessageDropdown extends Dropdown{get isBottomSheet(){return hasTouch()&&this.props.bottomSheet;}} 10299const Message=__exports.Message=class Message extends Component{static SHADOW_LINK_COLOR="#66598f";static SHADOW_HIGHLIGHT_COLOR="#e99d00bf";static SHADOW_LINK_HOVER_COLOR="#564b79";static components={ActionList,ActionSwiper,AttachmentList,Composer,Dropdown:MessageDropdown,ImStatus,MessageInReply,MessageLinkPreviewList,MessageReactions,Popover:MessageNotificationPopover,RelativeTime,NotificationMessage,};static defaultProps={hasActions:true,isInChatWindow:false,showDates:true,};static props=["asCard?","registerMessageRef?","hasActions?","isInChatWindow?","onParentMessageClick?","message","previousMessage?","squashed?","thread?","messageSearch?","className?","showDates?","isFirstMessage?","isReadOnly?",];static template="mail.Message";setup(){super.setup();this.store=useService("mail.store");this.popover=usePopover(this.constructor.components.Popover,{position:"top"});this.state=useState({isHovered:false,isClicked:false,expandOptions:false,emailHeaderOpen:false,});this.shadowRoot;this.root=useRef("root");
10299if(isMobileOS()){useLongPress("root",{action:()=>this.openMobileActions(),predicate:()=>!this.isEditing,});} 10300onWillUpdateProps((nextProps)=>{this.props.registerMessageRef?.(this.props.message,null);});onMounted(()=>this.props.registerMessageRef?.(this.props.message,this.root));onPatched(()=>this.props.registerMessageRef?.(this.props.message,this.root));onWillDestroy(()=>this.props.registerMessageRef?.(this.props.message,null));this.hasTouch=hasTouch;this.messageBody=useRef("body");this.messageActions=useMessageActions({message:()=>this.message,thread:()=>this.props.thread,});this.shadowBody=useRef("shadowBody");this.dialog=useService("dialog");this.ui=useService("ui");this.openReactionMenu=this.openReactionMenu.bind(this);this.optionsDropdown=useDropdownState();useSubEnv({inMessage:true});useChildSubEnv({message:this.props.message,alignedRight:this.isAlignedRight,});onMounted(()=>{if(this.shadowBody.el){this.shadowRoot=this.shadowBody.el.attachShadow({mode:"open"});const color=this.store.isOdooWhiteTheme?"dark":"white";loadCssFromBundle(this.shadowRoot,"mail.assets_message_email");const shadowStyle=document.createElement("style");shadowStyle.textContent=` 10301 * { 10302 background-color: transparent !important; 10303 color: ${color} !important; 10304 } 10305 a, a * { 10306 color: ${this.constructor.SHADOW_LINK_COLOR} !important; 10307 } 10308 a:hover, a *:hover { 10309 color: ${this.constructor.SHADOW_LINK_HOVER_COLOR} !important; 10310 } 10311 .o-mail-Message-searchHighlight { 10312 background: ${this.constructor.SHADOW_HIGHLIGHT_COLOR} !important; 10313 } 10314 `;if(!this.store.isOdooWhiteTheme){this.shadowRoot.appendChild(shadowStyle);} 10315const ellipsisStyle=document.createElement("style");ellipsisStyle.textContent=` 10316 .o-mail-ellipsis { 10317 min-width: 2.7ch; 10318 background-color: ButtonFace; 10319 border-radius: 50rem; 10320 border: 0; 10321 display: block 10322 font: -moz-button; 10323 font-size: .75rem; 10324 font-weight: 500; 10325 line-height: 1.1; 10326 cursor: pointer; 10327 padding: 0 4px; 10328 vertical-align: top; 10329 color #ffffff; 10330 text-decoration: none; 10331 text-align: center; 10332 &:hover { 10333 background-color: -moz-buttonhoverface; 10334 } 10335 } 10336 `;this.shadowRoot.appendChild(ellipsisStyle);}});useEffect(()=>{if(this.shadowBody.el){const bodyEl=createElementWithContent("span",this.message.showTranslation?this.message.richTranslationValue:this.props.messageSearch?.highlight(this.message.richBody)??this.message.richBody);this.prepareMessageBody(bodyEl);this.shadowRoot.appendChild(bodyEl);return()=>{this.shadowRoot.removeChild(bodyEl);};}},()=>[this.message.showTranslation,this.message.richTranslationValue,this.props.messageSearch?.searchTerm,this.message.richBody,this.isEditing,]);useEffect(()=>{if(!this.isEditing){this.prepareMessageBody(this.messageBody.el);}},()=>[this.isEditing,this.message.richBody]);} 10337computeActions(){const allActions=this.messageActions.actions;const quickActions=allActions.slice(0,allActions.length>this.quickActionCount?this.quickActionCount-1:this.quickActionCount);const moreActions=allActions.length>this.quickActionCount?allActions.slice(this.quickActionCount-1):false;const moreAction=moreActions?.length?this.messageActions.more({actions:moreActions,dropdownMenuClass:"o-mail-Message-moreMenu",dropdownPosition:this.isAlignedRight?this.message.threadAsNewest?"left-end":"left-start":this.message.threadAsNewest?"right-end":"right-start",name:this.expandText,}):undefined;const actions=moreAction?[...quickActions,moreAction]:quickActions;if(this.isAlignedRight){actions.reverse();} 10338this.state.moreAction=moreAction;this.quickActions=quickActions;this.actions=actions;} 10339get attClass(){return{"user-select-none o-isMobileOS":isMobileOS(),[this.props.className]:true,"o-card p-2 ps-1 mx-1 mt-1 mb-1 border border-dark rounded-2":this.props.asCard,"pt-1":!this.props.asCard&&!this.props.squashed,"o-pt-0_5":!this.props.asCard&&this.props.squashed,"o-selfAuthored":this.message.isSelfAuthored&&!this.env.messageCard,"o-selected":this.props.message.composerAsReplyToMessage?.thread.eq(this.props.thread),"o-squashed":this.props.squashed,"mt-1":!this.props.squashed&&this.props.thread&&!this.env.messageCard&&!this.props.asCard,"px-1":this.props.isInChatWindow,"o-actionMenuMobileOpen":this.ui.isSmall&&this.optionsDropdown.isOpen,"o-editing":this.isEditing,};} 10340get authorAvatarAttClass(){return{"object-fit-contain":this.props.message.author_id?.is_company,"object-fit-cover":!this.props.message.author_id?.is_company,};} 10341get authorAvatarUrl(){if(this.message.message_type&&this.message.message_type.includes("email")&&!this.message.author_id&&!this.message.author_guest_id){return url("/mail/static/src/img/email_icon.png");} 10342if(this.message.author){return this.message.author.avatarUrl;} 10343return this.store.DEFAULT_AVATAR;} 10344get expandText(){return _t("Expand");} 10345get isEditing(){return!this.props.isReadOnly&&this.props.message.composer;} 10346get message(){return this.props.message;} 10347get quickActionCount(){if(isMobileOS()){return 1;} 10348return this.env.inChatWindow||this.env.inMeetingChat?2:4;} 10349get showSubtypeDescription(){return(this.message.subtype_id?.description&&this.message.subtype_id.description.toLowerCase()!==htmlToTextContentInline(this.message.body||"").toLowerCase());} 10350get messageTypeText(){if(this.props.message.message_type==="notification"){return _t("System notification");} 10351if(this.props.message.message_type==="auto_comment"){return _t("Automated message");} 10352if(this.props.message.message_type==="out_of_office"){return _t("Out-of-office message");} 10353if(!this.props.message.isDiscussion&&this.props.message.message_type!=="user_notification"){return _t("Note");} 10354return _t("Message");} 10355get isActive(){return(this.state.isHovered||this.state.isClicked||this.emojiPicker?.isOpen||Boolean(this.state.moreAction?.isActive));} 10356get isAlignedRight(){return Boolean(this.env.inChatWindow&&this.props.message.isSelfAuthored);} 10357get isMobileOS(){return isMobileOS();} 10358get isPersistentMessageFromAnotherThread(){return(!this.message.is_transient&&!this.message.isPending&&this.message.thread&&this.message.thread.notEq(this.props.thread));} 10359get translatedFromText(){return _t("(Translated from: %(language)s)",{language:this.message.translationSource});} 10360get translationFailureText(){return _t("(Translation Failure: %(error)s)",{error:this.message.translationErrors});} 10361onMouseenter(){this.state.isHovered=true;} 10362onMouseleave(){this.state.isHovered=false;this.state.isClicked=null;} 10363get shouldDisplayAuthorName(){if(!this.env.inChatWindow){return true;} 10364if(this.message.isSelfAuthored){return false;} 10365if(this.props.thread.channel_type==="chat"){return false;} 10366return true;} 10367async onClickAttachmentUnlink(attachment){await toRaw(attachment).remove();} 10368async onClick(ev){if(this.store.handleClickOnLink(ev,this.props.thread)){return;} 10369if(!isEventHandled(ev,"Message.ClickAuthor")&&!isEventHandled(ev,"Message.ClickFailure")){if(this.state.isClicked){this.state.isClicked=false;}else{this.state.isClicked=true;document.body.addEventListener("click",()=>{this.state.isClicked=false;},{capture:true,once:true});}}} 10370prepareMessageBody(bodyEl){if(!bodyEl){return;} 10371const editedEl=bodyEl.querySelector(".o-mail-Message-edited");editedEl?.replaceChildren(renderToElement("mail.Message.edited"));const channelLinks=bodyEl.querySelectorAll("a.o_channel_redirect");this.store.handleValidChannelMention(Array.from(channelLinks));for(const el of bodyEl.querySelectorAll(".o_message_redirect")){if(el.getAttribute("href")?.startsWith(getOrigin())){const message=this.store["mail.message"].get(el.dataset.oeId);if(message?.thread?.displayName){el.classList.add("o_message_redirect_transformed");el.replaceChildren(renderToElement("mail.Message.messageLink",{message}));}}}} 10372getAuthorAttClass(){return{"opacity-50":this.message.isPending};} 10373getAvatarContainerAttClass(){return{"opacity-50":this.message.isPending,"o-inChatWindow":this.env.inChatWindow,};} 10374exitEditMode(){this.message.exitEditMode(this.props.thread);} 10375onClickNotification(ev){const message=toRaw(this.message);if(message.failureNotifications.length>0){markEventHandled(ev,"Message.ClickFailure");} 10376this.popover.open(ev.target,{message});} 10377openMobileActions(ev){if(!isMobileOS()){return;} 10378ev?.stopPropagation();this.optionsDropdown.open();} 10379openReactionMenu(reaction){const message=toRaw(this.props.message);this.dialog.add(MessageReactionMenu,{message,initialReaction:reaction},{context:this});} 10380async onClickToggleTranslation(){toRaw(this.props.message).onClickToggleTranslation();} 10381get shouldHideFromMessageListOnDelete(){return false;}}
10382discussComponentRegistry.add("Message",Message);return __exports;});; 10383 10384/* /mail/static/src/core/common/message_actions.js */ 10385odoo.define('@mail/core/common/message_actions',['@odoo/owl','@web/core/l10n/translation','@web/core/network/download','@web/core/registry','@mail/core/common/discuss_component_registry','@web/core/utils/concurrency','@mail/core/common/action','@web/core/emoji_picker/emoji_picker','@mail/core/common/quick_reaction_menu','@web/core/browser/feature_detection','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{toRaw,useComponent,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{download}=require("@web/core/network/download");const{registry}=require("@web/core/registry");const{discussComponentRegistry}=require("@mail/core/common/discuss_component_registry");const{Deferred}=require("@web/core/utils/concurrency");const{Action,ACTION_TAGS,UseActions}=require("@mail/core/common/action");const{useEmojiPicker}=require("@web/core/emoji_picker/emoji_picker");const{QuickReactionMenu}=require("@mail/core/common/quick_reaction_menu");const{isMobileOS}=require("@web/core/browser/feature_detection");const{useService}=require("@web/core/utils/hooks");const{DateTime}=luxon;const messageActionsRegistry=__exports.messageActionsRegistry=registry.category("mail.message/actions");__exports.registerMessageAction=registerMessageAction;function registerMessageAction(id,definition){messageActionsRegistry.add(id,definition);} 10386registerMessageAction("reaction",{component:QuickReactionMenu,componentProps:({action,message,owner})=>({action,message,messageActive:owner.isActive,}),componentCondition:()=>!isMobileOS(),condition:({message,thread})=>message.canAddReaction(thread),icon:"oi oi-smile-add",name:_t("Add a Reaction"),onSelected({owner}){return owner.reactionPicker.open({el:owner.root?.el?.querySelector(`[name="${this.id}"]`),});},setup:({message,owner,thread})=>(owner.reactionPicker=useEmojiPicker(undefined,{onSelect:(emoji)=>{const reaction=message.reactions.find(({content,personas})=>content===emoji&&thread.effectiveSelf.in(personas));if(!reaction){message.react(emoji);}},})),sequence:10,});registerMessageAction("reply-to",{condition:({message:msg,thread:thr})=>{const message=toRaw(msg);const thread=toRaw(thr);return(message.canReplyTo(thread)||(!["discuss.channel","mail.box"].includes(thread?.model)&&message.isNote&&!message.isSelfAuthored));},icon:"fa fa-reply",name:_t("Reply"),onSelected:({message:msg,owner,thread:thr})=>{const message=toRaw(msg);const thread=toRaw(thr);const composer=thread.composer;if(message.eq(composer.replyToMessage)){composer.replyToMessage=undefined;return;} 10387if(["discuss.channel","mail.box"].includes(thread.model)){composer.replyToMessage=message;} 10388if(thread.model==="discuss.channel"){return;} 10389if(!message.isSelfAuthored&&message.model!=="discuss.channel"&&message.author){composer.insertReplyFromNote(message);} 10390owner.env.inChatter?.toggleComposer("note",{force:true});composer.restoredFromFullComposer=false;if(!composer.isFocused){composer.autofocus++;}},sequence:({message,store,thread})=>thread?.eq(store.inbox)||message.isSelfAuthored?55:20,});registerMessageAction("toggle-star",{condition:({message})=>message.canToggleStar,icon:({message})=>(message.starred?"fa fa-star o-mail-Message-starred":"fa fa-star-o"),name:({message})=>(message.starred?_t("Remove Star"):_t("Add Star")),onSelected:({message})=>message.toggleStar(),sequence:30,});registerMessageAction("mark-as-read",{condition:({store,thread})=>thread?.eq(store.inbox),icon:"fa fa-check",name:_t("Mark as Read"),onSelected:({message})=>message.setDone(),sequence:40,});registerMessageAction("reactions",{condition:({message})=>message.reactions.length,icon:"fa fa-smile-o",name:_t("View Reactions"),onSelected:({owner})=>owner.openReactionMenu(),sequence:50,});registerMessageAction("unfollow",{condition:({message,thread})=>message.canUnfollow(thread),icon:"fa fa-user-times",name:_t("Unfollow"),onSelected:({message})=>message.unfollow(),sequence:60,});registerMessageAction("edit",{condition:({message})=>message.editable,icon:"fa fa-pencil",name:_t("Edit"),onSelected:({message,owner,thread})=>{message.enterEditMode(thread);owner.optionsDropdown?.close();},sequence:({message})=>(message.isSelfAuthored?20:115),});registerMessageAction("delete",{condition:({message})=>
10390message.editable,icon:"fa fa-trash",name:_t("Delete"),onSelected:async({message:msg,owner,store})=>{const message=toRaw(msg);const def=new Deferred();store.env.services.dialog.add(discussComponentRegistry.get("MessageConfirmDialog"),{message,prompt:_t("Are you sure you want to bid farewell to this message forever?"),onConfirm:()=>{def.resolve(true);message.remove({removeFromThread:owner.shouldHideFromMessageListOnDelete,});},},{context:owner,onClose:()=>def.resolve(false)});return def;},sequence:120,tags:ACTION_TAGS.DANGER,});registerMessageAction("download_files",{condition:({message,store})=>message.attachment_ids.length>1&&store.self.main_user_id?.share===false,icon:"fa fa-download",name:_t("Download Files"),onSelected:({message})=>download({data:{file_ids:message.attachment_ids.map((rec)=>rec.id),zip_name:`attachments_${DateTime.local().toFormat("HHmmddMMyyyy")}.zip`,},url:"/mail/attachment/zip",}),sequence:55,});registerMessageAction("toggle-translation",{condition:({message})=>message.isTranslatable(message.thread),icon:({message})=>`fa fa-language ${message.showTranslation ? "o-mail-Message-translated" : ""}`,name:({message})=>(message.showTranslation?_t("Revert"):_t("Translate")),onSelected:({message})=>message.onClickToggleTranslation(),sequence:100,});registerMessageAction("copy-message",{condition:({message})=>isMobileOS()&&!message.isBodyEmpty,onSelected:({message})=>message.copyMessageText(),name:_t("Copy to Clipboard"),icon:"fa fa-copy",sequence:30,});registerMessageAction("copy-link",{condition:({message,thread})=>message.message_type&&message.message_type!=="user_notification"&&thread&&(!thread.access_token||thread.hasReadAccess),icon:"fa fa-link",name:_t("Copy Link"),onSelected:({message})=>message.copyLink(),sequence:110,});const MessageAction=__exports.MessageAction=class MessageAction extends Action{messageFn;threadFn;constructor({message,thread}){super(...arguments);this.messageFn=typeof message==="function"?message:()=>message;this.threadFn=typeof thread==="function"?thread:()=>thread;} 10391get params(){return Object.assign(super.params,{message:this.messageFn(),thread:this.threadFn()});}} 10392class UseMessageActions extends UseActions{ActionClass=MessageAction;} 10393__exports.useMessageActions=useMessageActions;function useMessageActions({message,thread}={}){const component=useComponent();const transformedActions=messageActionsRegistry.getEntries().map(([id,definition])=>new MessageAction({owner:component,id,definition,message,thread}));for(const action of transformedActions){action.setup();} 10394const state=useState(new UseMessageActions(component,transformedActions,useService("mail.store")));return state;} 10395return __exports;});; 10396 10397/* /mail/static/src/core/common/message_card_list.js */ 10398odoo.define('@mail/core/common/message_card_list',['@mail/core/common/message','@mail/utils/common/hooks','@odoo/owl','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message");const{useVisible}=require("@mail/utils/common/hooks");const{Component,useSubEnv}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const MessageCardList=__exports.MessageCardList=class MessageCardList extends Component{static components={Message};static props=["emptyText?","messages","messageSearch?","loadMore?","mode","onClickJump?","onLoadMoreVisible?","showEmpty?","thread",];static template="mail.MessageCardList";setup(){super.setup();this.ui=useService("ui");this.store=useService("mail.store");useSubEnv({messageCard:true});useVisible("load-more",(isVisible)=>{if(isVisible){this.props.onLoadMoreVisible?.();}});} 10399async onClickJump(message){this.props.onClickJump?.();if(this.ui.isSmall||this.env.inChatWindow||this.env.inMeetingView){this.env.pinMenu?.close();this.env.searchMenu?.close();this.env.inMeetingView?.openChat();} 10400await new Promise((resolve)=>setTimeout(()=>requestAnimationFrame(resolve)));await this.env.messageHighlight?.highlightMessage(message,this.props.thread);} 10401get emptyText(){return this.props.emptyText??_t("No messages found");}} 10402return __exports;});; 10403 10404/* /mail/static/src/core/common/message_confirm_dialog.js */ 10405odoo.define('@mail/core/common/message_confirm_dialog',['@odoo/owl','@web/core/dialog/dialog','@web/core/l10n/translation','@mail/core/common/discuss_component_registry'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{discussComponentRegistry}=require("@mail/core/common/discuss_component_registry");const MessageConfirmDialog=__exports.MessageConfirmDialog=class MessageConfirmDialog extends Component{static components={Dialog};static props=["close","confirmColor?","confirmText?","message","prompt","size?","t
10405itle?","onConfirm",];static defaultProps={confirmColor:"btn-primary",confirmText:_t("Delete"),size:"xl",title:_t("Send this message to the great trash can in the sky?"),};static template="mail.MessageConfirmDialog";get messageComponent(){return discussComponentRegistry.get("Message");} 10406onClickConfirm(){this.props.onConfirm();this.props.close();}} 10407discussComponentRegistry.add("MessageConfirmDialog",MessageConfirmDialog);return __exports;});; 10408 10409/* /mail/static/src/core/common/message_in_reply.js */ 10410odoo.define('@mail/core/common/message_in_reply',['@odoo/owl','@web/core/utils/hooks','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{url}=require("@web/core/utils/urls");const MessageInReply=__exports.MessageInReply=class MessageInReply extends Component{static props=["class?","message","onClick?"];static defaultProps={class:""};static template="mail.MessageInReply";setup(){super.setup();this.store=useService("mail.store");} 10411get authorAvatarUrl(){if(this.props.message.message_type&&this.props.message.message_type.includes("email")&&!this.props.message.author_id&&!this.props.message.author_guest_id){return url("/mail/static/src/img/email_icon.png");} 10412if(this.props.message.parent_id.author){return this.props.message.parent_id.author.avatarUrl;} 10413return this.store.DEFAULT_AVATAR;}} 10414return __exports;});; 10415 10416/* /mail/static/src/core/common/message_link_preview_list.js */ 10417odoo.define('@mail/core/common/message_link_preview_list',['@mail/core/common/link_preview','@odoo/owl'],function(require){'use strict';let __exports={};const{LinkPreview}=require("@mail/core/common/link_preview");const{Component}=require("@odoo/owl");const MessageLinkPreviewList=__exports.MessageLinkPreviewList=class MessageLinkPreviewList extends Component{static template="mail.MessageLinkPreviewList";static props=["messageLinkPreviews"];static components={LinkPreview};} 10418return __exports;});; 10419 10420/* /mail/static/src/core/common/message_link_preview_model.js */ 10421odoo.define('@mail/core/common/message_link_preview_model',['@mail/core/common/record','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{rpc}=require("@web/core/network/rpc");const MessageLinkPreview=__exports.MessageLinkPreview=class MessageLinkPreview extends Record{static _name="mail.message.link.preview";static id="id";message_id=fields.One("mail.message",{inverse:"message_link_preview_ids"});link_preview_id=fields.One("mail.link.preview",{inverse:"message_link_preview_ids"});get gifPaused(){return!this.message_id.thread?.isFocused;} 10422hide(){rpc("/mail/link_preview/hide",{message_link_preview_ids:[this.id]});}} 10423MessageLinkPreview.register();return __exports;});; 10424 10425/* /mail/static/src/core/common/message_model.js */ 10426odoo.define('@mail/core/common/message_model',['@html_editor/utils/dom_info','@mail/core/common/record','@mail/utils/common/format','@web/core/browser/browser','@web/core/browser/router','@web/core/emoji_picker/emoji_picker','@web/core/l10n/translation','@web/core/network/rpc','@web/core/user','@web/core/utils/html','@web/core/utils/urls','@odoo/owl'],function(require){'use strict';let __exports={};const{isEmptyBlock}=require("@html_editor/utils/dom_info");const{fields,Record}=require("@mail/core/common/record");const{EMOJI_REGEX,convertBrToLineBreak,decorateEmojis,generateEmojisOnHtml,getNonEditableMentions,htmlToTextContentInline,}=require("@mail/utils/common/format");const{browser}=require("@web/core/browser/browser");const{router}=require("@web/core/browser/router");const{loadEmoji}=require("@web/core/emoji_picker/emoji_picker");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{rpc}=require("@web/core/network/rpc");const{user}=require("@web/core/user");const{createDocumentFragmentFromContent,createElementWithContent}=require("@web/core/utils/html");const{url}=require("@web/core/utils/urls");const{markup}=require("@odoo/owl");const{DateTime}=luxon;const Message=__exports.Message=class Message extends Record{static _name="mail.message";static id="id";update(data){super.update(data);if(this.isNotification&&!this.notificationType){const htmlBody=createDocumentFragmentFromContent(this.body);this.notificationType=htmlBody.querySelector(".o_mail_notification")?.dataset.oeType;}} 10427attachment_ids=fields.Many("ir.attachment",{inverse:"message"});author_id=fields.One("res.partner");author_guest_id=fields.One("mail.guest");get author(){return this.author_id||this.author_guest_id;} 10428body=fields.Html("");call_history_ids=fields.Many("discuss.call.history");
10428richBody=fields.Html("",{compute(){if(!this.store.emojiLoader.loaded){loadEmoji();} 10429return decorateEmojis(this.body)??"";},});richTranslationValue=fields.Html("",{compute(){if(!this.store.emojiLoader.loaded){loadEmoji();} 10430return decorateEmojis(this.translationValue)??"";},});composer=fields.One("Composer",{inverse:"message",onDelete:(r)=>r.delete()});composerAsReplyToMessage=fields.One("Composer",{inverse:"replyToMessage"});date=fields.Datetime();default_subject;edited=fields.Attr(false,{compute(){return Boolean(createDocumentFragmentFromContent(this.body).querySelector(".o-mail-Message-edited"));},});extra_body_attachment_ids=fields.Attr("ir.attachment",{compute(){const parsedBody=createDocumentFragmentFromContent(this.body);const inlinedImageAttachmentIds=[...parsedBody.querySelectorAll("img[data-attachment-id]"),].map((img)=>parseInt(img.dataset.attachmentId));return this.attachment_ids.filter((a)=>!inlinedImageAttachmentIds.includes(a.id));},});hasLink=fields.Attr(false,{compute(){if(this.isBodyEmpty){return false;} 10431const div=createElementWithContent("div",this.body);return Boolean(div.querySelector("a:not([data-oe-model])"));},});hasMailNotificationSummary=fields.Attr(false,{compute(){return Boolean(createDocumentFragmentFromContent(this.body).querySelector('[summary="o_mail_notification"]'));},});id;incoming_email_cc;incoming_email_to;get isDiscussion(){return this.store.mt_comment?.eq(this.subtype_id);} 10432get isNote(){return this.store.mt_note?.eq(this.subtype_id);} 10433is_transient;message_link_preview_ids=fields.Many("mail.message.link.preview",{inverse:"message_id"});parent_id=fields.One("mail.message");postFailRedo=undefined;reactions=fields.Many("MessageReactions",{inverse:"message",sort:(r1,r2)=>r1.sequence-r2.sequence,});notification_ids=fields.Many("mail.notification",{inverse:"mail_message_id"});partner_ids=fields.Many("res.partner");subtype_id=fields.One("mail.message.subtype");thread=fields.One("Thread");threadAsNeedaction=fields.One("Thread",{compute(){if(this.needaction){return this.thread;}},});threadAsNewest=fields.One("Thread");threadAsInEdition=fields.One("Thread",{compute(){if(this.composer){return this.thread;}},});scheduledDatetime=fields.Datetime();onlyEmojis=fields.Attr(false,{compute(){const bodyWithoutTags=createElementWithContent("div",this.body).textContent;const withoutEmojis=bodyWithoutTags.replace(EMOJI_REGEX,"");return(bodyWithoutTags.length>0&&bodyWithoutTags.match(EMOJI_REGEX)&&withoutEmojis.trim().length===0);},});subject;trackingValues=[];translationValue;translationSource;translationErrors;message_type;notificationType;create_date=fields.Datetime();write_date=fields.Datetime();needaction;starred=false;showTranslation=false;get allowsEdition(){return this.store.self.main_user_id?.is_admin||this.isSelfAuthored;} 10434get bubbleColor(){if(this.message_type==="notification"){return undefined;} 10435if(!this.isSelfAuthored&&!this.isNote&&!this.isHighlightedFromMention){return"blue";} 10436if(this.isSelfAuthored&&!this.isNote&&!this.isHighlightedFromMention){return"green";} 10437if(this.isHighlightedFromMention){return"orange";} 10438return undefined;} 10439get editable(){if(this.isEmpty||!this.allowsEdition){return false;} 10440return this.message_type==="comment";} 10441get dateDay(){let dateDay=this.datetime.toLocaleString(DateTime.DATE_MED);if(dateDay===DateTime.now().toLocaleString(DateTime.DATE_MED)){dateDay=_t("Today");} 10442return dateDay;} 10443get dateSimple(){return this.datetime.toLocaleString(DateTime.TIME_SIMPLE,{locale:user.lang,}).replace("â¯"," ");} 10444get dateSimpleWithDay(){const userLocale={locale:user.lang};if(this.datetime.hasSame(DateTime.now(),"day")){return this.datetime.toLocaleString(DateTime.TIME_SIMPLE,userLocale);} 10445if(this.datetime.hasSame(DateTime.now().minus({day:1}),"day")){return _t("Yesterday at %(time)s",{time:this.datetime.toLocaleString(DateTime.TIME_SIMPLE,userLocale),});} 10446if(this.datetime?.year===DateTime.now().year){return this.datetime.toLocaleString({...DateTime.DATETIME_MED,year:undefined},userLocale);} 10447return this.datetime.toLocaleString({...DateTime.DATETIME_MED},userLocale);} 10448get datetime(){return this.date||DateTime.now();} 10449get effectiveSelf(){return this.thread?.effectiveSelf??this.store.self;}
10450get datetimeShort(){return this.datetime.toLocaleString(DateTime.DATETIME_SHORT_WITH_SECONDS);} 10451get isSelfMentioned(){return this.effectiveSelf.in(this.partner_ids);} 10452get isHighlightedFromMention(){return this.isSelfMentioned&&this.thread?.model==="discuss.channel";} 10453isSelfAuthored=fields.Attr(false,{compute(){return Boolean(this.author?.eq(this.effectiveSelf));},});isPending=false;get hasActions(){return!this.is_transient;} 10454get isNotification(){return this.message_type==="notification"&&this.thread?.model==="discuss.channel";} 10455get isSubjectSimilarToThreadName(){if(!this.subject||!this.thread||!this.thread.display_name){return false;} 10456const regexPrefix=/^((re|fw|fwd)\s*:\s*)*/i;const cleanedThreadName=this.thread.display_name.replace(regexPrefix,"");const cleanedSubject=this.subject.replace(regexPrefix,"");return cleanedSubject===cleanedThreadName;} 10457get isSubjectDefault(){const name=this.thread?.display_name;const threadName=name?name.trim().toLowerCase():"";const defaultSubject=this.default_subject?this.default_subject.toLowerCase():"";const candidates=new Set([defaultSubject,threadName]);return candidates.has(this.subject?.toLowerCase());} 10458get persistent(){return Number.isInteger(this.id);} 10459get resUrl(){return url(router.stateToUrl({model:this.thread.model,resId:this.thread.id}));} 10460isTranslatable(thread){return(!this.isEmpty&&!this.isBodyEmpty&&!this.hasMailNotificationSummary&&this.store.hasMessageTranslationFeature&&!["discuss.channel","mail.box"].includes(thread?.model));} 10461get hasTextContent(){return!this.isBodyEmpty||this.subject||this.edited;} 10462isEmpty=fields.Attr(false,{compute(){return this.computeIsEmpty();},});isBodyEmpty=fields.Attr(undefined,{compute(){return!this.body||isEmptyBlock(createElementWithContent("div",this.body));},});computeIsEmpty(){return(this.isBodyEmpty&&this.attachment_ids.length===0&&this.trackingValues.length===0&&!this.subtype_id?.description&&!this.subject);} 10463get linkPreviewSquash(){return(this.store.hasLinkPreviewFeature&&this.body&&this.body.startsWith("<a")&&this.body.endsWith("/a>")&&this.body.match(/<\/a>/im)?.length===1&&this.message_link_preview_ids.length===1&&this.message_link_preview_ids[0].link_preview_id.isImage);} 10464get authorName(){if(this.author){return this.getPersonaName(this.author);} 10465return this.email_from||_t("Unnamed");} 10466get notificationHidden(){return false;} 10467inlineBody=fields.Html("",{compute(){if(this.notificationType==="call"){return _t("%(caller)s started a call",{caller:this.authorName});} 10468if(this.notificationType==="thread_deletion"){return _t('%(user)s deleted the thread "%(thread_name)s"',{user:this.authorName,thread_name:decorateEmojis(htmlToTextContentInline(this.body)),});} 10469if(this.notificationType==="channel_rename"){const name=htmlToTextContentInline(this.body);const params={user:this.authorName,name:markup`<b>${name}</b>`};return this.thread?.parent_channel_id?_t("%(user)s changed the thread name to %(name)s",params):_t("%(user)s changed the channel name to %(name)s",params);} 10470if(this.isEmpty){return _t("This message has been removed");} 10471if(!this.body){return"";} 10472return decorateEmojis(htmlToTextContentInline(this.body));},});get notificationIcon(){switch(this.notificationType){case"pin":return"fa fa-thumb-tack";case"call":return"fa fa-phone";} 10473return null;} 10474get failureNotifications(){return this.notification_ids.filter((notification)=>notification.isFailure);} 10475get scheduledDateSimple(){return this.scheduledDatetime.toLocaleString(DateTime.TIME_SIMPLE,{locale:user.lang,});} 10476get canToggleStar(){return Boolean(!this.is_transient&&!this.isPending&&this.store.self_partner?.main_user_id?.share===false&&this.persistent);} 10477get hasOnlyAttachments(){return this.isBodyEmpty&&this.attachment_ids.length>0;} 10478previewText=fields.Html("",{compute(){if(!this.hasOnlyAttachments){return this.inlineBody||this.subtype_id?.description;} 10479const{attachment_ids:attachments}=this;if(!attachments||attachments.length===0){return"";} 10480switch(attachments.length){case 1:return attachments[0].previewName;case 2:return _t("%(file1)s and %(file2)s",{file1:attachments[0].previewName,file2:attachments[1].previewName,count:attachments.length-1,});default:return _t("%(file1)s and %(count)s other attachments",{file1:attachments[0].previewName,count:attachments.length-1,});}},});get previewIcon(){const{attachment_ids:attachments}=this;if(!attachments||attachments.length===0){return"";} 10481const firstAttachment=attachments[0];switch(true){case firstAttachment.isImage:return"fa-picture-o";case firstAttachment.mimetype==="audio/mpeg":return firstAttachment.voice?"fa-microphone":"fa-headphones";case firstAttachment.isVideo:return"fa-video-camera";default:return"fa-file";}} 10482canAddReaction(thread){return Boolean(!this.is_transient&&!this.isPending&&this.thread?.can_react&&!this.thread.isTransient&&this.thread.has_mail_thread);} 10483canReplyTo(thread){return(["discuss.channel","mail.box"].includes(thread?.model)&&this.message_type!=="user_notification");} 10484canUnfollow(thread){return Boolean(this.thread?.selfFollower&&thread?.model==="mail.box");} 10485async copyLink(){let notification=_t("Message Link Copied!");let type="info";try{await browser.navigator.clipboard.writeText(url(`/mail/message/${this.id}`));}catch{notification=_t("Message Link Copy Failed (Permission denied?)!");type="danger";} 10486this.store.env.services.notification.add(notification,{type});} 10487async copyMessageText(){const messageBody=convertBrToLineBreak(this.body);try{await browser.navigator.clipboard.writeText(messageBody);}catch{this.store.env.services.notification.add(_t("Message Copy Failed (Permission denied?)!"),{type:"danger"});} 10488this.store.env.services.notification.add(_t("Message Copied!"),{type:"info"});} 10489async edit(body,attachments=[],{mentionedChannels=[],mentionedPartners=[],mentionedRoles=[]}={}){const messageBodyEl=createElementWithContent("div",this.body);const updatedBodyEl=createElementWithContent("div",body);messageBodyEl.querySelector("span.o-mail-Message-edited")?.remove();updatedBodyEl.querySelector("span.o-mail-Message-edited")?.remove();if(updatedBodyEl.innerHTML===messageBodyEl.innerHTML&&attachments.length===0){return;} 10490const validMentions=this.store.getMentionsFromText(body,{mentionedChannels,mentionedPartners,mentionedRoles,thread:this.thread,});const hadLink=this.hasLink;const updateData={attachment_ids:attachments.concat(this.attachment_ids).map((attachment)=>attachment.id),attachment_tokens:attachments.concat(this.attachment_ids).map((attachment)=>attachment.ownership_token),body:await generateEmojisOnHtml(body),partner_ids:validMentions?.partners?.map((partner)=>partner.id),role_ids:validMentions?.roles?.map((role)=>role.id),};this.store.fillPartnersMentionToken(updateData);const data=await rpc("/mail/message/update_content",{message_id:this.id,update_data:updateData,...this.thread.rpcParams,});this.store.insert(data);if((hadLink||this.hasLink)&&this.store.hasLinkPreviewFeature){rpc("/mail/link_preview",{message_id:this.id},{silent:true});} 10491return data;} 10492async enterEditMode(thread){const doc=createDocumentFragmentFromContent(this.body);const validChannels=(await Promise.all(Array.from(doc.querySelectorAll(".o_channel_redirect[data-oe-model='discuss.channel']")).map(async(el)=>this.store.Thread.getOrFetch({id:el.dataset.oeId,model:"discuss.channel"})))).filter((channel)=>channel?.exists());const validRoles=Array.from(doc.querySelectorAll(".o-discuss-mention[data-oe-model='res.role']")).map((el)=>this.store["res.role"].get(el.dataset.oeId));const text=convertBrToLineBreak(this.body);if(thread?.messageInEdition){thread.messageInEdition.composer=undefined;} 10493this.composer={composerHtml:getNonEditableMentions(this.body),mentionedChannels:validChannels,mentionedPartners:this.partner_ids,mentionedRoles:validRoles,selection:{start:text.length,end:text.length,direction:"none",},};} 10494exitEditMode(thread){const threadAsInEdition=this.threadAsInEdition;this.composer=undefined;if(threadAsInEdition&&threadAsInEdition.eq(thread)){threadAsInEdition.composer.autofocus++;}} 10495getPersonaName(persona){return(this.thread?.getPersonaName(persona)||persona?.displayName||persona?.n
10495ame||_t("Unnamed"));} 10496async onClickToggleTranslation(){if(!this.translationValue){const{error,lang_name,body}=await rpc("/mail/message/translate",{message_id:this.id,});this.translationValue=body&&markup(body);this.translationSource=lang_name;this.translationErrors=error;} 10497this.showTranslation=!this.showTranslation&&Boolean(this.translationValue);} 10498async react(content){this.store.insert(await rpc("/mail/message/reaction",{action:"add",content,message_id:this.id,...this.thread.rpcParams,},{silent:true}));} 10499async remove({removeFromThread=false}={}){const data=await rpc("/mail/message/update_content",{message_id:this.id,update_data:this.removeParams,...this.thread.rpcParams,});this.store.insert(data);if(this.thread&&removeFromThread){this.thread.messages=this.thread.messages.filter((message)=>message.notEq(this));} 10500this.composer=undefined;return data;} 10501get removeParams(){return{attachment_ids:[],attachment_tokens:[],body:"",subject:"",partner_ids:[],};} 10502async setDone(){await this.store.env.services.orm.silent.call("mail.message","set_message_done",[[this.id],]);} 10503async toggleStar(){this.store.insert(await this.store.env.services.orm.silent.call("mail.message","toggle_message_starred",[[this.id]]));} 10504async unfollow(){if(this.needaction){await this.setDone();} 10505const thread=this.thread;await thread.selfFollower.remove();this.store.env.services.notification.add(_t('You are no longer following "%(thread_name)s".',{thread_name:thread.display_name,}),{type:"success"});} 10506hideAllLinkPreviews(){rpc("/mail/link_preview/hide",{message_link_preview_ids:this.message_link_preview_ids.map((lpm)=>lpm.id),});}} 10507Message.register();return __exports;});; 10508 10509/* /mail/static/src/core/common/message_notification_popover.js */ 10510odoo.define('@mail/core/common/message_notification_popover',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const MessageNotificationPopover=__exports.MessageNotificationPopover=class MessageNotificationPopover extends Component{static template="mail.MessageNotificationPopover";static props=["message","close?"];} 10511return __exports;});; 10512 10513/* /mail/static/src/core/common/message_reaction_list.js */ 10514odoo.define('@mail/core/common/message_reaction_list',['@mail/utils/common/hooks','@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/emoji_picker/emoji_picker','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{useHover}=require("@mail/utils/common/hooks");const{Component}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{loadEmoji}=require("@web/core/emoji_picker/emoji_picker");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const MessageReactionList=__exports.MessageReactionList=class MessageReactionList extends Component{static template="mail.MessageReactionList";static components={Dropdown};static props=["message","openReactionMenu","reaction"];setup(){super.setup();this.loadEmoji=loadEmoji;this.store=useService("mail.store");this.ui=useService("ui");this.preview=useDropdownState();this.hover=useHover(["reactionButton","reactionList"],{onHover:()=>(this.preview.isOpen=true),onAway:()=>(this.preview.isOpen=false),stateObserver:()=>[this.preview?.isOpen],});} 10515previewText(reaction){const{count,content:emoji}=reaction;const personNames=reaction.personas.slice(0,3).map((persona)=>this.props.message.getPersonaName(persona));const shortcode=this.store.emojiLoader.loaded?.emojiValueToShortcodes?.[emoji]?.[0]??"?";switch(count){case 1:return _t("%(emoji)s reacted by %(person)s",{emoji:shortcode,person:personNames[0],});case 2:return _t("%(emoji)s reacted by %(person1)s and %(person2)s",{emoji:shortcode,person1:personNames[0],person2:personNames[1],});case 3:return _t("%(emoji)s reacted by %(person1)s, %(person2)s, and %(person3)s",{emoji:shortcode,person1:personNames[0],person2:personNames[1],person3:personNames[2],});case 4:return _t("%(emoji)s reacted by %(person1)s, %(person2)s, %(person3)s, and 1 other",{emoji:shortcode,person1:personNames[0],person2:personNames[1],person3:personNames[2],});default:return _t("%(emoji)s reacted by %(person1)s, %(person2)s, %(person3)s, and %(count)s others",{count:count-3,emoji:shortcode,person1:personNames[0],person2:personNames[1],person3:personNames[2],});}} 10516hasSelfReacted(reaction){return this.props.message.effectiveSelf.in(reaction.personas);} 10517onClickReaction(reaction){if(!this.props.message.canAddReaction()){return;} 10518if(this.hasSelfReacted(reaction)){reaction.remove();}else{this.props.message.react(reaction.content);}} 10519onContextMenu(ev){if(this.ui.isSmall){ev.preventDefault();this.props.openReactionMenu();}} 10520onClickReactionList(reaction){this.preview.isOpen=false;this.props.openReactionMenu(reaction);}} 10521return __exports;});; 10522 10523/* /mail/static/src/core/common/message_reaction_menu.js */ 10524odoo.define('@mail/core/common/message_reaction_menu',['@web/core/emoji_picker/emoji_picker','@mail/utils/common/hooks','@odoo/owl','@web/core/dialog/dialog','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{loadEmoji}=require("@web/core/emoji_picker/emoji_picker");const{onExternalClick}=require("@mail/utils/common/hooks");const{Component,onMounted,useEffect,useExternalListener,useRef,useState}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{useService}=require("@web/core/utils/hooks");const MessageReactionMenu=__exports.MessageReactionMenu=class MessageReactionMenu extends Component{static props=["close","message","initialReaction?"];static components={Dialog};static template="mail.MessageReactionMenu";setup(){super.setup();this.root=useRef("root");this.store=useService("mail.store");this.ui=useService("ui");this.state=useState({reaction:this.props.initialReaction?this.props.initialReaction:this.props.message.reactions[0],});useExternalListener(document,"keydown",this.onKeydown);onExternalClick("root",()=>this.props.close());useEffect(()=>{const activeReaction=this.props.message.reactions.find(({content})=>content===this.state.reaction.content);if(this.props.message.reactions.length===0){this.props.close();}else if(!activeReaction){this.state.reaction=this.props.message.reactions[0];}}
10524,()=>[this.props.message.reactions.length]);onMounted(()=>{if(!this.store.emojiLoader.loaded){loadEmoji();}});} 10525onKeydown(ev){switch(ev.key){case"Escape":this.props.close();break;case"q":this.props.close();break;default:return;}} 10526getEmojiShortcode(reaction){return this.store.emojiLoader.loaded?.emojiValueToShortcodes?.[reaction.content]?.[0]??"?";} 10527get contentClass(){const attClass={"o-mail-MessageReactionMenu h-50 d-flex":true,"position-absolute bottom-0":this.store.useMobileView,};return Object.entries(attClass).filter(([classNames,value])=>value).map(([classNames])=>classNames).join(" ");}} 10528return __exports;});; 10529 10530/* /mail/static/src/core/common/message_reactions.js */ 10531odoo.define('@mail/core/common/message_reactions',['@odoo/owl','@mail/core/common/message_actions','@mail/core/common/message_reaction_list','@mail/core/common/quick_reaction_menu','@web/core/utils/hooks','@web/core/emoji_picker/emoji_picker','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component,useRef}=require("@odoo/owl");const{useMessageActions}=require("@mail/core/common/message_actions");const{MessageReactionList}=require("@mail/core/common/message_reaction_list");const{QuickReactionMenu}=require("@mail/core/common/quick_reaction_menu");const{useService}=require("@web/core/utils/hooks");const{useEmojiPicker}=require("@web/core/emoji_picker/emoji_picker");const{isMobileOS}=require("@web/core/browser/feature_detection");const MessageReactions=__exports.MessageReactions=class MessageReactions extends Component{static props=["message","openReactionMenu"];static template="mail.MessageReactions";static components={MessageReactionList,QuickReactionMenu};setup(){super.setup();this.store=useService("mail.store");this.ui=useService("ui");this.addRef=useRef("add");this.isMobileOS=isMobileOS();this.messageActions=useMessageActions({message:()=>this.props.message});this.emojiPicker=useEmojiPicker(this.addRef,{onSelect:(emoji)=>{const reaction=this.props.message.reactions.find(({content,personas})=>content===emoji&&this.props.message.effectiveSelf.in(personas));if(!reaction){this.props.message.react(emoji);}},});}} 10532return __exports;});; 10533 10534/* /mail/static/src/core/common/message_reactions_model.js */ 10535odoo.define('@mail/core/common/message_reactions_model',['@mail/core/common/record','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{AND,fields,Record}=require("@mail/core/common/record");const{rpc}=require("@web/core/network/rpc");const MessageReactions=__exports.MessageReactions=class MessageReactions extends Record{static id=AND("message","content");content;count;guests=fields.Many("mail.guest");message=fields.One("mail.message");partners=fields.Many("res.partner");personas=fields.Attr([],{compute(){return[...this.partners,...this.guests];},});sequence;async remove(){this.store.insert(await rpc("/mail/message/reaction",{action:"remove",content:this.content,message_id:this.message.id,...this.message.thread.rpcParams,},{silent:true}));}} 10536MessageReactions.register();return __exports;});; 10537 10538/* /mail/static/src/core/common/message_search_hook.js */ 10539odoo.define('@mail/core/common/message_search_hook',['@mail/utils/common/hooks','@odoo/owl','@web/core/utils/hooks','@web/core/utils/html','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{useSequential}=require("@mail/utils/common/hooks");const{useState,onWillUnmount,markup}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{createDocumentFragmentFromContent}=require("@web/core/utils/html");const{escapeRegExp}=require("@web/core/utils/strings");const HIGHLIGHT_CLASS=__exports.HIGHLIGHT_CLASS="o-mail-Message-searchHighlight";__exports.searchHighlight=searchHighlight;function searchHighlight(searchTerm,target){if(!searchTerm){return target;} 10540const htmlDoc=createDocumentFragmentFromContent(target);for(const term of searchTerm.split(" ").filter(Boolean)){const regexp=new RegExp(`(${escapeRegExp(term)})`,"gi");const split=term.toLowerCase().split("'");let lowercase=split.map((s)=>`'${s}'`).join(', "\'", ');let uppercase=lowercase.toUpperCase();if(split.length>1){lowercase=`concat(${lowercase})`;uppercase=`concat(${uppercase})`;} 10541const matchs=htmlDoc.evaluate(`//*[text()[contains(translate(., ${uppercase}, ${lowercase}), ${lowercase})]]`,htmlDoc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);for(let i=0;i<matchs.snapshotLength;i++){const element=matchs.snapshotItem(i);const newNode=[];for(const node of element.childNodes){const match=node.textContent.match(regexp);if(node.nodeType===Node.TEXT_NODE&&match?.length>0){let curIndex=0;for(const match of node.textContent.matchAll(regexp)){const start=htmlDoc.createTextNode(node.textContent.slice(curIndex,match.index));newNode.push(start);const span=htmlDoc.createElement("span");span.setAttribute("class",HIGHLIGHT_CLASS);span.textContent=match[0];newNode.push(span);curIndex=match.index+match[0].length;} 10542const end=htmlDoc.createTextNode(node.textContent.slice(curIndex));newNode.push(end);}else{newNode.push(node);}} 10543element.replaceChildren(...newNode);}} 10544return markup(htmlDoc.body.innerHTML);} 10545__exports.useMessageSearch=useMessageSearch;function useMessageSearch(thread){const store=useService("mail.store");const sequential=useSequential();const state=useState({thread,async search(before=false){if(this.searchTerm||this.is_notification!==un
10545defined){this.searching=true;const data=await sequential(()=>store.searchMessagesInThread(this.searchTerm,this.thread,before,this.is_notification));if(!data){return;} 10546const{count,loadMore,messages}=data;this.searched=true;this.searching=false;this.count=count;this.loadMore=loadMore;if(before){this.messages.push(...messages);}else{this.messages=messages;}}else{this.clear();}},count:0,clear(){this.is_notification=undefined;this.messages=[];this.searched=false;this.searching=false;this.searchTerm=undefined;},is_notification:undefined,loadMore:false,messages:[],searchTerm:undefined,searched:false,searching:false,highlight:(target)=>searchHighlight(state.searchTerm,target),});onWillUnmount(()=>{state.clear();});return state;} 10547return __exports;});; 10548 10549/* /mail/static/src/core/common/navigable_list.js */ 10550odoo.define('@mail/core/common/navigable_list',['@mail/core/common/im_status','@mail/utils/common/hooks','@web/core/utils/misc','@odoo/owl','@web/core/hotkeys/hotkey_service','@web/core/position/position_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{ImStatus}=require("@mail/core/common/im_status");const{onExternalClick}=require("@mail/utils/common/hooks");const{markEventHandled,isEventHandled}=require("@web/core/utils/misc");const{Component,useChildSubEnv,useEffect,useExternalListener,useRef,useState,}=require("@odoo/owl");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{usePosition}=require("@web/core/position/position_hook");const{useService}=require("@web/core/utils/hooks");function optionsToString(options){return options.map((option)=>Object.entries(option).map(([name,value])=>`${name}:${value?.localId ?? value}`).join(",")).join("\n");} 10551const NavigableList=__exports.NavigableList=class NavigableList extends Component{static components={ImStatus};static template="mail.NavigableList";static props={anchorRef:{optional:true},class:{type:String,optional:true},onSelect:{type:Function},options:{type:Array},optionTemplate:{type:String,optional:true},position:{type:String,optional:true},closeOnSelect:{type:Boolean,optional:true},isLoading:{type:Boolean,optional:true},};static defaultProps={position:"bottom",closeOnSelect:true,isLoading:false,};setup(){super.setup();useChildSubEnv({inNavigableList:true});this.rootRef=useRef("root");this.state=useState({activeIndex:null,open:false,showLoading:false,});this.hotkey=useService("hotkey");this.hotkeysToRemove=[];useExternalListener(window,"keydown",this.onKeydown,true);onExternalClick("root",async(ev)=>{await new Promise(setTimeout);if(isEventHandled(ev,"composer.onClickTextarea")){return;} 10552this.close();});usePosition("root",()=>this.props.anchorRef,{position:this.props.position});useEffect(()=>{this.open();},()=>[optionsToString(this.props.options)]);useEffect(()=>{if(!this.props.isLoading){clearTimeout(this.loadingTimeoutId);this.state.showLoading=false;}else if(!this.loadingTimeoutId){this.loadingTimeoutId=setTimeout(()=>(this.state.showLoading=true),2000);}},()=>[this.props.isLoading]);} 10553get show(){return Boolean(this.state.open&&(this.props.isLoading||this.props.options.length));} 10554get sortedOptions(){return this.props.options.sort((o1,o2)=>(o1.group??0)-(o2.group??0));} 10555open(){this.state.open=true;this.state.activeIndex=null;this.navigate("first");} 10556close(){if(this.props.closeOnSelect){this.state.open=false;this.state.activeIndex=null;}} 10557selectOption(ev,index,params={}){const{option=this.props.options[index],...onSelectParams}=params;if(!option){return;} 10558if(option.unselectable){this.close();return;} 10559this.props.onSelect(ev,option,{...onSelectParams,});this.close();} 10560navigate(direction){if(this.props.options.length===0){return;} 10561const activeOptionId=this.state.activeIndex!==null?this.state.activeIndex:0;let targetId=undefined;switch(direction){case"first":targetId=0;break;case"last":targetId=this.props.options.length-1;break;case"previous":targetId=activeOptionId-1;if(targetId<0){this.navigate("last");return;} 10562break;case"next":targetId=activeOptionId+1;if(targetId>this.props.options.length-1){this.navigate("first");return;} 10563break;default:return;} 10564this.state.activeIndex=targetId;} 10565onKeydown(ev){if(!this.show){return;} 10566const hotkey=getActiveHotkey(ev);switch(hotkey){case"enter":markEventHandled(ev,"NavigableList.select");if(this.state.activeIndex===null){this.close();return;} 10567this.selectOption(ev,this.state.activeIndex);break;case"escape":markEventHandled(ev,"NavigableList.close");this.close();break;case"tab":this.navigate(this.state.activeIndex===null?"first":"next");break;case"arrowup":this.navigate(this.state.activeIndex===null?"first":"previous");break;case"arrowdown":this.navigate(this.state.activeIndex===null?"first":"next");break;default:return;} 10568if(this.props.options.length!==0){ev.stopPropagation();} 10569ev.preventDefault();} 10570onOptionMouseEnter(index){}} 10571return __exports;});; 10572 10573/* /mail/static/src/core/common/notification_message.js */ 10574odoo.define('@mail/core/common/notification_message',['@odoo/owl','@web/core/l10n/translation','@web/core/utils/hooks','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{Component,onMounted,onPatched,onWillDestroy,onWillUpdateProps,useRef,}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{escape}=require("@web/core/utils/strings");const NotificationMessage=__exports.NotificationMessage=class NotificationMessage extends Component{static template="mail.NotificationMessage";static props=["message","thread","registerMessageRef?"];setup(){super.setup();this.root=useRef("root");onWillUpdateProps((nextProps)=>{this.props.registerMessageRef?.(this.props.message,null);});onMounted(()=>this.props.registerMessageRef?.(this.props.message,this.root));onPatched(()=>this.props.registerMessageRef?.(this.props.message,this.root));onWillDestroy(()=>this.props.registerMessageRef?.(this.props.message,null));this.escape=escape;this.store=useService("mail.store");} 10575async onClickNotificationMessage(ev){this.store.handleClickOnLink(ev,this.props.thread);const{oeType,oeId}=ev.target.dataset;if(oeType==="highlight"){await this.env.messageHighlight?.highlightMessage(this.store["mail.message"].insert({id:Number(oeId),res_id:this.props.thread.id,model:this.props.thread.model,thread:this.props.thread,}),this.props.thread);}} 10576get message(){return this.props.message;} 10577get callInformation(){const history=this.message.call_history_ids[0];if(history?.duration_hour===undefined||!history?.end_dt){return _t("%(author)s started a call.",{author:this.message.authorName});} 10578let duration=luxon.Duration.fromObject({seconds:Math.max(1,Math.round(history.duration_hour*3600)),}).shiftTo("hours","minutes","seconds");if(duration.hours||duration.minutes){duration=duration.set({seconds:0});} 10579const units=Object.entries(duration.toObject()).filter(([unit,amount])=>amount!=0).map(([unit,amount])=>unit);return _t("Call lasted %(duration)s.",{duration:duration.shiftTo(...units).toHuman({unitDisplay:"short"}),});}} 10580return __exports;});; 10581 10582/* /mail/static/src/core/common/notification_model.js */ 10583odoo.define('@mail/core/common/notification_model',['@mail/core/common/record','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const Notification=__exports.Notification=class Notification extends Record{static _name="mail.n
10583otification";static id="id";id;mail_message_id=fields.One("mail.message",{onDelete(){this.delete();},});notification_status;notification_type;mail_email_address;failure=fields.One("Failure",{inverse:"notifications",compute(){const thread=this.mail_message_id?.thread;if(!this.mail_message_id?.isSelfAuthored){return;} 10584const failure=Object.values(this.store.Failure.records).find((f)=>f.resModel===thread?.model&&f.type===this.notification_type&&(f.resModel!=="discuss.channel"||f.resIds.has(thread?.id)));return this.isFailure?{id:failure?failure.id:this.store.Failure.nextId.value++,}:false;},eager:true,});failure_type;get failureMessage(){switch(this.failure_type){case"mail_smtp":return _t("Connection failed");case"mail_bounce":return _t("Bounce");case"mail_email_invalid":return _t("Invalid email address");case"mail_email_missing":return _t("Missing email address");case"mail_from_invalid":return _t("Invalid from address");case"mail_from_missing":return _t("Missing from address");case"mail_spam":return _t("Detected As Spam");default:return _t("Exception");}} 10585res_partner_id=fields.One("res.partner");get autoCanceledFailureType(){switch(this.failure_type){case"mail_bl":return _t("Blacklisted Address");case"mail_dup":return _t("Duplicated Email");case"mail_optout":return _t("Opted Out");} 10586return"";} 10587get isFailure(){return["exception","bounce"].includes(this.notification_status);} 10588get icon(){if(this.isFailure){return"fa fa-envelope";} 10589return"fa fa-envelope-o";} 10590get label(){return"";} 10591get isFollowerNotification(){return this.res_partner_id&&this.mail_message_id.thread.followers.some((follower)=>follower.partner_id.id===this.res_partner_id.id);} 10592get statusIcon(){switch(this.notification_status){case"process":return"fa fa-hourglass-half";case"pending":return"fa fa-paper-plane-o";case"sent":return"fa fa-check";case"bounce":return"fa fa-exclamation";case"exception":return"fa fa-times text-danger";case"ready":return"fa fa-send-o";case"canceled":if(this.autoCanceledFailureType){return"fa fa-remove";}
10593return"fa fa-trash-o";} 10594return"";} 10595get statusTitle(){switch(this.notification_status){case"process":return _t("Processing");case"pending":return _t("Sent");case"sent":return _t("Delivered");case"bounce":return _t("Bounced");case"exception":return _t("Error");case"ready":return _t("Queued");case"canceled":return this.autoCanceledFailureType||_t("Cancelled");} 10596return"";}} 10597Notification.register();return __exports;});; 10598 10599/* /mail/static/src/core/common/notification_permission_service.js */ 10600odoo.define('@mail/core/common/notification_permission_service',['@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/l10n/translation','@web/core/registry'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isAndroidApp,isDisplayStandalone,isIOS,isIosApp,}=require("@web/core/browser/feature_detection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");async function getIosPwaPermission(){if(browser.location.protocol!=="https:"){return"denied";} 10601const registration=await browser.navigator.serviceWorker?.getRegistration();return(await registration?.pushManager.permissionState())??"prompt";} 10602const notificationPermissionService=__exports.notificationPermissionService={dependencies:["notification"],_normalizePermission(permission){switch(permission){case"default":return"prompt";case undefined:return"denied";default:return permission;}},async start(env,services){const notification=services.notification;let permission;try{if(isIOS()&&isDisplayStandalone()){permission={state:await getIosPwaPermission()};}else if(isIOS()){permission={state:"denied"};}else{permission=await browser.navigator?.permissions?.query({name:"notifications",});}}catch{} 10603const state=reactive({permission:isIosApp()||isAndroidApp()?"denied":this._normalizePermission(permission?.state??browser.Notification?.permission),requestPermission:async()=>{if(browser.Notification&&state.permission==="prompt"){state.permission=this._normalizePermission(await browser.Notification.requestPermission());if(state.permission==="denied"){notification.add(_t("Odoo will not send notifications on this device."),{type:"warning",title:_t("Notifications blocked"),});}else if(state.permission==="granted"){notification.add(_t("Odoo will send notifications on this device!"),{type:"success",title:_t("Notifications allowed"),});}}},});if(permission&&!isIOS()){permission.addEventListener("change",()=>(state.permission=permission.state));} 10604return state;},};registry.category("services").add("mail.notification.permission",notificationPermissionService);return __exports;});; 10605 10606/* /mail/static/src/core/common/out_of_focus_service.js */ 10607odoo.define('@mail/core/common/out_of_focus_service',['@mail/utils/common/format','@web/core/browser/feature_detection','@web/core/browser/browser','@web/core/l10n/translation','@web/core/registry'],function(require){'use strict';let __exports={};const{htmlToTextContentInline}=require("@mail/utils/common/format");const{isAndroid}=require("@web/core/browser/feature_detection");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const PREVIEW_MSG_MAX_SIZE=350;const OutOfFocusService=__exports.OutOfFocusService=class OutOfFocusService{constructor(env,services){this.setup(env,services);} 10608setup(env,services){this.env=env;this.audio=undefined;this.multiTab=services.multi_tab;this.notificationService=services.notification;this.soundEffectService=services["mail.sound_effects"];this.store=services["mail.store"];this.closeFuncs=[];} 10609async notify(message,thread){const modelsHandleByPush=["mail.thread","discuss.channel"];if(modelsHandleByPush.includes(message.thread?.model)&&(await this.hasServiceWorkInstalledAndPushSubscriptionActive())){return;} 10610const author=message.author;let notificationTitle;let icon="/mail/static/src/img/odoobot_transparent.png";if(!author){notificationTitle=_t("New message");}else{icon=author.avatarUrl;if(message.thread?.channel_type==="channel"){notificationTitle=_t("%(author name)s from %(channel name)s",{"author name":message.authorName,"channel name":message.thread.displayName,});}else{notificationTitle=message.authorName;}} 10611const notificationContent=htmlToTextContentInline(message.previewText).substring(0,PREVIEW_MSG_MAX_SIZE);await this.sendNotification({message:notificationContent,sound:message.thread?.model==="discuss.channel",title:notificationTitle,type:"info",icon,});} 10612async hasServiceWorkInstalledAndPushSubscriptionActive(){const registration=await browser.navigator.serviceWorker?.getRegistration();if(registration){const pushManager=await registration.pushManager;if(pushManager){const subscription=await pushManager.getSubscription();return!!subscription;}} 10613return false;} 10614async sendNotification({message,sound=true,title,type,icon}){if(!this.canSendNativeNotification||!(await this.multiTab.isOnMainTab())){if(sound){this._playSound();} 10615return;} 10616try{this.sendNativeNotification(title,message,icon,{sound});}catch(error){if(error.message.includes("ServiceWorkerRegistration")){this.sendOdooNotification(message,{sound,title,type});}else{throw error;}}} 10617async sendOdooNotification(message,options){const{sound}=options;delete options.sound;this.closeFuncs.push(this.notificationService.add(message,options));if(this.closeFuncs.length>3){this.closeFuncs.shift()();} 10618if(sound){this._playSound();}} 10619sendNativeNotification(title,message,icon,{sound=true}={}){const notification=new Notification(title,{body:message,icon,});notification.addEventListener("click",({target:notification})=>{window.focus();
10619notification.close();});if(sound){this._playSound();}} 10620async _playSound(){if(isAndroid()&&browser.Notification?.permission==="granted"){return;} 10621if(this.canPlayAudio&&this.store.settings.messageSound&&(await this.multiTab.isOnMainTab())){this.soundEffectService.play("new-message");}} 10622get canPlayAudio(){return typeof Audio!=="undefined";} 10623get canSendNativeNotification(){return Boolean(window.Notification&&window.Notification.permission==="granted");}} 10624const outOfFocusService=__exports.outOfFocusService={dependencies:["multi_tab","notification","mail.sound_effects","mail.store"],start(env,services){const service=new OutOfFocusService(env,services);return service;},};registry.category("services").add("mail.out_of_focus",outOfFocusService);return __exports;});; 10625 10626/* /mail/static/src/core/common/partner_compare.js */ 10627odoo.define('@mail/core/common/partner_compare',['@mail/utils/common/format','@web/core/registry'],function(require){'use strict';let __exports={};const{cleanTerm}=require("@mail/utils/common/format");const{registry}=require("@web/core/registry");const partnerCompareRegistry=__exports.partnerCompareRegistry=registry.category("mail.partner_compare");partnerCompareRegistry.add("mail.archived-last-except-odoobot",(p1,p2)=>{const p1active=p1.active||p1.eq(p1.store.odoobot);const p2active=p2.active||p2.eq(p2.store.odoobot);if(!p1active&&p2active){return 1;} 10628if(!p2active&&p1active){return-1;}},{sequence:5});partnerCompareRegistry.add("mail.internal-users",(p1,p2)=>{const isAInternalUser=p1.main_user_id?.share===false;const isBInternalUser=p2.main_user_id?.share===false;if(isAInternalUser&&!isBInternalUser){return-1;} 10629if(!isAInternalUser&&isBInternalUser){return 1;}},{sequence:35});partnerCompareRegistry.add("mail.followers",(p1,p2,{thread})=>{if(thread){const followerList=[...thread.followers];if(thread.selfFollower){followerList.push(thread.selfFollower);} 10630const isFollower1=followerList.some((follower)=>p1.eq(follower.partner_id));const isFollower2=followerList.some((follower)=>p2.eq(follower.partner_id));if(isFollower1&&!isFollower2){return-1;} 10631if(!isFollower1&&isFollower2){return 1;}}},{sequence:25});partnerCompareRegistry.add("mail.name",(p1,p2,{searchTerm})=>{const cleanedName1=cleanTerm(p1.name);const cleanedName2=cleanTerm(p2.name);if(cleanedName1.startsWith(searchTerm)&&!cleanedName2.startsWith(searchTerm)){return-1;} 10632if(!cleanedName1.startsWith(searchTerm)&&cleanedName2.startsWith(searchTerm)){return 1;} 10633if(cleanedName1<cleanedName2){return-1;} 10634if(cleanedName1>cleanedName2){return 1;}},{sequence:50});partnerCompareRegistry.add("mail.email",(p1,p2,{searchTerm})=>{const cleanedEmail1=cleanTerm(p1.email);const cleanedEmail2=cleanTerm(p2.email);if(cleanedEmail1.startsWith(searchTerm)&&!cleanedEmail2.startsWith(searchTerm)){return-1;} 10635if(!cleanedEmail1.startsWith(searchTerm)&&cleanedEmail2.startsWith(searchTerm)){return 1;} 10636if(cleanedEmail1<cleanedEmail2){return-1;} 10637if(cleanedEmail1>cleanedEmail2){return 1;}},{sequence:55});partnerCompareRegistry.add("mail.id",(p1,p2)=>p1.id-p2.id,{sequence:75});return __exports;});; 10638 10639/* /mail/static/src/core/common/plugin/mail_composer_plugin.js */ 10640odoo.define('@mail/core/common/plugin/mail_composer_plugin',['@html_editor/plugin','@html_editor/utils/base_container','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@html_editor/utils/resource'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{baseContainerGlobalSelector}=require("@html_editor/utils/base_container");const{isEmptyBlock}=require("@html_editor/utils/dom_info");const{childNodes}=require("@html_editor/utils/dom_traversal");const{withSequence}=require("@html_editor/utils/resource");const ALLOWED_TAGS=["A","B","DIV","EM","I","LI","OL","P","S","SPAN","STRONG","U","UL",];const PRESERVED_CLASSNAMES=new Set(["o_mail_redirect","o_channel_redirect","o-discuss-mention"]);const MailComposerPlugin=__exports.MailComposerPlugin=class MailComposerPlugin extends Plugin{static id="mail_composer";static dependencies=["clipboard","dom","hint","history","input","selection"];resources={before_paste_handlers:this.config.composerPluginDependencies.onBeforePaste.bind(this),bypass_paste_image_files:()=>true,create_link_handlers:(linkEl)=>
10640(linkEl.target="_blank"),hints:[withSequence(1,{selector:`.odoo-editor-editable > ${baseContainerGlobalSelector}:only-child`,text:this.config.placeholder,}),],handle_paste_html_override:this.handlePasteHtmlOverride.bind(this),hint_targets_providers:(selectionData,editable)=>{const el=editable.firstChild;if(!selectionData.documentSelectionIsInEditable&&childNodes(editable).length===1&&isEmptyBlock(el)&&el.matches(baseContainerGlobalSelector)){return[el];}else{return[];}},input_handlers:this.config.composerPluginDependencies.onInput.bind(this),};setup(){this.addDomListener(this.editable,"keydown",this.config.composerPluginDependencies.onKeydown);this.addDomListener(this.editable,"focusin",this.config.composerPluginDependencies.onFocusin);this.addDomListener(this.editable,"focusout",this.config.composerPluginDependencies.onFocusout);} 10641handlePasteHtmlOverride(sanitizedFragment){if(sanitizedFragment.childNodes.length===0){return false;} 10642const removeStyle=(node)=>{if(node.nodeType===Node.ELEMENT_NODE){const tagName=node.nodeName.toUpperCase();if(tagName==="BR"){return;} 10643if(!ALLOWED_TAGS.includes(tagName)){node.replaceWith(document.createTextNode(node.textContent));return;} 10644node.removeAttribute("style");if(node.hasAttribute("class")){const preservedClasses=[...node.classList].filter((className)=>PRESERVED_CLASSNAMES.has(className));if(preservedClasses.length){node.className=preservedClasses.join(" ");}else{node.removeAttribute("class");}} 10645[...node.childNodes].forEach(removeStyle);}};[...sanitizedFragment.childNodes].forEach(removeStyle);this.dependencies.dom.insert(sanitizedFragment);this.dependencies.history.addStep();return true;}} 10646return __exports;});; 10647 10648/* /mail/static/src/core/common/plugin/mention_plugin.js */ 10649odoo.define('@mail/core/common/plugin/mention_plugin',['@html_editor/plugin','@html_editor/utils/dom_traversal','@mail/utils/common/format'],function(require){'use strict';let __exports={};const{Plugin}=require("@html_editor/plugin");const{closestElement}=require("@html_editor/utils/dom_traversal");const{generateThreadMentionElement}=require("@mail/utils/common/format");const MentionPlugin=__exports.MentionPlugin=class MentionPlugin extends Plugin{static id="mention";static dependencies=["baseContainer","selection","history"];resources={is_node_editable_predicates:(node)=>{for(const{selector}of this.MENTION_SELECTORS){if(closestElement(node,selector)){return true;}}},select_all_overrides:this.selectAll.bind(this),selectionchange_handlers:this.detectMentions.bind(this),selectors_for_feff_providers:()=>this.MENTION_SELECTORS.map(({selector})=>selector).join(", "),};setup(){super.setup();this.store=this.services["mail.store"];} 10650selectAll({anchorNode,anchorOffset,focusNode,focusOffset}){const SELECTOR=this.MENTION_SELECTORS.map(({selector})=>selector).join(", ");if(closestElement(anchorNode,SELECTOR)){const startMention=closestElement(anchorNode,SELECTOR);anchorNode=startMention.parentNode;anchorOffset=Array.prototype.indexOf.call(anchorNode.childNodes,startMention);} 10651if(closestElement(focusNode,SELECTOR)){const endMention=closestElement(focusNode,SELECTOR);focusNode=endMention.parentNode;focusOffset=Array.prototype.indexOf.call(focusNode.childNodes,endMention)+1;} 10652this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});} 10653get MENTION_SELECTORS(){return[{selector:"a.o_channel_redirect",checker:(el)=>this.isValidChannelMentionElement(el),validMentionsHandler:(channelLinks)=>{this.store.handleValidChannelMention(channelLinks);this.dependencies.history.addStep();},},{selector:"a.o_mail_redirect",checker:(el)=>true,},{selector:"a.o-discuss-mention",checker:(el)=>true,},];} 10654async detectMentions(ev){for(const{selector,checker,validMentionsHandler}of this.MENTION_SELECTORS){const mentionLinks=Array.from(this.editable.querySelectorAll(selector))||[];const validMentionLinks=(await Promise.all(mentionLinks.map(async(el)=>({el,isValid:await checker(el),})))).filter(({isValid})=>isValid).map(({el})=>el);this.prepareValidMentionLinks(validMentionLinks);validMentionsHandler?.(validMentionLinks);}} 10655prepareValidMentionLinks(validMentionLinks){for(const el of validMentionLinks){if(el.parentElement===this.editable){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(el.cloneNode(true));this.editable.replaceChild(baseContainer,el);this.dependencies.history.addStep();}}} 10656async isValidChannelMentionElement(el){if(el.dataset.oeModel!=="discuss.channel"){return false;} 10657const channel=await this.store.Thread.getOrFetch({model:"discuss.channel",id:Number(el.dataset.oeId),});if(!channel){return false;} 10658const validChannelMention=generateThreadMentionElement(channel);return(validChannelMention.getAttribute("href")===el.getAttribute("href")&&[...validChannelMention.classList].every((cls)=>el.classList.contains(cls)));}} 10659return __exports;});; 10660 10661/* /mail/static/src/core/common/plugin/plugin_sets.js */ 10662odoo.define('@mail/core/common/plugin/plugin_sets',['@html_editor/main/chatgpt/chatgpt_translate_plugin','@html_editor/main/font/color_plugin','@html_editor/plugin_sets','@html_editor/main/feff_plugin','@html_editor/main/hint_plugin','@html_editor/main/inline_code','@html_editor/main/link/link_paste_plugin','@html_editor/main/link/link_plugin','@html_editor/core/shortcut_plugin','@html_editor/main/tabulation_plugin','@html_editor/main/toolbar/toolbar_plugin','@mail/core/common/plugin/mail_composer_plugin','@mail/core/common/plugin/mention_plugin','@html_editor/core/protected_node_plugin'],function(require){'use strict';let __exports={};const{ChatGPTTranslatePlugin}=require("@html_editor/main/chatgpt/chatgpt_translate_plugin");const{ColorPlugin}=require("@html_editor/main/font/color_plugin");const{CORE_PLUGINS}=require("@html_editor/plugin_sets");const{FeffPlugin}=require("@html_editor/main/feff_plugin");const{HintPlugin}=require("@html_editor/main/hint_plugin");const{InlineCodePlugin}=require("@html_editor/main/inline_code");const{LinkPastePlugin}=require("@html_editor/main/link/link_paste_plugin");const{LinkPlugin}=require("@html_editor/main/link/link_plugin");const{ShortCutPlugin}=require("@html_editor/core/shortcut_plugin");const{TabulationPlugin}=require("@html_editor/main/tabulation_plugin");const{ToolbarPlugin}=require("@html_editor/main/toolbar/toolbar_plugin");const{MailComposerPlugin}=require("@mail/core/common/plugin/mail_composer_plugin");const{MentionPlugin}=require("@mail/core/common/plugin/mention_plugin");const{ProtectedNodePlugin}=require("@html_editor/core/protected_node_plugin");const MAIL_CORE_PLUGINS=__exports.MAIL_CORE_PLUGINS=[...CORE_PLUGINS,ChatGPTTranslatePlugin,ColorPlugin,FeffPlugin,HintPlugin,InlineCodePlugin,LinkPastePlugin,LinkPlugin,MailComposerPlugin,MentionPlugin,ProtectedNodePlugin,ShortCutPlugin,TabulationPlugin,];const MAIL_PLUGINS=__exports.MAIL_PLUGINS=[...MAIL_CORE_PLUGINS,ToolbarPlugin];
10662const MAIL_SMALL_UI_PLUGINS=__exports.MAIL_SMALL_UI_PLUGINS=MAIL_CORE_PLUGINS;return __exports;});; 10663 10664/* /mail/static/src/core/common/quick_reaction_menu.js */ 10665odoo.define('@mail/core/common/quick_reaction_menu',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_hooks','@web/core/emoji_picker/emoji_picker','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useExternalListener,useRef,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{loadEmoji,useEmojiPicker}=require("@web/core/emoji_picker/emoji_picker");const{useService}=require("@web/core/utils/hooks");const QuickReactionMenu=__exports.QuickReactionMenu=class QuickReactionMenu extends Component{static template="mail.QuickReactionMenu";static props={action:Object,classNames:{type:Object,optional:true},message:Object,messageActive:{type:Boolean,optional:true},};static components={Dropdown};static DEFAULT_EMOJIS=["ð","â¤ï¸","ð¤£","ð¯","ð ","ð"];setup(){this.toggle=useRef("toggle");this.store=useService("mail.store");this.ui=useService("ui");this.picker=useEmojiPicker(null,{onSelect:this.toggleReaction.bind(this),class:"overflow-hidden rounded-2"},{position:"bottom-middle",popoverClass:"o-mail-QuickReactionMenu-pickerPopover",});this.dropdown=useState(useDropdownState({onClose:()=>{const currentThread=this.env.getCurrentThread?.();if(!currentThread||currentThread.notEq(this.props.message.thread)){return;} 10666if(currentThread.messageInEdition){currentThread.messageInEdition.composer.autofocus++;}else{currentThread.composer.autofocus++;}},}));this.frequentEmojiService=useService("web.frequent.emoji");useExternalListener(window,"keydown",async(ev)=>{if(!this.dropdown.isOpen||this.picker.isOpen||!this.toggle.el?.contains(ev.target)||["Shift","Control","Meta","Alt"].includes(ev.key)){return;} 10667this.togglePicker(ev.key);});} 10668togglePicker(initialSearchTerm){if(this.picker.isOpen){this.picker.close();}else{this.picker.open(this.toggle,{initialSearchTerm});}} 10669getEmojiShortcode(emoji){return this.store.emojiLoader.loaded?.emojiValueToShortcodes?.[emoji]?.[0]??"?";} 10670onClick(){if(!this.store.emojiLoader.isLoaded){loadEmoji();} 10671if(this.ui.isSmall){this.props.action.onSelected();}else{this.picker.close();if(this.dropdown.isOpen){this.dropdown.close();}else{this.dropdown.open();}}} 10672toggleReaction(emoji,resetOnSelect=true){const reaction=this.props.message.reactions.find((r)=>r.content===emoji&&this.props.message.effectiveSelf.in(r.personas));if(reaction){reaction.remove();}else{this.props.message.react(emoji);this.frequentEmojiService.incrementEmojiUsage(emoji);} 10673if(resetOnSelect){this.dropdown.close();this.picker.close();}} 10674get attClass(){const invisible=typeof this.props.messageActive==="boolean"&&!this.props.messageActive&&!this.dropdown.isOpen&&!this.picker.isOpen;return{...this.props.classNames,"o-open":this.dropdown.isOpen,invisible,visible:!invisible,};} 10675reactedBySelf(emoji){return this.props.message.reactions.some((r)=>r.content===emoji&&this.props.message.effectiveSelf.in(r.personas));} 10676get mostFrequentEmojis(){const numberOfEmojis=6;const mostFrequent=this.frequentEmojiService.getMostFrequent(numberOfEmojis);return mostFrequent.concat(QuickReactionMenu.DEFAULT_EMOJIS.filter((emoji)=>!mostFrequent.includes(emoji)).slice(0,Math.max(0,numberOfEmojis-mostFrequent.length)));} 10677get navigationOptions(){return{onUpdated:(navigator)=>{if(!navigator.activeItem){navigator.items[0]?.setActive();}},hotkeys:{arrowright:(navigator)=>navigator.next(),arrowleft:(navigator)=>navigator.previous(),arrowdown:null,arrowup:null,},};}} 10678return __exports;});; 10679 10680/* /mail/static/src/core/common/record.js */ 10681odoo.define('@mail/core/common/record',['@mail/model/export'],function(require){'use strict';let __exports={};Object.assign(__exports,require("@mail/model/export"));return __exports;});; 10682 10683/* /mail/static/src/core/common/relative_time.js */ 10684odoo.define('@mail/core/common/relative_time',['@odoo/owl','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,onWillUpdateProps,xml}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const MINUTE=60*1000;const HOUR=60*MINUTE;const RelativeTime=__exports.RelativeTime=class RelativeTime extends Component{static props=["datetime"];static template=xml`<t t-esc="relativeTime"/>`;setup(){super.setup();this.timeout=null;this.computeRelativeTime(this.props.datetime);onWillDestroy(()=>clearTimeout(this.timeout));onWillUpdateProps((nextProps)=>{clearTimeout(this.timeout);this.computeRelativeTime(nextProps.datetime);});} 10685computeRelativeTime(datetime){if(!datetime){this.relativeTime="";return;} 10686const delta=Date.now()-datetime.ts;const absDelta=Math.abs(delta);if(absDelta<45*1000){this.relativeTime=delta<0?_t("in a few seconds"):_t("now");}else{this.relativeTime=datetime.toRelative();} 10687const updateDelay=absDelta<MINUTE?absDelta:absDelta<HOUR?MINUTE:HOUR;this.timeout=setTimeout(()=>{this.computeRelativeTime(this.props.datetime);this.render();},updateDelay);}} 10688return __exports;});; 10689 10690/* /mail/static/src/core/common/res_company_model.js */ 10691odoo.define('@mail/core/common/res_company_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const ResCompany=__exports.ResCompany=class ResCompany extends Record{static _name="res.company";static id="id";id;name;} 10692ResCompany.register();return __exports;});; 10693 10694/* /mail/static/src/core/common/res_groups_model.js */ 10695odoo.define('@mail/core/common/res_groups_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const ResGroups=__exports.ResGroups=class ResGroups extends Record{static _name="res.groups";static id="id";full_name;partners=fields.Many("res.partner",{inverse:"group_ids"});privilege_id=fields.One("res.groups.privilege");} 10696ResGroups.register();return __exports;});; 10697 10698/* /mail/static/src/core/common/res_groups_privilege_model.js */ 10699odoo.define('@mail/core/common/res_groups_privilege_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const ResGroupsPrivilege=__exports.ResGroupsPrivilege=class ResGroupsPrivilege extends Record{static _name="res.groups.privilege";} 10700ResGroupsPrivilege.register();return __exports;});; 10701 10702/* /mail/static/src/core/common/res_lang_model.js */ 10703odoo.define('@mail/core/common/res_lang_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const ResLang=__exports.ResLang=class ResLang extends Record{static id="id";static _name="res.lang";id;
10703name;} 10704ResLang.register();return __exports;});; 10705 10706/* /mail/static/src/core/common/res_partner_model.js */ 10707odoo.define('@mail/core/common/res_partner_model',['@mail/core/common/store_service','@mail/core/common/record','@web/core/utils/urls','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Store}=require("@mail/core/common/store_service");const{fields,Record}=require("@mail/core/common/record");const{imageUrl}=require("@web/core/utils/urls");const{debounce}=require("@web/core/utils/timing");const{DateTime}=luxon;const ResPartner=__exports.ResPartner=class ResPartner extends Record{static id="id";static _name="res.partner";static new(){const record=super.new(...arguments);record.debouncedSetImStatus=debounce((newStatus)=>record.updateImStatus(newStatus),Store.IM_STATUS_DEBOUNCE_DELAY);return record;} 10708_triggerPresenceSubscription=fields.Attr(null,{compute(){return this.monitorPresence&&this.presenceChannel;},onUpdate(){if(this.previousPresencechannel){this.store.env.services.bus_service.deleteChannel(this.previousPresencechannel);} 10709if(this._triggerPresenceSubscription){this.store.env.services.bus_service.addChannel(this.presenceChannel);} 10710this.previousPresencechannel=this.presenceChannel;},eager:true,});avatar_128_access_token;commercial_company_name;country_id=fields.One("res.country");debouncedSetImStatus;email;function;group_ids=fields.Many("res.groups",{inverse:"partners"});id;im_status=fields.Attr(null,{onUpdate(){if(this.eq(this.store.self_partner)&&this.im_status==="offline"){this.store.env.services.im_status.updateBusPresence();}},});im_status_access_token;is_company;is_public;main_user_id=fields.One("res.users");monitorPresence=fields.Attr(false,{compute(){if(!this.store.env.services.bus_service.isActive||this.id<=0){return false;} 10711return this.im_status!=="im_partner"&&!this.is_public;},});name;display_name;phone;offline_since=fields.Datetime();presenceChannel=fields.Attr(null,{compute(){const channel=`odoo-presence-res.partner_${this.id}`;if(this.im_status_access_token){return channel+`-${this.im_status_access_token}`;} 10712return channel;},});previousPresencechannel;write_date=fields.Datetime();_computeDisplayName(){return this.name||this.display_name;} 10713get avatarUrl(){const accessTokenParam={};if(this.store.self.main_user_id?.share!==false){accessTokenParam.access_token=this.avatar_128_access_token;} 10714return imageUrl("res.partner",this.id,"avatar_128",{...accessTokenParam,unique:this.write_date,});} 10715get displayName(){return this._computeDisplayName();} 10716searchChat(){return Object.values(this.store.Thread.records).find((thread)=>thread.channel_type==="chat"&&thread.correspondent?.persona.eq(this));} 10717updateImStatus(newStatus){if(newStatus==="offline"){this.offline_since=DateTime.now();} 10718this.im_status=newStatus;}} 10719ResPartner.register();return __exports;});; 10720 10721/* /mail/static/src/core/common/res_role_model.js */ 10722odoo.define('@mail/core/common/res_role_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const ResRole=__exports.ResRole=class ResRole extends Record{static id="id";static _name="res.role";id;name;} 10723ResRole.register();return __exports;});; 10724 10725/* /mail/static/src/core/common/res_users_model.js */ 10726odoo.define('@mail/core/common/res_users_model',['@odoo/owl','@web/core/utils/html','@mail/core/common/record'],function(require){'use strict';let __exports={};const{markup}=require("@odoo/owl");const{createElementWithContent}=require("@web/core/utils/html");const{fields,Record}=require("@mail/core/common/record");const ResUsers=__exports.ResUsers=class ResUsers extends Record{static _name="res.users";static id="id";id;company_id=fields.One("res.company");get email(){return this.partner_id?.email;} 10727im_status;is_admin;get name(){return this.partner_id?.name;} 10728notification_type;partner_id=fields.One("res.partner");get phone(){return this.partner_id?.phone;} 10729share;signature=fields.Html(undefined);getSignatureBlock(){if(!this.signature){return"";} 10730const divElement=document.createElement("div");divElement.setAttribute("data-o-mail-quote","1");divElement.append(document.createTextNode("-- "),document.createElement("br"),...createElementWithContent("div",this.signature).childNodes);return markup(divElement.outerHTML);}} 10731ResUsers.register();return __exports;});; 10732 10733/* /mail/static/src/core/common/search_message_input.js */ 10734odoo.define('@mail/core/common/search_message_input',['@odoo/owl','@web/core/browser/browser','@web/core/utils/hooks','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component,useExternalListener,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{useAutofocus}=require("@web/core/utils/hooks");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const SearchMessageInput=__exports.SearchMessageInput=class SearchMessageInput extends Component{static template="mail.SearchMessageInput";static props=["closeSearch?","messageSearch","thread"];static components={Dropdown,DropdownItem};setup(){super.setup();this.state=useState({searchTerm:"",searchedTerm:""});useAutofocus();useExternalListener(browser,"keydown",(ev)=>{if(ev.key==="Escape"){this.props.closeSearch?.();}},{capture:true});} 10735search(){this.props.messageSearch.searchTerm=this.state.searchTerm;this.props.messageSearch.search();this.state.searchedTerm=this.state.searchTerm;} 10736clear(){this.state.searchTerm="";this.state.searchedTerm=this.state.searchTerm;this.props.messageSearch.clear();this.props.closeSearch?.();} 10737onKeydownSearch(ev){if(ev.key!=="Enter"){return;} 10738if(!this.state.searchTerm){this.clear();}else{this.search();}} 10739onChangeSearchFilter(searchFilter){if(searchFilter.is_notification!==this.props.messageSearch.is_notification){this.props.messageSearch.is_notification=searchFilter.is_notification;this.search();}} 10740get searchFilters(){return[{label:"all",name:_t("All"),is_notification:undefined,},{label:"conversations",name:_t("Conversations"),is_notification:false,},{label:"tracked_changes",name:_t("Tracked Changes"),is_notification:true,},];}} 10741return __exports;});; 10742 10743/* /mail/static/src/core/common/search_message_result.js */ 10744odoo.define('@mail/core/common/search_message_result',['@odoo/owl','@mail/core/common/message_card_list','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{MessageCardList}=require("@mail/core/common/message_card_list");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const SearchMessageResult=__exports.SearchMessageResult=class SearchMessageResult extends Component{static template="mail.SearchMessageResult";static components={MessageCardList};static props=["thread","messageSearch","onClickJump?"];get MESSAGE_FOUND(){if(this.props.messageSearch.messages.length===0){return false;} 10745return _t("%s messages found",this.props.messageSearch.count);} 10746onLoadMoreVisible(){const before=this.props.messageSearch?.messages?Math.min(...this.props.messageSearch.messages.map((message)=>message.id)):false;this.props.messageSearch.search(before);}} 10747return __exports;});; 10748 10749/* /mail/static/src/core/common/search_messages_panel.js */ 10750odoo.define('@mail/core/common/search_messages_panel',['@odoo/owl','@mail/discuss/core/common/action_panel','@web/core/l10n/translation','@web/core/utils/hooks','@mail/core/common/search_message_input','@mail/core/common/search_message_result','@mail/core/common/message_search_hook'],function(require){'use strict';let __exports={};const{Component,onWillUpdateProps}=require("@odoo/owl");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{SearchMessageInput}=require("@mail/core/common/search_message_input");const{SearchMessageResult}=require("@mail/core/common/search_message_result");const{useMessageSearch}=require("@mail/core/common/message_search_hook");const SearchMessagesPanel=__exports.SearchMessagesPanel=class SearchMessagesPanel extends Component{static template="mail.SearchMessagesPanel";static components={ActionPanel,SearchMessageInput,SearchMessageResult};static props=["thread"];setup(){super.setup();this.store=useService("mail.store");this.messageSearch=this.env.messageSearch??useMessageSearch(this.props.thread);onWillUpdateProps((nextProps)=>
10750{if(this.props.thread.notEq(nextProps.thread)){this.env.searchMenu?.close();}});} 10751get title(){return _t("Search Message");}} 10752return __exports;});; 10753 10754/* /mail/static/src/core/common/settings_model.js */ 10755odoo.define('@mail/core/common/settings_model',['@mail/utils/common/misc','@web/core/l10n/translation','@web/core/browser/browser','@mail/core/common/record','@web/core/utils/timing','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{hasHardwareAcceleration}=require("@mail/utils/common/misc");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{browser}=require("@web/core/browser/browser");const{fields,Record}=require("@mail/core/common/record");const{debounce}=require("@web/core/utils/timing");const{rpc}=require("@web/core/network/rpc");const MESSAGE_SOUND=__exports.MESSAGE_SOUND="mail.user_setting.message_sound";const USE_BLUR_LS=__exports.USE_BLUR_LS="mail_user_setting_use_blur";const Settings=__exports.Settings=class Settings extends Record{id;static new(){const record=super.new(...arguments);record.onStorage=record.onStorage.bind(record);browser.addEventListener("storage",record.onStorage);return record;} 10756setup(){super.setup();this.saveVoiceThresholdDebounce=debounce(()=>{browser.localStorage.setItem("mail_user_setting_voice_threshold",this.voiceActivationThreshold.toString());},2000);this.hasCanvasFilterSupport=typeof document.createElement("canvas").getContext("2d").filter!=="undefined";this._loadLocalSettings();} 10757delete(){browser.removeEventListener("storage",this.onStorage);super.delete(...arguments);} 10758channel_notifications=fields.Attr("mentions",{compute(){return this.channel_notifications===false?"mentions":this.channel_notifications;},});_recomputeMessageSound=0;messageSound=fields.Attr(true,{compute(){void this._recomputeMessageSound;return browser.localStorage.getItem(MESSAGE_SOUND)!=="false";},});useCallAutoFocus=fields.Attr(true,{compute(){return!browser.localStorage.getItem("mail_user_setting_disable_call_auto_focus");},onUpdate(){if(this.useCallAutoFocus){browser.localStorage.removeItem("mail_user_setting_disable_call_auto_focus");return;} 10759browser.localStorage.setItem("mail_user_setting_disable_call_auto_focus","true");},});audioInputDeviceId="";audioOutputDeviceId="";cameraInputDeviceId="";use_push_to_talk=false;voice_active_duration=200;volumes=fields.Many("Volume");volumeSettingsTimeouts=new Map();voiceActivationThreshold=0.05;isRegisteringKey=false;push_to_talk_key;backgroundBlurAmount=10;edgeBlurAmount=10;showOnlyVideo=false;_recomputeUseBlur=0;useBlur=fields.Attr(false,{compute(){void this._recomputeUseBlur;return browser.localStorage.getItem(USE_BLUR_LS)==="true";},});blurPerformanceWarning=fields.Attr(false,{compute(){const rtc=this.store.rtc;if(!rtc||!this.useBlur){return false;} 10760return this.useBlur&&rtc.state?.cameraTrack&&!hasHardwareAcceleration();},});cameraFacingMode=undefined;logRtc=false;get audioConstraints(){const constraints={echoCancellation:true,noiseSuppression:true,};if(this.audioInputDeviceId){constraints.deviceId=this.audioInputDeviceId;} 10761return constraints;} 10762get cameraConstraints(){const constraints={width:1280,};if(this.cameraFacingMode){constraints.facingMode=this.cameraFacingMode;}else if(this.cameraInputDeviceId){constraints.deviceId=this.cameraInputDeviceId;} 10763return constraints;} 10764get NOTIFICATIONS(){return[{label:"all",name:_t("All Messages"),},{label:"mentions",name:_t("Mentions Only"),},{label:"no_notif",name:_t("Nothing"),},];} 10765get MUTES(){return[{label:"15_mins",value:15,name:_t("For 15 minutes"),},{label:"1_hour",value:60,name:_t("For 1 hour"),},{label:"3_hours",value:180,name:_t("For 3 hours"),},{label:"8_hours",value:480,name:_t("For 8 hours"),},{label:"24_hours",value:1440,name:_t("For 24 hours"),},{label:"forever",value:-1,name:_t("Until I turn it back on"),},];} 10766setUseBlur(newValue){if(newValue){browser.localStorage.setItem(USE_BLUR_LS,true);}else{browser.localStorage.removeItem(USE_BLUR_LS);} 10767this._recomputeUseBlur++;} 10768getMuteUntilText(dt){if(dt){return dt.year<=luxon.DateTime.now().year+2?_t(`Until %s`,dt.toLocaleStr
10768ing(luxon.DateTime.DATETIME_MED)):_t("Until I turn it back on");} 10769return undefined;} 10770async setCustomNotifications(custom_notifications,thread=undefined){return rpc("/discuss/settings/custom_notifications",{custom_notifications:!thread&&custom_notifications==="mentions"?false:custom_notifications,channel_id:thread?.id,});} 10771async setMuteDuration(minutes,thread=undefined){return rpc("/discuss/settings/mute",{minutes,channel_id:thread?.id,});} 10772async setAudioInputDevice(audioInputDeviceId){this.audioInputDeviceId=audioInputDeviceId;browser.localStorage.setItem("mail_user_setting_audio_input_device_id",audioInputDeviceId);} 10773async setAudioOutputDevice(audioOutputDeviceId){this.audioOutputDeviceId=audioOutputDeviceId;browser.localStorage.setItem("mail_user_setting_audio_output_device_id",audioOutputDeviceId);} 10774async setCameraInputDevice(cameraInputDeviceId){this.cameraFacingMode=undefined;this.cameraInputDeviceId=cameraInputDeviceId;browser.localStorage.setItem("mail_user_setting_camera_input_device_id",cameraInputDeviceId);} 10775setDelayValue(value){this.voice_active_duration=parseInt(value,10);this._saveSettings();} 10776async setPushToTalkKey(ev){const nonElligibleKeys=new Set(["Shift","Control","Alt","Meta"]);let pushToTalkKey=`${ev.shiftKey || ""}.${ev.ctrlKey || ev.metaKey || ""}.${ 10777 ev.altKey || "" 10778 }`;if(!nonElligibleKeys.has(ev.key)){pushToTalkKey+=`.${ev.key === " " ? "Space" : ev.key}`;} 10779this.push_to_talk_key=pushToTalkKey;this._saveSettings();} 10780async saveVolumeSetting({partnerId,guestId,volume}){if(!this.store.self_partner){return;} 10781const key=`${partnerId}_${guestId}`;if(this.volumeSettingsTimeouts.get(key)){browser.clearTimeout(this.volumeSettingsTimeouts.get(key));} 10782this.volumeSettingsTimeouts.set(key,browser.setTimeout(this._onSaveVolumeSettingTimeout.bind(this,{key,partnerId,guestId,volume}),5000));} 10783setThresholdValue(voiceActivationThreshold){this.voiceActivationThreshold=voiceActivationThreshold;this.saveVoiceThresholdDebounce();} 10784buildKeySet({shiftKey,ctrlKey,altKey,key}){const keys=new Set();if(key){keys.add(key==="Meta"?"Alt":key);} 10785if(shiftKey){keys.add("Shift");} 10786if(ctrlKey){keys.add("Control");} 10787if(altKey){keys.add("Alt");} 10788return keys;} 10789isPushToTalkKey(ev){if(!this.use_push_to_talk||!this.push_to_talk_key){return false;} 10790const[shiftKey,ctrlKey,altKey,key]=this.push_to_talk_key.split(".");const settingsKeySet=this.buildKeySet({shiftKey,ctrlKey,altKey,key});const eventKeySet=this.buildKeySet({shiftKey:ev.shiftKey,ctrlKey:ev.ctrlKey,altKey:ev.altKey,key:ev.key,});if(ev.type==="keydown"){return[...settingsKeySet].every((key)=>eventKeySet.has(key));} 10791return settingsKeySet.has(ev.key==="Meta"?"Alt":ev.key);} 10792pushToTalkKeyFormat(){if(!this.push_to_talk_key){return;} 10793const[shiftKey,ctrlKey,altKey,key]=this.push_to_talk_key.split(".");return{shiftKey:!!shiftKey,ctrlKey:!!ctrlKey,altKey:!!altKey,key:key||false,};} 10794setPushToTalk(value){this.use_push_to_talk=value;this._saveSettings();} 10795_loadLocalSettings(){const voiceActivationThresholdString=browser.localStorage.getItem("mail_user_setting_voice_threshold");this.voiceActivationThreshold=voiceActivationThresholdString?parseFloat(voiceActivationThresholdString):this.voiceActivationThreshold;this.audioInputDeviceId=browser.localStorage.getItem("mail_user_setting_audio_input_device_id");this.audioOutputDeviceId=browser.localStorage.getItem("mail_user_setting_audio_output_device_id");this.cameraInputDeviceId=browser.localStorage.getItem("mail_user_setting_camera_input_device_id");this.showOnlyVideo=browser.localStorage.getItem("mail_user_setting_show_only_video")==="true";const backgroundBlurAmount=browser.localStorage.getItem("mail_user_setting_background_blur_amount");this.backgroundBlurAmount=backgroundBlurAmount?parseInt(backgroundBlurAmount):10;const edgeBlurAmount=browser.localStorage.getItem("mail_user_setting_edge_blur_amount");this.edgeBlurAmount=edgeBlurAmount?parseInt(edgeBlurAmount):10;this.useCallAutoFocus=!browser.localStorage.getItem("mail_user_setting_disable_call_auto_focus");} 10796async _onSaveGlobalSettingsTimeout(){this.globalSettingsTimeout=undefined;await this.store.env.services.orm.call("res.users.settings","set_res_users_settings",[[this.id]],{new_settings:{push_to_talk_key:this.push_to_talk_key,use_push_to_talk:this.use_push_to_talk,voice_active_duration:this.voice_active_duration,},});} 10797async _onSaveVolumeSettingTimeout({key,partnerId,guestId,volume}){this.volumeSettingsTimeouts.delete(key);await this.store.env.services.orm.call("res.users.settings","set_volume_setting",[[this.id],partnerId,volume],{guest_id:guestId});} 10798onStorage(ev){if(ev.key===MESSAGE_SOUND){this._recomputeMessageSound++;} 10799if(ev.key===USE_BLUR_LS){this._recomputeUseBlur++;} 10800if(ev.key==="mail_user_setting_audio_input_device_id"){this.audioInputDeviceId=ev.newValue;} 10801if(ev.key==="mail_user_setting_audio_output_device_id"){this.audioOutputDeviceId=ev.newValue;} 10802if(ev.key==="mail_user_setting_camera_input_device_id"){this.cameraInputDeviceId=ev.newValue;}} 10803async _saveSettings(){if(!this.store.self_partner){return;} 10804browser.clearTimeout(this.globalSettingsTimeout);this.globalSettingsTimeout=browser.setTimeout(()=>this._onSaveGlobalSettingsTimeout(),2000);}} 10805Settings.register();return __exports;});; 10806 10807/* /mail/static/src/core/common/sound_effects_service.js */ 10808odoo.define('@mail/core/common/sound_effects_service',['@web/core/browser/browser','@web/core/registry','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{url}=require("@web/core/utils/urls");const SoundEffects=__exports.SoundEffects=class SoundEffects{constructor(env){this.soundEffects={"call-join":{defaultVolume:0.75,path:"/mail/static/src/audio/call-join"},"call-leave":{defaultVolume:0.75,path:"/mail/static/src/audio/call-leave"},"earphone-off":{defaultVolume:0.15,path:"/mail/static/src/audio/earphone-off"},"earphone-on":{defaultVolume:0.15,path:"/mail/static/src/audio/earphone-on"},"mic-off":{defaultVolume:0.2,path:"/mail/static/src/audio/mic-off"},"mic-on":{defaultVolume:0.2,path:"/mail/static/src/audio/mic-on"},"ptt-press":{defaultVolume:0.1,path:"/mail/static/src/audio/ptt-press"},"ptt-release":{defaultVolume:0.1,path:"/mail/static/src/audio/ptt-release"},"call-invitation":{defaultVolume:0.5,path:"/mail/static/src/audio/call-invitation",},"new-message":{defaultVolume:1,path:"/mail/static/src/audio/new-message"},"screen-sharing":{defaultVolume:0.75,path:"/mail/static/src/audio/screen-sharing",},"member-leave":{defaultVolume:0.5,path:"/mail/static/src/audio/c
10808hannel_01_out"},};} 10809play(soundEffectName,{loop=false,volume}={}){if(typeof browser.Audio==="undefined"){return;} 10810const soundEffect=this.soundEffects[soundEffectName];if(!soundEffect){return;} 10811if(!soundEffect.audio){const audio=new browser.Audio();const ext=audio.canPlayType("audio/ogg; codecs=vorbis")?".ogg":".mp3";audio.src=url(soundEffect.path+ext);soundEffect.audio=audio;} 10812if(!soundEffect.audio.paused){soundEffect.audio.pause();} 10813soundEffect.audio.currentTime=0;soundEffect.audio.loop=loop;soundEffect.audio.volume=volume??soundEffect.defaultVolume??1;Promise.resolve(soundEffect.audio.play()).catch(()=>{});} 10814stop(soundEffectName){const soundEffect=this.soundEffects[soundEffectName];if(soundEffect){if(soundEffect.audio){soundEffect.audio.pause();soundEffect.audio.currentTime=0;}}else{for(const soundEffect of Object.values(this.soundEffects)){if(soundEffect.audio){soundEffect.audio.pause();soundEffect.audio.currentTime=0;}}}}} 10815const soundEffects=__exports.soundEffects={start(env){return new SoundEffects(env);},};registry.category("services").add("mail.sound_effects",soundEffects);return __exports;});; 10816 10817/* /mail/static/src/core/common/store_service.js */ 10818odoo.define('@mail/core/common/store_service',['@mail/core/common/record','@mail/core/common/thread_compare','@mail/utils/common/format','@mail/utils/common/misc','@odoo/owl','@web/core/l10n/translation','@web/core/network/rpc','@web/core/registry','@web/core/user','@web/core/utils/concurrency','@web/core/utils/render','@web/core/utils/timing','@web/session','@web/core/browser/browser','@web/core/emoji_picker/emoji_picker','@web/core/utils/patch','@web/core/browser/feature_detection','@web/core/utils/urls','@web/core/browser/cookie','@web/core/utils/html'],function(require){'use strict';let __exports={};const{Store:BaseStore,fields,makeStore,storeInsertFns}=require("@mail/core/common/record");const{threadCompareRegistry}=require("@mail/core/common/thread_compare");const{attClassObjectToString,cleanTerm,generateEmojisOnHtml,prettifyMessageText,}=require("@mail/utils/common/format");const{compareDatetime}=require("@mail/utils/common/misc");const{reactive}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const{user}=require("@web/core/user");const{Deferred,Mutex}=require("@web/core/utils/concurrency");const{renderToElement}=require("@web/core/utils/render");const{debounce}=require("@web/core/utils/timing");const{session}=require("@web/session");const{browser}=require("@web/core/browser/browser");const{loader}=require("@web/core/emoji_picker/emoji_picker");const{patch}=require("@web/core/utils/patch");const{isMobileOS}=require("@web/core/browser/feature_detection");const{getOrigin}=require("@web/core/utils/urls");const{cookie}=require("@web/core/browser/cookie");const{isMarkup,createDocumentFragmentFromContent}=require("@web/core/utils/html");let prevLastMessageId=null;let temporaryIdOffset=0.01;const pyToJsModels=__exports.pyToJsModels={"discuss.channel":"Thread","mail.thread":"Thread",};const addFieldsByPyModel=__exports.addFieldsByPyModel={"discuss.channel":{model:"discuss.channel"},};patch(storeInsertFns,{makeContext(store){if(!(store instanceof Store)){return super.makeContext(...arguments);} 10819return{pyModels:Object.values(pyToJsModels)};},getActualModelName(store,ctx,pyOrJsModelName){if(!(store instanceof Store)){return super.getActualModelName(...arguments);} 10820if(ctx.pyModels.includes(pyOrJsModelName)){console.warn(`store.insert() should receive the python model name instead of â${pyOrJsModelName}â.`);} 10821return pyToJsModels[pyOrJsModelName]||pyOrJsModelName;},getExtraFieldsFromModel(store,pyOrJsModelName){if(!(store instanceof Store)){return super.getExtraFieldsFromModel(...arguments);} 10822return addFieldsByPyModel[pyOrJsModelName];},});const Store=__exports.Store=class Store extends BaseStore{static FETCH_DATA_DEBOUNCE_DELAY=1;static OTHER_LONG_TYPING=60000;static IM_STATUS_DEBOUNCE_DELAY=1000;FETCH_LIMIT=30;DEFAULT_AVATAR="/mail/static/src/img/smiley/avatar.jpg";isReady=new Deferred();self_partner=fields.One("res.partner");self_guest=fields.One("mail.guest");get self(){return this.self_partner||this.self_guest;} 10823allChannels=fields.Many("Thread",{inverse:"storeAsAllChannels",onUpdate(){const busService=this.store.env.services.bus_service;if(!busService.isActive&&this.allChannels.some((t)=>!t.isTransient)){busService.start();}},});inPublicPage=false;odoobot=fields.One("res.partner");useMobileView=fields.Attr(undefined,{compute(){return this.store.env.services.ui.isSmall||isMobileOS();},});users={};internalUserGroupId;mt_comment=fields.One("mail.message.subtype");mt_note=fields.One("mail.message.subtype");hasMessageTranslationFeature;hasLinkPreviewFeature=true;menu={counter:0};chatHub=fields.One("ChatHub",{compute:()=>({})});failures=fields.Many("Failure",{sort:(f1,f2)=>
10823f2.lastMessage?.id-f1.lastMessage?.id,});settings=fields.One("Settings");emojiLoader=loader;fetchParams=[];fetchReadonly=true;fetchSilent=true;cannedReponses=this.makeCachedFetchData("mail.canned.response");specialMentions=[{isSpecial:true,label:"everyone",channel_types:["channel","group"],displayName:"Everyone",description:_t("Notify everyone"),},];isNotificationPermissionDismissed=fields.Attr(false,{compute(){return(browser.localStorage.getItem("mail.user_setting.push_notification_dismissed")==="true");},onUpdate(){if(this.isNotificationPermissionDismissed){browser.localStorage.setItem("mail.user_setting.push_notification_dismissed","true");}else{browser.localStorage.removeItem("mail.user_setting.push_notification_dismissed");}},});messagePostMutex=new Mutex();menuThreads=fields.Many("Thread",{compute(){const searchTerm=cleanTerm(this.discuss.searchTerm);let threads=Object.values(this.Thread.records).filter((thread)=>(thread.displayToSelf||(thread.needactionMessages.length>0&&thread.model!=="mail.box"))&&cleanTerm(thread.displayName).includes(searchTerm));const tab=this.discuss.activeTab;if(tab==="inbox"){threads=threads.filter(({channel_type})=>this.tabToThreadType("mailbox").includes(channel_type));}else if(tab==="starred"){threads=[this.starred];}else if(tab!=="notification"){threads=threads.filter(({channel_type})=>this.tabToThreadType(tab).includes(channel_type));} 10824return threads;},sort(thread1,thread2){const compareFunctions=threadCompareRegistry.getAll();for(const fn of compareFunctions){const result=fn(thread1,thread2);if(result!==undefined){return result;}} 10825return thread2.localId>thread1.localId?1:-1;},});shouldSimulateDarkTheme(ctx){return((ctx?.env?.inDiscussCallView||ctx?.env?.inCallInvitation||ctx?.env.isDiscussPipBanner||ctx?.env?.inWelcomePage)&&this.isOdooWhiteTheme&&!ctx?.env.inMeetingSideActions&&!ctx?.env.inDiscussActionPanel);} 10826discussDropdownMenuClass(ctx){const simulateDarkTheme=this.shouldSimulateDarkTheme(ctx);return attClassObjectToString({"o-discuss-dropdownMenu d-flex flex-column border-secondary":true,"o-simulateDarkTheme":simulateDarkTheme,"bg-view":!simulateDarkTheme,});} 10827standaloneInboxMessages=fields.Many("mail.message",{compute(){const messages=(this.store.inbox?.messages??[]).filter((m)=>!m.thread);return messages.sort((m1,m2)=>compareDatetime(m2.datetime,m1.datetime)||m2.id-m1.id);},});async doMessagePost(params,tmpMessage){return this.messagePostMutex.exec(async()=>{let res;try{res=await rpc("/mail/message/post",params,{silent:true});}catch(err){if(!tmpMessage){throw err;} 10828tmpMessage.postFailRedo=()=>{tmpMessage.postFailRedo=undefined;tmpMessage.thread.messages.delete(tmpMessage);tmpMessage.thread.messages.add(tmpMessage);this.doMessagePost(params,tmpMessage);};} 10829return res;});} 10830async fetchStoreData(name,params,{requestData=false,readonly=true,silent=true}={}){const dataRequest=this.DataResponse.createRequest();dataRequest._autoResolve=!requestData;this.fetchParams.push([name,params,dataRequest]);this.fetchReadonly=this.fetchReadonly&&readonly;this.fetchSilent=this.fetchSilent&&silent;this._fetchStoreDataDebounced();return dataRequest._resultDef;} 10831async initialize(){await this.fetchStoreData("init_messaging");this.isReady.resolve();} 10832makeCachedFetchData(name,params){let def=null;const r=reactive({status:"not_fetched",fetch:()=>{if(["fetching","fetched"].includes(r.status)){return def;} 10833r.status="fetching";def=new Deferred();this.fetchStoreData(name,params).then((result)=>{r.status="fetched";def.resolve(result);},(error)=>{r.status="not_fetched";def.reject(error);});return def;},});return r;} 10834_fetchStoreDataDebounced(){const fetchParams=this.fetchParams;this._fetchStoreDataRpc(fetchParams.map(([name,params,dataRequest])=>{if(dataRequest._autoResolve){if(params!==undefined){return[name,params];}else{return name;}}else{return[name,params,dataRequest.id];}})).then((data)=>{this.insert(data);for(const[,,dataRequest]of fetchParams){if(dataRequest._autoResolve){dataRequest._resolve=true;}}},(error)=>{for(const[,,dataRequest]of fetchParams){dataRequest._resultDef.reject(error);}});this.fetchParams=[];this.fetchReadonly=true;this.fetchSilent=true;} 10835_fetchStoreDataRpc(fetchParams){return rpc(this.fetchReadonly?"/mail/data":"/mail/action",{fetch_params:fetchParams,context:user.context},{silent:this.fetchSilent});} 10836async startMeeting(){const thread=await this.createGroupChat({default_display_mode:"video_full_screen",partners_to:[this.self.id],});await this.store.chatHub.initPromise;this.ChatWindow.get(thread)?.update({autofocus:0});await this.env.services["discuss.rtc"].toggleCall(thread,{camera:true});if(this.rtc.selfSession){this.rtc.enterFullscreen({autoOpenAction:"invite-people"});}} 10837tabToThreadType(tab){return tab==="chat"?["chat","group"]:[tab];} 10838handleClickOnLink(ev,thread){const link=ev.target.closest("a");if(!link){return;} 10839const model=link.dataset.oeModel;const id=Number(link.dataset.oeId);if(link.classList.contains("o_channel_redirect")&&model&&id){ev.preventDefault();this.Thread.getOrFetch({model,id}).then((thread)=>{if(thread){thread.open({focus:true});}else{this.env.services.notification.add(_t("This thread is no longer available."),{type:"danger",});}});return true;}else if(link.classList.contains("o_mail_redirect")&&id){ev.preventDefault();this.onClickPartnerMention(ev,id);return true;}else if(link.classList.contains("o_message_redirect")){const message=this["mail.message"].get(id);const targetThread=message?.thread;const showAccessError=()=>this.env.services.notification.add(_t("This conversation isnât available."),{type:"danger",});if(targetThread){targetThread.checkReadAccess().then((hasAccess)=>
10839{if(hasAccess){targetThread.highlightMessage=message;let isOpen=targetThread.eq(thread);if(!isOpen){isOpen=targetThread.open({focus:true,swapOpened:false});} 10840if(!isOpen){window.open(link.href);}}else{if(this.self_partner){showAccessError();}else{window.open(link.href);}}});ev.preventDefault();return true;}else if(link.getAttribute("href")?.startsWith(getOrigin())){showAccessError();ev.preventDefault();return true;}}else if(this.env.services.ui.isSmall&&ev.target.closest(".o-mail-ChatWindow")&&link.href&&!link.href.startsWith("#")){let url;try{url=new URL(link.href);}catch{return false;} 10841if(browser.location.host===url.host&&browser.location.pathname.startsWith("/odoo")){this.ChatWindow.get({thread})?.fold();}} 10842return false;} 10843setup(){super.setup();this._fetchStoreDataDebounced=debounce(this._fetchStoreDataDebounced,Store.FETCH_DATA_DEBOUNCE_DELAY);} 10844onStarted(){this.isOdooWhiteTheme=cookie.get("color_scheme")!=="dark"||this.inPublicPage;navigator.serviceWorker?.addEventListener("message",({data={}})=>{const{type,payload}=data;if(type==="notification-display-request"){const{correlationId,model,res_id}=payload;const thread=this.Thread.get({model,id:res_id});let isTabFocused;try{isTabFocused=parent.document.hasFocus();}catch{} 10845const isInbox=this.store.self.main_user_id?.notification_type==="inbox"&&model!=="discuss.channel";if((isTabFocused&&thread?.isDisplayed)||isInbox){navigator.serviceWorker.controller?.postMessage({type:"notification-display-response",payload:{correlationId},});}} 10846if(type==="notification-displayed"){this.onPushNotificationDisplayed(payload);}});} 10847onPushNotificationDisplayed(payload){if(["mail.thread","discuss.channel"].includes(payload.model)){this.env.services["mail.out_of_focus"]._playSound();}} 10848async getChat({userId,partnerId}){const partner=await this.getPartner({userId,partnerId});if(!partner){return;} 10849let chat=partner.searchChat();if(!chat?.self_member_id?.is_pinned){chat=await this.joinChat(partner.id);} 10850if(!chat){this.env.services.notification.add(_t("An unexpected error occurred during the creation of the chat."),{type:"warning"});return;} 10851return chat;} 10852fillPartnersMentionToken(postData){postData.partner_ids_mention_token||={};for(const pid of postData.partner_ids){const partner=this["res.partner"].get(pid);if(partner?.mention_token){postData.partner_ids_mention_token[pid]=partner.mention_token;}}} 10853getLastMessageId(){return Object.values(this["mail.message"].records).reduce((lastMessageId,message)=>Math.max(lastMessageId,message.id),0);} 10854handleValidChannelMention(channelLinks){for(const linkEl of channelLinks.filter((el)=>!el.querySelector(".fa-comments-o, .fa-hashtag"))){const text=linkEl.textContent.substring(1);const icon=linkEl.classList.contains("o_channel_redirect_asThread")?"fa fa-comments-o":"fa fa-hashtag";const iconEl=renderToElement("mail.Message.mentionedChannelIcon",{icon});linkEl.replaceChildren(iconEl);linkEl.insertAdjacentText("beforeend",` ${text}`);}} 10855getMentionsFromText(body,{mentionedChannels=[],mentionedPartners=[],mentionedRoles=[],thread}={}){const validMentions={};const segments=isMarkup(body)?Array.from(createDocumentFragmentFromContent(body).querySelectorAll("a"),(a)=>a.textContent):[body];validMentions.threads=mentionedChannels.filter((thread)=>{const mention=thread.parent_channel_id?`#${thread.parent_channel_id.displayName} > ${thread.displayName}`:`#${thread.displayName}`;return segments.some((segment)=>segment.includes(mention));});const mentionText=(partner)=>`@${thread?.getPersonaName?.(partner) ?? partner.name}`;const remaining=[...segments];const kept=new Set([...mentionedPartners].sort((p1,p2)=>mentionText(p2).length-mentionText(p1).length).filter((partner)=>{const text=mentionText(partner);const i=remaining.findIndex((s)=>s.includes(text));if(i===-1){return false;} 10856remaining[i]=remaining[i].replace(text," ".repeat(text.length));return true;}));validMentions.partners=mentionedPartners.filter((partner)=>kept.has(partner));validMentions.roles=mentionedRoles.filter((role)=>segments.some((segment)=>segment.includes(`@${role.name}`)));validMentions.specialMentions=this.specialMentions.filter((special)=>segments.some((segment)=>segment.includes(`@${special.label}`))).map((special)=>special.label);return validMentions;}
10857async getMessagePostParams({body,postData,thread}){const{attachments,cannedResponseIds,emailAddSignature,isNote,mentionedChannels,mentionedPartners,mentionedRoles,}=postData;const subtype=isNote?"mail.mt_note":"mail.mt_comment";const validMentions=this.getMentionsFromText(body,{mentionedChannels,mentionedPartners,mentionedRoles,thread,});const partner_ids=validMentions?.partners.map((partner)=>partner.id)??[];const role_ids=validMentions?.roles.map((role)=>role.id)??[];const recipientEmails=[];if(!isNote){const allRecipients=[...thread.suggestedRecipients,...thread.additionalRecipients];const recipientIds=allRecipients.filter((recipient)=>recipient.persona).map((recipient)=>recipient.persona.id);allRecipients.filter((recipient)=>!recipient.persona).forEach((recipient)=>{recipientEmails.push(recipient.email);});partner_ids.push(...recipientIds);} 10858postData={body:await generateEmojisOnHtml(body),email_add_signature:emailAddSignature,message_type:"comment",subtype_xmlid:subtype,};if(attachments.length){postData.attachment_ids=attachments.map(({id})=>id);} 10859if(partner_ids.length){Object.assign(postData,{partner_ids});this.fillPartnersMentionToken(postData);} 10860if(role_ids.length){Object.assign(postData,{role_ids});} 10861if(thread.model==="discuss.channel"&&validMentions?.specialMentions.length){postData.special_mentions=validMentions.specialMentions;} 10862if(attachments.length){postData.attachment_tokens=attachments.map((attachment)=>attachment.ownership_token);} 10863if(recipientEmails.length){postData.partner_emails=recipientEmails;} 10864const params={post_data:postData,thread_id:thread.id,thread_model:thread.model,};if(cannedResponseIds?.length){params.canned_response_ids=cannedResponseIds;} 10865return params;} 10866notifySendFromMailbox(recordName){this.env.services.notification.add(_t('Message posted on "%s"',recordName),{type:"info",});} 10867getNextTemporaryId(){const lastMessageId=this.getLastMessageId();if(prevLastMessageId===lastMessageId){temporaryIdOffset+=0.01;}else{prevLastMessageId=lastMessageId;temporaryIdOffset=0.01;} 10868return lastMessageId+temporaryIdOffset;} 10869async getPartner({userId,partnerId}
10869){if(userId){let user=this.users[userId];if(!user){this.users[userId]={id:userId};user=this.users[userId];} 10870if(!user.partner_id){const[userData]=await this.env.services.orm.silent.read("res.users",[user.id],["partner_id"],{context:{active_test:false}});if(userData){user.partner_id=userData.partner_id[0];}} 10871if(!user.partner_id){this.env.services.notification.add(_t("You can only chat with existing users."),{type:"warning",});return;} 10872partnerId=user.partner_id;} 10873if(partnerId){const partner=this["res.partner"].insert({id:partnerId});if(!partner.main_user_id){const[userId]=await this.env.services.orm.silent.search("res.users",[["partner_id","=",partnerId]],{context:{active_test:false}});if(!userId){this.env.services.notification.add(_t("You can only chat with partners that have a dedicated user."),{type:"info"});return;} 10874if(!partner.main_user_id){partner.main_user_id=userId;}} 10875return partner;}} 10876async joinChat(id,forceOpen=false){const{channel}=await this.fetchStoreData("/discuss/get_or_create_chat",{partners_to:[id]},{readonly:false,requestData:true});if(forceOpen){await channel.open({focus:true});} 10877return channel;} 10878async openChat(person){const chat=await this.getChat(person);chat?.open({focus:true});} 10879openDocument({id,model}){this.env.services.action.doAction({type:"ir.actions.act_window",res_model:model,views:[[false,"form"]],res_id:id,});} 10880onClickPartnerMention(ev,id){this.openChat({partnerId:id});} 10881async searchMessagesInThread(searchTerm,thread,before,is_notification){const{count,data,messages}=await rpc(thread.getFetchRoute(),{...thread.getFetchParams(),fetch_params:{is_notification,search_term:await prettifyMessageText(searchTerm),before,},});this.insert(data);return{count,loadMore:messages.length===this.FETCH_LIMIT,messages:this["mail.message"].insert(messages),};}} 10882Store.register();const storeService=__exports.storeService={dependencies:["bus_service","im_status","ui","popover"],start(env,services){const store=makeStore(env);store.insert(session.storeData);store.self_guest??={id:-1};store.settings??={};store.initialize();store.onStarted();return store;},};registry.category("services").add("mail.store",storeService);return __exports;});; 10883 10884/* /mail/static/src/core/common/suggestion_hook.js */ 10885odoo.define('@mail/core/common/suggestion_hook',['@html_editor/utils/dom_info','@html_editor/utils/position','@mail/utils/common/format','@odoo/owl','@web/core/network/rpc','@web/core/utils/hooks','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{isContentEditable,isTextNode}=require("@html_editor/utils/dom_info");const{rightPos}=require("@html_editor/utils/position");const{generatePartnerMentionElement,generateRoleMentionElement,generateSpecialMentionElement,generateThreadMentionElement,}=require("@mail/utils/common/format");const{status,useComponent,useEffect,useState}=require("@odoo/owl");const{ConnectionAbortedError}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const{useDebounced}=require("@web/core/utils/timing");const DELAY_FETCH=__exports.DELAY_FETCH=250;const UseSuggestion=__exports.UseSuggestion=class UseSuggestion{constructor(comp){this.comp=comp;this.fetchSuggestions=useDebounced(this.fetchSuggestions.bind(this),DELAY_FETCH);useEffect(()=>{this.update();if(this.search.position===undefined||!this.search.delimiter){return;} 10886if(!this.composer.store.self_partner){return;} 10887if(this.lastFetchedSearch?.count===0&&(!this.search.delimiter||this.isSearchMoreSpecificThanLastFetch)){return;} 10888this.fetchSuggestions();},()=>[this.search.delimiter,this.search.position,this.search.term]);useEffect(()=>{this.detect();},()=>[this.composer.selection.start,this.composer.selection.end,this.composer.composerText,this.composer.composerHtml,]);} 10889comp;get composer(){return this.comp.props.composer;} 10890suggestionService=useService("mail.suggestion");state=useState({count:0,items:undefined,isFetching:false,});search={delimiter:undefined,position:undefined,term:"",};lastFetchedSearch;get isSearchMoreSpecificThanLastFetch(){return(this.lastFetchedSearch.delimiter===this.search.delimiter&&this.search.term.startsWith(this.lastFetchedSearch.term)&&this.lastFetchedSearch.position>=this.search.position);} 10891clearRawMentions(){this.composer.mentionedChannels.length=0;this.composer.mentionedPartners.length=0;this.composer.mentionedRoles.length=0;} 10892clearCannedResponses(){this.composer.cannedResponses=[];} 10893clearSearch(){Object.assign(this.search,{delimiter:undefined,position:undefined,term:"",});this.state.items=undefined;} 10894detect(){let start=0;let end=0;let text="";if(this.comp.composerService.htmlEnabled){const selection=this.comp.editor.shared.selection.getEditableSelection();if(!isTextNode(selection.startContainer)||!isContentEditable(selection.startContainer)||!selection.isCollapsed){this.clearSearch();return;} 10895start=selection.startOffset;end=selection.endOffset;text=selection.anchorNode.textContent;}else{start=this.composer.selection.start;end=this.composer.selection.end;text=this.composer.composerText;} 10896if(start!==end){this.clearSearch();return;} 10897const candidatePositions=[];let numberOfSpaces=0;for(let index=start-1;index>=0;
10897--index){if(/\s/.test(text[index])){numberOfSpaces++;if(numberOfSpaces===2){break;}} 10898candidatePositions.push(index);} 10899if(this.search.position!==undefined&&this.search.position<start){candidatePositions.push(this.search.position);} 10900const supportedDelimiters=this.suggestionService.getSupportedDelimiters(this.thread,this.comp.env);for(const candidatePosition of candidatePositions){if(candidatePosition<0||candidatePosition>=text.length){continue;} 10901const findAppropriateDelimiter=()=>{let goodCandidate;for(const[delimiter,allowedPosition,minCharCountAfter]of supportedDelimiters){if(text.substring(candidatePosition).startsWith(delimiter)&&(allowedPosition===undefined||allowedPosition===candidatePosition)&&(minCharCountAfter===undefined||start-candidatePosition-delimiter.length+1>minCharCountAfter)&&(!goodCandidate||delimiter.length>goodCandidate)){goodCandidate=delimiter;}} 10902return goodCandidate;};const candidateDelimiter=findAppropriateDelimiter();if(!candidateDelimiter){continue;} 10903const charBeforeCandidate=text[candidatePosition-1];if(charBeforeCandidate&&!/\s/.test(charBeforeCandidate)){continue;} 10904Object.assign(this.search,{delimiter:candidateDelimiter,position:candidatePosition,term:text.substring(candidatePosition+candidateDelimiter.length,start),});this.state.count++;return;} 10905this.clearSearch();} 10906get thread(){return this.composer.thread||this.composer.message?.thread;} 10907insert(option){let position=this.search.position+1;if([":","::"].includes(this.search.delimiter)||(this.comp.composerService.htmlEnabled&&this.search.delimiter!=="/")){position=this.search.position;} 10908if(this.comp.composerService.htmlEnabled){const{startContainer,endContainer,endOffset}=this.comp.editor.shared.selection.getEditableSelection();this.comp.editor.shared.selection.setSelection({anchorNode:startContainer,anchorOffset:position,focusNode:endContainer,focusOffset:endOffset,});} 10909if(option.partner){this.composer.mentionedPartners.add({id:option.partner.id});}else if(option.role){this.composer.mentionedRoles.add(option.role);}else if(option.thread){this.composer.mentionedChannels.add({model:"discuss.channel",id:option.thread.id});}else if(option.cannedResponse){this.composer.cannedResponses.push(option.cannedResponse);} 10910if(this.comp.composerService.htmlEnabled){const inlineElement=makeMentionFromOption(option,{thread:this.thread});this.comp.editor.shared.dom.insert(inlineElement);const[anchorNode,anchorOffset]=rightPos(inlineElement);this.comp.editor.shared.selection.setSelection({anchorNode,anchorOffset});this.comp.editor.shared.dom.insert("\u00A0");this.comp.editor.shared.history.addStep();}else{this.composer.composerText=this.composer.composerText.substring(0,position)+ 10911this.composer.composerText.substring(this.composer.selection.end);this.clearSearch();this.composer.insertText(`${option.label} `,position);}} 10912update(){if(!this.search.delimiter){return;} 10913const{type,suggestions}=this.suggestionService.searchSuggestions(this.search,{thread:this.thread,});if(!suggestions.length){this.state.items=undefined;return;} 10914const limit=8;suggestions.length=Math.min(suggestions.length,limit);this.state.items={type,suggestions};} 10915async fetchSuggestions(){if(!this.thread||status(this.comp)==="destroyed"){return;} 10916let resetFetchingState=true;try{this.abortController?.abort();this.abortController=new AbortController();this.state.isFetching=true;await this.suggestionService.fetchSuggestions(this.search,{thread:this.thread,abortSignal:this.abortController.signal,});}catch(e){this.lastFetchedSearch=null;if(e instanceof ConnectionAbortedError){resetFetchingState=false;return;} 10917throw e;}finally{if(resetFetchingState){this.state.isFetching=false;}} 10918if(!this.thread||status(this.comp)==="destroyed"){return;} 10919this.update();this.lastFetchedSearch={...this.search,count:this.state.items?.suggestions.length??0,};if(!this.state.items?.suggestions.length){this.clearSearch();}}} 10920__exports.useSuggestion=useSuggestion;function useSuggestion(){return new UseSuggestion(useComponent());} 10921__exports.mapSuggestionsToOptions=mapSuggestionsToOptions;function mapSuggestionsToOptions(type,suggestions,{thread}={}){const classList="o-mail-Composer-suggestion";switch(type){case"Partner":return{optionTemplate:"mail.Composer.suggestionPartner",options:suggestions.map((suggestion)=>
10921{if(suggestion.isSpecial){return{...suggestion,group:1,optionTemplate:"mail.Composer.suggestionSpecial",classList,};} 10922if(suggestion?.Model?.getName?.()==="res.role"){return{label:suggestion.name,role:suggestion,thread,optionTemplate:"mail.Composer.suggestionRole",classList,};} 10923return{label:thread?.getPersonaName(suggestion)??suggestion.name,partner:suggestion,thread,classList,};}),};case"Thread":return{optionTemplate:"mail.Composer.suggestionThread",options:suggestions.map((suggestion)=>({label:suggestion.fullNameWithParent,thread:suggestion,classList,})),};case"ChannelCommand":return{optionTemplate:"mail.Composer.suggestionChannelCommand",options:suggestions.map((suggestion)=>({label:suggestion.name,help:suggestion.help,classList,})),};case"mail.canned.response":return{optionTemplate:"mail.Composer.suggestionCannedResponse",options:suggestions.map((suggestion)=>({cannedResponse:suggestion,label:suggestion.substitution,source:suggestion.source,title:suggestion.substitution,classList,})),};case"emoji":return{optionTemplate:"mail.Composer.suggestionEmoji",options:suggestions.map((suggestion)=>({emoji:suggestion,label:suggestion.codepoints,})),};default:return{options:[]};}} 10924__exports.makeMentionFromOption=makeMentionFromOption;function makeMentionFromOption(option,{thread}={}){let inlineElement;if(option.partner){inlineElement=generatePartnerMentionElement(option.partner,thread);}else if(option.isSpecial){inlineElement=generateSpecialMentionElement(option.label);}else if(option.role){inlineElement=generateRoleMentionElement(option.role);}else if(option.thread){inlineElement=generateThreadMentionElement(option.thread);}else{inlineElement=document.createTextNode(option.label);} 10925return inlineElement;} 10926return __exports;});; 10927 10928/* /mail/static/src/core/common/suggestion_service.js */ 10929odoo.define('@mail/core/common/suggestion_service',['@mail/core/common/partner_compare','@mail/utils/common/format','@odoo/owl','@web/core/emoji_picker/emoji_picker','@web/core/registry','@web/core/utils/search'],function(require){'use strict';let __exports={};const{partnerCompareRegistry}=require("@mail/core/common/partner_compare");const{cleanTerm}=require("@mail/utils/common/format");const{toRaw}=require("@odoo/owl");const{loadEmoji}=require("@web/core/emoji_picker/emoji_picker");const{registry}=require("@web/core/registry");const{fuzzyLookup}=require("@web/core/utils/search");const SuggestionService=__exports.SuggestionService=class SuggestionService{constructor(env,services){this.env=env;this.orm=services.orm;this.store=services["mail.store"];this.composer=services["mail.composer"];this.emojis;} 10930getSupportedDelimiters(thread,env){return[["@"],["#"],["::"],[":",undefined,2]];} 10931async fetchSuggestions({delimiter,term},{thread,abortSignal}={}){const cleanedSearchTerm=cleanTerm(term);switch(delimiter){case"@":await this.fetchPartnersRoles(cleanedSearchTerm,thread,{abortSignal});break;case"#":await this.fetchThreads(cleanedSearchTerm,{abortSignal});break;case"::":await this.store.cannedReponses.fetch();break;case":":{const{emojis}=await loadEmoji();this.emojis=emojis;break;}}} 10932makeOrmCall(model,method,args,kwargs,{abortSignal}={}){return new Promise((res,rej)=>{const req=this.orm.silent.call(model,method,args,kwargs);const onAbort=()=>{try{req.abort();}catch(e){rej(e);}};abortSignal?.addEventListener("abort",onAbort);req.then(res).catch(rej).finally(()=>abortSignal?.removeEventListener("abort",onAbort));});} 10933async fetchPartnersRoles(term,thread,{abortSignal}={}){const kwargs={search:term};if(thread?.model==="discuss.channel"){kwargs.channel_id=thread.id;} 10934const data=await this.makeOrmCall("res.partner",thread?.model==="discuss.channel"?"get_mention_suggestions_from_channel":"get_mention_suggestions",[],kwargs,{abortSignal});this.store.insert(data);} 10935async fetchThreads(term,{abortSignal}={}){const data=await this.makeOrmCall("discuss.channel","get_mention_suggestions",[],{search:term},{abortSignal});this.store.insert(data);} 10936searchCannedResponseSuggestions(cleanedSearchTerm){const cannedResponses=Object.values(this.store["mail.canned.response"].records).filter((cannedResponse)=>cleanTerm(cannedResponse.source).includes(cleanedSearchTerm));const sortFunc=(c1,c2)=>{const cleanedName1=cleanTerm(c1.source);const cleanedName2=cleanTerm(c2.source);if(cleanedName1.startsWith(cleanedSearchTerm)&&!cleanedName2.startsWith(cleanedSearchTerm)){return-1;} 10937if(!cleanedName1.startsWith(cleanedSearchTerm)&&cleanedName2.startsWith(cleanedSearchTerm)){return 1;} 10938if(cleanedName1<cleanedName2){return-1;} 10939if(cleanedName1>cleanedName2){return 1;} 10940return c1.id-c2.id;};return{type:"mail.canned.response",suggestions:cannedResponses.sort(sortFunc),};} 10941searchEmojisSuggestions(cleanedSearchTerm){let emojis=[];if(this.emojis&&cleanedSearchTerm){emojis=fuzzyLookup(cleanedSearchTerm,this.emojis,(emoji)=>emoji.shortcodes);} 10942return{type:"emoji",suggestions:emojis,};} 10943searchSuggestions({delimiter,term},{thread}={}){thread=toRaw(thread);const cleanedSearchTerm=cleanTerm(term);switch(delimiter){case"@":{const partners=this.searchPartnerSuggestions(cleanedSearchTerm,thread);const roles=this.searchRoleSuggestions(cleanedSearchTerm);return{type:"Partner",suggestions:[...partners.suggestions,...roles.suggestions],};} 10944case"#":return this.searchChannelSuggestions(cleanedSearchTerm);case"::":return this.searchCannedResponseSuggestions(cleanedSearchTerm);case":":return this.searchEmojisSuggestions(cleanedSearchTerm);} 10945return{type:undefined,suggestions:[],};} 10946searchRoleSuggestions(cleanedSearchTerm){const roles=Object.values(this.store["res.role"].records).filter((role)=>cleanTerm(role.name).includes(cleanedSearchTerm));const sortFunc=(r1,r2)=>{const cleanedName1=cleanTerm(r1.name);const cleanedName2=cleanTerm(r2.name);if(cleanedName1.startsWith(cleanedSearchTerm)&&!cleanedName2.startsWith(cleanedSearchTerm)){return-1;} 10947if(!cleanedName1.startsWith(cleanedSearchTerm)&&cleanedName2.startsWith(cleanedSearchTerm)){return 1;} 10948if(cleanedName1<cleanedName2){return-1;} 10949if(cleanedName1>cleanedName2){return 1;} 10950return r1.id-r2.id;};return{suggestions:roles.sort(sortFunc),};} 10951isSuggestionValid(partner,thread){return((this.store.self_partner?.main_user_id?.share===false||partner.mention_token)&&partner.notEq(this.store.odoobot));} 10952getPartnerSuggestions(thread){return Object.values(this.store["res.partner"].records).filter((partner)=>this.isSuggestionValid(partner,thread));} 10953searchPartnerSuggestions(cleanedSearchTerm,thread){const partners=this.getPartnerSuggestions(thread);const suggestions=[];for(const partner of partners){if(!partner.name){continue;} 10954if(cleanTerm(partner.name).includes(cleanedSearchTerm)||(partner.email&&cleanTerm(partner.email).includes(cleanedSearchTerm))){suggestions.push(partner);}} 10955suggestions.push(...this.store.specialMentions.filter((special)=>thread&&special.channel_types.includes(thread.channel_type)&&cleanedSearchTerm.length>=Math.min(4,special.label.length)&&(special.label.startsWith(cleanedSearchTerm)||cleanTerm(special.description.toString()).includes(cleanedSearchTerm))));return{type:"Partner",suggestions:[...this.sortPartnerSuggestions(suggestions,cleanedSearchTerm,thread)],};} 10956sortPartnerSuggestions(partners,searchTerm="",thread=undefined){const cleanedSearchTerm=cleanTerm(searchTerm);const compareFunctions=partnerCompareRegistry.getAll();const context=this.sortPartnerSuggestionsContext(thread);return partners.sort((p1,p2)=>{p1=toRaw(p1);p2=toRaw(p2);if(p1.isSpecial||p2.isSpecial){return 0;} 10957for(const fn of compareFunctions){const result=fn(p1,p2,{env:this.env,searchTerm:cleanedSearchTerm,thread,context,});if(result!==undefined){return result;}}});} 10958sortPartnerSuggestionsContext(){return{};} 10959searchChannelSuggestions(cleanedSearchTerm){const suggestionList=Object.values(this.store.Thread.records).filter((thread)=>thread.channel_type==="channel"&&thread.displayName&&cleanTerm(thread.displayName).includes(cleanedSearchTerm));const sortFunc=(c1,c2)=>{const isPublicChannel1=c1.channel_type==="channel"&&!c2.group_public_id;const isPublicChannel2=c2.channel_type==="channel"&&!c2.group_public_id;if(isPublicChannel1&&!isPublicChannel2){return-1;} 10960if(!isPublicChannel1&&isPublicChannel2){return 1;} 10961if(c1.hasSelfAsMember&&!c2.hasSelfAsMember){return-1;} 10962if(!c1.hasSelfAsMember&&c2.hasSelfAsMember){return 1;} 10963const cleanedDisplayName1=cleanTerm(c1.displayName);const cleanedDisplayName2=cleanTerm(c2.displayName);if(cleanedDisplayName1.startsWith(cleanedSearchTerm)&&!cleanedDisplayName2.startsWith(cleanedSearchTerm)){return-1;} 10964if(!cleanedDisplayName1.startsWith(cleanedSearchTerm)&&cleanedDisplayName2.startsWith(cleanedSearchTerm)){return 1;} 10965if(cleanedDisplayName1<cleanedDisplayName2){return-1;} 10966if(cleanedDisplayName1>cleanedDisplayName2){return 1;} 10967return c1.id-c2.id;};return{type:"Thread",suggestions:suggestionList.sort(sortFunc),};}} 10968const suggestionService=__exports.suggestionService={dependencies:["orm","mail.store","mail.composer"],start(env,services){return new SuggestionService(env,services);},};registry.category("services").add("mail.suggestion",suggestionService);return __exports;});; 10969 10970/* /mail/static/src/core/common/thread.js */ 10971odoo.define('@mail/core/common/thread',['@mail/core/common/date_section','@mail/core/common/message','@mail/core/common/notification_message','@mail/core/common/record','@mail/utils/common/hooks','@odoo/owl','@web/core/browser/browser','@web/core/l10n/translation','@web/core/transition','@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{DateSection}=require("@mail/core/common/date_section");const{Message}=require("@mail/core/common/message");const{NotificationMessage}=require("@mail/core/common/notification_message");const{Record}=require("@mail/core/common/record");const{useVisible}=require("@mail/utils/common/hooks");const{Component,markRaw,onMounted,onWillDestroy,onWillPatch,onWillUnmount,onWillUpdateProps,reactive,toRaw,useChildSubEnv,useEffect,useRef,useState,}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{Transition}=require("@web/core/transition");const{Deferred}=require("@web/core/utils/concurrency");const{useBus,useRefListener,useService}=require("@web/core/utils/hooks");const{escape}=require("@web/core/utils/strings");const PRESENT_VIEWPORT_THRESHOLD=__exports.PRESENT_VIEWPORT_THRESHOLD=1;const Thread=__exports.Thread=class Thread extends Component{static components={Message,NotificationMessage,Transition,DateSection};static props=["autofocus?","showDates?","isInChatWindow?","jumpPresent?","jumpToNewMessage?","thread","order?","scrollRef?","showEmptyMessage?","showJumpPresent?","messageActions?",];static defaultProps={isInChatWindow:false,jumpPresent:0,order:"asc",showDates:true,showEmptyMessage:true,showJumpPresent:true,messageActions:true,};static template="mail.Thread";smoothScrollingDeferred;smoothScrollingTimeout;isSmoothScrolling=false;setup(){super.setup();this.escape=escape;this.applyScroll=this.applyScroll.bind(this);this.saveScroll=this.saveScroll.bind(this);this.onScroll=this.onScroll.bind(this);this.registerMessageRef=this.registerMessageRef.bind(this);this.store=useService("mail.store");this.ui=useService("ui");this.state=useState({isReplyingTo:false,mountedAndLoaded:false,resetCount:0,showJumpPresent:false,scrollTop:null,});this.lastJumpPresent=this.props.jumpPresent;this.orm=useService("orm");this.ui=useService("ui");this.messageHighlight=this.env.messageHighlight?useState(this.env.messageHighlight):null;this.scrollingToHighlight=false;this.refByMessageId=reactive(new Map(),()=>{this.scrollToHighlighted();});useEffect(()=>{this.scrollToHighlighted();},()=>[this.messageHighlight?.highlightedMessageId]);this.present=useRef("load-newer");this.jumpPresentRef=useRef("jump-present");this.root=useRef("messages");this.visibleState=useVisible("messages",()=>{this.updateShowJumpPresent();});this.scrollableRef=this.props.scrollRef??this.root;useRefListener(this.scrollableRef,"scrollend",()=>(this.state.scrollTop=this.scrollableRef.el.scrollTop));this.loadOlderState=useVisible("load-older",async()=>{await Promise.all([this.messageHighlight?.scrollPromise,this.smoothScrollingDeferred,]);if(this.loadOlderState.isVisible){toRaw(this.props.thread).fetchMoreMessages();}},{ready:false});this.loadNewerState=useVisible("load-newer",async()=>{await Promise.all([this.messageHighlight?.scrollPromise,this.smoothScrollingDeferred,]);if(this.loadNewerState.isVisible){toRaw(this.props.thread).fetchMoreMessages("newer");}},{ready:false});this.presentThresholdState=useVisible("present-treshold",()=>this.updateShowJumpPresent());this.setupScroll();useEffect((focus)=>{if(focus&&this.state.mountedAndLoaded){this.root.el.focus();}},()=>[this.props.autofocus+this.props.thread.autofocus,this.state.mountedAndLoaded]);useEffect(()=>{this.computeJumpPresentPosition();},()=>[this.jumpPresentRef.el,this.viewportEl]);useEffect(()=>this.updateShowJumpPresent(),()=>[this.props.thread.loadNewer]);useEffect(()=>{if(this.props.jumpPresent!==this.lastJumpPresent){this.jumpToPresent({immediate:true});}},()=>[this.props.jumpPresent]);useEffect(()=>{if(this.props.thread.highlightMessage&&this.state.mountedAndLoaded){this.messageHighlight?.highlightMessage(this.props.thread.highlightMessage,this.props.thread);this.props.thread.highlightMessage=null;}},()=>[this.props.thread.highlightMessage,this.state.mountedAndLoaded]);useEffect(()=>{if(!this.state.mountedAndLoaded){return;} 10972this.updateShowJumpPresent();},()=>[this.state.mountedAndLoaded]);onMounted(()=>
10972{if(!this.env.chatter||this.env.chatter?.fetchMessages){if(this.env.chatter){this.env.chatter.fetchMessages=false;} 10973this.fetchMessages();}});onWillUnmount(()=>{if(this.props.thread.isFocusedByThread){this.props.thread.isFocusedByThread=false;}});useEffect((isLoaded)=>{this.state.mountedAndLoaded=isLoaded;},()=>[this.props.thread.isLoaded,this.state.resetCount]);useEffect(()=>{if(!this.props.jumpToNewMessage){return;} 10974const el=this.refByMessageId.get(this.props.thread.self_member_id.new_message_separator_ui-1)?.el;if(el){el.querySelector(".o-mail-Message-jumpTarget").scrollIntoView({behavior:"instant",block:"center",});}},()=>[this.props.jumpToNewMessage]);useBus(this.env.bus,"MAIL:RELOAD-THREAD",({detail})=>{const{model,id}=this.props.thread;if(detail.model===model&&detail.id===id){toRaw(this.props.thread).fetchNewMessages();}});onWillUpdateProps((nextProps)=>{if(nextProps.thread.notEq(this.props.thread)){this.lastJumpPresent=nextProps.jumpPresent;} 10975if(!this.env.chatter||this.env.chatter?.fetchMessages){if(this.env.chatter){this.env.chatter.fetchMessages=false;} 10976toRaw(nextProps.thread).fetchNewMessages();}});} 10977computeJumpPresentPosition(){if(!this.viewportEl||!this.jumpPresentRef.el){return;} 10978const width=this.viewportEl.clientWidth;const height=this.viewportEl.clientHeight;const computedStyle=window.getComputedStyle(this.viewportEl);const ps=parseInt(computedStyle.getPropertyValue("padding-left"));const pe=parseInt(computedStyle.getPropertyValue("padding-right"));const pt=parseInt(computedStyle.getPropertyValue("padding-top"));const pb=parseInt(computedStyle.getPropertyValue("padding-bottom"));this.jumpPresentRef.el.style.transform=`translate(${ 10979 this.env.inChatter ? 22 : width - ps - pe - 22 10980 }px, ${ 10981 this.env.inChatter && !this.env.inChatter.aside 10982 ? -22 10983 : height - pt - pb - (this.env.inChatter?.aside ? 75 : 0) 10984 }px)`;} 10985setupScroll(){this.lastSetValue=undefined;this.loadedAndPatched=false;this.snapshot=undefined;this.newestPersistentMessage=undefined;this.oldestPersistentMessage=undefined;this.loadNewer=undefined;let stopOnChange=Record.onChange(this.props.thread,"isLoaded",()=>{if(!this.props.thread.isLoaded||!this.state.mountedAndLoaded){this.reset();}});onWillUpdateProps((nextProps)=>{if(nextProps.thread.notEq(this.props.thread)){stopOnChange();stopOnChange=Record.onChange(nextProps.thread,"isLoaded",()=>{if(!nextProps.thread.isLoaded||!this.state.mountedAndLoaded){this.reset();}});}});onWillDestroy(()=>stopOnChange());onWillPatch(()=>{if(!this.loadedAndPatched){return;} 10986this.snapshot={scrollHeight:this.scrollableRef.el.scrollHeight,scrollTop:this.scrollableRef.el.scrollTop,};});useEffect(this.applyScroll);useChildSubEnv({getCurrentThread:()=>this.props.thread,onImageLoaded:this.applyScroll,});const observer=new ResizeObserver(()=>{this.computeJumpPresentPosition();this.applyScroll();});useEffect((el,mountedAndLoaded)=>{if(el&&mountedAndLoaded){el.addEventListener("scroll",this.onScroll);observer.observe(el);return()=>{observer.unobserve(el);el.removeEventListener("scroll",this.onScroll);};}},()=>[this.scrollableRef.el,this.state.mountedAndLoaded]);} 10987applyScroll(){if(!this.props.thread.isLoaded||!this.state.mountedAndLoaded){this.reset();return;} 10988const thread=toRaw(this.props.thread);this.applyScrollContextually(thread);this.snapshot=undefined;this.newestPersistentMessage=thread.newestPersistentMessage;this.oldestPersistentMessage=thread.oldestPersistentMessage;this.loadNewer=thread.loadNewer;if(!this.loadedAndPatched){this.loadedAndPatched=true;this.loadOlderState.ready=true;this.loadNewerState.ready=true;}} 10989applyScrollContextually(thread){const olderMessages=thread.oldestPersistentMessage?.id<this.oldestPersistentMessage?.id;const newerMessages=thread.newestPersistentMessage?.id>this.newestPersistentMessage?.id;const messagesAtTop=(this.props.order==="asc"&&olderMessages)||(this.props.order==="desc"&&newerMessages);const messagesAtBottom=(this.props.order==="desc"&&olderMessages)||(this.props.order==="asc"&&newerMessages&&(this.loadNewer||typeof thread.scrollTop!=="string"||!thread.scrollTop?.includes("bottom")));if(this.snapshot&&messagesAtTop){this.setScroll(this.snapshot.scrollTop+ 10990this.scrollableRef.el.scrollHeight- 10991this.snapshot.scrollHeight);}else if(this.snapshot&&messagesAtBottom){this.setScroll(this.snapshot.scrollTop);}else if(!this.env.messageHighlight?.highlightedMessageId&&thread.scrollTop!==undefined){let value;
10991if(typeof thread.scrollTop==="string"&&thread.scrollTop?.includes("bottom")){value=this.props.order==="asc"?this.scrollableRef.el.scrollHeight-this.scrollableRef.el.clientHeight:0;}else{value=this.props.order==="asc"?thread.scrollTop:this.scrollableRef.el.scrollHeight- 10992thread.scrollTop- 10993this.scrollableRef.el.clientHeight;} 10994if((this.lastSetValue===undefined||Math.abs(this.lastSetValue-value)>1)&&!this.isSmoothScrolling){this.setScroll(value,{smooth:typeof thread.scrollTop==="string"&&thread.scrollTop?.includes("smooth"),});}}} 10995fetchMessages(){toRaw(this.props.thread).fetchNewMessages();} 10996get viewportEl(){let viewportEl=this.scrollableRef.el;if(viewportEl&&viewportEl.clientHeight>browser.innerHeight){while(viewportEl&&viewportEl.clientHeight>browser.innerHeight){viewportEl=viewportEl.parentElement;}} 10997return viewportEl;} 10998get PRESENT_THRESHOLD(){const threshold=(this.viewportEl?.clientHeight??0)*PRESENT_VIEWPORT_THRESHOLD;return this.state.showJumpPresent?threshold-200:threshold;} 10999updateShowJumpPresent(){this.state.showJumpPresent=this.visibleState.isVisible&&(this.props.thread.loadNewer||this.presentThresholdState.isVisible===false);} 11000onClickLoadOlder(){this.props.thread.fetchMoreMessages();} 11001onClickRetry(){if(!this.props.thread.oldestPersistentMessage){this.fetchMessages();return;} 11002this.onClickLoadOlder();} 11003async onClickPreferences(){const actionDescription=await this.orm.call("res.users","action_get");actionDescription.res_id=this.store.self.main_user_id?.id;this.env.services.action.doAction(actionDescription);} 11004onFocusin(){this.props.thread.isFocusedByThread=true;const thread=toRaw(this.props.thread);if(thread?.scrollTop==="bottom"&&!thread.scrollUnread&&!thread.markedAsUnread){thread?.markAsRead();}} 11005onFocusout(){this.props.thread.isFocusedByThread=false;} 11006async onParentMessageClick(parentMessage){if(!parentMessage){return;} 11007const targetThread=parentMessage.thread;if(!targetThread){return;} 11008if(targetThread.eq(this.props.thread)){this.env.messageHighlight?.highlightMessage(parentMessage,targetThread);}else{targetThread.highlightMessage=parentMessage;await targetThread.open({focus:true});}} 11009getMessageClassName(message){return!message.isNotification&&this.messageHighlight?.highlightedMessageId===message.id?"o-highlighted bg-view shadow-lg pb-1":"";} 11010async jumpToPresent({immediate=false}={}){this.messageHighlight?.clear();if(!immediate||this.props.thread.loadNewer){await this.props.thread.loadAround();this.props.thread.loadNewer=false;this.state.showJumpPresent=false;} 11011this.props.thread.scrollTop=immediate?"bottom":"bottom-smooth";if(!this.ui.isSmall){this.props.thread.composer.autofocus++;}} 11012registerMessageRef(message,ref){if(!ref){this.refByMessageId.delete(message.id);return;} 11013this.refByMessageId.set(message.id,markRaw(ref));} 11014reset(){this.state.mountedAndLoaded=false;if(this.props.thread.isLoaded){this.state.resetCount++;} 11015this.loadOlderState.ready=false;this.loadNewerState.ready=false;this.lastSetValue=undefined;this.snapshot=undefined;this.newestPersistentMessage=undefined;this.oldestPersistentMessage=undefined;this.loadedAndPatched=false;this.loadNewer=false;} 11016isSquashed(msg,prevMsg){if(this.props.thread.model==="mail.box"){return false;} 11017if(!prevMsg||prevMsg.message_type==="notification"||this.env.inChatter){return false;} 11018if(!msg.author?.eq(prevMsg.author)){return false;} 11019if(!msg.thread?.eq(prevMsg.thread)){return false;} 11020if(msg.isNote){return false;} 11021return msg.datetime.ts-prevMsg.datetime.ts<5*60*1000;} 11022get isAtBottom(){if(this.loadNewer){return false;} 11023return this.props.order==="asc"?this.scrollableRef.el.scrollHeight- 11024this.scrollableRef.el.scrollTop- 11025this.scrollableRef.el.clientHeight<30:this.scrollableRef.el.scrollTop<30;} 11026onScroll(){const thread=toRaw(this.props.thread);if(this.isAtBottom&&!thread.markedAsUnread&&thread.isFocused&&!thread.markingAsRead){thread.markAsRead();} 11027this.saveScroll();} 11028saveScroll(){const thread=toRaw(this.props.thread);const isBottom=this.isAtBottom;if(isBottom){thread.scrollTop="bottom";}else{thread.scrollTop=this.props.order==="asc"?this.scrollableRef.el.scrollTop:this.scrollableRef.el.scrollHeight- 11029this.scrollableRef.el.scrollTop- 11030this.scrollableRef.el.clientHeight;}} 11031async scrollToHighlighted(){if(!this.messageHighlight?.highlightedMessageId||this.scrollingToHighlight){return;} 11032const el=this.refByMessageId.get(this.messageHighlight.highlightedMessageId)?.el;if(el){this.scrollingToHighlight=true;await this.messageHighlight.startupDeferred;this.messageHighlight.scrollTo(el.querySelector(".o-mail-Message-jumpTarget")).then(()=>(this.scrollingToHighlight=false));}} 11033get orderedMessages(){const messages=this.state.mountedAndLoaded?this.props.thread.messages:this.props.thread.phantomMessages;return this.props.order==="asc"?[...messages]:[...messages].reverse();} 11034get showLoadOlder(){return(this.props.thread.loadOlder&&this.props.thread.isLoaded&&!this.props.thread.isTransient&&!this.props.thread.hasLoadingFailed&&!this.messageHighlight?.initiated&&!this.messageHighlight?.highlightedMessageId);} 11035setScroll(value,{smooth=false}={}){if(smooth){clearTimeout(this.smoothScrollingTimeout);this.isSmoothScrolling=true;this.smoothScrollingDeferred=new Deferred();const onSmoothScrollingEnd=()=>{this.smoothScrollingDeferred.resolve();this.smoothScrollingDeferred=undefined;this.isSmoothScrolling=false;};if("onscrollend"in window){document.addEventListener("scrollend",onSmoothScrollingEnd,{capture:true,once:true,});}else{this.smoothScrollingTimeout=setTimeout(onSmoothScrollingEnd,250);}} 11036this.scrollableRef.el.scrollTo({behavior:smooth?"smooth":undefined,top:value});this.lastSetValue=value;this.messageHighlight?.startupDeferred?.resolve();this.saveScroll();} 11037get showStartMessage(){return(this.state.mountedAndLoaded&&["channel","group","chat"].includes(this.props.thread.channel_type));} 11038get startMessageTitle(){const channelName=this.props.thread.name;if(this.props.thread.parent_channel_id){return channelName;} 11039if(this.props.thread.channel_type==="channel"){return _t("Welcome to #%(channelName)s!",{channelName});} 11040return this.props.thread.displayName;} 11041get startMessageSubtitle(){if(this.props.thread.parent_channel_id){const authorName=Object.values(this.store["res.partner"].records).find((partner)=>partner.main_user_id?.eq(this.props.thread.create_uid))?.name;if(authorName){return _t("Started by %(authorName)s",{authorName});}} 11042if(this.props.thread.channel_type==="channel"){return _t("This is the start of the #%(channelName)s channel",{channelName:this.props.thread.name,});} 11043if(this.props.thread.channel_type==="group"){return _t("This is the start of %(conversationName)s group",{conversationName:this.props.thread.displayName,});} 11044return _t("This is the start of your direct chat with %(userName)s",{userName:this.props.thread.displayName,});}} 11045return __exports;});; 11046 11047/* /mail/static/src/core/common/thread_actions.js */ 11048odoo.define('@mail/core/common/thread_actions',['@odoo/owl','@web/core/l10n/translation','@web/core/registry','@mail/core/common/search_messages_panel','@web/core/utils/misc','@mail/core/common/action','@mail/discuss/call/common/meeting_chat','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{useSubEnv,useComponent,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const{SearchMessagesPanel}=require("@mail/core/common/search_messages_panel");const{markEventHandled}=require("@web/core/utils/misc");const{Action,ACTION_TAGS,UseActions}=require("@mail/core/common/action");const{MeetingChat}=require("@mail/discuss/call/common/meeting_chat");const{useService}=require("@web/core/utils/hooks");const threadActionsRegistry=__exports.threadActionsRegistry=registry.category("mail.thread/actions");__exports.registerThreadAction=registerThreadAction;function registerThreadAction(id,definition){threadActionsRegistry.add(id,definition);} 11049registerThreadAction("fold-chat-window",{condition:({owner})=>owner.props.chatWindow&&!owner.isDiscussSidebarChannelActions,icon:"oi oi-fw oi-minus",name:({owner})=>(!owner.props.chatWindow?.isOpen?_t("Open"):_t("Fold")),open:({owner})=>owner.toggleFold(),displayActive:({owner})=>!owner.props.chatWindow?.isOpen,sequence:99,sequenceQuick:20,});registerThreadAction("rename-thread",{condition:({owner,thread})=>thread&&owner.props.chatWindow?.isOpen&&(thread.is_editable||thread.channel_type==="chat")&&!owner.isDiscussSidebarChannelActions,icon:"fa fa-fw fa-pencil",name:_t("Rename Thread"),open:({owner})=>(owner.state.editingName=true),sequence:30,sequenceGroup:20,});
11049registerThreadAction("close",{condition:({owner})=>owner.props.chatWindow&&!owner.isDiscussSidebarChannelActions,icon:"oi fa-fw oi-close",name:_t("Close Chat Window (ESC)"),open:({owner})=>owner.close(),sequence:100,sequenceQuick:10,});registerThreadAction("search-messages",{actionPanelComponent:SearchMessagesPanel,condition:({owner,thread})=>["discuss.channel","mail.box"].includes(thread?.model)&&(!owner.props.chatWindow||owner.props.chatWindow.isOpen)&&!owner.isDiscussSidebarChannelActions,hotkey:"f",panelOuterClass:"o-mail-SearchMessagesPanel bg-inherit",icon:"oi oi-fw oi-search",name:({action})=>(action.isActive?_t("Close Search"):_t("Search Messages")),sequence:20,sequenceGroup:20,setup:({action})=>useSubEnv({searchMenu:{open:()=>action.open(),close:()=>{if(action.isActive){action.close();}},},}),toggle:true,});registerThreadAction("meeting-chat",{actionPanelComponent:MeetingChat,badge:({thread})=>thread.isUnread,badgeIcon:({thread})=>!thread.importantCounter&&"fa fa-circle text-700",badgeText:({thread})=>thread.importantCounter||undefined,condition:({owner})=>owner.env.inMeetingView,icon:"fa fa-fw fa-comments",name:_t("Chat"),panelOuterClass:"bg-100 border border-secondary",sequence:30,toggle:true,tags:({thread})=>{const tags=[];if(thread.importantCounter){tags.push(ACTION_TAGS.IMPORTANT_BADGE);} 11050return tags;},});const ThreadAction=__exports.ThreadAction=class ThreadAction extends Action{popover=null;threadFn;constructor({thread}){super(...arguments);this.threadFn=typeof thread==="function"?thread:()=>thread;} 11051get params(){return Object.assign(super.params,{thread:this.threadFn()});} 11052get actionPanelComponent(){return this.definition.actionPanelComponent;} 11053get actionPanelComponentCondition(){return this.isActive&&this.actionPanelComponent&&this.condition&&!this.popover;} 11054get actionPanelComponentProps(){return this.definition.actionPanelComponentProps?.call(this,this.params);} 11055close({nextActiveAction}={}){if(this.toggle){this.owner.threadActions.activeAction=this.owner.threadActions.actionStack.pop();} 11056this.definition.close?.call(this,Object.assign(this.params,{nextActiveAction}));} 11057get isActive(){return this.id===this.owner.threadActions.activeAction?.id;} 11058get nameClass(){return typeof this.definition.nameClass==="function"?this.definition.nameClass.call(this,this.params):this.definition.nameClass;} 11059onSelected(ev,{keepPrevious}={}){if(ev){markEventHandled(ev,"ThreadAction.onSelected");} 11060if(this.toggle&&this.isActive){this.close();}else{this.open({keepPrevious});}} 11061open({keepPrevious}={}){if(this.toggle){if(this.owner.threadActions.activeAction){if(keepPrevious){this.owner.threadActions.actionStack.push(this.owner.threadActions.activeAction);}else{this.owner.threadActions.activeAction.close({nextActiveAction:this});}} 11062this.owner.threadActions.activeAction=this;} 11063this.definition.open?.call(this,this.params);} 11064get panelOuterClass(){return typeof this.definition.panelOuterClass==="function"?this.definition.panelOuterClass.call(this,this.params):this.definition.panelOuterClass;} 11065get toggle(){return this.definition.toggle;}} 11066class UseThreadActions extends UseActions{ActionClass=ThreadAction;actionStack=[];activeAction=null;} 11067__exports.useThreadActions=useThreadActions;function useThreadActions({thread}={}){const component=useComponent();const transformedActions=threadActionsRegistry.getEntries().map(([id,definition])=>new ThreadAction({owner:component,id,definition,thread}));for(const action of transformedActions){action.setup();} 11068return useState(new UseThreadActions(component,transformedActions,useService("mail.store")));} 11069return __exports;});; 11070 11071/* /mail/static/src/core/common/thread_compare.js */ 11072odoo.define('@mail/core/common/thread_compare',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const threadCompareRegistry=__exports.threadCompareRegistry=registry.category("mail.thread_compare");threadCompareRegistry.add("mail.needaction",(thread1,thread2)=>{const aNeedaction=thread1.needactionMessages.length;const bNeedaction=thread2.needactionMessages.length;if(aNeedaction>
110720&&bNeedaction===0){return-1;} 11073if(bNeedaction>0&&aNeedaction===0){return 1;}},{sequence:10});threadCompareRegistry.add("mail.message-datetime",(thread1,thread2)=>{const aMessageDatetime=thread1.newestPersistentOfAllMessage?.datetime;const bMessageDateTime=thread2.newestPersistentOfAllMessage?.datetime;if(!aMessageDatetime&&bMessageDateTime){return 1;} 11074if(!bMessageDateTime&&aMessageDatetime){return-1;} 11075if(aMessageDatetime&&bMessageDateTime&&aMessageDatetime!==bMessageDateTime){return bMessageDateTime-aMessageDatetime;}},{sequence:40});return __exports;});; 11076 11077/* /mail/static/src/core/common/thread_icon.js */ 11078odoo.define('@mail/core/common/thread_icon',['@web/core/utils/hooks','@odoo/owl','@mail/core/common/thread_model','@web/core/l10n/translation','@mail/core/common/im_status'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{Component}=require("@odoo/owl");const{Thread}=require("@mail/core/common/thread_model");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{ImStatus}=require("@mail/core/common/im_status");const ThreadIcon=__exports.ThreadIcon=class ThreadIcon extends Component{static template="mail.ThreadIcon";static components={ImStatus};static props={thread:{type:Thread},size:{optional:true,validate:(size)=>["small","medium","large"].includes(size)},className:{type:String,optional:true},title:{type:Boolean,optional:true},};static defaultProps={size:"medium",className:"",title:true,};setup(){super.setup();this.store=useService("mail.store");} 11079get correspondent(){return this.props.thread.correspondent;} 11080get defaultChatIcon(){return{class:"fa fa-question-circle opacity-75",title:_t("No IM status available"),};}} 11081return __exports;});; 11082 11083/* /mail/static/src/core/common/thread_model.js */ 11084odoo.define('@mail/core/common/thread_model',['@mail/core/common/record','@mail/utils/common/format','@mail/utils/common/misc','@web/core/network/rpc','@web/core/l10n/translation','@web/core/user','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{AND,fields,Record}=require("@mail/core/common/record");const{generateEmojisOnHtml}=require("@mail/utils/common/format");const{assignDefined}=require("@mail/utils/common/misc");const{rpc}=require("@web/core/network/rpc");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{user}=require("@web/core/user");const{Deferred}=require("@web/core/utils/concurrency");const Thread=__exports.Thread=class Thread extends Record{static id=AND("model","id");static localIdToActiveId(localId){if(!localId){return undefined;} 11085return localId.split(",").slice(1).join("_").replace(" AND ","_");} 11086static async getOrFetch(data,fieldNames=[]){let thread=this.get(data);if(data.id>0&&(!thread||fieldNames.some((fieldName)=>thread[fieldName]===undefined))){await this.store.fetchStoreData("mail.thread",{thread_model:data.model,thread_id:data.id,request_list:fieldNames,});thread=this.get(data);if(!thread?.exists()){return;}} 11087return thread;} 11088autofocus=0;create_uid=fields.One("res.users");id;uuid;model;allMessages=fields.Many("mail.message",{inverse:"thread",});storeAsAllChannels=fields.One("Store",{compute(){if(this.model==="discuss.channel"){return this.store;}},eager:true,});areAttachmentsLoaded=false;group_public_id=fields.One("res.groups");attachments=fields.Many("ir.attachment",{sort:(a1,a2)=>(a1.id<a2.id?1:-1),});get allowedToLeaveChannelTypes(){return["channel","group"];} 11089get canLeave(){return(this.allowedToLeaveChannelTypes.includes(this.channel_type)&&this.group_ids.length===0&&this.store.self_partner);} 11090get allowedToUnpinChannelTypes(){return["chat"];} 11091get canUnpin(){return(this.parent_channel_id||this.allowedToUnpinChannelTypes.includes(this.channel_type));} 11092can_react=true;chat_window=fields.One("ChatWindow",{inverse:"thread",});close_chat_window=fields.Attr(undefined,{onUpdate(){if(this.close_chat_window){this.close_chat_window=undefined;this.closeChatWindow({force:true});}},});composer=fields.One("Composer",{compute:()=>({}),inverse:"thread",onDelete:(r)=>r.delete(),});counter=0;counter_bus_id=0;description;display_name;displayToSelf=fields.Attr(false,{compute(){return(this.self_member_id?.is_pinned||(["channel","group"].includes(this.channel_type)&&this.hasSelfAsMember&&!this.parent_channel_id));},onUpdate(){this.onPinStateUpdated();},});followers=fields.Many("mail.followers",{onAdd(r){r.thread=this;},onDelete:(r)=>r.delete(),});selfFollower=fields.One("mail.followers",{onAdd(r){r.thread=this;},onDelete:(r)=>r.delete(),});followersCount;loadOlder=false;loadNewer=false;get importantCounter(){if(this.model==="mail.box"){return this.counter;} 11093return this.message_needaction_counter;} 11094isDisplayed=fields.Attr(false,{compute(){return this.computeIsDisplayed();},onUpdate(){this.isDisplayedOnUpdate();},});isDisplayedOnUpdate(){} 11095get composerDisabled(){return false;} 11096get isFocused(){return this.isFocusedCounter!==0;} 11097isFocusedByThread=fields.Attr(false,{onUpdate(){if(this.isFocusedByThread){this.isFocusedCounter++;}else{this.isFocusedCounter--;}},});isFocusedCounter=fields.Attr(0,{onUpdate(){if(this.isFocusedCounter<0){this.isFocusedCounter=0;}},});isLoadingAttachments=false;isLoadedDeferred=new Deferred();isLoaded=fields.Attr(false,{onUpdate(){if(this.isLoaded){this.isLoadedDeferred.resolve();}else{const def=this.isLoadedDeferred;this.isLoadedDeferred=new Deferred();this.isLoadedDeferred.then(()=>def.resolve());}},});has_mail_thread;message_main_attachment_id=fields.One("ir.attachment");message_needaction_counter=0;message_needaction_counter_bus_id=0;messageInEdition=fields.One("mail.message",{inverse:"threadAsInEdition"});messages=fields.Many("mail.message");phantomMessages=fields.Many("mail.message");modelName;module_icon;pendingNewMessages=fields.Many("mail.message");needactionMessages=fields.Many("mail.message",{inverse:"threadAsNeedaction",sort:(message1,message2)=>message1.id-message2.id,});portal_partner=fields.One("res.partner");status="new";scrollTop="bottom";transientMessages=fields.Many("mail.message");additionalRecipients=fields.Attr([]);suggestedRecipients=fields.Attr([]);partner_fields;primary_email_field;hasLoadingFailed=false;hasLoadingFailedError;canPostOnReadonly;is_editable;isLocallyPinned=fields.Attr(false,{onUpdate(){this.onPinStateUpdated();},});
11097fetchMembersState="not_fetched";highlightMessage=fields.One("mail.message");access_token;hash;pid;get accessRestrictedToGroupText(){if(!this.group_public_id?.full_name){return false;} 11098return _t('Access restricted to group "%(groupFullName)s"',{groupFullName:this.group_public_id.full_name,});} 11099get busChannel(){return`${this.model}_${this.id}`;} 11100get followersFullyLoaded(){return(this.followersCount===(this.selfFollower?this.followers.length+1:this.followers.length));} 11101get attachmentsInWebClientView(){const attachments=this.attachments.filter((attachment)=>(attachment.isPdf||attachment.isImage)&&!attachment.uploading);attachments.sort((a1,a2)=>a2.id-a1.id);return attachments;} 11102get isUnread(){return this.needactionMessages.length>0;} 11103get typesAllowingCalls(){return["chat","channel","group"];} 11104get allowCalls(){return(!this.isTransient&&this.typesAllowingCalls.includes(this.channel_type)&&!this.correspondent?.persona.eq(this.store.odoobot));} 11105get canPostMessage(){return this.hasWriteAccess||(this.hasReadAccess&&this.canPostOnReadonly);} 11106getPersonaName(persona){return persona?.displayName||persona?.name;} 11107get hasAttachmentPanel(){return this.model==="discuss.channel";} 11108get isChatChannel(){return["chat","group"].includes(this.channel_type);} 11109get supportsCustomChannelName(){return this.isChatChannel&&this.channel_type!=="group";} 11110get displayName(){return this.display_name;} 11111computeIsDisplayed(){return this.store.ChatWindow.get({thread:this})?.isOpen;} 11112get avatarUrl(){return this.module_icon??this.store.DEFAULT_AVATAR;} 11113get allowDescription(){return["channel","group"].includes(this.channel_type);} 11114get fullNameWithParent(){const text=this.parent_channel_id?`${this.parent_channel_id.displayName} > ${this.displayName}`:this.displayName;return text;} 11115get isTransient(){return!this.id||this.id<0;} 11116get lastEditableMessageOfSelf(){const editableMessagesBySelf=this.nonEmptyMessages.filter((message)=>message.isSelfAuthored&&message.editable);if(editableMessagesBySelf.length>0){return editableMessagesBySelf.at(-1);} 11117return null;} 11118get needactionCounter(){return this.message_needaction_counter;} 11119newestMessage=fields.One("mail.message",{inverse:"threadAsNewest",compute(){return this.messages.at(-1);},});get newestPersistentMessage(){return this.messages.findLast((msg)=>Number.isInteger(msg.id));} 11120newestPersistentAllMessages=fields.Many("mail.message",{compute(){const allPersistentMessages=this.allMessages.filter((message)=>Number.isInteger(message.id));allPersistentMessages.sort((m1,m2)=>m2.id-m1.id);return allPersistentMessages;},});newestPersistentOfAllMessage=fields.One("mail.message",{compute(){return this.newestPersistentAllMessages[0];},});get oldestPersistentMessage(){return this.messages.find((msg)=>Number.isInteger(msg.id));} 11121onPinStateUpdated(){} 11122get invitationLink(){if(!this.uuid||this.channel_type==="chat"){return undefined;} 11123return`${window.location.origin}/chat/${this.id}/${this.uuid}`;} 11124get isEmpty(){return this.messages.length===0;} 11125get nonEmptyMessages(){return this.messages.filter((message)=>!message.isEmpty);} 11126get persistentMessages(){return this.messages.filter((message)=>!message.is_transient&&!message.isPending);} 11127get prefix(){return this.isChatChannel?"@":"#";} 11128get rpcParams(){return{};} 11129async checkReadAccess(){await this.store.Thread.getOrFetch(this,["hasReadAccess"]);return this.hasReadAccess;} 11130executeCommand(command,body=""){return this.store.env.services.orm.call("discuss.channel",command.methodName,[[this.id]],{body});} 11131async fetchMessages({after,around,before}={}){this.status="loading";if(!["mail.box","discuss.channel"].includes(this.model)&&!this.id){this.isLoaded=true;return[];} 11132let res;try{res=await this.fetchMessagesData({after,around,before});this.hasLoadingFailedError=undefined;this.hasLoadingFailed=false;}catch(e){this.hasLoadingFailed=true;this.hasLoadingFailedError=e;this.isLoaded=true;this.status="ready";throw e;} 11133this.store.insert(res.data);const msgs=this.store["mail.message"].insert(res.messages.reverse());this.isLoaded=true;this.status="ready";return msgs;} 11134async fetchMessagesData({after,around,before}={}){return await rpc(this.getFetchRoute(),{...this.getFetchParams(),fetch_params:{limit:!around&&around!==0?this.store.FETCH_LIMIT:this.store.FETCH_LIMIT*2,after,around,before,},});} 11135async fetchMoreMessages(epoch="older"){if(this.status==="loading"||(epoch==="older"&&!this.loadOlder)||(epoch==="newer"&&!this.loadNewer)){return;} 11136const before=epoch==="older"?this.oldestPersistentMessage?.id:undefined;const after=epoch==="newer"?this.newestPersistentMessage?.id:undefined;let fetched=[];try{fetched=await this.fetchMessages({after,before});}catch{return;} 11137if((after!==undefined&&!this.messages.some((message)=>message.id===after))||(before!==undefined&&!this.messages.some((message)=>message.id===before))){return;} 11138const alreadyKnownMessages=new Set(this.messages.map(({id})=>id));const messagesToAdd=fetched.filter((message)=>!alreadyKnownMessages.has(message.id));if(epoch==="older"){this.messages.unshift(...messagesToAdd);}else{this.messages.push(...messagesToAdd);} 11139if(fetched.length<this.store.FETCH_LIMIT){if(epoch==="older"){this.loadOlder=false;}else if(epoch==="newer"){this.loadNewer=false;const missingMessages=this.pendingNewMessages.filter(({id})=>!alreadyKnownMessages.has(id));if(missingMessages.length>0){this.messages.push(...missingMessages);this.messages.sort((m1,m2)=>m1.id-m2.id);}}} 11140this._enrichMessagesWithTransient();this.pendingNewMessages=[];} 11141get effectiveSelf(){return this.store.self_partner||this.store.self_guest;} 11142async fetchNewMessages(){if(this.status==="loading"||(!this.hasLoadingFailed&&this.isLoaded&&["discuss.channel","mail.box"].includes(this.model))){return;} 11143const after=this.isLoaded?this.newestPersistentMessage?.id:undefined;let fetched=[];try{fetched=await this.fetchMessages({after});}catch{return;} 11144let startIndex;if(after===undefined){startIndex=0;}else{const afterIndex=this.messages.findIndex((message)=>message.id===after);if(afterIndex===-1){return;}else{startIndex=afterIndex+1;}} 11145const alreadyKnownMessages=new Set(this.messages.map((m)=>m.id));const filtered=fetched.filter((message)=>!alreadyKnownMessages.has(message.id)&&(this.persistentMessages.length===0||message.id<this.oldestPersistentMessage.id||message.id>this.newestPersistentMessage.id));this.messages.splice(startIndex,0,...filtered);Object.assign(this,{loadOlder:after===undefined&&fetched.length===this.store.FETCH_LIMIT?true:after===undefined&&fetched.length!==this.store.FETCH_LIMIT?false:this.loadOlder,});}
11146getFetchParams(){if(this.model==="discuss.channel"){return{channel_id:this.id};} 11147if(this.model==="mail.box"){return{};} 11148return{thread_id:this.id,thread_model:this.model,...this.rpcParams,};} 11149getFetchRoute(){if(this.model==="discuss.channel"){return"/discuss/channel/messages";} 11150if(this.model==="mail.box"&&this.id==="inbox"){return`/mail/inbox/messages`;} 11151if(this.model==="mail.box"&&this.id==="starred"){return`/mail/starred/messages`;} 11152if(this.model==="mail.box"&&this.id==="history"){return`/mail/history/messages`;} 11153return this.fetchRouteChatter;} 11154get fetchRouteChatter(){return"/mail/thread/messages";} 11155async loadAround(messageId){if(this.status==="loading"||(this.isLoaded&&this.messages.some(({id})=>id===messageId))){return;} 11156this.isLoaded=false;this.scrollTop=undefined;try{this.phantomMessages=this.messages;this.messages=await this.fetchMessages({around:messageId});this.phantomMessages=[];}catch{this.isLoaded=true;return;} 11157this.isLoaded=true;this.loadNewer=messageId!==undefined?true:false;this.loadOlder=true;const limit=!messageId&&messageId!==0?this.store.FETCH_LIMIT:this.store.FETCH_LIMIT*2;if(this.messages.length<limit){const olderMessagesCount=this.messages.filter(({id})=>id<messageId).length;const newerMessagesCount=this.messages.filter(({id})=>id>messageId).length;if(olderMessagesCount<limit/2-1){this.loadOlder=false;} 11158if(newerMessagesCount<limit/2){this.loadNewer=false;}} 11159this._enrichMessagesWithTransient();} 11160async markAllMessagesAsRead(){await this.store.env.services.orm.silent.call("mail.message","mark_all_as_read",[[["model","=",this.model],["res_id","=",this.id],],]);this.message_needaction_counter=0;} 11161async markAsFetched(){await this.store.env.services.orm.silent.call("discuss.channel","channel_fetched",[[this.id],]);} 11162markAsRead(options){const newestPersistentMessage=this.newestPersistentOfAllMessage;if(!newestPersistentMessage&&!this.isLoaded){this.isLoadedDeferred.then(()=>new Promise(setTimeout)).then(()=>this.markAsRead(options));return;} 11163if(this.message_needaction_counter>0){this.markAllMessagesAsRead();}} 11164async notifyAvatarToServer(data){await rpc("/discuss/channel/update_avatar",{channel_id:this.id,data,});} 11165async notifyDescriptionToServer(description){this.description=description;return this.store.env.services.orm.call("discuss.channel","channel_change_description",[[this.id]],{description});} 11166onNewSelfMessage(message){} 11167open(options){return false;} 11168async openChatWindow({focus=false,fromMessagingMenu,bypassCompact,swapOpened}={}){const thread=await this.store.Thread.getOrFetch(this);if(!thread){return;} 11169await this.store.chatHub.initPromise;const cw=this.store.ChatWindow.insert(assignDefined({thread:this},{fromMessagingMenu,bypassCompact}));cw.open({focus,swapOpened});return cw;} 11170async closeChatWindow(options={}){await this.store.chatHub.initPromise;const chatWindow=this.store.ChatWindow.get({thread:this});await chatWindow?.close({notifyState:false,...options});} 11171async rename(name){const newName=name.trim();if(newName!==this.displayName&&((newName&&this.channel_type==="channel")||this.isChatChannel)){if(this.channel_type==="channel"||this.channel_type==="group"){this.name=newName;await this.store.env.services.orm.call("discuss.channel","channel_rename",[[this.id]],{name:newName});}else if(this.supportsCustomChannelName){if(this.self_member_id){this.self_member_id.custom_channel_name=newName;} 11172await this.store.env.services.orm.call("discuss.channel","channel_set_custom_name",[[this.id]],{name:newName});}}} 11173addOrReplaceMessage(message,tmpMsg){if(tmpMsg&&tmpMsg.in(this.messages)&&this.effectiveSelf.eq(message.author)){this.messages.splice(this.messages.indexOf(tmpMsg),1,message);return;} 11174this.messages.add(message);} 11175async post(body,postData={},extraData={}){let tmpMsg;postData.attachments=postData.attachments?[...postData.attachments]:[];const{attachments,parentId}=postData;const params=await this.store.getMessagePostParams({body,postData,thread:this});Object.assign(params,extraData);const tmpId=this.store.getNextTemporaryId();params.context={...user.context,...params.context,temporary_id:tmpId};if(parentId){params.post_data.parent_id=parentId;} 11176if(this.model!=="discuss.channel"){params.thread_id=this.id;params.thread_model=this.model;}else{const tmpData={id:tmpId,attachment_ids:attachments,res_id:this.id,model:"discuss.channel",};if(this.store.self_partner){tmpData.author_id=this.store.self_partner;}else{tmpData.author_guest_id=this.store.self_guest;} 11177if(parentId){tmpData.parent_id=this.store["mail.message"].get(parentId);} 11178tmpMsg=this.store["mail.message"].insert({...tmpData,body:await generateEmojisOnHtml(body),isPending:true,thread:this,});this.messages.push(tmpMsg);this.onNewSelfMessage(tmpMsg);} 11179const data=await this.store.doMessagePost(params,tmpMsg);if(!data){return;} 11180this.store.insert(data.store_data);const message=this.store["mail.message"].get(data.message_id);this.addOrReplaceMessage(message,tmpMsg);this.onNewSelfMessage(message);tmpMsg?.delete();if(message.hasLink&&this.store.hasLinkPreviewFeature){rpc("/mail/link_preview",{message_id:message.id},{silent:true});} 11181return message;} 11182async setMainAttachmentFromIndex(index){this.message_main_attachment_id=this.attachmentsInWebClientView[index];await this.store.env.services.orm.call("ir.attachment","register_as_main_attachment",[this.message_main_attachment_id.id,]);} 11183_enrichMessagesWithTransient(){for(const message of this.transientMessages){if(message.id<this.oldestPersistentMessage&&!this.loadOlder){this.messages.unshift(message);}else if(message.id>this.newestPersistentMessage&&!this.loadNewer){this.messages.push(message);}else{let afterIndex=this.messages.findIndex((msg)=>msg.id>message.id);if(afterIndex===-1){afterIndex=this.messages.length+1;} 11184this.messages.splice(afterIndex-1,0,message);}}} 11185async leaveChannel({force=false}={}){if(this.channel_type!=="group"&&this.create_uid?.eq(this.store.self.main_user_id)&&!force){await this.askLeaveConfirmation(_t("You are the administrator of this channel. Are you sure you want to leave?"));} 11186if(this.channel_type==="group"&&!force){await this.askLeaveConfirmation(_t("You are about to leave this group conversation and will no longer have access to it unless you are invited again. Are you sure you want to continue?"));} 11187await this.closeChatWindow();await this.store.env.services.orm.silent.call("discuss.channel","action_unfollow",[this.id,]);if(this.exists()){this.update({self_member_id:undefined,isLocallyPinned:false,close_chat_window:true,});}} 11188_getActualModelName(){return this.model==="discuss.channel"?"discuss.channel":"mail.thread";}} 11189Thread.register();return __exports;});; 11190 11191/* /mail/static/src/core/common/volume_model.js */ 11192odoo.define('@mail/core/common/volume_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{OR,fields,Record}=require("@mail/core/common/record");const Volume=__exports.Volume=class Volume extends Record{static id=OR("partner_id","guest_id");partner_id=fields.One("res.partner");guest_id=fields.One("mail.guest");get persona(){return this.partner_id||this.guest_id;} 11193volume=1;} 11194Volume.register();return __exports;});; 11195 11196/* /mail/static/src/discuss/core/common/action_panel.js */ 11197odoo.define('@mail/discuss/core/common/action_panel',['@mail/utils/common/format','@odoo/owl','@web/core/resizable_panel/resizable_panel','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{attClassObjectToString}=require("@mail/utils/common/format");const{Component,useSubEnv}=require("@odoo/owl");const{ResizablePanel}=require("@web/core/resizable_panel/resizable_panel");const{useForwardRefToParent,useService}=require("@web/core/utils/hooks");const ActionPanel=__exports.ActionPanel=class ActionPanel extends Component{static template="mail.ActionPanel";static components={ResizablePanel};static props=["contentRef?","icon?","title?","resizable?","slots?","initialWidth?","minWidth?",];static defaultProps={contentPadding:true,resizable:true};setup(){super.setup();this.store=useService("mail.store");this.ui=useService("ui");useForwardRefToParent("contentRef");useSubEnv({inDiscussActionPanel:true});} 11198get classNames(){return attClassObjectToString({"o-mail-ActionPanel overflow-auto o-scrollbar-thin d-flex flex-column flex-shrink-0 position-relative py-2 pt-0 h-100 bg-inherit":true,"o-mail-ActionPanel-chatter":this.env.inChatter,"o-chatWindow":this.env.inChatWindow,"px-2":!this.env.inChatter&&!this.env.inMeetingChat,rounded:!this.props.resizable,});} 11199get minWidth(){return this.props.minWidth;} 11200get initialWidth(){return this.props.initialWidth;}} 11201return __exports;});; 11202 11203/* /mail/static/src/discuss/core/common/attachment_model_patch.js */ 11204odoo.define('@mail/discuss/core/common/attachment_model_patch',['@mail/core/common/attachment_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Attachment}=require("@mail/core/common/attachment_model");const{patch}=require("@web/core/utils/patch");const attachmentPatch={get isDeletable(){if(this.message&&this.thread?.model==="discuss.channel"){return this.message.editable;} 11205return super.isDeletable;},};patch(Attachment.prototype,attachmentPatch);return __exports;});; 11206 11207/* /mail/static/src/discuss/core/common/attachment_panel.js */ 11208odoo.define('@mail/discuss/core/common/attachment_panel',['@mail/core/common/date_section','@mail/discuss/core/common/action_panel','@mail/core/common/attachment_list','@odoo/owl','@web/core/utils/hooks','@mail/utils/common/hooks'],function(require){'use strict';let __exports={};const{DateSection}=require("@mail/core/common/date_section");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{AttachmentList}=require("@mail/core/common/attachment_list");const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{useSequential,useVisible}=require("@mail/utils/common/hooks");const AttachmentPanel=__exports.AttachmentPanel=class AttachmentPanel extends Component{static components={ActionPanel,AttachmentList,DateSection};static props=["thread"];static template="mail.AttachmentPanel";setup(){super.setup();this.sequential=useSequential();this.store=useService("mail.store");this.ormService=useService("orm");this.attachmentUploadService=useService("mail.attachment_upload");onWillStart(()=>{this.props.thread.fetchMoreAttachments();});onWillUpdateProps((nextProps)=>
11208{if(nextProps.thread.notEq(this.props.thread)){nextProps.thread.fetchMoreAttachments();}});useVisible("load-older",(isVisible)=>{if(isVisible){this.props.thread.fetchMoreAttachments();}});} 11209get attachmentsByDate(){const attachmentsByDate={};for(const attachment of this.props.thread.attachments){const attachments=attachmentsByDate[attachment.monthYear]??[];attachments.push(attachment);attachmentsByDate[attachment.monthYear]=attachments;} 11210return attachmentsByDate;}} 11211return __exports;});; 11212 11213/* /mail/static/src/discuss/core/common/avatar_stack.js */ 11214odoo.define('@mail/discuss/core/common/avatar_stack',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const AvatarStack=__exports.AvatarStack=class AvatarStack extends Component{static template="mail.AvatarStack";static props={containerClass:{type:String,optional:true},direction:{type:String,optional:true,validate:(d)=>["v","h"].includes(d)},avatarClass:{type:Function,optional:true},max:{type:Number,optional:true},onClick:{type:Function,optional:true},personas:Array,size:{type:Number,optional:true},slots:{optional:true},};static defaultProps={avatarClass:()=>"",onClick:()=>{},max:4,size:24,direction:"h",};getStyle(index){const styles=["box-sizing: content-box",`height: ${this.props.size}px`,"margin: 1px",`padding: 1.5px`,`width: ${this.props.size}px`,`z-index: ${this.props.personas.length - index}`,];if(index!==0){const marginDirection=this.props.direction==="v"?"top":"left";styles.push(`margin-${marginDirection}: -${this.props.size / 4.5}px`);} 11215return styles.join(";");}} 11216return __exports;});; 11217 11218/* /mail/static/src/discuss/core/common/channel_commands.js */ 11219odoo.define('@mail/discuss/core/common/channel_commands',['@web/core/l10n/translation','@web/core/registry'],function(require){'use strict';let __exports={};const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const commandRegistry=registry.category("discuss.channel_commands");commandRegistry.add("help",{condition:({store,thread})=>store.self_partner&&!store.self.main_user_id.share,help:_t("Show a helper message"),methodName:"execute_command_help",}).add("leave",{condition:({store,thread})=>store.self_partner&&!store.self.main_user_id.share,help:_t("Leave this channel"),methodName:"execute_command_leave",}).add("who",{condition:({store,thread})=>store.self_partner&&!store.self.main_user_id.share,channel_types:["channel","chat","group"],help:_t("List users in the current channel"),methodName:"execute_command_who",});return __exports;});; 11220 11221/* /mail/static/src/discuss/core/common/channel_invitation.js */ 11222odoo.define('@mail/discuss/core/common/channel_invitation',['@mail/core/common/im_status','@mail/discuss/core/common/action_panel','@odoo/owl','@mail/utils/common/hooks','@web/core/l10n/translation','@web/core/utils/hooks','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{ImStatus}=require("@mail/core/common/im_status");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{Component,onWillStart,useState}=require("@odoo/owl");const{useSequential}=require("@mail/utils/common/hooks");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useAutofocus,useService}=require("@web/core/utils/hooks");const{useDebounced}=require("@web/core/utils/timing");const ChannelInvitation=__exports.ChannelInvitation=class ChannelInvitation extends Component{static components={ImStatus,ActionPanel};static defaultProps={hasSizeConstraints:false};static props=["autofocus?","hasSizeConstraints?","thread?","close?","className?","state?",];static template="discuss.ChannelInvitation";setup(){super.setup();this.orm=useService("orm");this.store=useService("mail.store");this.rtc=useService("discuss.rtc");this.notification=useService("notification");this.suggestionService=useService("mail.suggestion");this.sequential=useSequential();this.state=useState({searchResultCount:0,searchStr:"",selectableEmails:[],selectablePartners:[],selectedEmails:[],selectedPartners:[],sentEmails:new Set(),});this.debouncedFetchPartnersToInvite=useDebounced(this.fetchPartnersToInvite.bind(this),250);this.inputRef=useAutofocus({refName:"input"});onWillStart(()=>{if(this.store.self_partner){this.fetchPartnersToInvite();}});} 11223get selectablePartners(){return this.props.state?.selectablePartners??this.state.selectablePartners;} 11224set selectablePartners(partners){if(this.props.state?.selectablePartners){this.props.state.selectablePartners=partners;}else{this.state.selectablePartners=partners;}} 11225get selectedPartners(){return this.props.state?.selectedPartners??this.state.selectedPartners;} 11226set selectedPartners(partners){if(this.props.state?.selectedPartners){this.props.state.selectedPartners=partners;}else{this.state.selectedPartners=partners;}} 11227get searchStr(){return this.props.state?.searchStr??this.state.searchStr;} 11228set searchStr(newSearchStr){if(this.props.state?.searchStr!==undefined){this.props.state.searchStr=newSearchStr;}else{this.state.searchStr=newSearchStr;}} 11229get showingResultNarrowText(){return _t("Showing %(result_count)s results out of %(total_count)s. Narrow your search to see more choices.",{result_count:this.selectablePartners.length,total_count:this.state.searchResultCount,});} 11230get searchPlaceholder(){if(this.props.thread?.allow_invite_by_email){return _t("Invite people or email");} 11231return _t("Search people to invite");} 11232async fetchPartnersToInvite(){const results=await this.sequential(()=>this.orm.call("res.partner","search_for_channel_invite",[this.searchStr,this.props.thread?.id??false,]));if(!results){return;} 11233this.store.insert(results.store_data);const selectablePartners=results.partner_ids.map((id)=>this.store["res.partner"].get(id));this.selectablePartners=this.suggestionService.sortPartnerSuggestions(selectablePartners,this.searchStr,this.props.thread);this.state.searchResultCount=results["count"];const selectableEmails=this.state.selectedEmails.filter((addr)=>addr.includes(this.searchStr));if(results.selectable_email){selectableEmails.push(results.selectable_email);} 11234if(results.email_already_sent){this.state.sentEmails.add(results.selectable_email);} 11235this.state.selectableEmails=[...new Set(selectableEmails)];} 11236onInput(){this.searchStr=this.inputRef.el.value;this.debouncedFetchPartnersToInvite();} 11237onClickSelectablePartner(partner){if(partner.in(this.selectedPartners)){const index=this.selectedPartners.indexOf(partner);if(index!==-1){this.selectedPartners.splice(index,1);} 11238return;} 11239this.selectedPartners.push(partner);} 11240onClickSelectableEmail(email){const index=this.state.selectedEmails.indexOf(email);if(index!==-1){this.state.selectedEmails.splice(index,1);return;} 11241this.state.selectedEmails.push(email);} 11242onClickSelectedPartner(partner){const index=this.selectedPartners.indexOf(partner);this.selectedPartners.splice(index,1);} 11243onClickSelectedEmail(email){const index=this.state.selectedEmails.indexOf(email);this.state.selectedEmails.splice(index,1);} 11244onFocusInvitationLinkInput(ev){ev.target.select();} 11245async onClickCopy(ev){let notification=_t("Invitation link copied!");let type="success";const clipboard=this.env.inDiscussCallView?.isPip?this.rtc.pipService.pipWindow?.navigator.clipboard:navigator.clipboard;try{await clipboard.writeText(this.props.thread.invitationLink);}catch{notification=_t("Invitation link copy failed (Permission denied?)!");type="danger";} 11246this.notification.add(notification,{type});} 11247async onClickInvite(){if(this.props.thread.channel_type==="chat"){const partnerIds=this.selectedPartners.map((partner)=>partner.id);if(this.props.thread.correspondent?.partner_id){partnerIds.unshift(this.props.thread.correspondent.partner_id.id);} 11248await this.store.startChat(partnerIds);this.props.close?.();return;} 11249const invitePromises=[];if(this.selectedPartners.length){invitePromises.push(this.orm.call("discuss.channel","add_members",[[this.props.thread.id]],{partner_ids:this.selectedPartners.map((partner)=>partner.id),invite_to_rtc_call:this.rtc.state.channel?.eq(this.props.thread),}));} 11250if(this.state.selectedEmails.length){invitePromises.push(this.orm.call("discuss.channel","invite_by_email",[this.props.thread.id],{emails:this.state.selectedEmails,}));} 11251await Promise.all(invitePromises);this.state.selectedEmails=[];this.state.selectedPartners=[];this.props.close?.();} 11252get invitationButtonText(){if(!this.props.thread){return"";} 11253if(this.props.thread.channel_type==="channel"){return _t("Invite");}else if(this.props.thread.channel_type==="group"){return _t("Invite to Group Chat");}else if(this.props.thread.channel_type==="chat"){if(this.props.thread.correspondent?.persona.eq(this.store.self)){if(this.selectedPartners.length===0){return _t("Invite");} 11254if(this.selectedPartners.length===1){const alreadyChat=Object.values(this.store.Thread.records).some((thread)=>thread.channel_type==="chat"&&thread.correspondent?.partner_id?.eq(this.selectedPartners[0]));if(alreadyChat){return _t("Go to conversation");} 11255return _t("Start a Conversation");}} 11256return _t("Create Group Chat");} 11257return _t("Invite");}} 11258return __exports;});; 11259 11260/* /mail/static/src/discuss/core/common/channel_member_list.js */ 11261odoo.define('@mail/discuss/core/common/channel_member_list',['@mail/core/common/im_status','@mail/discuss/core/common/action_panel','@odoo/owl','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{ImStatus}=require("@mail/core/common/im_status");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{Component,onWillUpdateProps,onWillStart}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const ChannelMemberList=__exports.ChannelMemberList=class ChannelMemberList extends Component{static components={ImStatus,ActionPanel};static props=["thread","openChannelInvitePanel","className?"];static template="discuss.ChannelMemberList";setup(){super.setup();this.store=useService("mail.store");onWillStart(()=>{if(this.props.thread.fetchMembersState==="not_fetched"){this.props.thread.fetchChannelMembers();}});onWillUpdateProps((nextProps)=>
11261{if(nextProps.thread.fetchMembersState==="not_fetched"){nextProps.thread.fetchChannelMembers();}});} 11262get onlineSectionText(){return _t("Online - %(online_count)s",{online_count:this.props.thread.onlineMembers.length,});} 11263get offlineSectionText(){return _t("Offline - %(offline_count)s",{offline_count:this.props.thread.offlineMembers.length,});} 11264canOpenChatWith(member){return!this.store.inPublicPage&&!member.guest_id&&member.persona.main_user_id;} 11265onClickAvatar(ev,member){if(!this.canOpenChatWith(member)){return;} 11266this.store.openChat({partnerId:member.partner_id.id});}} 11267return __exports;});; 11268 11269/* /mail/static/src/discuss/core/common/channel_member_model.js */ 11270odoo.define('@mail/discuss/core/common/channel_member_model',['@mail/core/common/store_service','@mail/core/common/record','@web/core/browser/browser','@web/core/l10n/dates','@web/core/user'],function(require){'use strict';let __exports={};const{Store}=require("@mail/core/common/store_service");const{fields,Record}=require("@mail/core/common/record");const{browser}=require("@web/core/browser/browser");const{deserializeDateTime}=require("@web/core/l10n/dates");const{user}=require("@web/core/user");const{DateTime}=luxon;const ChannelMember=__exports.ChannelMember=class ChannelMember extends Record{static _name="discuss.channel.member";static id="id";create_date;custom_channel_name;custom_notifications;id;is_pinned=fields.Attr(undefined,{compute(){return(!this.unpin_dt||(this.last_interest_dt&&this.last_interest_dt>=this.unpin_dt)||(this.channel_id?.last_interest_dt&&this.channel_id?.last_interest_dt>=this.unpin_dt));},onUpdate(){this.channel_id?.onPinStateUpdated();},});last_interest_dt=fields.Datetime();last_seen_dt=fields.Datetime();guest_id=fields.One("mail.guest");partner_id=fields.One("res.partner");get persona(){return this.partner_id||this.guest_id;} 11271channel_id=fields.One("Thread",{inverse:"channel_member_ids"});threadAsSelf=fields.One("Thread",{compute(){if(this.store.self?.eq(this.persona)){return this.channel_id;}},});fetched_message_id=fields.One("mail.message");seen_message_id=fields.One("mail.message");hideUnreadBanner=false;message_unread_counter=fields.Attr(0,{onUpdate(){if(this.message_unread_counter===0||!this.channel_id?.isDisplayed||this.channel_id?.scrollTop!=="bottom"||this.channel_id.markedAsUnread||!this.channel_id.isFocused){this.message_unread_counter_ui=this.message_unread_counter;}},});message_unread_counter_ui=0;message_unread_counter_bus_id=0;mute_until_dt=fields.Datetime();new_message_separator=fields.Attr(null,{onUpdate(){if(!this.channel_id?.isDisplayed){this.new_message_separator_ui=this.new_message_separator;}},});new_message_separator_ui=null;isTyping=fields.Attr(false,{onUpdate(){browser.clearTimeout(this.typingTimeoutId);if(this.isTyping){this.registerTypingTimeout();}},});is_typing_dt=fields.Datetime({onUpdate(){browser.clearTimeout(this.typingTimeoutId);if(!this.is_typing_dt||DateTime.now().diff(this.is_typing_dt).milliseconds>Store.OTHER_LONG_TYPING){this.isTyping=false;} 11272if(this.isTyping){this.registerTypingTimeout();}},});registerTypingTimeout(){this.typingTimeoutId=browser.setTimeout(()=>(this.isTyping=false),Store.OTHER_LONG_TYPING);} 11273threadAsTyping=fields.One("Thread",{compute(){return this.isTyping?this.channel_id:undefined;},eager:true,onDelete(){browser.clearTimeout(this.typingTimeoutId);},});typingTimeoutId;unpin_dt=fields.Datetime();get name(){if(this.guest_id){return this.guest_id.name;} 11274return this.channel_id.getPersonaName(this.partner_id);} 11275get avatarUrl(){return this.partner_id?.avatarUrl||this.guest_id?.avatarUrl;} 11276get im_status(){return this.partner_id?.im_status||this.guest_id?.im_status;} 11277getLangName(){return this.persona.lang_name;} 11278get memberSince(){return this.create_date?deserializeDateTime(this.create_date):undefined;} 11279hasSeen(message){return this.persona.eq(message.author)||this.seen_message_id?.id>=message.id;} 11280get lastSeenDt(){return this.last_seen_dt?this.last_seen_dt.toLocaleString(DateTime.TIME_24_SIMPLE,{locale:user.lang,}):undefined;}} 11281ChannelMember.register();return __exports;});; 11282 11283/* /mail/static/src/discuss/core/common/delete_thread_dialog.js */ 11284odoo.define('@mail/discuss/core/common/delete_thread_dialog',['@mail/discuss/core/common/action_panel','@odoo/owl','@web/core/network/rpc','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{Component}=require("@odoo/owl");const{rpc}=require("@web/core/network/rpc");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const DeleteThreadDialog=__exports.DeleteThreadDialog=class DeleteThreadDialog extends Component{static components={ActionPanel};static props=["thread","close"];static template="discuss.DeleteThreadDialog";setup(){super.setup();this.store=useService("mail.store");} 11285async onConfirmation(){let toOpenThread;const threadName=this.props.thread.name;if(this.store.discuss?.thread?.eq(this.props.thread)||this.env.inChatWindow){toOpenThread=this.props.thread.parent_channel_id;} 11286await rpc("/discuss/channel/sub_channel/delete",{sub_channel_id:this.props.thread.id,});if(toOpenThread?.exists()){toOpenThread.open();} 11287this.props.close();this.env.services.notification.add(_t('Thread "%(thread_name)s" has been deleted',{thread_name:threadName}),{type:"info"});}} 11288return __exports;});; 11289 11290/* /mail/static/src/discuss/core/common/discuss_core_common_service.js */ 11291odoo.define('@mail/discuss/core/common/discuss_core_common_service',['@odoo/owl','@web/core/registry'],function(require){'use strict';let __exports={};const{markup,reactive}=require("@odoo/owl");const{registry}=require("@web/core/registry");const DiscussCoreCommon=__exports.DiscussCoreCommon=class DiscussCoreCommon{constructor(env,services){this.busService=services.bus_service;this.env=env;this.notificationService=services.notification;this.orm=services.orm;this.presence=services.presence;this.store=services["mail.store"];} 11292setup(){this.busService.subscribe("discuss.channel/delete",(payload,metadata)=>{const thread=this.store.Thread.insert({id:payload.id,model:"discuss.channel",});this._handleNotificationChannelDelete(thread,metadata);});this.busService.subscribe("discuss.channel/new_message",(payload,metadata)=>{this.store.insert(payload.data);this._handleNotificationNewMessage(payload,metadata);});this.busService.subscribe("discuss.channel/transient_message",(payload)=>{const{body,channel_id}=payload;const lastMessageId=this.store.getLastMessageId();const message=this.store["mail.message"].insert({author_id:this.store.odoobot,body:markup(body),id:lastMessageId+0.01,subtype_id:this.store.mt_note,is_transient:true,thread:{id:ch
11292annel_id,model:"discuss.channel"},});message.thread.messages.push(message);message.thread.transientMessages.push(message);});this.busService.subscribe("discuss.channel.member/fetched",(payload)=>{const{channel_id,id,last_message_id,partner_id}=payload;this.store["discuss.channel.member"].insert({id,fetched_message_id:{id:last_message_id},partner_id:{id:partner_id},thread:{id:channel_id,model:"discuss.channel"},});});this.env.bus.addEventListener("mail.message/delete",({detail:{message,notifId}})=>{if(message.thread){const{self_member_id}=message.thread;if(self_member_id&&message.id>(self_member_id.seen_message_id?.id??0)&¬ifId>self_member_id.message_unread_counter_bus_id){self_member_id.message_unread_counter--;}}});} 11293async _handleNotificationChannelDelete(thread,metadata){await thread.closeChatWindow({force:true});thread.messages.splice(0,thread.messages.length);thread.delete();} 11294async _handleNotificationNewMessage(payload,{id:notifId}){const{data,id:channelId,silent,temporary_id}=payload;const channel=await this.store.Thread.getOrFetch({model:"discuss.channel",id:channelId,});if(!channel){return;} 11295const message=this.store["mail.message"].get(data["mail.message"][0]);if(!message){return;} 11296if(message.notIn(channel.messages)){if(!channel.loadNewer){channel.addOrReplaceMessage(message,this.store["mail.message"].get(temporary_id));}else if(channel.status==="loading"){channel.pendingNewMessages.push(message);} 11297if(message.isSelfAuthored){channel.onNewSelfMessage(message);}else{if(channel.isDisplayed&&channel.self_member_id?.new_message_separator_ui===0){channel.self_member_id.new_message_separator_ui=message.id;} 11298if(!channel.isDisplayed&&channel.self_member_id){channel.scrollUnread=true;} 11299if(notifId>channel.self_member_id?.message_unread_counter_bus_id&&!message.isNotification){channel.self_member_id.message_unread_counter++;}}} 11300if(channel.channel_type!=="channel"&&this.store.self_partner&&channel.self_member_id){channel.markAsFetched();} 11301if(!channel.loadNewer&&!message.isSelfAuthored&&channel.scrollTop==="bottom"&&channel.composer.isFocused&&this.store.self_partner&&channel.newestPersistentMessage?.eq(channel.newestMessage)&&!channel.markedAsUnread){channel.markAsRead();} 11302this.env.bus.trigger("discuss.channel/new_message",{channel,message,silent});const authorMember=channel.channel_member_ids.find((member)=>member.persona?.eq(message.author));if(authorMember){authorMember.seen_message_id=message;}}} 11303const discussCoreCommon=__exports.discussCoreCommon={dependencies:["bus_service","mail.out_of_focus","mail.store","notification","orm","presence",],start(env,services){const discussCoreCommon=reactive(new Discu
11303ssCoreCommon(env,services));discussCoreCommon.setup(env,services);return discussCoreCommon;},};registry.category("services").add("discuss.core.common",discussCoreCommon);return __exports;});; 11304 11305/* /mail/static/src/discuss/core/common/discuss_notification_settings.js */ 11306odoo.define('@mail/discuss/core/common/discuss_notification_settings',['@mail/core/common/settings_model','@odoo/owl','@web/core/browser/browser','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{MESSAGE_SOUND}=require("@mail/core/common/settings_model");const{Component,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{useService}=require("@web/core/utils/hooks");const DiscussNotificationSettings=__exports.DiscussNotificationSettings=class DiscussNotificationSettings extends Component{static props={};static template="mail.DiscussNotificationSettings";setup(){this.store=useService("mail.store");this.state=useState({selectedDuration:false,});} 11307onChangeMessageSound(){if(this.store.settings.messageSound){this.disableMessageSound();}else{this.enableMessageSound();}} 11308enableMessageSound(){browser.localStorage.removeItem(MESSAGE_SOUND);this.store.settings._recomputeMessageSound++;} 11309disableMessageSound(){browser.localStorage.setItem(MESSAGE_SOUND,false);this.store.settings._recomputeMessageSound++;}} 11310return __exports;});; 11311 11312/* /mail/static/src/discuss/core/common/discuss_notification_settings_client_action.js */ 11313odoo.define('@mail/discuss/core/common/discuss_notification_settings_client_action',['@odoo/owl','@web/core/registry','@mail/discuss/core/common/discuss_notification_settings'],function(require){'use strict';let __exports={};const{Component,xml}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{DiscussNotificationSettings}=require("@mail/discuss/core/common/discuss_notification_settings");const DiscussNotificationSettingsClientAction=__exports.DiscussNotificationSettingsClientAction=class DiscussNotificationSettingsClientAction extends Component{static components={DiscussNotificationSettings};static props=["*"];static template=xml` 11314 <div class="o-mail-DiscussNotificationSettingsClientAction mx-3 my-2"> 11315 <DiscussNotificationSettings/> 11316 </div> 11317 `;} 11318registry.category("actions").add("mail.discuss_notification_settings_action",DiscussNotificationSettingsClientAction);return __exports;});; 11319 11320/* /mail/static/src/discuss/core/common/mail_guest_model_patch.js */ 11321odoo.define('@mail/discuss/core/common/mail_guest_model_patch',['@mail/core/common/mail_guest_model','@mail/core/common/record','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{MailGuest}=require("@mail/core/common/mail_guest_model");const{fields}=require("@mail/core/common/record");const{patch}=require("@web/core/utils/patch");const mailGuestPatch={setup(){super.setup();this.channelMembers=fields.Many("discuss.channel.member");},};patch(MailGuest.prototype,mailGuestPatch);return __exports;});; 11322 11323/* /mail/static/src/discuss/core/common/message_actions.js */ 11324odoo.define('@mail/discuss/core/common/message_actions',['@mail/core/common/message_actions','@odoo/owl','@web/core/l10n/translation','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{registerMessageAction}=require("@mail/core/common/message_actions");const{toRaw}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{rpc}=require("@web/core/network/rpc");registerMessageAction("set-new-message-separator",{condition:({message,thread})=>thread&&thread.self_member_id&&thread.eq(message.thread)&&!message.hasNewMessageSeparator&&message.persistent,icon:"fa fa-eye-slash",name:_t("Mark as Unread"),onSelected:({message:msg})=>{const message=toRaw(msg);const selfMember=message.thread?.self_member_id;if(selfMember){selfMember.new_message_separator=message.id;selfMember.new_message_separator_ui=selfMember.new_message_separator;} 11325message.thread.markedAsUnread=true;rpc("/discuss/channel/set_new_message_separator",{channel_id:message.thread.id,message_id:message.id,});},sequence:70,});return __exports;});; 11326 11327/* /mail/static/src/discuss/core/common/message_model_patch.js */ 11328odoo.define('@mail/discuss/core/common/message_model_patch',['@mail/core/common/message_model','@mail/core/common/record','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message_model");const{fields}=require("@mail/core/common/record");const{patch}=require("@web/core/utils/patch");const messagePatch={setup(){super.setup();this.hasEveryoneSeen=fields.Attr(false,{compute(){return this.thread?.membersThatCanSeen.every((m)=>m.hasSeen(this));},});this.hasNewMessageSeparator=fields.Attr(false,{compute(){return this.thread?.self_member_id?.new_message_separator===this.id;},});this.hasSomeoneFetched=fields.Attr(false,{compute(){return this.thread?.channel_member_ids.some((m)=>m.persona.notEq(this.author)&&m.fetched_message_id?.id>=this.id);},});this.hasSomeoneSeen=fields.Attr(false,{compute(){return this.thread?.membersThatCanSeen.filter((member)=>member.persona.notEq(this.author)).some((m)=>m.hasSeen(this));},});this.isMessagePreviousToLastSelfMessageSeenByEveryone=fields.Attr(false,{compute(){if(!this.thread?.lastSelfMessageSeenByEveryone){return false;} 11329return this.id<this.thread.lastSelfMessageSeenByEveryone.id;},});this.mentionedChannelPromises=[];this.threadAsFirstUnread=fields.One("Thread",{inverse:"firstUnreadMessage"});},get channelMemberHaveSeen(){return this.thread.membersThatCanSeen.filter((m)=>m.hasSeen(this)&&m.persona.notEq(this.author));},async edit(body,attachments=[],{mentionedChannels=[],mentionedPartners=[],mentionedRoles=[]}={}){return await super.edit(body,attachments,{mentionedChannels,mentionedPartners,mentionedRoles,});},};patch(Message.prototype,messagePatch);return __exports;});; 11330 11331/* /mail/static/src/discuss/core/common/message_patch.js */ 11332odoo.define('@mail/discuss/core/common/message_patch',['@mail/core/common/message','@mail/discuss/core/common/message_seen_indicator','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message");const{MessageSeenIndicator}=require("@mail/discuss/core/common/message_seen_indicator");const{patch}=require("@web/core/utils/patch");Message.components={...Message.components,MessageSeenIndicator};const messagePatch={get showSeenIndicator(){return this.props.message.isSelfAuthored&&this.props.thread?.hasSeenFeature;},};patch(Message.prototype,messagePatch);return __exports;});; 11333 11334/* /mail/static/src/discuss/core/common/message_seen_indicator.js */ 11335odoo.define('@mail/discuss/core/common/message_seen_indicator',['@odoo/owl','@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/utils/hooks','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{Component,useExternalListener,useRef}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{browser}=require("@web/core/browser/browser");class MessageSeenIndicatorDialog extends Component{static components={Dialog};static template="mail.MessageSeenIndicatorDialog";static props=["message","close?"];setup(){super.setup();this.contentRef=useRef("content");useExternalListener(browser,"click",(ev)=>{if(!this.contentRef?.el.contains(ev.target)){this.props.close();}},true);}} 11336const MessageSeenIndicator=__exports.MessageSeenIndicator=class MessageSeenIndicator extends Component{static template="mail.MessageSeenIndicator";static props=["message","thread","className?"];setup(){super.setup();this.dialog=useService("dialog");}
11337get summary(){if(this.props.message.hasEveryoneSeen){if(this.props.thread.correspondent&&this.props.thread.channel_member_ids.length===2){return _t("Seen by %(user)s",{user:this.props.thread.correspondent.name});} 11338return _t("Seen by everyone");} 11339const seenMembers=this.props.message.channelMemberHaveSeen;const[user1,user2,user3]=seenMembers.map((member)=>member.name);switch(seenMembers.length){case 0:return _t("Sent");case 1:return _t("Seen by %(user)s",{user:user1});case 2:return _t("Seen by %(user1)s and %(user2)s",{user1,user2});case 3:return _t("Seen by %(user1)s, %(user2)s and %(user3)s",{user1,user2,user3});case 4:return _t("Seen by %(user1)s, %(user2)s, %(user3)s and 1 other",{user1,user2,user3,});default:return _t("Seen by %(user1)s, %(user2)s, %(user3)s and %(count)s others",{user1,user2,user3,count:seenMembers.length-3,});}} 11340openDialog(){if(this.props.message.channelMemberHaveSeen.length===0){return;} 11341this.dialog.add(MessageSeenIndicatorDialog,{message:this.props.message});}} 11342return __exports;});; 11343 11344/* /mail/static/src/discuss/core/common/notification_settings.js */ 11345odoo.define('@mail/discuss/core/common/notification_settings',['@odoo/owl','@mail/discuss/core/common/action_panel','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/utils/hooks','@mail/discuss/core/common/discuss_notification_settings_client_action','@web/core/dialog/dialog'],function(require){'use strict';let __exports={};const{Component,xml}=require("@odoo/owl");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{useService}=require("@web/core/utils/hooks");const{DiscussNotificationSettingsClientAction}=require("@mail/discuss/core/common/discuss_notification_settings_client_action");const{Dialog}=require("@web/core/dialog/dialog");class NotificationDialog extends Component{static props=["close?"];static components={Dialog,DiscussNotificationSettingsClientAction};static template=xml` 11346 <Dialog size="'md'" footer="false"> 11347 <DiscussNotificationSettingsClientAction/> 11348 </Dialog> 11349 `;} 11350const NotificationSettings=__exports.NotificationSettings=class NotificationSettings extends Component{static components={ActionPanel,Dropdown,DropdownItem};static props=["hasSizeConstraints?","thread","close?","className?"];static template="discuss.NotificationSettings";setup(){this.store=useService("mail.store");this.dialog=useService("dialog");this.ui=useService("ui");} 11351setMute(minutes){this.store.settings.setMuteDuration(minutes,this.props.thread);this.props.close?.();} 11352onClickAllConversationsMuted(){this.dialog.add(NotificationDialog);}} 11353return __exports;});; 11354 11355/* /mail/static/src/discuss/core/common/partner_compare.js */ 11356odoo.define('@mail/discuss/core/common/partner_compare',['@mail/core/common/partner_compare'],function(require){'use strict';let __exports={};const{partnerCompareRegistry}=require("@mail/core/common/partner_compare");partnerCompareRegistry.add("discuss.recent-chats",(p1,p2,{env,context})=>{const recentChatPartnerIds=context.recentChatPartnerIds||env.services["mail.store"].getRecentChatPartnerIds();const recentChatIndex_p1=recentChatPartnerIds.findIndex((partnerId)=>partnerId===p1.id);const recentChatIndex_p2=recentChatPartnerIds.findIndex((partnerId)=>partnerId===p2.id);if(recentChatIndex_p1!==-1&&recentChatIndex_p2===-1){return-1;}else if(recentChatIndex_p1===-1&&recentChatIndex_p2!==-1){return 1;}else if(recentChatIndex_p1<recentChatIndex_p2){return-1;}else if(recentChatIndex_p1>recentChatIndex_p2){return 1;}},{sequence:45});partnerCompareRegistry.add("discuss.members",(p1,p2,{thread,context:{memberPartnerIds}})=>{if(thread?.model==="discuss.channel"){const isMember1=memberPartnerIds.has(p1.id);const isMember2=memberPartnerIds.has(p2.id);if(isMember1&&!isMember2){return-1;} 11357if(!isMember1&&isMember2){return 1;}}},{sequence:40});return __exports;});; 11358 11359/* /mail/static/src/discuss/core/common/res_partner_model_patch.js */ 11360odoo.define('@mail/discuss/core/common/res_partner_model_patch',['@mail/core/common/res_partner_model','@mail/core/common/record','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ResPartner}=require("@mail/core/common/res_partner_model");const{fields}=require("@mail/core/common/record");const{patch}=require("@web/core/utils/patch");const resPartnerPatch={setup(){super.setup();this.channelMembers=fields.Many("discuss.channel.member");},};patch(ResPartner.prototype,resPartnerPatch);return __exports;});; 11361 11362/* /mail/static/src/discuss/core/common/store_service_patch.js */ 11363odoo.define('@mail/discuss/core/common/store_service_patch',['@mail/core/common/store_service','@mail/utils/common/misc','@web/core/utils/patch','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Store}=require("@mail/core/common/store_service");const{compareDatetime}=require("@mail/utils/common/misc");const{patch}=require("@web/core/utils/patch");const{debounce}=require("@web/core/utils/timing");const storeServicePatch={setup(){super.setup();this.channelIdsFetchingDeferred=new Map();this.channel_types_with_seen_infos=[];this.updateBusSubscription=debounce(()=>this.env.services.bus_service.forceUpdateChannels(),0);},get onlineMemberStatuses(){return["away","bot","busy","online"];},async createGroupChat({default_display_mode,partners_to,name}){const{channel}=await this.fetchStoreData("/discuss/create_group",{default_display_mode,partners_to,name},{readonly:false,requestData:true});await channel.open({focus:true});return channel;},async fetchChannel(channelId){const fetchParam=this.fetchParams.find(([name])=>name==="discuss.channel");
11363if(fetchParam){const[,channelIds,dataRequest]=fetchParam;channelIds.push(channelId);await dataRequest._resultDef;}else{await this.fetchStoreData("discuss.channel",[channelId]);}},getRecentChatPartnerIds(){return Object.values(this.Thread.records).filter((thread)=>thread.channel_type==="chat"&&thread.correspondent?.partner_id).sort((a,b)=>compareDatetime(b.lastInterestDt,a.lastInterestDt)||b.id-a.id).map((thread)=>thread.correspondent.partner_id.id);},sortMembers(m1,m2){return m1.name?.localeCompare(m2.name)||m1.id-m2.id;},async startChat(partnerIds){const partners_to=[...new Set([this.self.id,...partnerIds])];if(partners_to.length===1){const chat=await this.joinChat(partners_to[0],true);chat.open({focus:true,bypassCompact:true});}else if(partners_to.length===2){const correspondentId=partners_to.find((partnerId)=>partnerId!==this.store.self.id);const chat=await this.joinChat(correspondentId,true);chat.open({focus:true,bypassCompact:true});}else{await this.createGroupChat({partners_to});}},};patch(Store.prototype,storeServicePatch);return __exports;});; 11364 11365/* /mail/static/src/discuss/core/common/suggestion_service_patch.js */ 11366odoo.define('@mail/discuss/core/common/suggestion_service_patch',['@mail/core/common/suggestion_service','@mail/utils/common/format','@web/core/registry','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{SuggestionService}=require("@mail/core/common/suggestion_service");const{cleanTerm}=require("@mail/utils/common/format");const{registry}=require("@web/core/registry");const{patch}=require("@web/core/utils/patch");const commandRegistry=registry.category("discuss.channel_commands");const suggestionServicePatch={getChannelCommands(thread){if(!thread||thread.model!=="discuss.channel"){return[];} 11367return commandRegistry.getEntries().map(([name,command])=>({channel_types:command.channel_types,condition:command.condition,help:command.help,id:command.id,name,})).filter(({condition,channel_types})=>{const passesCondition=!condition||condition({store:this.store,thread});const passesChannelType=!channel_types||channel_types.includes(thread.channel_type);return passesCondition&&passesChannelType;});},getSupportedDelimiters(thread,env){const res=super.getSupportedDelimiters(...arguments);return thread?.model==="discuss.channel"?[...res,["/",0]]:res;},isSuggestionValid(partner,thread){if(thread?.model==="discuss.channel"&&partner.eq(this.store.odoobot)){return true;} 11368return super.isSuggestionValid(...arguments);},getPartnerSuggestions(thread){const isNonPublicChannel=thread&&(thread.channel_type==="group"||thread.channel_type==="chat"||(thread.channel_type==="channel"&&(thread.parent_channel_id||thread).group_public_id));if(isNonPublicChannel){const partnersById=new Map([...thread.channel_member_ids,...(thread.parent_channel_id?.channel_member_ids??[]),].filter((m)=>m.partner_id).map((m)=>[m.partner_id.id,m.partner_id]));if(thread.channel_type==="channel"){const group=(thread.parent_channel_id||thread).group_public_id;group.partners.forEach((partner)=>partnersById.set(partner.id,partner));} 11369return Array.from(partnersById.values());}else{return super.getPartnerSuggestions(...arguments);}},searchSuggestions({delimiter,term},{thread}={}){if(delimiter==="/"){return this.searchChannelCommand(cleanTerm(term),thread);} 11370return super.searchSuggestions(...arguments);},searchChannelCommand(cleanedSearchTerm,thread){if(!thread.model==="discuss.channel"){return;} 11371const commands=this.getChannelCommands(thread).filter(({name})=>cleanTerm(name).includes(cleanedSearchTerm));const sortFunc=(c1,c2)=>{if(c1.channel_types&&!c2.channel_types){return-1;} 11372if(!c1.channel_types&&c2.channel_types){return 1;} 11373const cleanedName1=cleanTerm(c1.name);const cleanedName2=cleanTerm(c2.name);if(cleanedName1.startsWith(cleanedSearchTerm)&&!cleanedName2.startsWith(cleanedSearchTerm)){return-1;} 11374if(!cleanedName1.startsWith(cleanedSearchTerm)&&cleanedName2.startsWith(cleanedSearchTerm)){return 1;} 11375if(cleanedName1<cleanedName2){return-1;} 11376if(cleanedName1>cleanedName2){return 1;} 11377return c1.id-c2.id;};return{type:"ChannelCommand",suggestions:commands.sort(sortFunc),};},sortPartnerSuggestionsContext(thread){return Object.assign(super.sortPartnerSuggestionsContext(),{recentChatPartnerIds:this.store.getRecentChatPartnerIds(),memberPartnerIds:new Set(thread?.channel_member_ids.filter((member)=>member.partner_id).map((member)=>member.partner_id.id)),});},};patch(SuggestionService.prototype,suggestionServicePatch);return __exports;});; 11378 11379/* /mail/static/src/discuss/core/common/thread_actions.js */ 11380odoo.define('@mail/discuss/core/common/thread_actions',['@mail/core/common/action','@mail/core/common/thread_actions','@mail/discuss/core/common/attachment_panel','@mail/discuss/core/common/channel_invitation','@mail/discuss/core/common/delete_thread_dialog','@mail/discuss/core/common/notification_settings','@odoo/owl','@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/popover/popover_hook'],function(require){'use strict';let __exports={};const{ACTION_TAGS}=require("@mail/core/common/action");const{registerThreadAction}=require("@mail/core/common/thread_actions");const{AttachmentPanel}=require("@mail/discuss/core/common/attachment_panel");const{ChannelInvitation}=require("@mail/discuss/core/common/channel_invitation");const{DeleteThreadDialog}=require("@mail/discuss/core/common/delete_thread_dialog");const{NotificationSettings}=require("@mail/discuss/core/common/notification_settings");const{Component,xml}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{usePopover}=require("@web/core/popover/popover_hook");class ChannelActionDialog extends Component{static props=["title","contentComponent","contentProps","close?"];static components={Dialog};static template=xml` 11381 <Dialog size="'md'" title="props.title" footer="false" contentClass="'o-bg-body'" bodyClass="'p-1'"> 11382 <t t-component="props.contentComponent" t-props="props.contentProps"/> 11383 </Dialog> 11384 `;} 11385registerThreadAction("notification-settings",{actionPanelComponent:NotificationSettings,condition:({owner,store,thread})=>thread?.model==="discuss.channel"&&store.self_partner&&(!owner.props.chatWindow||owner.props.chatWindow.isOpen),setup({owner}){if(!owner.props.chatWindow){this.popover=usePopover(NotificationSettings,{onClose:()=>this.close(),position:"bottom-end",fixedPosition:true,popoverClass:this.panelOuterClass,});}},open({owner,store,thread}){if(owner.isDiscussSidebarChannelActions||owner.env.inMeetingView){store.env.services.dialog?.add(ChannelActionDialog,{title:thread.displayName,contentComponent:NotificationSettings,contentProps:{thread},});}else{this.popover?.open(owner.root.el.querySelector(`[name="${this.id}"]`),{hasSizeConstraints:true,thread,});}},close:({action})=>action.popover?.close(),icon:({thread})=>thread.self_member_id?.mute_until_dt?"fa fa-fw text-danger fa-bell-slash":"fa fa-fw fa-bell",name:_t("Notification Settings"),panelOuterClass:"bg-100 border border-secondary",sequence:10,sequenceGroup:30,toggle:true,});registerThreadAction("attachments",{actionPanelComponent:AttachmentPanel,condition:({owner,thread})=>thread?.hasAttachmentPanel&&(!owner.props.chatWindow||owner.props.chatWindow.isOpen)&&!owner.isDiscussSidebarChannelActions,icon:"fa fa-fw fa-paperclip",name:_t("Attachments"),sequence:10,sequenceGroup:10,toggle:true,});registerThreadAction("invite-people",{actionPanelComponent:ChannelInvitation,actionPanelComponentProps:({action})=>({close:()=>action.close()}),close:({action})=>action.popover?.close(),condition:({owner,thread})=>thread?.model==="discuss.channel"&&(!owner.props.chatWindow||owner.props.chatWindow.isOpen),panelOuterClass:({owner})=>`o-discuss-ChannelInvitation ${ 11386 owner.props.chatWindow ? "bg-inherit" : "" 11387 } bg-100 border border-secondary`,icon:"oi oi-fw oi-user-plus",name:_t("Invite People"),open({owner,store,thread}){if(owner.isDiscussSidebarChannelActions){store.env.services.dialog?.add(ChannelActionDialog,{title:thread.displayName,contentComponent:ChannelInvitation,contentProps:{autofocus:true,thread,close:()=>store.env.services.dialog.closeAll(),},});}else if(!owner.env.inMeetingView){this.popover?.open(owner.root.el.querySelector(`[name="${this.id}"]`),{hasSizeConstraints:true,thread,});}},sequence:({owner})=>(owner.isDiscussSidebarChannelActions?20:10),sequenceGroup:20,setup({owner}){if(!owner.props.chatWindow&&!owner.env.inMeetingView){this.popover=usePopover(ChannelInvitation,{onClose:()=>this.close(),popoverClass:this.panelOuterClass,});}},toggle:true,});registerThreadAction("mark-read",{condition:({owner,thread})=>thread?.self_member_id&&thread.self_member_id.message_unread_counter>0&&!thread.self_member_id.mute_until_dt&&owner.isDiscussSidebarChannelActions,open:({owner})=>owner.thread.markAsRead(),icon:"fa fa-fw fa-check",name:_t("Mark Read"),sequence:10,sequenceGroup:20,});registerThreadAction("delete-thread",{actionPanelComponent:DeleteThreadDialog,actionPanelComponentProps({action}){return{close:()=>action.close()};},condition({owner,store,thread}){return(thread?.parent_channel_id&&store.self.main_user_id?.eq(thread.create_uid)&&!owner.isDiscussContent);}
11387,panelOuterClass:"bg-100",icon:"fa fa-fw fa-trash",iconLarge:"fa fa-fw fa-lg fa-trash",name:_t("Delete Thread"),close:({action})=>action.popover?.close(),toggle:true,open:({action,owner,store,thread})=>{if(owner.isDiscussSidebarChannelActions){store.env.services.dialog?.add(ChannelActionDialog,{title:thread.name,contentComponent:DeleteThreadDialog,contentProps:{close:()=>store.env.services.dialog.closeAll(),thread,},});}},sequence:({owner})=>(owner.props.chatWindow?50:40),sequenceGroup:40,tags:[ACTION_TAGS.DANGER],});return __exports;});; 11388 11389/* /mail/static/src/discuss/core/common/thread_compare_patch.js */ 11390odoo.define('@mail/discuss/core/common/thread_compare_patch',['@mail/core/common/thread_compare','@mail/utils/common/misc'],function(require){'use strict';let __exports={};const{threadCompareRegistry}=require("@mail/core/common/thread_compare");const{compareDatetime}=require("@mail/utils/common/misc");threadCompareRegistry.add("mail.unread",(thread1,thread2)=>{const aUnread=thread1.self_member_id?.message_unread_counter;const bUnread=thread2.self_member_id?.message_unread_counter;if(aUnread>0&&bUnread===0){return-1;} 11391if(bUnread>0&&aUnread===0){return 1;}},{sequence:20});threadCompareRegistry.add("mail.last-interest",(thread1,thread2)=>{const aLastInterestDt=thread1.lastInterestDt;const bLastInterestDt=thread2.lastInterestDt;if(aLastInterestDt&&bLastInterestDt){const res=compareDatetime(bLastInterestDt,aLastInterestDt);if(res!==0){return res;}}},{sequence:30});return __exports;});; 11392 11393/* /mail/static/src/discuss/core/common/thread_model_patch.js */ 11394odoo.define('@mail/discuss/core/common/thread_model_patch',['@mail/core/common/record','@mail/core/common/thread_model','@mail/utils/common/hooks','@mail/utils/common/misc','@web/core/l10n/translation','@web/core/l10n/utils','@web/core/network/rpc','@web/core/registry','@web/core/utils/concurrency','@web/core/utils/html','@web/core/utils/patch','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{fields}=require("@mail/core/common/record");const{Thread}=require("@mail/core/common/thread_model");const{useSequential}=require("@mail/utils/common/hooks");const{compareDatetime,effectWithCleanup,nearestGreaterThanOrEqual,}=require("@mail/utils/common/misc");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{formatList}=require("@web/core/l10n/utils");const{rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const{Deferred}=require("@web/core/utils/concurrency");const{createElementWithContent}=require("@web/core/utils/html");const{patch}=require("@web/core/utils/patch");const{imageUrl}=require("@web/core/utils/urls");const commandRegistry=registry.category("discuss.channel_commands");const threadStaticPatch={new(){const thread=super.new(...arguments);effectWithCleanup({effect(busChannel,busService){if(busService&&busChannel){busService.addChannel(busChannel);return()=>busService.deleteChannel(busChannel);}},dependencies:(thread)=>[thread.shouldSubscribeToBusChannel&&thread.busChannel,thread.store.env.services.bus_service,],reactiveTargets:[thread],});return thread;},async getOrFetch(data,fieldNames=[]){if(data.model!=="discuss.channel"||data.id<1){return super.getOrFetch(...arguments);} 11395const thread=this.store.Thread.get({id:data.id,model:data.model});if(thread?.fetchChannelInfoState==="fetched"){return Promise.resolve(thread);} 11396const fetchChannelInfoDeferred=this.store.channelIdsFetchingDeferred.get(data.id);if(fetchChannelInfoDeferred){return fetchChannelInfoDeferred;} 11397const def=new Deferred();this.store.channelIdsFetchingDeferred.set(data.id,def);this.store.fetchChannel(data.id).then(()=>{this.store.channelIdsFetchingDeferred.delete(data.id);const thread=this.store.Thread.get({id:data.id,model:data.model});if(thread?.exists()){thread.fetchChannelInfoState="fetched";def.resolve(thread);}else{def.resolve();}},()=>{this.store.channelIdsFetchingDeferred.delete(data.id);const thread=this.store.Thread.get({id:data.id,model:data.model});if(thread?.exists()){def.reject(thread);}else{def.reject();}});return def;},};patch(Thread,threadStaticPatch);const threadPatch={setup(){super.setup();this.channel_member_ids=fields.Many("discuss.channel.member",{inverse:"channel_id",onDelete:(r)=>r.delete(),sort:(m1,m2)=>m1.id-m2.id,});this.correspondent=fields.One("discuss.channel.member",{compute(){return this.computeCorrespondent();},});this.correspondentCountry=fields.One("res.country",{compute(){return this.correspondent?.persona?.country_id??this.country_id;},});this.default_display_mode=undefined;this.fetchChannelInfoDeferred=undefined;this.fetchChannelInfoState="not_fetched";this.group_ids=fields.Many("res.groups");this.hasOtherMembersTyping=fields.Attr(false,{compute(){return this.otherTypingMembers.length>0;},});this.hasSeenFeature=fields.Attr(false,{compute(){return this.store.channel_types_with_seen_infos.includes(this.channel_type);},});this.firstUnreadMessage=fields.One("mail.message",{compute(){if(!this.self_member_id){return null;} 11398const messages=this.messages.filter((m)=>!m.isNotification);const separator=this.self_member_id.new_message_separator_ui;if(separator===0&&!this.loadOlder){return messages[0];} 11399if(!separator||messages.length===0||messages.at(-1).id<separator){return null;} 11400let message=this.store["mail.message"].get({id:separator});if(!message||this.notEq(message.thread)){message=nearestGreaterThanOrEqual(messages,separator,(msg)=>msg.id);} 11401return message;},inverse:"threadAsFirstUnread",});this.invited_member_ids=fields.Many("discuss.channel.member");this.last_interest_dt=fields.Datetime();this.lastInterestDt=fields.Datetime({compute(){const selfMemberLastInterestDt=this.self_member_id?.last_interest_dt;const lastInterestDt=this.last_interest_dt;return compareDatetime(selfMemberLastInterestDt,lastInterestDt)>0?selfMemberLastInterestDt:lastInterestDt;},});this.lastMessageSeenByAllId=fields.Attr(undefined,{compute(){if(!this.hasSeenFeature){return;} 11402return this.channel_member_ids.reduce((lastMessageSeenByAllId,member)=>{if(member.notEq(this.selfMember)&&member.seen_message_id){return lastMessageSeenByAllId?Math.min(lastMessageSeenByAllId,member.seen_message_id.id):member.seen_message_id.id;}else{return lastMessageSeenByAllId;}},undefined);},});this.lastSelfMessageSeenByEveryone=fields.One("mail.message",{compute(){if(!this.lastMessageSeenByAllId){return false;} 11403let res;for(let i=this.persistentMessages.length-1;i>=0;i--){const message=this.persistentMessages[i];if(!message.isSelfAuthored||message.isNotification||message.id>this.lastMessageSeenByAllId){continue;} 11404res=message;break;} 11405return res;},});this.markReadSequential=useSequential();this.markedAsUnread=false;this.markingAsRead=false;this.member_count=undefined;this.name=undefined;this.channel_name_member_ids=fields.Many("discuss.channel.member");this.onlineMembers=fields.Many("discuss.channel.member",{compute(){return this.channel_member_ids.filter((member)=>this.store.onlineMemberStatuses.includes(member.im_status)).sort((m1,m2)=>this.store.sortMembers(m1,m2));},});this.offlineMembers=fields.Many("discuss.channel.member",{compute(){return this._computeOfflineMembers().sort((m1,m2)=>this.store.sortMembers(m1,m2));},});this.otherTypingMembers=fields.Many("discuss.channel.member",{compute(){return this.typingMembers.filter((member)=>!member.persona?.eq(this.store.self));},});this.self_member_id=fields.One("discuss.channel.member",{inverse:"threadAsSelf",});this.scrollUnread=true;this.toggleBusSubscription=fields.Attr("not_member",{compute(){if(!this.self_member_id){return"not_member";} 11406return this.self_member_id.memberSince>=this.store.env.services.bus_service.startedAt?"member_after_start":"member_before_start";},onUpdate(){if(this.toggleBusSubscription!=="member_before_start"){this.store.updateBusSubscription();}},});this.typingMembers=fields.Many("discuss.channel.member",{inverse:"threadAsTyping"});},_computeOfflineMembers(){return this.channel_member_ids.filter((member)=>!this.store.onlineMemberStatuses.includes(member.im_status));},get allow_invite_by_email(){return(this.channel_type==="group"||(this.channel_type==="channel"&&!this.group_public_id));},get areAllMembersLoaded(){return this.member_count===this.channel_member_ids.length;},get avatarUrl(){if(this.channel_type==="channel"||this.channel_type==="group"){return imageUrl("discuss.channel",this.id,"avatar_128",{unique:this.avatar_cache_key,});} 11407if(this.channel_type==="chat"&&this.correspondent){return this.correspondent.avatarUrl;} 11408return super.avatarUrl;},get showCorrespondentCountry(){return false;},async checkReadAccess(){const res=await super.checkReadAccess();if(!res&&this.model==="discuss.channel"){return this.channel_type;} 11409return res;},computeCorrespondent(){if(["channel","group"].includes(this.channel_type)){return undefined;} 11410const correspondents=this.correspondents;if(correspondents.length===1){return correspondents[0];} 11411if(correspondents.length===0&&this.channel_member_ids.length===1){return this.channel_member_ids[0];} 11412return undefined;},get correspondents(){return this.channel_member_ids.filter(({persona})=>persona?.notEq(this.store.self));},get displayName(){if(this.supportsCustomChannelName&&this.self_member_id?.custom_channel_name){return this.self_member_id.custom_channel_name;} 11413if(this.channel_type==="chat"&&this.correspondent){return this.correspondent.name;} 11414if(this.channel_name_member_ids.length&&!this.name){const nameParts=this.channel_name_member_ids.sort((m1,m2)=>m1.id-m2.id).slice(0,3).map((member)=>member.name);if(this.member_count>3){const remaining=this.member_count-3;nameParts.push(remaining===1?_t("1 other"):_t("%s others",remaining));} 11415return formatList(nameParts);} 11416if(this.model==="discuss.channel"&&this.name){return this.name;} 11417return super.displayName;},async fetchChannelMembers(){if(this.fetchMembersState==="pending"){return;} 11418const previousState=this.fetchMembersState;this.fetchMembersState="pending";const known_member_ids=this.channel_member_ids.map((channelMember)=>channelMember.id);let data;try{data=await rpc("/discuss/channel/members",{channel_id:this.id,known_member_ids:known_member_ids,});}catch(e){this.fetchMembersState=previousState;throw e;} 11419this.fetchMembersState="fetched";this.store.insert(data);},async fetchMoreAttachments(limit=30){if(this.isLoadingAttachments||this.areAttachmentsLoaded){return;} 11420this.isLoadingAttachments=true;try{const data=await rpc("/discuss/channel/attachments",{before:Math.min(...this.attachments.map(({id})=>id)),channel_id:this.id,limit,});this.store.insert(data.store_data);if(data.count<limit){this.areAttachmentsLoaded=true;}}finally{this.isLoadingAttachments=false;}},get hasMemberList(){return["channel","group"].includes(this.channel_type);},get hasSelfAsMember(){return Boolean(this.self_member_id);},get importantCounter(){if(this.isChatChannel&&this.self_member_id?.message_unread_counter_ui){return this.self_member_id.message_unread_counter_ui;} 11421if(this.discussAppCategory?.id==="channels"){if(this.store.settings.channel_notifications==="no_notif"){return 0;} 11422if(this.store.settings.channel_notifications==="all"&&!this.self_member_id?.mute_until_dt){return this.self_member_id?.message_unread_counter_ui;}} 11423return super.importantCounter;},isDisplayedOnUpdate(){super.isDisplayedOnUpdate(...arguments);if(!this.self_member_id){return;} 11424if(!this.isDisplayed){this.self_member_id.new_message_separator_ui=this.self_member_id.new_message_separator;this.markedAsUnread=false;}},get isUnread(){return this.self_member_id?.message_unread_counter>0||super.isUnread;},markAsRead(){super.markAsRead(...arguments);if(!this.self_member_id){return;} 11425const newestPersistentMessage=this.newestPersistentOfAllMessage;if(!newestPersistentMessage){return;} 11426const alreadyReadBySelf=this.self_member_id.seen_message_id?.id>=newestPersistentMessage.id&&this.self_member_id.new_message_separator>newestPersistentMessage.id;if(alreadyReadBySelf){return;} 11427this.markReadSequential(async()=>{this.markingAsRead=true;return rpc("/discuss/channel/mark_as_read",{channel_id:this.id,last_message_id:newestPersistentMessage.id,},{silent:true}).catch((e)=>{if(e.code!==404){throw e;}});}).then(()=>(this.markingAsRead=false));},get membersThatCanSeen(){return this.channel_member_ids;},get needactionCounter(){return this.isChatChannel?this.self_member_id?.message_unread_counter??0:super.needactionCounter;},onNewSelfMessage(message){if(!this.self_member_id||message.id<this.self_member_id.seen_message_id?.id){return;} 11428this.self_member_id.seen_message_id=message;this.self_member_id.new_message_separator=message.id+1;this.self_member_id.new_message_separator_ui=this.self_member_id.new_message_separator;this.markedAsUnread=false;},open(options){if(this.model==="discuss.channel"){const res=this.openChannel();if(res){return res;} 11429this.openChatWindow(options);return true;} 11430return super.open(...arguments);},openChannel(){return false;},async post(body){const textContent=createElementWithContent("div",body).textContent.trim();if(this.model==="discuss.channel"&&textContent.startsWith("/")){const[firstWord]=textContent.substring(1).split(/\s/);const command=commandRegistry.get(firstWord,false);
11430if(command&&(!command.condition||command.condition({store:this.store,thread:this}))&&(!command.channel_types||command.channel_types.includes(this.channel_type))){await this.executeCommand(command,textContent);return;}} 11431return super.post(...arguments);},get shouldSubscribeToBusChannel(){return Boolean(this.model==="discuss.channel"&&!this.isTransient&&!this.self_member_id&&(this.isLocallyPinned||this.chat_window?.isOpen));},get showUnreadBanner(){return this.self_member_id?.message_unread_counter_ui>0;},get unknownMembersCount(){return(this.member_count??0)-this.channel_member_ids.length;},};patch(Thread.prototype,threadPatch);return __exports;});; 11432 11433/* /mail/static/src/discuss/core/common/thread_patch.js */ 11434odoo.define('@mail/discuss/core/common/thread_patch',['@mail/core/common/thread','@odoo/owl','@web/core/l10n/translation','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Thread}=require("@mail/core/common/thread");const{useEffect,toRaw}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{patch}=require("@web/core/utils/patch");const threadPatch={setup(){super.setup(...arguments);useEffect((loadNewer,mountedAndLoaded)=>{if(loadNewer||!mountedAndLoaded||!this.props.thread.self_member_id||!this.scrollableRef.el){return;} 11435const el=this.scrollableRef.el;if(Math.abs(el.scrollTop+el.clientHeight-el.scrollHeight)<=1){this.props.thread.self_member_id.hideUnreadBanner=true;}},()=>[this.props.thread.loadNewer,this.state.mountedAndLoaded,this.state.scrollTop]);},applyScrollContextually(thread){if(thread.self_member_id&&thread.scrollUnread){if(thread.firstUnreadMessage){const messageEl=this.refByMessageId.get(thread.firstUnreadMessage.id)?.el;if(!messageEl){return;} 11436const messageCenter=messageEl.offsetTop- 11437this.scrollableRef.el.offsetHeight/2+ 11438messageEl.offsetHeight/2;this.setScroll(messageCenter);}else{const scrollTop=this.props.order==="asc"?this.scrollableRef.el.scrollHeight-this.scrollableRef.el.clientHeight:0;this.setScroll(scrollTop);} 11439thread.scrollUnread=false;if(this.isAtBottom&&!thread.markedAsUnread&&thread.isFocused){thread.markAsRead();}}else{super.applyScrollContextually(...arguments);}},fetchMessages(){if(this.props.thread.self_member_id&&this.props.thread.scrollUnread){toRaw(this.props.thread).loadAround(this.props.thread.self_member_id.new_message_separator);}else{super.fetchMessages();}},get newMessageBannerText(){if(this.props.thread.self_member_id?.message_unread_counter>1){return _t("%s new messages",this.props.thread.self_member_id.message_unread_counter);} 11440return _t("1 new message");},async onClickUnreadMessagesBanner(){await this.props.thread.loadAround(this.props.thread.self_member_id.new_message_separator_ui);this.messageHighlight?.highlightMessage(this.props.thread.firstUnreadMessage,this.props.thread);},};patch(Thread.prototype,threadPatch);return __exports;});; 11441 11442/* /mail/static/src/discuss/call/common/blur_manager.js */ 11443odoo.define('@mail/discuss/call/common/blur_manager',['@mail/utils/common/misc','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{closeStream}=require("@mail/utils/common/misc");const{browser}=require("@web/core/browser/browser");const FPS=30;function drawAndBlurImageOnCanvas(image,blurAmount,canvas){canvas.width=image.width;canvas.height=image.height;if(blurAmount===0){canvas.getContext("2d").drawImage(image,0,0,image.width,image.height);return;} 11444canvas.getContext("2d").clearRect(0,0,image.width,image.height);canvas.getContext("2d").save();canvas.getContext("2d").filter=`blur(${blurAmount}px)`;canvas.getContext("2d").drawImage(image,0,0,image.width,image.height);canvas.getContext("2d").restore();} 11445const BlurManager=__exports.BlurManager=class BlurManager{canvas=document.createElement("canvas");canvasBlur=document.createElement("canvas");canvasMask=document.createElement("canvas");canvasStream;isVideoDataLoaded=false;rejectStreamPromise;resolveStreamPromise;selfieSegmentation=new window.SelfieSegmentation({locateFile:(file)=>{return`https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/${file}`;},});stream;video=document.createElement("video");worker;constructor(stream,{backgroundBlur=10,edgeBlur=10,modelSelection=1,selfieMode=false}={}){this.edgeBlur=edgeBlur;this.backgroundBlur=backgroundBlur;this._onVideoPlay=this._onVideoPlay.bind(this);this.video.addEventListener("loadeddata",this._onVideoPlay);this.canvas.getContext("2d");
11445this.canvasStream=this.canvas.captureStream();let rejectStreamPromise;let resolveStreamPromise;Object.assign(this,{stream:new Promise((resolve,reject)=>{rejectStreamPromise=reject;resolveStreamPromise=resolve;}),rejectStreamPromise,resolveStreamPromise,});try{this.worker=new Worker("/mail/static/src/discuss/call/common/tick_worker.js");this.worker.onmessage=(e)=>this._handleWorkerMessage(e);this.worker.onerror=()=>{this._terminateWorker();this._requestFrame();};}catch{this.worker=null;} 11446this.video.srcObject=stream;this.video.load();this.selfieSegmentation.setOptions({selfieMode,modelSelection,});this.selfieSegmentation.onResults((r)=>this._onSelfieSegmentationResults(r));this.video.autoplay=true;Promise.resolve(this.video.play()).catch(()=>{});} 11447close(){this.video.removeEventListener("loadeddata",this._onVideoPlay);this.video.srcObject=null;this.isVideoDataLoaded=false;this.selfieSegmentation.reset();closeStream(this.canvasStream);this.canvasStream=null;this._terminateWorker();if(this.rejectStreamPromise){this.rejectStreamPromise(new Error("The source stream was removed before the beginning of the blur process"));}} 11448async _handleWorkerMessage(e){if(e.data.command==="tick"){await this._onFrame();this.worker.postMessage({command:"tock"});}} 11449_terminateWorker(){if(this.worker){this.worker.postMessage({command:"stop"});this.worker.terminate();} 11450this.worker=null;} 11451_drawWithCompositing(image,compositeOperation){this.canvas.getContext("2d").globalCompositeOperation=compositeOperation;
11451this.canvas.getContext("2d").drawImage(image,0,0);} 11452_onVideoPlay(){this.isVideoDataLoaded=true;if(this.worker){this.worker.postMessage({command:"start",fps:FPS});}else{this._requestFrame();}} 11453async _onFrame(){if(!this.selfieSegmentation){return;} 11454if(!this.video){return;} 11455if(!this.isVideoDataLoaded){return;} 11456await this.selfieSegmentation.send({image:this.video});} 11457_onSelfieSegmentationResults(results){drawAndBlurImageOnCanvas(results.image,this.backgroundBlur,this.canvasBlur);this.canvas.width=this.canvasBlur.width;this.canvas.height=this.canvasBlur.height;drawAndBlurImageOnCanvas(results.segmentationMask,this.edgeBlur,this.canvasMask);this.canvas.getContext("2d").save();this.canvas.getContext("2d").drawImage(results.image,0,0,this.canvas.width,this.canvas.height);this._drawWithCompositing(this.canvasMask,"destination-in");this._drawWithCompositing(this.canvasBlur,"destination-over");this.canvas.getContext("2d").restore();if(this.resolveStreamPromise){this.resolveStreamPromise(this.canvasStream);this.resolveStreamPromise=null;}} 11458_requestFrame(){if(!this.isVideoDataLoaded){return;} 11459browser.requestAnimationFrame(async()=>{await this._onFrame();if(!this.worker){browser.setTimeout(()=>this._requestFrame(),Math.floor(1000/FPS));}});}} 11460return __exports;});; 11461 11462/* /mail/static/src/discuss/call/common/blur_performance_warning.js */ 11463odoo.define('@mail/discuss/call/common/blur_performance_warning',['@mail/discuss/call/common/call_dropdown','@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{CallDropdown}=require("@mail/discuss/call/common/call_dropdown");const{Component}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const BlurPerformanceWarning=__exports.BlurPerformanceWarning=class BlurPerformanceWarning extends Component{static template="discuss.BlurPerformanceWarning";static props={};static components={CallDropdown};setup(){this.store=useService("mail.store");} 11464onClickClose(){this.store.settings.blurPerformanceWarning=false;}} 11465return __exports;});; 11466 11467/* /mail/static/src/discuss/call/common/call.js */ 11468odoo.define('@mail/discuss/call/common/call',['@mail/discuss/call/common/blur_performance_warning','@mail/discuss/call/common/call_action_list','@mail/discuss/call/common/call_participant_card','@mail/discuss/call/common/ptt_ad_banner','@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/h
11468otkeys/hotkey_hook','@web/core/utils/hooks','@web/core/utils/misc','@mail/discuss/call/common/call_actions','@mail/core/common/action_list','@mail/core/common/action','@mail/utils/common/hooks'],function(require){'use strict';let __exports={};const{BlurPerformanceWarning}=require("@mail/discuss/call/common/blur_performance_warning");const{CallActionList}=require("@mail/discuss/call/common/call_action_list");const{CallParticipantCard}=require("@mail/discuss/call/common/call_participant_card");const{PttAdBanner}=require("@mail/discuss/call/common/ptt_ad_banner");const{Component,onMounted,onPatched,onWillUnmount,toRaw,useRef,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isMobileOS}=require("@web/core/browser/feature_detection");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{useService}=require("@web/core/utils/hooks");const{isEventHandled,markEventHandled}=require("@web/core/utils/misc");const{useCallActions}=require("@mail/discuss/call/common/call_actions");const{ActionList}=require("@mail/core/common/action_list");const{ACTION_TAGS}=require("@mail/core/common/action");const{inDiscussCallViewProps,useInDiscussCallView}=require("@mail/utils/common/hooks");const Call=__exports.Call=class Call extends Component{static components={ActionList,BlurPerformanceWarning,CallActionList,CallParticipantCard,PttAdBanner,};static props=["thread?","compact?","hasOverlay?",...inDiscussCallViewProps];static defaultProps={hasOverlay:true};static template="discuss.Call";overlayTimeout;setup(){super.setup();this.grid=useRef("grid");this.root=useRef("root");this.notification=useService("notification");this.rtc=useService("discuss.rtc");this.isMobileOs=isMobileOS();this.ui=useService("ui");this.state=useState({sidebar:false,tileWidth:0,tileHeight:0,columnCount:0,overlay:false,insetCard:undefined,});this.store=useService("mail.store");this.callActions=useCallActions({thread:()=>this.channel});onMounted(()=>{this.resizeObserver=new ResizeObserver(()=>this.arrangeTiles());this.resizeObserver.observe(this.grid.el);this.arrangeTiles();});onPatched(()=>this.arrangeTiles());onWillUnmount(()=>{this.resizeObserver.disconnect();browser.clearTimeout(this.overlayTimeout);});useHotkey("shift+d",()=>this.rtc.toggleDeafen());useHotkey("shift+m",()=>this.rtc.toggleMicrophone());useInDiscussCallView();} 11469get layoutActions(){if(!this.isActiveCall){return[];} 11470return this.callActions.actions.filter((action)=>action.tags.includes(ACTION_TAGS.CALL_LAYOUT));} 11471get isFullSize(){return this.props.isPip||this.rtc.state.isFullscreen;} 11472get isActiveCall(){return Boolean(this.channel.eq(this.rtc.channel));} 11473get minimized(){if(this.rtc.state.isFullscreen||!this.channel||this.channel.activeRtcSession){return false;} 11474if(!this.isActiveCall||this.channel.videoCount===0||this.props.compact){return true;} 11475return false;} 11476get channel(){return this.props.thread||this.rtc.channel;} 11477get visibleMainCards(){const activeSession=this.channel.activeRtcSession;if(!activeSession){this.state.insetCard=undefined;return this.channel.visibleCards;} 11478const type=activeSession.mainVideoStreamType;if(type==="screen"||activeSession.is_screen_sharing_on){this.setInset(activeSession,type==="camera"?"screen":"camera");}else{this.state.insetCard=undefined;} 11479return[{key:"session_"+activeSession.id,session:activeSession,type,videoStream:activeSession.getStream(type),},];} 11480setInset(session,videoType){const key="session_"+session.id;if(toRaw(this.state).insetCard?.key===key){this.state.insetCard.type=videoType;this.state.insetCard.videoStream=session.getStream(videoType);}else{this.state.insetCard={key,session,type:videoType,videoStream:session.getStream(videoType),};}} 11481get hasCallNotifications(){return Boolean((!this.props.compact||this.rtc.state.isFullscreen)&&this.isActiveCall&&this.rtc.notifications.size);} 11482get hasSidebarButton(){return Boolean(this.channel.activeRtcSession&&this.state.overlay&&(!this.props.compact||this.rtc.state.isFullscreen));} 11483get isControllerFloating(){return this.rtc.state.isFullscreen||(this.channel.activeRtcSession&&!this.ui.isSmall);} 11484onMouseleaveMain(ev){if(ev.relatedTarget&&ev.relatedTarget.closest(".o-dropdown--menu")){return;} 11485this.state.overlay=false;} 11486onMousemoveMain(ev){if(isEventHandled(ev,"CallMain.MousemoveOverlay")){return;} 11487this.showOverlay();} 11488onMousemoveOverlay(ev){markEventHandled(ev,"CallMain.MousemoveOverlay");this.state.overlay=true;browser.clearTimeout(this.overlayTimeout);} 11489showOverlay(){this.state.overlay=true;browser.clearTimeout(this.overlayTimeout);this.overlayTimeout=browser.setTimeout(()=>{this.state.overlay=false;},3000);} 11490arrangeTiles(){if(!this.grid.el){return;} 11491this.grid.el.style.setProperty("--width","0");this.grid.el.style.setProperty("--height","0");const{width,height}=this.grid.el.getBoundingClientRect();const aspectRatio=this.minimized?1:16/9;const tileCount=this.grid.el.children.length;let optimal={area:0,columnCount:0,tileHeight:0,tileWidth:0,};for(let columnCount=1;columnCount<=tileCount;columnCount++){const rowCount=Math.ceil(tileCount/columnCount);
11491const potentialHeight=width/(columnCount*aspectRatio);const potentialWidth=height/rowCount;let tileHeight;let tileWidth;if(potentialHeight>potentialWidth){tileHeight=Math.floor(potentialWidth);tileWidth=Math.floor(tileHeight*aspectRatio);}else{tileWidth=Math.floor(width/columnCount);tileHeight=Math.floor(tileWidth/aspectRatio);} 11492const area=tileHeight*tileWidth;if(area<=optimal.area){continue;} 11493optimal={area,columnCount,tileHeight,tileWidth,};} 11494Object.assign(this.state,{tileWidth:optimal.tileWidth,tileHeight:optimal.tileHeight,columnCount:optimal.columnCount,});this.grid.el.style.setProperty("--width",`${this.state.tileWidth}px`);this.grid.el.style.setProperty("--height",`${this.state.tileHeight}px`);}} 11495return __exports;});; 11496 11497/* /mail/static/src/discuss/call/common/call_action_list.js */ 11498odoo.define('@mail/discuss/call/common/call_action_list',['@odoo/owl','@web/core/browser/feature_detection','@web/core/l10n/translation','@web/core/utils/hooks','@mail/discuss/call/common/call_actions','@web/core/popover/popover_hook','@web/core/tooltip/tooltip','@mail/discuss/call/common/thread_model_patch','@mail/core/common/action_list','@mail/core/common/action'],function(require){'use strict';let __exports={};const{Component,onWillRender,toRaw,useRef}=require("@odoo/owl");const{isMobileOS}=require("@web/core/browser/feature_detection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{useCallActions}=require("@mail/discuss/call/common/call_actions");const{usePopover}=require("@web/core/popover/popover_hook");const{Tooltip}=require("@web/core/tooltip/tooltip");const{CALL_PROMOTE_FULLSCREEN}=require("@mail/discuss/call/common/thread_model_patch");const{ActionList}=require("@mail/core/common/action_list");const{ACTION_TAGS}=require("@mail/core/common/action");const CallActionList=__exports.CallActionList=class CallActionList extends Component{static components={ActionList};static props=["thread","compact?"];static template="discuss.CallActionList";setup(){super.setup();this.store=useService("mail.store");this.rtc=useService("discuss.rtc");this.pipService=useService("discuss.pip_service");this.callActions=useCallActions({thread:()=>this.props.thread});this.more=useRef("more");this.root=useRef("root");this.popover=usePopover(Tooltip,{position:"top-middle",});onWillRender(()=>{const partition=toRaw(this.callActions).partition;const other=partition.other.filter((a)=>!a.tags.includes(ACTION_TAGS.CALL_LAYOUT));const group2=[];for(const groupActions of partition.group){const filtered=groupActions.filter((a)=>!a.tags.includes(ACTION_TAGS.CALL_LAYOUT));const sequenceGroup=filtered[0].sequenceGroup;const maxQuickActions=sequenceGroup===200?1:4;const quickActions=filtered.slice(0,maxQuickActions);const moreActions=filtered.slice(maxQuickActions);const newGroup=moreActions?.length?[...quickActions,this.callActions.more({actions:moreActions,dropdownMenuClass:"m-0 mb-1",dropdownPosition:"top-end",name:this.MORE,},sequenceGroup),]:quickActions;group2.push(newGroup);} 11499this.actions=[...group2,other];});} 11500get isPromotingFullscreen(){return Boolean(!this.env.pipWindow&&this.props.thread.promoteFullscreen===CALL_PROMOTE_FULLSCREEN.ACTIVE);} 11501get MORE(){return _t("More");} 11502get isOfActiveCall(){return Boolean(this.props.thread.eq(this.rtc.channel));} 11503get isSmall(){return Boolean(this.props.compact&&this.rtc.state.isFullscreen);} 11504get isMobileOS(){return isMobileOS();} 11505onMouseenterMore(){if(this.isPromotingFullscreen){this.popover.open(this.more.el,{tooltip:_t("Enter full screen!")});this.props.thread.promoteFullscreen=CALL_PROMOTE_FULLSCREEN.DISCARDED;}} 11506onMouseleaveMore(){if(this.popover.isOpen){this.popover.close();}} 11507onClickMore(){if(this.popover.isOpen){this.popover.close();}}} 11508return __exports;});; 11509 11510/* /mail/static/src/discuss/call/common/call_actions.js */ 11511odoo.define('@mail/discuss/call/common/call_actions',['@mail/core/common/action','@odoo/owl','@web/core/browser/feature_detection','@web/core/l10n/translation','@web/core/registry','@web/core/utils/hooks','@mail/discuss/call/common/quick_voice_settings','@mail/discuss/call/common/quick_video_settings','@mail/utils/common/format','@mail/discuss/call/common/thread_model_patch'],function(require){'use strict';let __exports={};const{Action,ACTION_TAGS,UseActions}=require("@mail/core/common/action");const{useComponent,useState}=require("@odoo/owl");const{isMobileOS}=require("@web/core/browser/feature_detection");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const{useService}=require("@web/core/utils/hooks");const{QuickVoiceSettings}=require("@mail/discuss/call/common/quick_voice_settings");const{QuickVideoSettings}=require("@mail/discuss/call/common/quick_video_settings");const{attClassObjectToString}=require("@mail/utils/common/format");const{CALL_PROMOTE_FULLSCREEN}=require("@mail/discuss/call/common/thread_model_patch");const callActionsRegistry=__exports.callActionsRegistry=registry.category("discuss.call/actions");const CALL_ICON_DEAFEN=__exports.CALL_ICON_DEAFEN="fa fa-deaf";const CALL_ICON_MUTED=__exports.CALL_ICON_MUTED="fa fa-microphone-slash";__exports.registerCallAction=registerCallAction;function registerCallAction(id,definition){callActionsRegistry.add(id,definition);} 11512const muteAction=__exports.muteAction={badge:({owner,store})=>!owner.env.inCallMenu&&store.rtc.microphonePermission!=="granted",badgeIcon:"fa fa-exclamation",condition:({owner,store,thread})=>thread?.isSelfInCall&&(owner.env.inCallMenu||!store.rtc.selfSession?.is_deaf),name:({store})=>(store.rtc.selfSession.isMute?_t("Unmute"):_t("Mute")),isActive:({store})=>(store.rtc.selfSession?.isMute&&store.rtc.microphonePermission==="granted")||store.rtc.selfSession?.is_deaf,isTracked:true,icon:({action,owner,store})=>action.isActive?store.rtc.selfSession?.is_deaf&&!owner.env.inCallMenu?CALL_ICON_DEAFEN:CALL_ICON_MUTED:"fa fa-microphone",hotkey:"shift+m",onSelected:({store})=>store.rtc.toggleMicrophone(),sequence:10,sequenceGroup:100,tags:({action,store})=>{const tags=[];if(action.isActive){tags.push(ACTION_TAGS.DANGER);} 11513if(store.rtc.microphonePermission!=="granted"){tags.push(ACTION_TAGS.DANGER,ACTION_TAGS.WARNING_BADGE);} 11514return tags;},};registerCallAction("mute",muteAction);const quickActionSettings=__exports.quickActionSettings={condition:({owner,thread})=>!owner.env.inCallMenu&&thread?.isSelfInCall,dropdown:true,dropdownComponent:QuickVoiceSettings,dropdownMenuClass:"p-2",dropdownPosition:"top-end",icon:"oi oi-chevron-up o-xsmaller",name:_t("Voice Settings"),sequence:15,sequenceGroup:100,};registerCallAction("quick-voice-settings",quickActionSettings);registerCallAction("deafen",{condition:({owner,store,thread})=>thread?.isSelfInCall&&(owner.env.inCallMenu||store.rtc.selfSession?.is_deaf),name:({store})=>(store.rtc.selfSession.is_deaf?_t("Undeafen"):_t("Deafen")),isActive:({store})=>store.rtc.selfSession?.is_deaf,isTracked:true,icon:({action})=>(action.isActive?CALL_ICON_DEAFEN:"fa fa-headphones"),hotkey:"shift+d",onSelected:({store})=>store.rtc.toggleDeafen(),sequence:10,sequenceGroup:100,tags:({action})=>
11514(action.isActive?ACTION_TAGS.DANGER:undefined),});const cameraOnAction=__exports.cameraOnAction={badge:({owner,store,thread})=>!owner.env.inCallMenu&&thread?.default_display_mode==="video_full_screen"&&store.rtc.cameraPermission!=="granted",badgeIcon:"fa fa-exclamation",condition:({thread})=>thread?.isSelfInCall,disabledCondition:({store})=>store.rtc?.isRemote,name:({store})=>store.rtc?.isRemote?_t("Camera is unavailable outside the call tab."):store.rtc.selfSession.is_camera_on?_t("Stop camera"):_t("Turn camera on"),isActive:({store})=>store.rtc.selfSession?.is_camera_on,isTracked:true,icon:"fa fa-video-camera",onSelected:({owner,store})=>store.rtc.toggleVideo("camera",{env:owner.env}),sequence:10,sequenceGroup:120,tags:({action,store,thread})=>{const tags=[];if(action.isActive){tags.push(ACTION_TAGS.SUCCESS);} 11515if(thread?.default_display_mode==="video_full_screen"&&store.rtc.cameraPermission!=="granted"){tags.push(ACTION_TAGS.DANGER,ACTION_TAGS.WARNING_BADGE);} 11516return tags;},};registerCallAction("camera-on",cameraOnAction);const quickVideoSettings=__exports.quickVideoSettings={condition:({owner,thread})=>!owner.env.inCallMenu&&thread?.isSelfInCall,dropdown:true,dropdownComponent:QuickVideoSettings,dropdownMenuClass:"p-2",dropdownPosition:"top-end",icon:"oi oi-chevron-up o-xsmaller",name:_t("Video Settings"),sequence:15,sequenceGroup:120,};registerCallAction("quick-video-settings",quickVideoSettings);const switchCameraAction=__exports.switchCameraAction={condition:({store,thread})=>thread?.isSelfInCall&&isMobileOS()&&store.rtc.selfSession?.is_camera_on,name:_t("Switch Camera"),isActive:false,icon:"fa fa-refresh",onSelected:({store})=>store.rtc.toggleCameraFacingMode(),sequence:40,sequenceGroup:100,};registerCallAction("switch-camera",switchCameraAction);registerCallAction("raise-hand",{condition:({thread})=>thread?.isSelfInCall,name:({store})=>(store.rtc.selfSession.raisingHand?_t("Lower Hand"):_t("Raise Hand")),isActive:({store})=>store.rtc.selfSession?.raisingHand,isTracked:true,icon:"fa fa-hand-paper-o",onSelected:({store})=>store.rtc.raiseHand(!store.rtc.selfSession.raisingHand),sequence:50,sequenceGroup:200,});registerCallAction("share-screen",{condition:({thread})=>thread?.isSelfInCall&&!isMobileOS(),disabledCondition:({store})=>store.rtc?.isRemote,name:({store})=>store.rtc?.isRemote?_t("Screen sharing is unavailable outside the call tab."):store.rtc.selfSession.is_screen_sharing_on?_t("Stop Sharing Screen"):_t("Share Screen"),isTracked:true,isActive:({store})=>store.rtc.selfSession?.is_screen_sharing_on,icon:"fa fa-desktop",onSelected:({owner,store})=>store.rtc.toggleVideo("screen",{env:owner.env}),sequence:40,sequenceGroup:200,tags:({action})=>(action.isActive?ACTION_TAGS.SUCCESS:undefined),});registerCallAction("auto-focus",{condition:({owner,thread})=>!owner.env.inCallMenu&&thread?.isSelfInCall,name:({store})=>store.settings.useCallAutoFocus?_t("Disable speaker autofocus"):_t("Autofocus speaker"),isActive:({store})=>store.settings?.useCallAutoFocus,icon:({action})=>(action.isActive?"fa fa-eye":"fa fa-eye-slash"),onSelected:({store})=>(store.settings.useCallAutoFocus=!store.settings.useCallAutoFocus),sequence:50,sequenceGroup:200,});const blurBackgroundAction=__exports.blurBackgroundAction={condition:false,name:({store})=>(store.settings.useBlur?_t("Remove Blur"):_t("Blur Background")),isActive:({store})=>store?.settings?.useBlur,icon:"fa fa-photo",onSelected:({store})=>store.settings.setUseBlur(!store.settings.useBlur),sequence:60,sequenceGroup:200,};registerCallAction("fullscreen",{btnClass:({thread})=>attClassObjectToString({"o-discuss-CallActionList-pulse":Boolean(thread.promoteFullscreen===CALL_PROMOTE_FULLSCREEN.ACTIVE),}),condition:({thread})=>thread?.isSelfInCall,name:({store})=>(store.rtc.state.isFullscreen?_t("Exit Fullscreen"):_t("Fullscreen")),isActive:({store})=>store.rtc.state.isFullscreen,icon:({action})=>(action.isActive?"fa fa-compress":"fa fa-expand"),onSelected:({store,thread})=>{thread.promoteFullscreen=CALL_PROMOTE_FULLSCREEN.DISCARDED;if(store.rtc.state.isFullscreen){store.rtc.exitFullscreen();}else{store.rtc.closePip();store.rtc.enterFullscreen();}},sequence:80,tags:ACTION_TAGS.CALL_LAYOUT,});registerCallAction("picture-in-picture",{condition:({owner,store,thread})=>thread?.isSelfInCall&&!store.env?.isSmall,disabledCondition:({store})=>store.rtc?.isRemote,name:({store})=>
11516store.rtc?.state.isPipMode?_t("Exit Picture in Picture"):_t("Picture in Picture"),isActive:({store})=>store.rtc?.state.isPipMode,icon:"oi oi-launch",onSelected:({owner,store,thread})=>{thread.promoteFullscreen=CALL_PROMOTE_FULLSCREEN.DISCARDED;const isPipMode=store.rtc?.state.isPipMode;if(isPipMode){store.rtc.closePip();}else{store.rtc.openPip({context:owner});}},sequence:70,tags:ACTION_TAGS.CALL_LAYOUT,});const acceptWithCamera=__exports.acceptWithCamera={condition:({thread})=>thread?.self_member_id?.rtc_inviting_session_id?.is_camera_on&&typeof thread?.useCameraByDefault!=="boolean",disabledCondition:({store})=>store.rtc?.state.hasPendingRequest,name:_t("Accept with camera"),icon:"fa fa-video-camera",onSelected:({store,thread})=>store.rtc.toggleCall(thread,{camera:true}),sequence:100,sequenceGroup:300,tags:[ACTION_TAGS.JOIN_LEAVE_CALL,ACTION_TAGS.SUCCESS],};registerCallAction("accept-with-camera",acceptWithCamera);registerCallAction("join-back",{btnClass:({owner})=>attClassObjectToString({"text-nowrap pe-2 rounded-pill":true,"mx-1":!owner.env.inCallInvitation,}),condition:({thread})=>!thread?.isSelfInCall&&typeof thread?.useCameraByDefault==="boolean",disabledCondition:({store})=>store.rtc?.state.hasPendingRequest,icon:({thread})=>(thread.useCameraByDefault?"fa fa-video-camera":"fa fa-phone"),inlineName:({owner})=>(owner.env.inCallInvitation?undefined:_t("Join")),name:({thread})=>(thread.useCameraByDefault?_t("Join Video Call"):_t("Join Call")),onSelected:({store,thread})=>store.rtc.toggleCall(thread,{camera:thread.useCameraByDefault}),sequence:110,sequenceGroup:300,tags:[ACTION_TAGS.JOIN_LEAVE_CALL,ACTION_TAGS.SUCCESS],});registerCallAction("join-with-camera",{btnClass:"text-nowrap",condition:({thread})=>!thread?.isSelfInCall&&!thread?.self_member_id?.rtc_inviting_session_id&&typeof thread?.useCameraByDefault!=="boolean",disabledCondition:({store})=>store.rtc?.state.hasPendingRequest,name:_t("Join Video Call"),icon:"fa fa-video-camera",onSelected:({store,thread})=>store.rtc.toggleCall(thread,{camera:true}),sequence:120,sequenceGroup:300,tags:[ACTION_TAGS.JOIN_LEAVE_CALL,ACTION_TAGS.SUCCESS],});const joinAction=__exports.joinAction={condition:({thread})=>!thread?.isSelfInCall&&typeof thread?.useCameraByDefault!=="boolean",disabledCondition:({store})=>store.rtc?.state.hasPendingRequest,name:_t("Join Call"),icon:"fa fa-phone",onSelected:({store,thread},ev)=>store.rtc.toggleCall(thread),sequence:130,sequenceGroup:300,tags:[ACTION_TAGS.JOIN_LEAVE_CALL,ACTION_TAGS.SUCCESS],};registerCallAction("join",joinAction);const rejectAction=__exports.rejectAction={btnClass:({owner,thread})=>attClassObjectToString({"pe-2 rounded-pill":typeof thread?.useCameraByDefault==="boolean","mx-1":!owner.env.inCallInvitation&&typeof thread?.useCameraByDefault==="boolean",}),condition:({thread})=>thread?.self_member_id?.rtc_inviting_session_id,disabledCondition:({store})=>store.rtc?.state.hasPendingRequest,icon:"oi oi-close",inlineName:({owner,thread})=>!owner.env.inCallInvitation&&typeof thread?.useCameraByDefault==="boolean"?_t("Reject"):undefined,name:_t("Reject"),onSelected:({store,thread})=>{if(store.rtc.state.hasPendingRequest){return;} 11517store.rtc.leaveCall(thread);},sequence:140,sequenceGroup:300,tags:[ACTION_TAGS.JOIN_LEAVE_CALL,ACTION_TAGS.DANGER],};registerCallAction("reject",rejectAction);registerCallAction("disconnect",{condition:({thread})=>thread?.isSelfInCall&&!thread?.self_member_id?.rtc_inviting_session_id,disabledCondition:({store})=>store.rtc?.state.hasPendingRequest,name:_t("Disconnect"),icon:"fa fa-phone",onSelected:({store,thread})=>store.rtc.toggleCall(thread),sequence:150,sequenceGroup:300,tags:[ACTION_TAGS.JOIN_LEAVE_CALL,ACTION_TAGS.DANGER],});const CallAction=__exports.CallAction=class CallAction extends Action{threadFn;constructor({thread}){super(...arguments);this.threadFn=typeof thread==="function"?thread:()=>thread;} 11518get params(){return Object.assign(super.params,{thread:this.threadFn()});} 11519get isTracked(){return this.definition.isTracked;}} 11520class UseCallActions extends UseActions{ActionClass=CallAction;} 11521__exports.useCallActions=useCallActions;function useCallActions({thread}={}){const component=useComponent();const transformedActions=callActionsRegistry.getEntries().map(([id,definition])=>new CallAction({owner:component,id,definition,thread}));return useState(new UseCallActions(component,transformedActions,useService("mail.store")));} 11522return __exports;});; 11523 11524/* /mail/static/src/discuss/call/common/call_components.js */ 11525odoo.define('@mail/discuss/call/common/call_components',['@web/core/registry','@mail/discuss/call/common/call','@mail/discuss/call/common/meeting'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{Call}=require("@mail/discuss/call/common/call");const{Meeting}=require("@mail/discuss/call/common/meeting");const callComponentsRegistry=registry.category("discuss.call/components");callComponentsRegistry.add("Call",Call).add("Meeting",Meeting);return __exports;});; 11526 11527/* /mail/static/src/discuss/call/common/call_context_menu.js */ 11528odoo.define('@mail/discuss/call/common/call_context_menu',['@odoo/owl','@web/core/browser/browser','@web/core/l10n/translation','@web/core/utils/hooks','@mail/discuss/call/common/rtc_service'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillUnmount,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{CONNECTION_TYPES}=require("@mail/discuss/call/common/rtc_service");const PROTOCOLS_TEXT={host:"HOST",srflx:"STUN",prflx:"STUN",relay:"TURN"};const CallContextMenu=__exports.CallContextMenu=class CallContextMenu extends Component{static props=["rtcSession","close?"];static template="discuss.CallContextMenu";updateStatsTimeout;rtcConnectionTypes=CONNECTION_TYPES;setup(){super.setup();this.store=useService("mail.store");this.rtc=useService("discuss.rtc");this.state=useState({downloadStats:{},uploadStats:{},producerStats:{},peerStats:{},rangeVolume:this.volume,});onMounted(()=>
11528{if(!this.env.debug){return;} 11529this.updateStats();this.updateStatsTimeout=browser.setInterval(()=>this.updateStats(),3000);});onWillUnmount(()=>browser.clearInterval(this.updateStatsTimeout));} 11530get isSelf(){return this.rtc.selfSession?.eq(this.props.rtcSession);} 11531get inboundConnectionTypeText(){const candidateType=this.rtc.state.connectionType===CONNECTION_TYPES.SERVER?this.state.downloadStats.remoteCandidateType:this.state.peerStats.remoteCandidateType;return this.formatProtocol(candidateType);} 11532get outboundConnectionTypeText(){const candidateType=this.rtc.state.connectionType===CONNECTION_TYPES.SERVER?this.state.uploadStats.localCandidateType:this.state.peerStats.localCandidateType;return this.formatProtocol(candidateType);} 11533get volume(){return this.store.settings.getVolume(this.props.rtcSession);} 11534formatProtocol(candidateType){if(!candidateType){return _t("no connection");} 11535return _t("%(candidateType)s (%(protocol)s)",{candidateType,protocol:PROTOCOLS_TEXT[candidateType],});} 11536async updateStats(){if(this.rtc.localSession?.eq(this.props.rtcSession)){if(this.rtc.sfuClient){const{uploadStats,downloadStats,...producerStats}=await this.rtc.sfuClient.getStats();if(!uploadStats||!downloadStats){return;} 11537const formattedUploadStats={};for(const value of uploadStats.values?.()||[]){switch(value.type){case"candidate-pair":if(value.state==="succeeded"&&value.localCandidateId){formattedUploadStats.localCandidateType=uploadStats.get(value.localCandidateId)?.candidateType||"";formattedUploadStats.availableOutgoingBitrate=value.availableOutgoingBitrate;} 11538break;case"transport":formattedUploadStats.dtlsState=value.dtlsState;formattedUploadStats.iceState=value.iceState;formattedUploadStats.packetsSent=value.packetsSent;break;}} 11539const formattedDownloadStats={};for(const value of downloadStats.values?.()||[]){switch(value.type){case"candidate-pair":if(value.state==="succeeded"&&value.localCandidateId){formattedDownloadStats.remoteCandidateType=downloadStats.get(value.remoteCandidateId)?.candidateType||"";} 11540break;case"transport":formattedDownloadStats.dtlsState=value.dtlsState;formattedDownloadStats.iceState=value.iceState;formattedDownloadStats.packetsReceived=value.packetsReceived;break;}} 11541const formattedProducerStats={};for(const[type,stat]of Object.entries(producerStats)){const currentTypeStats={};for(const value of stat.values()){switch(value.type){case"codec":currentTypeStats.codec=value.mimeType;currentTypeStats.clockRate=value.clockRate;break;}} 11542formattedProducerStats[type]=currentTypeStats;} 11543this.state.uploadStats=formattedUploadStats;this.state.downloadStats=formattedDownloadStats;this.state.producerStats=formattedProducerStats;} 11544return;} 11545this.state.peerStats=await this.rtc.p2pService.getFormattedStats(this.props.rtcSession.id);} 11546onChangeVolume(ev){const volume=Number(ev.target.value);this.rtc.setVolume(this.props.rtcSession,volume);}} 11547return __exports;});; 11548 11549/* /mail/static/src/discuss/call/common/call_dropdown.js */ 11550odoo.define('@mail/discuss/call/common/call_dropdown',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/navigation/navigation','@web/core/position/position_hook'],function(require){'use strict';let __exports={};const{Component,useRef,useState,useExternalListener,useSubEnv,useEffect}=require("@odoo/owl");const{getFirstElementOfNode}=require("@web/core/dropdown/dropdown");const{useNavigation}=require("@web/core/navigation/navigation");const{usePosition}=require("@web/core/position/position_hook");const CallDropdown=__exports.CallDropdown=class CallDropdown extends Component{static template="discuss.CallDropdown";static props={position:{type:String,optional:true},class:{type:String,optional:true},menuClass:{type:String,optional:true},slots:{optional:true},openByDefault:{type:Boolean,optional:true},state:{type:Object,optional:true},};static defaultProps={position:"bottom",class:"",menuClass:"",openByDefault:false,};setup(){super.setup();this.menuRef=useRef("menu");this.state=useState({isOpen:this.props.openByDefault});usePosition("menu",()=>this.triggerRef.el,{position:this.props.position,margin:4,flip:true,});useExternalListener(this.window,"click",this.onClickAway,{capture:true});useExternalListener(this.window,"keydown",this.onKeydown);useSubEnv({inCallDropdown:{close:()=>this.close()}});this.navigation=useNavigation(this.menuRef,{isNavigationAvailable:()=>this.state.isOpen,getItems:()=>
11550{if(this.state.isOpen&&this.menuRef.el){return this.menuRef.el.querySelectorAll(":scope .o-navigable, :scope .o-dropdown");} 11551return[];},});this.handleClick=this.handleClick.bind(this);useEffect((triggerEl)=>{if(triggerEl){triggerEl.addEventListener("click",this.handleClick);return()=>triggerEl.removeEventListener("click",this.handleClick);}},()=>[this.triggerRef.el]);} 11552get triggerRef(){return{el:getFirstElementOfNode(this.__owl__.bdom)};} 11553get window(){return this.env.pipWindow||window;} 11554get isOpen(){return this.state.isOpen;} 11555toggle(){this.isOpen?this.close():this.open();} 11556open(){this.state.isOpen=true;} 11557close(){this.state.isOpen=false;} 11558handleClick(ev){ev.preventDefault();ev.stopPropagation();this.toggle();} 11559onClickAway(ev){if(!this.isOpen){return;} 11560const isOutsideClick=!this.triggerRef.el?.contains(ev.target)&&!this.menuRef.el?.contains(ev.target);if(isOutsideClick){this.close();}} 11561onClickMenu(ev){ev.stopPropagation();} 11562onKeydown(ev){if(ev.key==="Escape"&&this.isOpen){ev.preventDefault();this.close();}}} 11563return __exports;});; 11564 11565/* /mail/static/src/discuss/call/common/call_infinite_mirroring_warning.js */ 11566odoo.define('@mail/discuss/call/common/call_infinite_mirroring_warning',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const CallInfiniteMirroringWarning=__exports.CallInfiniteMirroringWarning=class CallInfiniteMirroringWarning extends Component{static template="discuss.CallInfiniteMirroringWarning";static props={onClose:{type:Function},};} 11567return __exports;});; 11568 11569/* /mail/static/src/discuss/call/common/call_invitation.js */ 11570odoo.define('@mail/discuss/call/common/call_invitation',['@mail/core/common/action','@mail/core/common/action_list','@mail/discuss/call/common/call_actions','@mail/discuss/call/common/call_preview','@odoo/owl','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Action,ACTION_TAGS}=require("@mail/core/common/action");const{ActionList}=require("@mail/core/common/action_list");const{acceptWithCamera,CallAction,joinAction,rejectAction,}=require("@mail/discuss/call/common/call_actions");const{CallPreview}=require("@mail/discuss/call/common/call_preview");const{Component,useState,useSubEnv}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const CallInvitation=__exports.CallInvitation=class CallInvitation extends Component{static props=["thread"];static template="discuss.CallInvitation";static components={ActionList,CallPreview};setup(){super.setup();this.rtc=useService("discuss.rtc");this.store=useService("mail.store");this.ui=useService("ui");this.state=useState({activateCamera:0,activateMicrophone:0,showCameraPreview:false,hasCamera:false,hasMicrophone:this.rtc.microphonePermission==="granted",});useSubEnv({inCallInvitation:true});} 11571joinCall(){this.props.thread.open({focus:true});this.rtc.toggleCall(this.props.thread,{audio:this.state.hasMicrophone,camera:this.state.hasCamera,});} 11572get acceptOrRejectActions(){const joinUpdated={...joinAction,btnClass:joinAction.btnClass+" o-me-0_5",onSelected:()=>this.joinCall(),};const acceptWithCameraUpdated={...acceptWithCamera,btnClass:acceptWithCamera.btnClass+" o-me-0_5",onSelected:()=>{this.state.hasCamera=true;this.joinCall();},condition:true,};return[new CallAction({id:"accept-with-camera",definition:acceptWithCameraUpdated,owner:this,store:this.store,thread:this.props.thread,}),new CallAction({id:"join",definition:joinUpdated,owner:this,store:this.store,thread:this.props.thread,}),new CallAction({id:"reject",definition:rejectAction,owner:this,store:this.store,thread:this.props.thread,}),];} 11573get otherActions(){return[new Action({id:"toggle-camera-preview",definition:{name:()=>this.state.showCameraPreview?_t("Hide camera preview"):_t("Show camera preview"),icon:()=>this.state.showCameraPreview?"fa fa-chevron-up":"fa fa-chevron-down",onSelected:()=>{this.state.showCameraPreview=!this.state.showCameraPreview;if(this.rtc.cameraPermission!=="denied"){this.state.activateCamera++;} 11574if(this.state.hasMicrophone){this.state.activateMicrophone++;}},tags:()=>[ACTION_TAGS.CALL_LAYOUT],},store:this.store,}),];} 11575get avatarTitle(){const channelName=this.props.thread.displayName;if(this.props.thread.channel_type==="chat"){return _t("View chat with %(channel_name)s",{channel_name:channelName});} 11576return _t("View the %(channel_name)s channel",{channel_name:channelName});} 11577get inviter(){return this.props.thread.self_member_id?.rtc_inviting_session_id?.channel_member_id;} 11578get incomingCallText(){if(this.props.thread.channel_type==="chat"||!this.inviter){return _t("Incoming call");} 11579return _t("Incoming call from %(inviter)s",{inviter:this.inviter.name});} 11580onCallSettingsChanged(settings){if(settings.microphone!==undefined){this.state.hasMicrophone=settings.microphone;}
11581if(settings.camera!==undefined){this.state.hasCamera=settings.camera;}}} 11582return __exports;});; 11583 11584/* /mail/static/src/discuss/call/common/call_invitations.js */ 11585odoo.define('@mail/discuss/call/common/call_invitations',['@mail/discuss/call/common/call_invitation','@mail/utils/common/misc','@odoo/owl','@web/core/registry','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{CallInvitation}=require("@mail/discuss/call/common/call_invitation");const{onChange}=require("@mail/utils/common/misc");const{Component}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{useService}=require("@web/core/utils/hooks");const CallInvitations=__exports.CallInvitations=class CallInvitations extends Component{static props=[];static components={CallInvitation};static template="discuss.CallInvitations";setup(){super.setup();this.rtc=useService("discuss.rtc");this.store=useService("mail.store");}} 11586const callInvitationsService=__exports.callInvitationsService={dependencies:["discuss.rtc","mail.store","overlay"],start(env,services){const store=services["mail.store"];let removeOverlay;const onChangeRingingThreadsLength=()=>{if(store.ringingThreads.length>0){if(!removeOverlay){removeOverlay=services.overlay.add(CallInvitations,{});}}else{removeOverlay?.();removeOverlay=undefined;}};onChangeRingingThreadsLength();
11586onChange(store.ringingThreads,"length",onChangeRingingThreadsLength);},};registry.category("services").add("discuss.call_invitations",callInvitationsService);return __exports;});; 11587 11588/* /mail/static/src/discuss/call/common/call_menu.js */ 11589odoo.define('@mail/discuss/call/common/call_menu',['@odoo/owl','@mail/core/common/action_list','@mail/discuss/call/common/call_actions','@web/core/dropdown/dropdown','@web/core/registry','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useSubEnv}=require("@odoo/owl");const{ActionList}=require("@mail/core/common/action_list");const{useCallActions}=require("@mail/discuss/call/common/call_actions");const{Dropdown}=require("@web/core/dropdown/dropdown");const{registry}=require("@web/core/registry");const{useService}=require("@web/core/utils/hooks");const CallMenu=__exports.CallMenu=class CallMenu extends Component{static props=[];static template="discuss.CallMenu";static components={ActionList,Dropdown};setup(){super.setup();this.rtc=useService("discuss.rtc");this.callActions=useCallActions({thread:()=>this.rtc.channel});this.isEnterprise=odoo.info&&odoo.info.isEnterprise;useSubEnv({inCallMenu:true});} 11590get icon(){const res=this.rtc.callActions.find((action)=>action.id===this.rtc.lastSelfCallAction)?.icon;return(typeof res==="function"?res():res)??"fa fa-microphone";}} 11591registry.category("systray").add("discuss.CallMenu",{Component:CallMenu},{sequence:100});return __exports;});; 11592 11593/* /mail/static/src/discuss/call/common/call_participant_card.js */ 11594odoo.define('@mail/discuss/call/common/call_participant_card',['@mail/discuss/call/common/call_context_menu','@mail/discuss/call/common/call_participant_video','@mail/discuss/call/common/call_dropdown','@mail/discuss/call/common/rtc_service','@mail/utils/common/hooks','@web/core/utils/misc','@web/core/browser/browser','@web/core/browser/feature_detection','@odoo/owl','@web/core/utils/hooks','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{CallContextMenu}=require("@mail/discuss/call/common/call_context_menu");const{CallParticipantVideo}=require("@mail/discuss/call/common/call_participant_video");const{CallDropdown}=require("@mail/discuss/call/common/call_dropdown");const{CONNECTION_TYPES}=require("@mail/discuss/call/common/rtc_service");const{useHover}=require("@mail/utils/common/hooks");const{isEventHandled}=require("@web/core/utils/misc");const{browser}=require("@web/core/browser/browser");const{isMobileOS}=require("@web/core/browser/feature_detection");const{Component,onMounted,onWillUnmount,useRef,useExternalListener}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{rpc}=require("@web/core/network/rpc");const HIDDEN_CONNECTION_STATES=new Set(["connected","completed"]);const CallParticipantCard=__exports.CallParticipantCard=class CallParticipantCard extends Component{static props=["className","cardData","thread","minimized?","inset?","isSidebarItem?","compact?",];static components={CallParticipantVideo,CallContextMenu,CallDropdown};static template="discuss.CallParticipantCard";setup(){super.setup();this.contextMenuAnchorRef=useRef("contextMenuAnchor");this.root=useRef("root");this.rtc=useService("discuss.rtc");this.store=useService("mail.store");this.ui=useService("ui");this.rootHover=useHover("root");this.resumeStreamHover=useHover("resumeStream");this.isMobileOS=isMobileOS();this.dragPos=undefined;this.isDrag=false;this.parentBoundingRect=undefined;onMounted(()=>{if(!this.rtcSession){return;} 11595this.rtc.updateVideoDownload(this.rtcSession,{viewCountIncrement:1,});});onWillUnmount(()=>{if(!this.rtcSession){return;} 11596this.rtc.updateVideoDownload(this.rtcSession,{viewCountIncrement:-1,});});useExternalListener(browser,"fullscreenchange",this.onFullScreenChange);} 11597get isContextMenuAvailable(){return(this.isOfActiveCall&&(this.rtcSession.notEq(this.rtc.selfSession)||(this.env.debug&&this.rtc.state.connectionType===CONNECTION_TYPES.SERVER)));} 11598get isRemoteVideo(){if(!this.rtcSession){return false;} 11599return(this.rtc.isRemote&&(this.rtcSession.is_screen_sharing_on||this.rtcSession.is_camera_on));} 11600get isSmall(){return Boolean(this.props.isSidebarItem||this.ui.isSmall||this.props.minimized||this.props.inset);} 11601get window(){return this.env.pipWindow||window;} 11602get showLiveLabel(){if(this.props.isSidebarItem){return false;} 11603if(this.props.cardData.type==="screen"){if(this.props.inset){return true;}else{return(!this.rtcSession.eq(this.rtcSession.channel.activeRtcSession)&&!this.props.minimized);}} 11604return false;} 11605get showRemoteWarning(){return!this.props.minimized&&!this.props.inset&&this.isRemoteVideo;} 11606get rtcSession(){return this.props.cardData.session;} 11607get channelMember(){return this.rtcSession?this.rtcSession.channel_member_id:this.props.cardData.member;} 11608get isOfActiveCall(){return Boolean(this.rtcSession&&this.rtcSession.channel?.eq(this.rtc.channel));} 11609get showConnectionState(){if(!this.rtcSession||!this.rtc.isHost||!this.isOfActiveCall||HIDDEN_CONNECTION_STATES.has(this.rtcSession.connectionState)){return false;} 11610if(this.rtc.state.connectionType===CONNECTION_TYPES.SERVER){return this.rtcSession.eq(this.rtc?.selfSession);}else{return this.rtcSession.notEq(this.rtc?.selfSession);}} 11611get showServerState(){return false;} 11612get name(){return this.channelMember?.name;} 11613get hasMediaError(){return(this.isOfActiveCall&&Boolean(this.rtcSession?.videoError||this.rtcSession?.audioError));} 11614get hasVideo(){return Boolean(this.props.cardData.videoStream);} 11615get isTalking(){return Boolean(this.rtcSession&&this.rtcSession.isActuallyTalking&&!this.rtc.selfSession?.is_deaf);} 11616get hasRaisingHand(){const screenStream=this.rtcSession.videoStreams.get("screen");return Boolean(this.rtcSession.raisingHand&&(!screenStream||screenStream!==this.props.cardData.videoStream));} 11617get isActiveRtcSession(){return this.rtcSession&&this.rtcSession.eq(this.rtcSession.channel?.activeRtcSession);} 11618async onClick(ev){if(isEventHandled(ev,"CallParticipantCard.clickVolumeAnchor")){return;} 11619if(this.isDrag){this.isDrag=false;return;} 11620if(this.rtcSession){const channel=this.rtcSession.channel;this.rtcSession.mainVideoStreamType=this.props.cardData.type;if(this.rtcSession.eq(channel.activeRtcSession)&&!this.props.inset){channel.activeRtcSession=undefined;this.rtcSession.mainVideoStreamType=undefined;}else{const activeRtcSession=channel.activeRtcSession;const currentMainVideoType=this.rtcSession.mainVideoStreamType;channel.activeRtcSession=this.rtcSession;if(this.props.inset&&activeRtcSession){this.props.inset(activeRtcSession,currentMainVideoType);}} 11621return;} 11622await rpc("/mail/rtc/channel/cancel_call_invitation",{channel_id:this.props.thread.id,member_ids:[this.channelMember.id],});} 11623async onClickReplay(){this.env.bus.trigger("RTC-SERVICE:PLAY_MEDIA");} 11624onMouseDown(){if(!this.props.inset){return;} 11625const onMousemove=(ev)=>this.drag(ev);const onMouseup=()=>{const insetEl=this.root.el;const bottomOffset=this.env.inChatWindow?this.window.innerHeight*0.05:0;if(parseInt(insetEl.style.left)<insetEl.parentNode.offsetWidth/2){insetEl.style.left="1vh";insetEl.style.right="";}else{insetEl.style.left="";insetEl.style.right="1vh";} 11626if(parseInt(insetEl.style.top)<(insetEl.parentNode.offsetHeight-bottomOffset)/2){insetEl.style.top="1vh";insetEl.style.bottom="";}else{insetEl.style.bottom=this.env.inChatWindow?"5vh":"1vh";insetEl.style.top="unset";} 11627this.dragPos=undefined;this.parentBoundingRect=undefined;document.removeEventListener("mouseup",onMouseup);document.removeEventListener("mousemove",onMousemove);};document.addEventListener("mouseup",onMouseup);document.addEventListener("mousemove",onMousemove);} 11628onTouchMove(ev){if(!this.props.inset){return;} 11629this.drag(ev);} 11630drag(ev){this.isDrag=true;const insetEl=this.root.el;const parent=insetEl.parentNode;const boundingRect=this.parentBoundingRect||(this.parentBoundingRect=parent.getBoundingClientRect());const bottomOffset=this.env.inChatWindow?this.window.innerHeight*0.05:0;const clientX=Math.max((ev.clientX??ev.touches[0].clientX)-boundingRect.left,0);const clientY=Math.max((ev.clientY??ev.touches[0].clientY)-boundingRect.top,0);if(!this.dragPos){this.dragPos={posX:clientX,posY:clientY};} 11631const dX=this.dragPos.posX-clientX;const dY=this.dragPos.posY-clientY;
11631const widthOffset=parent.offsetWidth-insetEl.clientWidth;const heightOffset=parent.offsetHeight-insetEl.clientHeight-bottomOffset;this.dragPos.posX=Math.min(clientX,widthOffset);this.dragPos.posY=Math.min(clientY,heightOffset);insetEl.style.left=Math.min(Math.max(insetEl.offsetLeft-dX,0),widthOffset)+"px";insetEl.style.top=Math.min(Math.max(insetEl.offsetTop-dY,0),heightOffset)+"px";} 11632onFullScreenChange(){this.root.el.style="left:''; top:''";}} 11633return __exports;});; 11634 11635/* /mail/static/src/discuss/call/common/call_participant_video.js */ 11636odoo.define('@mail/discuss/call/common/call_participant_video',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onMounted,onPatched,status,useExternalListener,useRef}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const CallParticipantVideo=__exports.CallParticipantVideo=class CallParticipantVideo extends Component{static props=["session","type","inset?"];static template="discuss.CallParticipantVideo";setup(){super.setup();this.rtc=useService("discuss.rtc");this.store=useService("mail.store");this.root=useRef("root");onMounted(()=>this._update());onPatched(()=>this._update());useExternalListener(this.env.bus,"RTC-SERVICE:PLAY_MEDIA",async()=>{await this.play();});} 11637_update(){if(!this.root.el){return;} 11638if(!this.props.session||!this.props.session.getStream(this.props.type)){this.root.el.srcObject=undefined;}else{this.root.el.srcObject=this.props.session.getStream(this.props.type);} 11639this.root.el.load();} 11640async play(){try{await this.root.el?.play?.();this.props.session.videoError=undefined;}catch(error){if(status(this)==="destroyed"){return;} 11641this.props.session.videoError=error.name;}} 11642async onVideoLoadedMetaData(){await this.play();}} 11643return __exports;});; 11644 11645/* /mail/static/src/discuss/call/common/call_permission_dialog.js */ 11646odoo.define('@mail/discuss/call/common/call_permission_dialog',['@odoo/owl','@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const CallPermissionDialog=__exports.CallPermissionDialog=class CallPermissionDialog extends Component{static components={Dialog};static props={close:Function,media:{type:String,validate:(s)=>["camera","microphone"].includes(s),},useMicrophone:Function,useCamera:Function,};static template="discuss.CallPermissionDialog";setup(){this.rtc=useService("discuss.rtc");} 11647async onClickUseMicrophone(){if(await this.rtc.askForBrowserPermission({audio:true})){await this.props.useMicrophone();} 11648this.props.close();} 11649async onClickUseCamera(){if(await this.rtc.askForBrowserPermission({video:true})){await this.props.useCamera();} 11650this.props.close();} 11651async onClickUseMicAndCamera(){if(await this.rtc.askForBrowserPermission({audio:true,video:true})){await Promise.all([this.props.useMicrophone(),this.props.useCamera()]);} 11652this.props.close();} 11653get primaryActionText(){return this.props.media==="camera"?_t("Use Camera"):_t("Use Microphone");} 11654get permissionPrompt(){if(this.props.media==="microphone"){return _t("Do you want people to hear you in the meeting?");} 11655return _t("Do you want people to see you in the meeting?");} 11656get permissionNote(){return _t("You can still turn off your %s anytime.",this.props.media);}} 11657return __exports;});; 11658 11659/* /mail/static/src/discuss/call/common/call_preview.js */ 11660odoo.define('@mail/discuss/call/common/call_preview',['@mail/core/common/action','@mail/core/common/action_list','@mail/discuss/call/common/call_actions','@mail/discuss/call/common/call_permission_dialog','@mail/utils/common/misc','@odoo/owl','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Action,ACTION_TAGS}=require("@mail/core/common/action");const{ActionList}=require("@mail/core/common/action_list");const{cameraOnAction,muteAction,quickActionSettings,quickVideoSettings,}=require("@mail/discuss/call/common/call_actions");const{CallPermissionDialog}=require("@mail/discuss/call/common/call_permission_dialog");const{closeStream,onChange}=require("@mail/utils/common/misc");const{Component,onWillDestroy,status,useEffect,useRef,useState}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const CallPreview=__exports.CallPreview=class CallPreview extends Component{static template="mail.CallPreview";static props=["activateCamera?","activateMicrophone?","onSettingsChanged?"];static components={ActionList};setup(){this.dialog=useService("dialog");this.notification=useService("notification");this.rtc=useService("discuss.rtc");this.store=useService("mail.store");this.state=useState({audioStream:null,blurManager:null,videoStream:null});this.audioRef=useRef("audio");this.videoRef=useRef("video");useEffect((videoEl,audioEl,audioStream,videoStream,blurStream)=>{if(audioEl&&!audioEl.srcObject&&audioStream){audioEl.srcObject=audioStream;} 11661if(videoEl&&!videoEl.srcObject&&videoStream){videoEl.srcObject=blurStream??videoStream;}},()=>[this.videoRef.el,this.audioRef.el,this.state.audioStream,this.state.videoStream,this.state.blurManager?.stream,]);
11661if(this.hasRtcSupport){onChange(this.rtc,"microphonePermission",()=>{if(this.rtc.microphonePermission!=="granted"){this.disableMicrophone();}});onChange(this.rtc,"cameraPermission",()=>{if(this.rtc.cameraPermission!=="granted"){this.disableCamera();}});onChange(this.store.settings,"audioInputDeviceId",()=>{if(this.state.audioStream){closeStream(this.state.audioStream);this.enableMicrophone();}});onChange(this.store.settings,"cameraInputDeviceId",()=>{if(this.state.videoStream){closeStream(this.state.videoStream);this.enableCamera();}});onChange(this.store.settings,"audioOutputDeviceId",(deviceId)=>{this.audioRef.el?.setSinkId?.(deviceId).catch(()=>{});});onChange(this.store.settings,"useBlur",()=>{if(this.store.settings.useBlur){this.enableBlur();}else{this.disableBlur();}});onChange(this.store.settings,["edgeBlurAmount","backgroundBlurAmount"],()=>{if(this.state.blurManager){this.state.blurManager.edgeBlur=this.store.settings.edgeBlurAmount;this.state.blurManager.backgroundBlur=this.store.settings.backgroundBlurAmount;}});onWillDestroy(()=>{closeStream(this.state.audioStream);closeStream(this.state.videoStream);});useEffect((activateCamera)=>{if(activateCamera>0&&!this.state.videoStream){this.enableCamera();}},()=>[this.props.activateCamera]);useEffect((activateMicrophone)=>{if(activateMicrophone>0&&!this.state.audioStream){this.enableMicrophone();}},()=>[this.props.activateMicrophone]);}} 11662get hasRtcSupport(){return Boolean(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&window.MediaStream);} 11663get actions(){const cameraOnActionUpdated={...cameraOnAction,name:()=>(this.state.videoStream?_t("Stop camera"):_t("Turn camera on")),isActive:()=>this.state.videoStream,onSelected:()=>this.toggleCamera(),tags:(...args)=>{const tags=cameraOnAction.tags?.(...args)??[];if(!args[0].action.isActive){tags.push(ACTION_TAGS.DANGER);} 11664return tags;},};const muteActionUpdated={...muteAction,isActive:()=>!this.state.audioStream,name:({action})=>(action.isActive?_t("Unmute"):_t("Mute")),onSelected:()=>this.toggleMic(),};return[[new Action({id:"toggle-microphone",owner:this,definition:muteActionUpdated,store:this.store,}),new Action({id:"audio-settings",owner:this,definition:quickActionSettings,store:this.store,}),],[new Action({id:"toggle-camera",owner:this,definition:cameraOnActionUpdated,store:this.store,}),new Action({id:"video-settings",owner:this,definition:quickVideoSettings,store:this.store,}),],];} 11665async enableMicrophone(){if(this.rtc.microphonePermission!=="granted"&&!(await this.rtc.askForBrowserPermission({audio:true}))){return;} 11666this.state.audioStream=await navigator.mediaDevices.getUserMedia({audio:this.store.settings.audioConstraints,});if(status(this)==="destroyed"){closeStream(this.state.audioStream);return;} 11667if(this.audioRef.el){this.audioRef.el.srcObject=this.state.audioStream;} 11668this.props.onSettingsChanged?.({microphone:true});} 11669disableMicrophone(){closeStream(this.state.audioStream);this.state.audioStream=null;if(this.audioRef.el){this.audioRef.el.srcObject=null;} 11670this.props.onSettingsChanged?.({microphone:false});} 11671async toggleMic(){if(this.state.audioStream){this.disableMicrophone();return;} 11672if(this.rtc.microphonePermission==="prompt"){this.dialog.add(CallPermissionDialog,{media:"microphone",useMicrophone:()=>this.enableMicrophone(),useCamera:()=>this.enableCamera(),});return;} 11673await this.enableMicrophone();} 11674async enableCamera(){if(this.rtc.cameraPermission!=="granted"&&!(await this.rtc.askForBrowserPermission({video:true}))){return;} 11675this.state.videoStream=await navigator.mediaDevices.getUserMedia({video:this.store.settings.cameraConstraints,});if(!this.videoRef.el){return;} 11676if(status(this)==="destroyed"){closeStream(this.state.videoStream);return;} 11677if(this.videoRef.el){this.videoRef.el.srcObject=this.state.videoStream;} 11678this.props.onSettingsChanged?.({camera:true});if(this.store.settings.useBlur){await this.enableBlur();}} 11679disableCamera(){closeStream(this.state.videoStream);this.state.videoStream=null;this.state.blurManager?.close();this.state.blurManager=undefined;if(this.videoRef.el){this.videoRef.el.srcObject=null;} 11680this.props.onSettingsChanged?.({camera:false});} 11681async toggleCamera(){if(this.state.videoStream){this.disableCamera();return;} 11682if(this.rtc.cameraPermission==="prompt"){this.dialog.add(CallPermissionDialog,{media:"camera",useMicrophone:()=>this.enableMicrophone(),useCamera:()=>this.enableCamera(),});return;} 11683await this.enableCamera();} 11684async enableBlur(){this.store.settings.setUseBlur(true);if(!this.videoRef.el){return;} 11685try{this.state.blurManager=await this.rtc.applyBlurEffect(this.state.videoStream);this.videoRef.el.srcObject=await this.state.blurManager.stream;}catch(_e){this.notification.add(_e.message,{type:"warning"});this.disableBlur();}} 11686disableBlur(){this.store.settings.setUseBlur(false);
11686if(this.videoRef.el){this.videoRef.el.srcObject=this.state.videoStream;} 11687this.state.blurManager?.close();this.state.blurManager=undefined;} 11688toggleBlur(){if(this.state.blurManager){this.disableBlur();return;} 11689this.enableBlur();}} 11690return __exports;});; 11691 11692/* /mail/static/src/discuss/call/common/call_settings.js */ 11693odoo.define('@mail/discuss/call/common/call_settings',['@odoo/owl','@web/core/l10n/translation','@web/core/browser/browser','@web/core/utils/timing','@web/core/browser/feature_detection','@web/core/utils/hooks','@mail/utils/common/hooks','@mail/discuss/core/common/action_panel','@mail/discuss/call/common/device_select','@web/core/dialog/dialog'],function(require){'use strict';let __exports={};const{Component,onWillStart,useExternalListener,useState,xml}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{browser}=require("@web/core/browser/browser");const{debounce}=require("@web/core/utils/timing");const{isMobileOS}=require("@web/core/browser/feature_detection");const{useService}=require("@web/core/utils/hooks");const{useMicrophoneVolume}=require("@mail/utils/common/hooks");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{DeviceSelect}=require("@mail/discuss/call/common/device_select");const{Dialog}=require("@web/core/dialog/dialog");const CallSettings=__exports.CallSettings=class CallSettings extends Component{static template="discuss.CallSettings";static props=["withActionPanel?","*"];static defaultProps={withActionPanel:true,};static components={ActionPanel,DeviceSelect};setup(){super.setup();this.notification=useService("notification");this.store=useService("mail.store");this.rtc=useService("discuss.rtc");this.microphoneVolume=useMicrophoneVolume();this.state=useState({userDevices:[],});this.pttExtService=useService("discuss.ptt_extension");this.saveBackgroundBlurAmount=debounce(()=>{browser.localStorage.setItem("mail_user_setting_background_blur_amount",this.store.settings.backgroundBlurAmount.toString());},2000);this.saveEdgeBlurAmount=debounce(()=>{browser.localStorage.setItem("mail_user_setting_edge_blur_amount",this.store.settings.edgeBlurAmount.toString());},2000);useExternalListener(browser,"keydown",this._onKeyDown,{capture:true});useExternalListener(browser,"keyup",this._onKeyUp,{capture:true});onWillStart(async()=>{if(!browser.navigator.mediaDevices){this.notification.add(_t("Media devices unobtainable. SSL might not be set up properly."),{type:"warning"});console.warn("Media devices unobtainable. SSL might not be set up properly.");return;} 11694this.state.userDevices=await browser.navigator.mediaDevices.enumerateDevices();});} 11695get stopText(){return _t("Stop");} 11696get testText(){return _t("Test");} 11697get pushToTalkKeyText(){const{shiftKey,ctrlKey,altKey,key}=this.store.settings.pushToTalkKeyFormat();const f=(k,name)=>(k?name:"");const keys=[f(ctrlKey,"Ctrl"),f(altKey,"Alt"),f(shiftKey,"Shift"),key].filter(Boolean);return keys.join(" + ");} 11698get isMobileOS(){return isMobileOS();} 11699_onKeyDown(ev){if(!this.store.settings.isRegisteringKey){return;} 11700ev.stopPropagation();ev.preventDefault();this.store.settings.setPushToTalkKey(ev);} 11701_onKeyUp(ev){if(!this.store.settings.isRegisteringKey){return;} 11702ev.stopPropagation();ev.preventDefault();this.store.settings.isRegisteringKey=false;} 11703onChangeLogRtc(ev){this.store.settings.logRtc=ev.target.checked;} 11704onChangeSelectAudioInput(ev){this.store.settings.setAudioInputDevice(ev.target.value);} 11705onClickDownloadLogs(){this.rtc.dumpLogs({download:true});} 11706onClickRegisterKeyButton(){this.store.settings.isRegisteringKey=!this.store.settings.isRegisteringKey;} 11707onChangeDelay(ev){this.store.settings.setDelayValue(ev.target.value);} 11708onChangeBlur(ev){this.store.settings.setUseBlur(ev.target.checked);} 11709onChangeShowOnlyVideo(ev){const showOnlyVideo=ev.target.checked;this.store.settings.showOnlyVideo=showOnlyVideo;browser.localStorage.setItem("mail_user_setting_show_only_video",this.store.settings.showOnlyVideo);const activeRtcSessions=this.store.allActiveRtcSessions;if(showOnlyVideo&&activeRtcSessions){activeRtcSessions.filter((rtcSession)=>!rtcSession.videoStream).forEach((rtcSession)=>{rtcSession.channel.activeRtcSession=undefined;});}}
11710onChangeBackgroundBlurAmount(ev){this.store.settings.backgroundBlurAmount=Number(ev.target.value);this.saveBackgroundBlurAmount();} 11711onChangeEdgeBlurAmount(ev){this.store.settings.edgeBlurAmount=Number(ev.target.value);this.saveEdgeBlurAmount();}} 11712const CallSettingsDialog=__exports.CallSettingsDialog=class CallSettingsDialog extends Component{static template=xml` 11713 <Dialog size="medium" footer="false" title.translate="Voice & Video Settings"> 11714 <CallSettings withActionPanel="false"/> 11715 </Dialog> 11716 `;static props=["*"];static components={CallSettings,Dialog};} 11717return __exports;});; 11718 11719/* /mail/static/src/discuss/call/common/channel_member_patch.js */ 11720odoo.define('@mail/discuss/call/common/channel_member_patch',['@mail/discuss/core/common/channel_member_model','@mail/core/common/record','@web/core/browser/browser','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChannelMember}=require("@mail/discuss/core/common/channel_member_model");const{fields}=require("@mail/core/common/record");const{browser}=require("@web/core/browser/browser");const{patch}=require("@web/core/utils/patch");ChannelMember.CANCEL_CALL_INVITE_DELAY=30000;const ChannelMemberPatch={setup(){super.setup(...arguments);this.rtc_inviting_session_id=fields.One("discuss.channel.rtc.session",{onAdd(r){if(!this.channel_id){return;} 11721this.channel_id.rtc_session_ids.add(r);this.store.ringingThreads.add(this.channel_id);this.channel_id.cancelRtcInvitationTimeout=browser.setTimeout(()=>{this.store.env.services["discuss.rtc"].leaveCall(this.channel_id);},ChannelMember.CANCEL_CALL_INVITE_DELAY);},onDelete(){if(!this.channel_id){return;} 11722browser.clearTimeout(this.channel_id.cancelRtcInvitationTimeout);this.store.ringingThreads.delete(this.channel_id);},});this.rtcSession=fields.One("discuss.channel.rtc.session");},};patch(ChannelMember.prototype,ChannelMemberPatch);return __exports;});; 11723 11724/* /mail/static/src/discuss/call/common/chat_window_patch.js */ 11725odoo.define('@mail/discuss/call/common/chat_window_patch',['@mail/core/common/chat_window','@mail/discuss/call/common/call','@mail/discuss/call/common/pip_banner','@web/core/utils/hooks','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChatWindow}=require("@mail/core/common/chat_window");const{Call}=require("@mail/discuss/call/common/call");const{PipBanner}=require("@mail/discuss/call/common/pip_banner");const{useService}=require("@web/core/utils/hooks");const{patch}=require("@web/core/utils/patch");Object.assign(ChatWindow.components,{Call,PipBanner});patch(ChatWindow.prototype,{setup(){super.setup(...arguments);this.rtc=useService("discuss.rtc");},});return __exports;});; 11726 11727/* /mail/static/src/discuss/call/common/device_select.js */ 11728odoo.define('@mail/discuss/call/common/device_select',['@odoo/owl','@web/core/browser/browser','@web/core/l10n/translation','@web/core/utils/hooks','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,onWillStart,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");const{isBrowserChrome}=require("@web/core/browser/feature_detection");const deviceKind=new Set(["audioinput","videoinput","audiooutput"]);const DeviceSelect=__exports.DeviceSelect=class DeviceSelect extends Component{static props={kind:{type:String,validate:(string)=>deviceKind.has(string),},};static template="discuss.CallDeviceSelect";setup(){super.setup();this.store=useService("mail.store");this.notification=useService("notification");this.state=useState({userDevices:[],});this.abortController=new AbortController();this.isBrowserChrome=isBrowserChrome();onWillStart(async()=>{if(!browser.navigator.mediaDevices){this.notification.add(_t("Media devices unobtainable. SSL might not be set up properly."),{type:"warning"});console.warn("Media devices unobtainable. SSL might not be set up properly.");return;} 11729await this.updateDevicesList();this.setupEventListeners();});onWillDestroy(()=>{this.abortController.abort();});} 11730async updateDevicesList(){this.state.userDevices=await browser.navigator.mediaDevices.enumerateDevices();} 11731async setupEventListeners(){const boundHandler=this.updateDevicesList.bind(this);const signal=this.abortController.signal;browser.navigator.mediaDevices.addEventListener("devicechange",boundHandler,{signal});if(this.props.kind=="videoinput"){const cameraPermission=await browser.navigator.permissions.query({name:"camera"});cameraPermission.addEventListener("change",boundHandler,{signal});}else{const microphonePermission=await browser.navigator.permissions.query({name:"microphone",});microphonePermission.addEventListener("change",boundHandler,{signal});}} 11732async showPermissionDialog(kind){if(kind==="videoinput"){if(this.store.rtc.cameraPermission==="denied"){this.store.rtc.showMediaUnavailableWarning({camera:true});}else{this.store.rtc.showMediaPermissionDialog("camera");return;}}else{if(this.store.rtc.microphonePermission==="denied"){this.store.rtc.showMediaUnavailableWarning({microphone:true});}else{this.store.rtc.showMediaPermissionDialog("microphone");return;}}}
11733isSelected(id){switch(this.props.kind){case"audioinput":return this.store.settings.audioInputDeviceId===id;case"videoinput":return this.store.settings.cameraInputDeviceId===id;case"audiooutput":return this.store.settings.audioOutputDeviceId===id;}} 11734onChangeSelectAudioInput(ev){switch(this.props.kind){case"audioinput":this.store.rtc.askForBrowserPermission({audio:true,deviceId:ev.target.value}).then((granted)=>{if(granted){this.store.settings.setAudioInputDevice(ev.target.value);}else{ev.target.value=this.store.settings.audioInputDeviceId;}});return;case"videoinput":this.store.rtc.askForBrowserPermission({video:true,deviceId:ev.target.value}).then((granted)=>{if(granted){this.store.settings.setCameraInputDevice(ev.target.value);}else{ev.target.value=this.store.settings.cameraInputDeviceId;}});return;case"audiooutput":this.store.settings.setAudioOutputDevice(ev.target.value);return;}} 11735isPermissionGranted(kind){if(kind==="videoinput"){return this.store.rtc.cameraPermission==="granted";} 11736return this.store.rtc.microphonePermission==="granted";}} 11737return __exports;});; 11738 11739/* /mail/static/src/discuss/call/common/discuss_call_settings_client_action.js */ 11740odoo.define('@mail/discuss/call/common/discuss_call_settings_client_action',['@odoo/owl','@web/core/registry','@mail/discuss/call/common/call_settings'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{CallSettings}=require("@mail/discuss/call/common/call_settings");const DiscussCallSettingsClientAction=__exports.DiscussCallSettingsClientAction=class DiscussCallSettingsClientAction extends Component{static components={CallSettings};static props=["*"];static template="mail.DiscussCallSettingsClientAction";} 11741registry.category("actions").add("mail.discuss_call_settings_action",DiscussCallSettingsClientAction);return __exports;});; 11742 11743/* /mail/static/src/discuss/call/common/discuss_p2p_service.js */ 11744odoo.define('@mail/discuss/call/common/discuss_p2p_service',['@web/core/registry','@mail/discuss/call/common/peer_to_peer'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{PeerToPeer}=require("@mail/discuss/call/common/peer_to_peer");const discussP2P=__exports.discussP2P={dependencies:["bus_service"],start(env,services){const p2p=new PeerToPeer({logLevel:env.debug?"info":undefined,notificationRoute:"/mail/rtc/session/notify_call_members",});services["bus_service"].subscribe("discuss.channel.rtc.session/peer_notification",({sender,notifications})=>{for(const content of notifications){p2p.handleNotification(sender,content);}});return p2p;},};registry.category("services").add("discuss.p2p",discussP2P);return __exports;});; 11745 11746/* /mail/static/src/discuss/call/common/mail_guest_model_patch.js */ 11747odoo.define('@mail/discuss/call/common/mail_guest_model_patch',['@mail/core/common/mail_guest_model','@mail/model/misc','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{MailGuest}=require("@mail/core/common/mail_guest_model");const{fields}=require("@mail/model/misc");const{patch}=require("@web/core/utils/patch");patch(MailGuest.prototype,{setup(){super.setup(...arguments);this.currentRtcSession=fields.One("discuss.channel.rtc.session",{inverse:"guest_id"});},});return __exports;});; 11748 11749/* /mail/static/src/discuss/call/common/meeting.js */ 11750odoo.define('@mail/discuss/call/common/meeting',['@mail/core/common/composer','@mail/core/common/thread','@mail/discuss/call/common/call','@mail/discuss/call/common/call_action_list','@mail/discuss/core/common/channel_invitation','@mail/utils/common/hooks','@odoo/owl','@web/core/dropdown/dropdown','@web/core/utils/hooks','@mail/discuss/call/common/meeting_side_actions','@mail/core/common/thread_actions','@mail/core/common/message_search_hook'],function(require){'use strict';let __exports={};const{Composer}=require("@mail/core/common/composer");const{Thread}=require("@mail/core/common/thread");const{Call}=require("@mail/discuss/call/common/call");const{CallActionList}=require("@mail/discuss/call/common/call_action_list");const{ChannelInvitation}=require("@mail/discuss/core/common/channel_invitation");const{inDiscussCallViewProps,useInDiscussCallView,useMessageScrolling,}=require("@mail/utils/common/hooks");const{Component,onMounted,onWillUnmount,useChildSubEnv,useSubEnv}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{useService}=require("@web/core/utils/hooks");const{MeetingSideActions}=require("@mail/discuss/call/common/meeting_side_actions");const{useThreadActions}=require("@mail/core/common/thread_actions");const{useMessageSearch}=require("@mail/core/common/message_search_hook");const Meeting=__exports.Meeting=class Meeting extends Component{static template="mail.Meeting";static props=["autoOpenAction?",...inDiscussCallViewProps];static components={Call,CallActionList,ChannelInvitation,Composer,Dropdown,MeetingSideActions,Thread,};setup(){this.store=useService("mail.store");this.ui=useService("ui");this.rtc=useService("discuss.rtc");onMounted(()=>
11750{if(this.props.autoOpenAction){this.threadActions.actions.find((a)=>a.id===this.props.autoOpenAction)?.onSelected();}});useInDiscussCallView();useSubEnv({inMeetingView:{openChat:()=>this.threadActions.actions.find((action)=>action.id==="meeting-chat")?.open(),},});this.threadActions=useThreadActions({thread:()=>this.thread});this.messageHighlight=useMessageScrolling();this.messageSearch=useMessageSearch(this.thread);useChildSubEnv({closeActionPanel:()=>this.threadActions.activeAction?.close(),messageHighlight:this.messageHighlight,messageSearch:this.messageSearch,});onMounted(()=>(this.store.meetingViewOpened=true));onWillUnmount(()=>(this.store.meetingViewOpened=false));} 11751get thread(){return this.store.rtc.channel;}} 11752return __exports;});; 11753 11754/* /mail/static/src/discuss/call/common/meeting_chat.js */ 11755odoo.define('@mail/discuss/call/common/meeting_chat',['@mail/core/common/composer','@mail/core/common/thread','@mail/discuss/core/common/action_panel','@mail/discuss/typing/common/typing','@odoo/owl','@web/core/browser/feature_detection','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Composer}=require("@mail/core/common/composer");const{Thread}=require("@mail/core/common/thread");const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{Typing}=require("@mail/discuss/typing/common/typing");const{Component,useState,useSubEnv}=require("@odoo/owl");const{isMobileOS}=require("@web/core/browser/feature_detection");const{useChildRef,useService}=require("@web/core/utils/hooks");const MeetingChat=__exports.MeetingChat=class MeetingChat extends Component{static template="mail.MeetingChat";static components={ActionPanel,Composer,Thread,Typing,};static props=["thread?"];setup(){this.store=useService("mail.store");this.ui=useService("ui");this.rtc=useService("discuss.rtc");this.state=useState({jumpPresent:0});this.panelContentRef=useChildRef();this.isMobileOS=isMobileOS();useSubEnv({inMeetingChat:true});} 11756get thread(){return this.store.rtc.channel;}} 11757return __exports;});; 11758 11759/* /mail/static/src/discuss/call/common/meeting_side_actions.js */ 11760odoo.define('@mail/discuss/call/common/meeting_side_actions',['@mail/core/common/action_list','@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{ActionList}=require("@mail/core/common/action_list");const{Component,useSubEnv}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const MeetingSideActions=__exports.MeetingSideActions=class MeetingSideActions extends Component{static template="mail.MeetingSideActions";static props=["threadActions"];static components={ActionList};setup(){this.store=useService("mail.store");useSubEnv({inMeetingSideActions:true});} 11761computeActions(){const quickThreadActionIds=["invite-people","meeting-chat"];const threadActions=this.props.threadActions;const{quick,other,group}=threadActions.partition;const partitionedActions={quick:quick.filter((action)=>!quickThreadActionIds.includes(action.id)),other:other.filter((action)=>!quickThreadActionIds.includes(action.id)),group:group.map((group)=>group.filter((action)=>!quickThreadActionIds.includes(action.id))).filter((g)=>g.length>0),};const actions=threadActions.actions.filter((action)=>quickThreadActionIds.includes(action.id));actions.push(threadActions.more({actions:[partitionedActions.quick,partitionedActions.other,...partitionedActions.group,],}));this.actions=actions;}} 11762return __exports;});; 11763 11764/* /mail/static/src/discuss/call/common/peer_to_peer.js */ 11765odoo.define('@mail/discuss/call/common/peer_to_peer',['@web/core/network/rpc','@web/core/utils/concurrency','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{rpc}=require("@web/core/network/rpc");const{Deferred}=require("@web/core/utils/concurrency");const{browser}=require("@web/core/browser/browser");const STREAM_TYPE=__exports.STREAM_TYPE=Object.freeze({AUDIO:"audio",CAMERA:"camera",SCREEN:"screen",});const UPDATE_EVENT=__exports.UPDATE_EVENT=Object.freeze({BROADCAST:"broadcast",CONNECTION_CHANGE:"connection_change",DISCONNECT:"disconnect",INFO_CHANGE:"info_change",RECOVERY:"recovery",TRACK:"track",});const LOG_LEVEL=Object.freeze({NONE:"none",DEBUG:"debug",INFO:"info",WARN:"warn",ERROR:"error",});const INTERNAL_EVENT=Object.freeze({ANSWER:"answer",BROADCAST:"broadcast",DISCONNECT:"disconnect",ICE_CA
11765NDIDATE:"ice-candidate",INFO:"info",OFFER:"offer",TRACK_CHANGE:"trackChange",});const ORDERED_TRANSCEIVER_TYPES=[STREAM_TYPE.AUDIO,STREAM_TYPE.CAMERA,STREAM_TYPE.SCREEN];const DEFAULT_BUS_BATCH_DELAY=100;const INITIAL_RECONNECT_DELAY=2_000+Math.random()*1_000;const MAXIMUM_RECONNECT_DELAY=25_000+Math.random()*5_000;const INVALID_ICE_CONNECTION_STATES=new Set(["disconnected","failed","closed"]);const IS_CLIENT_RTC_COMPATIBLE=Boolean(window.RTCPeerConnection&&window.MediaStream);const DEFAULT_ICE_SERVERS=[{urls:["stun:stun1.l.google.com:19302","stun:stun2.l.google.com:19302"]},];const DEFAULT_NOTIFICATION_ROUTE="/mail/rtc/session/notify_call_members";const Peer=__exports.Peer=class Peer{id;connection;connectRetryDelay=INITIAL_RECONNECT_DELAY;sequence=0;dataChannel;hasPriority=false;isBuildingOffer=false;isBuildingAnswer=false;medias=Object.seal({[STREAM_TYPE.AUDIO]:{track:null,active:false,accepted:true,},[STREAM_TYPE.SCREEN]:{track:null,active:false,accepted:true,},[STREAM_TYPE.CAMERA]:{track:null,active:false,accepted:true,},});constructor(id,{connection,dataChannel,hasPriority=false,connectRetryDelay=INITIAL_RECONNECT_DELAY,sequence=0,}){this.id=id;this.connection=connection;this.dataChannel=dataChannel;this.hasPriority=hasPriority;this.connectRetryDelay=connectRetryDelay;this.sequence=sequence;this.ready=new Deferred();} 11766disconnect(){if(this.connection){const RTCRtpSenders=this.connection.getSenders();for(const sender of RTCRtpSenders){try{this.connection.removeTrack(sender);}catch{}} 11767for(const transceiver of this.connection.getTransceivers()){try{transceiver.stop();}catch{}}} 11768this.ready.resolve?.();this.connection?.close();this.connection=undefined;this.dataChannel?.close();this.dataChannel=undefined;for(const media of Object.values(this.medias)){media.track?.stop();}} 11769getRecommendedTransceiverDirection(streamType,canUpload=false){if(this.medias[streamType].accepted){return canUpload?"sendrecv":"recvonly";}else{return canUpload?"sendonly":"inactive";}} 11770getTransceiver(streamType){if(!this.connection){return;} 11771const transceivers=this.connection.getTransceivers();return transceivers[ORDERED_TRANSCEIVER_TYPES.indexOf(streamType)];} 11772getTransceiverStreamType(transceiver){const transceivers=this.connection.getTransceivers();return ORDERED_TRANSCEIVER_TYPES[transceivers.indexOf(transceiver)];}} 11773const PeerToPeer=__exports.PeerToPeer=class PeerToPeer extends EventTarget{selfId;channelId;peers=new Map();acceptOffer=async(id,sequence)=>true;_batchDelay=DEFAULT_BUS_BATCH_DELAY;_localInfo=Object.seal({isSelfMuted:false,isRaisingHand:false,isDeaf:false,isTalking:false,isCameraOn:false,isScreenSharingOn:false,});_iceServers;_isPendingNotify=false;_notificationsToSend=new Map();_isAntiGlareEnabled=true;_tmpNotificationId=0;_recoverTimeouts=new Map();_notificationRoute;_isStreamingEnabled=true;_tracks=Object.seal({[STREAM_TYPE.AUDIO]:null,[STREAM_TYPE.SCREEN]:null,[STREAM_TYPE.CAMERA]:null,});_loggingFunctions={[LOG_LEVEL.DEBUG]:()=>{},[LOG_LEVEL.INFO]:()=>{},[LOG_LEVEL.WARN]:()=>{},[LOG_LEVEL.ERROR]:()=>{},};get isActive(){return Boolean(this.selfId!==undefined&&this.channelId!==undefined);} 11774constructor({notificationRoute=DEFAULT_NOTIFICATION_ROUTE,logLevel=LOG_LEVEL.ERROR,batchDelay=DEFAULT_BUS_BATCH_DELAY,antiGlare=true,enableStreaming=true,}={}){super();this._isStreamingEnabled=enableStreaming;this._isAntiGlareEnabled=antiGlare;this._notificationRoute=notificationRoute;this._batchDelay=batchDelay;this.setLoggingLevel(logLevel);} 11775connect(selfId,channelId,{info={},iceServers=DEFAULT_ICE_SERVERS}={}){if(!IS_CLIENT_RTC_COMPATIBLE){throw new Error("RTCPeerConnection is not supported");} 11776this.selfId=selfId;this.channelId=channelId;this._iceServers=iceServers;this._localInfo=Object.assign(this._localInfo,info);} 11777removeALlPeers(){for(const peer of this.peers.values()){this.removePeer(peer.id);} 11778this.peers.clear();} 11779disconnect(){this.removeALlPeers();this.selfId=undefined;this.channelId=undefined;this._isPendingNotify=false;this._notificationsToSend.clear();this._localInfo=Object.assign(this._localInfo,{isSelfMuted:false,isRaisingHand:false,isDeaf:false,isTalking:false,isCameraOn:false,isScreenSharingOn:false,});} 11780async addPeer(id,options={}){const peer=this.peers.get(id);if(peer){return peer;} 11781const newPeer=this._createPeer(id,options);await newPeer.ready;return newPeer;} 11782removePeer(id){const recoverTimeoutId=this._recoverTimeouts.get(id);browser.clearTimeout(recoverTimeoutId);this._recoverTimeouts.delete(id);const peer=this.peers.get(id);if(!peer){return;} 11783this.peers.delete(id);peer.disconnect();} 11784broadcast(message){this._dataChannelBroadcast(INTERNAL_EVENT.BROADCAST,message);} 11785async getFormattedStats(id){const peer=this.peers.get(id);const formattedStats={};if(!peer){return formattedStats;} 11786formattedStats.connectionState=peer.connection.connectionState;formattedStats.iceConnectionState=peer.connection.iceConnectionState;formattedStats.iceGatheringState=peer.connection.iceGatheringState;const stats=await peer.connection.getStats();for(const value of stats?.values()||[]){switch(value.type){case"candidate-pair":if(value.state==="succeeded"&&value.localCandidateId){formattedStats.localCandidateType=stats.get(value.localCandidateId)?.candidateType||"";formattedStats.remoteCandidateType=stats.get(value.remoteCandidateId)?.candidateType||"";} 11787break;case"data-channel":formattedStats.dataChannelState=value.state;break;case"transport":formattedStats.dtlsState=value.dtlsState;formattedStats.iceState=value.iceState;formattedStats.packetsReceived=value.packetsReceived;formattedStats.packetsSent=value.packetsSent;break;}} 11788return formattedStats;} 11789updateDownload(id,states){const peer=this.peers.get(id);if(!peer){return;} 11790for(const[streamType,accepted]of Object.entries(states)){peer.medias[streamType].accepted=accepted;const transceiver=peer.getTransceiver(streamType);if(!transceiver){this._recover(id,`no transceiver available when updating direction`);return;} 11791transceiver.direction=peer.getRecommendedTransceiverDirection(streamType,Boolean(this._tracks[streamType]));}} 11792async updateUpload(streamType,track){this._tracks[streamType]=track||null;this.updateInfo({isScreenSharingOn:Boolean(this._tracks[STREAM_TYPE.SCREEN]),isCameraOn:Boolean(this._tracks[STREAM_TYPE.CAMERA]),});const proms=[];for(const peer of this.peers.values()){proms.push(peer.ready.then(()=>this._updateRemote(peer,streamType)));} 11793await Promise.all(proms);} 11794updateInfo(info){this._localInfo=Object.assign(this._localInfo,info);this._dataChannelBroadcast(INTERNAL_EVENT.INFO,this._localInfo);} 11795async handleNotification(id,content){const{event,channelId,payload}=JSON.parse(content);this._emitLog(id,`received notification: ${event}`,LOG_LEVEL.DEBUG);
11795if(channelId!==this.channelId){return;} 11796let peer=this.peers.get(id);if(event!==INTERNAL_EVENT.OFFER&&!peer?.connection){this._emitLog(id,`received ${event} for missing peer ${id}`,LOG_LEVEL.WARN);return;} 11797switch(event){case INTERNAL_EVENT.ANSWER:{this._emitLog(id,`received answer`,LOG_LEVEL.DEBUG);if(INVALID_ICE_CONNECTION_STATES.has(peer.connection.iceConnectionState)||peer.connection.signalingState==="stable"||peer.connection.signalingState==="have-remote-offer"){return;} 11798const description=new window.RTCSessionDescription(payload.sdp);try{await peer.connection.setRemoteDescription(description);}catch{this._recover(id,"answer handling: Failed at setting remoteDescription");} 11799break;} 11800case INTERNAL_EVENT.BROADCAST:{this._emitUpdate({name:UPDATE_EVENT.BROADCAST,payload:{senderId:id,message:payload},});peer.ready.resolve(true);break;} 11801case INTERNAL_EVENT.DISCONNECT:{this.removePeer(id);this._emitUpdate({name:UPDATE_EVENT.DISCONNECT,payload:{sessionId:id}});break;} 11802case INTERNAL_EVENT.ICE_CANDIDATE:{if(INVALID_ICE_CONNECTION_STATES.has(peer.connection.iceConnectionState)){return;} 11803const rtcIceCandidate=new window.RTCIceCandidate(payload.candidate);try{await peer.connection.addIceCandidate(rtcIceCandidate);}catch{this._recover(id,"failed at adding ice candidate");} 11804break;} 11805case INTERNAL_EVENT.INFO:{const{isTalking,isCameraOn,isScreenSharingOn}=payload;peer.medias[STREAM_TYPE.AUDIO].active=isTalking;peer.medias[STREAM_TYPE.CAMERA].active=isCameraOn;peer.medias[STREAM_TYPE.SCREEN].active=isScreenSharingOn;this._emitUpdate({name:UPDATE_EVENT.INFO_CHANGE,payload:{[id]:payload},});break;} 11806case INTERNAL_EVENT.OFFER:{try{const accepted=await this.acceptOffer(id,payload.sequence);if(!accepted){this._emitLog(id,"offer rejected",LOG_LEVEL.INFO);return;}}catch(error){this._emitLog(id,`offer rejected: ${error}`,LOG_LEVEL.INFO);} 11807if(!peer){peer=this._createPeer(id,{sequence:payload.sequence});} 11808if(!peer.connection||INVALID_ICE_CONNECTION_STATES.has(peer.connection.iceConnectionState)||peer.connection.signalingState==="have-remote-offer"){return;} 11809const isStable=peer.connection.signalingState==="stable"||peer.isBuildingAnswer;const hasOfferCollision=!isStable||peer.isBuildingOffer;if(hasOfferCollision&&peer.hasPriority&&this._isAntiGlareEnabled){this._emitLog(peer.id,`rolling back due to offer collision: ${peer.connection.signalingState}`,LOG_LEVEL.WARN);try{await peer.connection.setLocalDescription({type:"rollback"});}catch{this._recover(id,`failed rollback`);}} 11810const description=new window.RTCSessionDescription(payload.sdp);try{await peer.connection.setRemoteDescription(description);}catch{this._recover(id,"failed at setting remoteDescription");return;} 11811if(!peer.connection){this._emitLog(id,"the peer connection was closed during offer negotiation",LOG_LEVEL.WARN);return;} 11812if(this._isStreamingEnabled){if(peer.connection.getTransceivers().length===0){for(const streamType of ORDERED_TRANSCEIVER_TYPES){const type=streamType===STREAM_TYPE.AUDIO?"audio":"video";peer.connection.addTransceiver(type);}} 11813for(const transceiverName of ORDERED_TRANSCEIVER_TYPES){await this._updateRemote(peer,transceiverName);}} 11814peer.isBuildingAnswer=true;try{await peer.connection.setLocalDescription(await peer.connection.createAnswer());}catch{peer.isBuildingAnswer=false;this._recover(id,"offer handling: failed at setting answer localDescription");return;} 11815peer.isBuildingAnswer=false;if(!this.isActive||!this.peers.has(id)){return;} 11816this._emitLog(id,`sending answer`,LOG_LEVEL.DEBUG);await this._busNotify(INTERNAL_EVENT.ANSWER,{payload:{sdp:peer.connection.localDescription,},targets:[peer.id],});this._recover(peer.id,"standard answer timeout");break;}}} 11817setLoggingLevel(logLevel){const makeLog=(level)=>(id,message)=>{this.dispatchEvent(new CustomEvent("log",{detail:{id,level,message}}));};this._loggingFunctions={[LOG_LEVEL.DEBUG]:()=>{},[LOG_LEVEL.INFO]:()=>{},[LOG_LEVEL.WARN]:()=>{},[LOG_LEVEL.ERROR]:()=>{},};switch(logLevel){case LOG_LEVEL.DEBUG:this._loggingFunctions[LOG_LEVEL.DEBUG]=makeLog(LOG_LEVEL.DEBUG);case LOG_LEVEL.INFO:this._loggingFunctions[LOG_LEVEL.INFO]=makeLog(LOG_LEVEL.INFO);case LOG_LEVEL.WARN:this._loggingFunctions[LOG_LEVEL.WARN]=makeLog(LOG_LEVEL.WARN);case LOG_LEVEL.ERROR:this._loggingFunctions[LOG_LEVEL.ERROR]=makeLog(LOG_LEVEL.ERROR);}} 11818_dataChannelBroadcast(internalEvent,message){for(const peer of this.peers.values()){if(!peer?.dataChannel||peer?.dataChannel.readyState!=="open"){continue;} 11819peer.dataChannel.send(JSON.stringify({event:internalEvent,channelId:this.channelId,payload:message,}));}} 11820_emitUpdate(detail){this.dispatchEvent(new CustomEvent("update",{detail}));} 11821_emitLog(id,message,level=LOG_LEVEL.DEBUG){this._loggingFunctions[level](id,message);} 11822_recover(id,reason=""){this._emitLog(id,`connection recovery candidate: ${reason}`,LOG_LEVEL.WARN);if(this._recoverTimeouts.get(id)){return;} 11823const peer=this.peers.get(id);if(!peer){return;} 11824const delay=Math.min(peer.connectRetryDelay*1.5,MAXIMUM_RECONNECT_DELAY)+1000*Math.random();this._recoverTimeouts.set(id,browser.setTimeout(async()=>{const peer=this.peers.get(id);this._recoverTimeouts.delete(id);const connectionSuccess=peer.connection.connectionState==="connected"||peer.connection.connectionState==="completed";const iceSuccess=peer.connection.iceConnectionState==="connected"||peer.connection.iceConnectionState==="completed";if(!peer?.connection||!this.channelId||(connectionSuccess&&iceSuccess)){return;} 11825this._emitUpdate({name:UPDATE_EVENT.RECOVERY,payload:{id}});
11825this._emitLog(id,`attempting to recover connection: ${reason}`,LOG_LEVEL.ERROR);this._busNotify(INTERNAL_EVENT.DISCONNECT,{targets:[peer.id]});this.removePeer(peer.id);this.addPeer(peer.id,{connectRetryDelay:delay,sequence:peer.sequence});},delay));} 11826async _sendNotifications(){if(this._isPendingNotify){return;} 11827this._isPendingNotify=true;await new Promise((resolve)=>setTimeout(resolve,this._batchDelay));if(!this.isActive){this._isPendingNotify=false;return;} 11828const ids=[];const notifications=[];this._notificationsToSend.forEach((notification,id)=>{ids.push(id);notifications.push([notification.sender,notification.targets,JSON.stringify({event:notification.event,channelId:notification.channelId,payload:notification.payload,}),]);});try{await rpc(this._notificationRoute,{peer_notifications:notifications,},{silent:true});for(const id of ids){this._notificationsToSend.delete(id);}}finally{this._isPendingNotify=false;if(this._notificationsToSend.size>0){await this._sendNotifications();}}} 11829async _busNotify(event,{payload,targets}={}){targets=targets||Array.from(this.peers.keys());let id;if(event===INTERNAL_EVENT.OFFER){id=`latestOffer_to:${targets[0]}`;}else{id=++this._tmpNotificationId;} 11830this._notificationsToSend.set(id,{channelId:this.channelId,event,payload,sender:this.selfId,targets,});await this._sendNotifications();} 11831async _updateRemote(peer,streamType){const track=this._tracks[streamType];const transceiver=peer.getTransceiver(streamType);if(!transceiver){return;} 11832try{await transceiver.sender.replaceTrack(track);transceiver.direction=peer.getRecommendedTransceiverDirection(streamType,Boolean(track));}catch(error){this._recover(peer.id,`failed to update ${streamType} transceiver for peer ${peer.id}: ${error}`);}} 11833_createPeer(id,options={}){this.removePeer(id);const peerConnection=new window.RTCPeerConnection({iceServers:this._iceServers});const dataChannel=peerConnection.createDataChannel("notifications",{negotiated:true,id:1,});const peer=new Peer(id,{...options,connection:peerConnection,dataChannel,hasPriority:id>this.selfId,});this._emitUpdate({name:UPDATE_EVENT.CONNECTION_CHANGE,payload:{id,peer,state:"searching for network"},});this.peers.set(id,peer);peerConnection.addEventListener("icecandidate",async(event)=>{if(!event.candidate){return;} 11834if(!this.isActive||!this.peers.has(id)){return;} 11835await this._busNotify(INTERNAL_EVENT.ICE_CANDIDATE,{payload:{candidate:event.candidate,},targets:[id],});});peerConnection.addEventListener("iceconnectionstatechange",async()=>{switch(peerConnection.iceConnectionState){case"closed":this.removePeer(id);break;case"failed":case"disconnected":this._recover(peer.id,1000,"ice connection disconnected");break;}});peerConnection.addEventListener("icegatheringstatechange",()=>{this._emitLog(id,`gathering state change: ${peerConnection.iceGatheringState}`,LOG_LEVEL.INFO);});peerConnection.addEventListener("connectionstatechange",async()=>{this._emitUpdate({name:UPDATE_EVENT.CONNECTION_CHANGE,payload:{id,peer,state:peerConnection.connectionState},});switch(peerConnection.connectionState){case"closed":this.removePeer(id);break;case"failed":case"disconnected":this._recover(peer.id,1000,"connection disconnected");break;} 11836this._emitLog(id,`connection state change: ${peerConnection.connectionState}`,LOG_LEVEL.INFO);});peerConnection.addEventListener("icecandidateerror",async(error)=>{this._recover(id,`ice candidate error: ${error.errorText}`);});peerConnection.addEventListener("negotiationneeded",async()=>{peer.isBuildingOffer=true;try{await peerConnection.setLocalDescription(await peerConnection.createOffer());}catch(error){this._recover(id,`failed to set local Description for offer: ${error}`);peer.isBuildingOffer=false;return;} 11837peer.isBuildingOffer=false;if(!this.isActive||!this.peers.has(id)){return;} 11838await this._busNotify(INTERNAL_EVENT.OFFER,{payload:{sdp:peerConnection.localDescription,sequence:peer.sequence,},targets:[id],});});peerConnection.addEventListener("track",async({transceiver,track})=>{if(!peer?.id||!this.peers.has(peer.id)){return;} 11839const streamType=peer.getTransceiverStreamType(transceiver);if(!streamType){this._recover(id,"received track for unknown transceiver");return;} 11840peer.medias[streamType].track=track;if(!(await peer.ready)){return;} 11841this._emitUpdate({name:UPDATE_EVENT.TRACK,payload:{sessionId:id,type:streamType,track,active:peer.medias[streamType].active,sequence:peer.sequence,},});});dataChannel.addEventListener("message",async(event)=>{await this.handleNotification(id,event.data);});dataChannel.addEventListener("open",()=>{if(dataChannel.readyState!=="open"){return;} 11842dataChannel.send(JSON.stringify({event:INTERNAL_EVENT.INFO,channelId:this.channelId,payload:this._localInfo,}));this.broadcast({sequence:peer.sequence});});return peer;}} 11843return __exports;});; 11844 11845/* /mail/static/src/discuss/call/common/pip_banner.js */ 11846odoo.define('@mail/discuss/call/common/pip_banner',['@odoo/owl','@mail/discuss/call/common/call_action_list','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useSubEnv}=require("@odoo/owl");const{CallActionList}=require("@mail/discuss/call/common/call_action_list");const{useService}=require("@web/core/utils/hooks");const PipBanner=__exports.PipBanner=class PipBanner extends Component{static template="discuss.pipBanner";static props=["compact?"];static components={CallActionList};setup(){super.setup();this.rtc=useService("discuss.rtc");useSubEnv({isDiscussPipBanner:true});} 11847onClickClose(){this.rtc.closePip();}} 11848return __exports;});; 11849 11850/* /mail/static/src/discuss/call/common/pip_service.js */ 11851odoo.define('@mail/discuss/call/common/pip_service',['@web/core/registry','@odoo/owl','@mail/discuss/call/common/meeting'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{reactive}=require("@odoo/owl");const{Meeting}=require("@mail/discuss/call/common/meeting");const callPipService=__exports.callPipService={dependencies:["mail.popout"],start(env,services){const popoutService=services["mail.popout"];const popout=popoutService.createManager(Symbol("discuss.native.pip"));let pipWindow=null;const state=reactive({active:false,});popout.addHooks(()=>{},()=>{state.active=false;env.services["discuss.rtc"]?.channel?.openChatWindow();});function closePip(){state.active=false;pipWindow?.close();} 11852async function openPip({context}){const rtc=env.services["discuss.rtc"];if(!rtc?.channel){return;} 11853state.active=true;const isShadowRoot=context?.root?.el?.getRootNode()instanceof ShadowRoot;pipWindow=await popout.pip(Meeting,{props:{isPip:true}
11853,options:{useAlternativeAssets:isShadowRoot},});pipWindow.addEventListener("keydown",(ev)=>{rtc.onKeyDown(ev);});pipWindow.addEventListener("keyup",(ev)=>{rtc.onKeyUp(ev);});pipWindow.document.body.style.backgroundColor="black";pipWindow.document.body.style.overflow="hidden";pipWindow.document.body.style.display="block";} 11854return reactive({get isNativePipAvailable(){return Boolean(window.documentPictureInPicture);},get pipWindow(){return pipWindow;},state,closePip,openPip,});},};registry.category("services").add("discuss.pip_service",callPipService);return __exports;});; 11855 11856/* /mail/static/src/discuss/call/common/ptt_ad_banner.js */ 11857odoo.define('@mail/discuss/call/common/ptt_ad_banner',['@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useState}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isMobileOS}=require("@web/core/browser/feature_detection");const{useService}=require("@web/core/utils/hooks");const PttAdBanner=__exports.PttAdBanner=class PttAdBanner extends Component{static template="discuss.pttAdBanner";static props={};static LOCAL_STORAGE_KEY="ptt_ad_banner_discarded";setup(){super.setup();this.pttExtService=useService("discuss.ptt_extension");this.store=useService("mail.store");this.state=useState({wasDiscarded:browser.localStorage.getItem(PttAdBanner.LOCAL_STORAGE_KEY),});} 11858onClickClose(){browser.localStorage.setItem(PttAdBanner.LOCAL_STORAGE_KEY,true);this.state.wasDiscarded=true;} 11859get isVisible(){return(!this.pttExtService.isEnabled&&this.store.settings.use_push_to_talk&&!isMobileOS()&&!this.state.wasDiscarded);}} 11860return __exports;});; 11861 11862/* /mail/static/src/discuss/call/common/ptt_extension_service.js */ 11863odoo.define('@mail/discuss/call/common/ptt_extension_service',['@odoo/owl','@mail/utils/common/misc','@web/core/browser/browser','@web/core/registry','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{markup,reactive}=require("@odoo/owl");const{parseVersion}=require("@mail/utils/common/misc");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const pttExtensionServiceInternal=__exports.pttExtensionServiceInternal={onAnswerIsEnabled(pttService){pttService.isEnabled=true;},};const pttExtensionHookService=__exports.pttExtensionHookService={start(env){const INITIAL_RELEASE_TIMEOUT=750;const COMMON_RELEASE_TIMEOUT=200;const EXT_ID="mdiacebcbkmjjlpclnbcgiepgifcnpmg";const versionPromise=window.chrome?.runtime?.sendMessage(EXT_ID,{type:"ask-version"}).catch(()=>"1.0.0.0")??Promise.resolve("1.0.0.0");const self=reactive({isEnabled:undefined,voiceActivated:undefined,notifyIsTalking(isTalking){sendMessage("is-talking",isTalking);},subscribe(){sendMessage("subscribe");},unsubscribe(){self.voiceActivated=false;sendMessage("unsubscribe");},downloadURL:`https://chromewebstore.google.com/detail/discuss-push-to-talk/${EXT_ID}`,get downloadText(){return _t("The Push-to-Talk feature is only accessible within tab focus. To enable the Push-to-Talk functionality outside of this tab, we recommend downloading our %(anchor_start)sextension%(anchor_end)s.",{anchor_start:markup`<a href="${this.downloadURL}" target="_blank" class="text-reset text-decoration-underline">`,anchor_end:markup`</a>`,});},});browser.addEventListener("message",({data,origin,source})=>{const rtc=env.services["discuss.rtc"];if(source!==window||origin!==location.origin||data?.from!=="discuss-push-to-talk"||(!rtc&&data.type!=="answer-is-enabled")){return;} 11864switch(data.type){case"push-to-talk-pressed":{self.voiceActivated=false;const isFirstPress=!rtc.selfSession?.isTalking;rtc.onPushToTalk();if(rtc.selfSession?.isTalking){rtc.setPttReleaseTimeout(isFirstPress?INITIAL_RELEASE_TIMEOUT:COMMON_RELEASE_TIMEOUT);}} 11865break;case"toggle-voice":{if(self.voiceActivated){rtc.setPttReleaseTimeout(0);}else{rtc.onPushToTalk();} 11866self.voiceActivated=!self.voiceActivated;} 11867break;case"answer-is-enabled":pttExtensionServiceInternal.onAnswerIsEnabled(self);break;}});async function sendMessage(type,value){if(!self.isEnabled&&type!=="ask-is-enabled"){return;} 11868const version=parseVersion(await versionPromise);if(location.origin==="null"){return;} 11869if(version.isLowerThan("1.0.0.2")){window.postMessage({from:"discuss",type,value},location.origin);return;} 11870window.chrome?.runtime?.sendMessage(EXT_ID,{type,value});} 11871sendMessage("ask-is-enabled");return self;},};registry.category("services").add("discuss.ptt_extension",pttExtensionHookService);return __exports;});; 11872 11873/* /mail/static/src/discuss/call/common/quick_video_settings.js */ 11874odoo.define('@mail/discuss/call/common/quick_video_settings',['@odoo/owl','@mail/discuss/call/common/call_settings','@mail/discuss/call/common/device_select','@web/core/utils/hooks','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{CallSettingsDialog}=require("@mail/discuss/call/common/call_settings");const{DeviceSelect}=require("@mail/discuss/call/common/device_select");const{useService}=require("@web/core/utils/hooks");const{isBrowserSafari}=require("@web/core/browser/feature_detection");const QuickVideoSettings=__exports.QuickVideoSettings=class QuickVideoSettings extends Component{static template="discuss.QuickVideoSettings";static props=[];static components={DeviceSelect};setup(){super.setup();this.store=useService("mail.store");this.dialogService=useService("dialog");this.isBrowserSafari=isBrowserSafari;} 11875onClickVideoSettings(){this.dialogService.add(CallSettingsDialog,{});}} 11876return __exports;});; 11877 11878/* /mail/static/src/discuss/call/common/quick_voice_settings.js */ 11879odoo.define('@mail/discuss/call/common/quick_voice_settings',['@odoo/owl','@mail/discuss/call/common/call_settings','@mail/discuss/call/common/device_select','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{CallSettingsDialog}=require("@mail/discuss/call/common/call_settings");const{DeviceSelect}=require("@mail/discuss/call/common/device_select");const{useService}=require("@web/core/utils/hooks");const QuickVoiceSettings=__exports.QuickVoiceSettings=class QuickVoiceSettings extends Component{static template="discuss.QuickVoiceSettings";static props=[];static components={DeviceSelect};setup(){super.setup();this.store=useService("mail.store");this.dialogService=useService("dialog");} 11880onClickVoiceSettings(){this.dialogService.add(CallSettingsDialog,{});}} 11881return __exports;});; 11882 11883/* /mail/static/src/discuss/call/common/res_partner_model_patch.js */ 11884odoo.define('@mail/discuss/call/common/res_partner_model_patch',['@mail/core/common/res_partner_model','@mail/model/misc','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ResPartner}=require("@mail/core/common/res_partner_model");const{fields}=require("@mail/model/misc");const{patch}=require("@web/core/utils/patch");patch(ResPartner.prototype,{setup(){super.setup(...arguments);this.currentRtcSession=fields.One("discuss.channel.rtc.session",{inverse:"partner_id",});},});return __exports;});; 11885 11886/* /mail/static/src/discuss/call/common/rtc_service.js */ 11887odoo.define('@mail/discuss/call/common/rtc_service',['@mail/core/common/record','@mail/discuss/call/common/blur_manager','@mail/discuss/call/common/call_permission_dialog','@mail/discuss/call/common/thread_model_patch','@mail/utils/common/media_monitoring','@web/core/network/rpc','@mail/utils/common/misc','@mail/discuss/call/common/call_infinite_mirroring_warning','@odoo/owl','@web/core/browser/browser','@web/core/l10n/translation','@web/core/registry','@web/core/utils/objects','@web/core/utils/timing','@web/core/assets','@web/core/utils/functions','@web/core/utils/urls','@web/core/browser/feature_detection','@mail/discuss/call/common/call_actions'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{BlurManager}=require("@mail/discuss/call/common/blur_manager");const{CallPermissionDialog}=require("@mail/discuss/call/common/call_permission_dialog");const{CALL_PROMOTE_FULLSCREEN}=require("@mail/discuss/call/common/thread_model_patch");const{monitorAudio}=require("@mail/utils/common/media_monitoring");const{rpc}=require("@web/core/network/rpc");const{assignDefined,closeStream,onChange}=require("@mail/utils/common/misc");const{CallInfiniteMirroringWarning}=require("@mail/discuss/call/common/call_infinite_mirroring_warning");const{reactive,toRaw}
11887=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{registry}=require("@web/core/registry");const{pick}=require("@web/core/utils/objects");const{debounce}=require("@web/core/utils/timing");const{loadBundle,loadJS}=require("@web/core/assets");const{memoize}=require("@web/core/utils/functions");const{url}=require("@web/core/utils/urls");const{isBrowserSafari,isMobileOS}=require("@web/core/browser/feature_detection");const{CallAction}=require("@mail/discuss/call/common/call_actions");let sequence=1;const getSequence=()=>sequence++;const loadSfuAssets=memoize(async()=>await loadBundle("mail.assets_odoo_sfu"));function subscribe(target,event,f){target.addEventListener(event,f);return()=>target.removeEventListener(event,f);} 11888const PTT_RELEASE_DURATION=__exports.PTT_RELEASE_DURATION=200;const SW_MESSAGE_TYPE={POST_RTC_LOGS:"POST_RTC_LOGS",};const CONNECTION_TYPES=__exports.CONNECTION_TYPES={P2P:"p2p",SERVER:"server"};const SCREEN_CONFIG={width:{max:1920},height:{max:1080},aspectRatio:16/9,frameRate:{max:24,},};const IS_CLIENT_RTC_COMPATIBLE=Boolean(window.RTCPeerConnection&&window.MediaStream);function GET_DEFAULT_ICE_SERVERS(){return[{urls:["stun:stun1.l.google.com:19302","stun:stun2.l.google.com:19302"]}];} 11889const CROSS_TAB_HOST_MESSAGE=__exports.CROSS_TAB_HOST_MESSAGE={PING:"PING",UPDATE_REMOTE:"UPDATE_REMOTE",CLOSE:"CLOSE",PIP_CHANGE:"PIP_CHANGE",};const CROSS_TAB_CLIENT_MESSAGE=__exports.CROSS_TAB_CLIENT_MESSAGE={INIT:"INIT",REQUEST_ACTION:"REQUEST_ACTION",LEAVE:"LEAVE",UPDATE_VOLUME:"UPDATE_VOLUME",};const PING_INTERVAL=30_000;const UNAVAILABLE_AS_REMOTE=_t("This action can only be done in the call tab.");const CALL_FULLSCREEN_ID=Symbol("CALL_FULLSCREEN");function hasTurn(iceServers){return iceServers.some((server)=>{let hasTurn=false;if(server.url){hasTurn=server.url.startsWith("turn:");} 11890if(server.urls){if(Array.isArray(server.urls)){hasTurn=server.urls.some((url)=>url.startsWith("turn:"))||hasTurn;}else{hasTurn=server.urls.startsWith("turn:")||hasTurn;}} 11891return hasTurn;});} 11892const Network=__exports.Network=class Network{p2p;sfu;_listeners=[];constructor(p2p,sfu){this.p2p=p2p;this.sfu=sfu;} 11893getSfuConsumerStats(sessionId){const consumers=this.sfu?._consumers.get(sessionId);if(!consumers){return[];} 11894return Object.entries(consumers).map(([type,consumer])=>{let state="active";if(!consumer){state="no consumer";}else if(consumer.closed){state="closed";}else if(consumer.paused){state="paused";}else if(!consumer.track){state="no track";}else if(!consumer.track.enabled){state="track disabled";}else if(consumer.track.muted){state="track muted";} 11895return{type,state};});} 11896addSfu(sfu){if(this.sfu){this.sfu.disconnect();} 11897this.sfu=sfu;} 11898removeSfu(){if(!this.sfu){return;} 11899for(const{name,f}of this._listeners){this.sfu.removeEventListener(name,f);} 11900this.sfu.disconnect();} 11901addEventListener(name,f){this._listeners.push({name,f});this.p2p.addEventListener(name,f);this.sfu?.addEventListener(name,f);} 11902async updateUpload(type,track){const proms=[this.p2p.updateUpload(type,track)];if(this.sfu?.state==="connected"){proms.push(this.sfu.updateUpload(type,track));} 11903await Promise.all(proms);} 11904updateDownload(sessionId,states){this.p2p.updateDownload(sessionId,states);this.sfu?.updateDownload(sessionId,states);} 11905updateInfo(info,options={}){this.p2p.updateInfo(info,options);this.sfu?.updateInfo(info,options);} 11906disconnect(){for(const{name,f}of this._listeners.splice(0)){this.p2p.removeEventListener(name,f);this.sfu?.removeEventListener(name,f);} 11907this.p2p.disconnect();this.sfu?.disconnect();}} 11908const Rtc=__exports.Rtc=class Rtc extends Record{notifications=reactive(new Map());timeouts=new Map();downloadTimeouts=new Map();iceServers=fields.Attr(undefined,{compute(){return this.iceServers?this.iceServers:GET_DEFAULT_ICE_SERVERS();},});microphonePermission;cameraPermission;localSession=fields.One("discuss.channel.rtc.session");selfSession=fields.One("discuss.channel.rtc.session",{compute(){return(this.localSession||this.store["discuss.channel.rtc.session"].get(this._remotelyHostedSessionId));},onDelete(){if(this.channel){this.channel.promoteFullscreen=CALL_PROMOTE_FULLSCREEN.INACTIVE;}},});channel=fields.One("Thread",{compute(){if(this.state.channel){return this.state.channel;} 11909if(this._remotelyHostedChannelId){return this.store.Thread.insert({model:"discuss.channel",id:this._remotelyHostedChannelId,});}},onUpdate(){if(!this.channel){return;} 11910this.store.Thread.getOrFetch({model:"discuss.channel",id:this.channel.i
11910d,});},});rootEl;serverInfo;network;sfuClient=undefined;lastActions={};actionsStack=[];lastSelfCallAction=undefined;cleanups=[];sfuTimeout;audioContext;_broadcastChannel=new browser.BroadcastChannel("call_sync_state");_remotelyHostedSessionId;_remotelyHostedChannelId;_crossTabTimeoutId;_p2pRecoveryCount=0;upgradeConnectionDebounce=debounce(()=>{this._upgradeConnection();},15000,{leading:true,trailing:false});get isRemote(){return Boolean(this._remotelyHostedChannelId);} 11911get isHost(){return Boolean(this.localSession);} 11912callActions=fields.Attr([],{compute(){const transformedActions=registry.category("discuss.call/actions").getEntries().map(([id,definition])=>new CallAction({owner:this,id,definition}));for(const action of transformedActions){action.setup();} 11913return transformedActions;},onUpdate(){for(const action of this.callActions){if(action.isActive===this.lastActions[action.id]){continue;} 11914if(!action.isTracked){continue;} 11915if(action.isActive){if(!this.actionsStack.includes(action.id)){this.actionsStack.unshift(action.id);}}else{this.actionsStack.splice(this.actionsStack.indexOf(action.id),1);}} 11916this.lastSelfCallAction=this.actionsStack[0];this.lastActions=Object.fromEntries(this.callActions.map((action)=>[action.id,action.isActive]));},});setup(){this.linkVoiceActivationDebounce=debounce(this.linkVoiceActivation,500);this.state=reactive({connectionType:undefined,hasPendingRequest:false,channel:undefined,logs:{},sendCamera:false,sendScreen:false,updateAndBroadcastDebounce:undefined,micAudioTrack:undefined,screenAudioTrack:undefined,audioTrack:undefined,cameraTrack:undefined,screenTrack:undefined,disconnectAudioMonitor:undefined,pttReleaseTimeout:undefined,sourceCameraStream:null,sourceScreenStream:null,fallbackMode:false,isPipMode:false,isFullscreen:false,});this.blurManager=undefined;} 11917start(){const services=this.store.env.services;this.notification=services.notification;this.overlay=services.overlay;this.dialog=services.dialog;this.soundEffectsService=services["mail.sound_effects"];this.pttExtService=services["discuss.ptt_extension"];if(this._broadcastChannel){this._broadcastChannel.onmessage=this._onBroadcastChannelMessage.bind(this);this._postToTabs({type:CROSS_TAB_CLIENT_MESSAGE.INIT});} 11918this.p2pService=services["discuss.p2p"];onChange(this.store.settings,"useBlur",()=>{if(this.state.sendCamera){this.toggleVideo("camera",{force:true});}});onChange(this.store.settings,["edgeBlurAmount","backgroundBlurAmount"],()=>{if(this.blurManager){this.blurManager.edgeBlur=this.store.settings.edgeBlurAmount;this.blurManager.backgroundBlur=this.store.settings.backgroundBlurAmount;}});onChange(this.store.settings,["voiceActivationThreshold","use_push_to_talk"],()=>{this.linkVoiceActivationDebounce();});onChange(this.store.settings,"audioInputDeviceId",async()=>{if(this.localSession){await this.resetMicAudioTrack({force:true});}});onChange(this.store.settings,"audioOutputDeviceId",async()=>{if(this.localSession){await this.setOutputDevice(this.store.settings.audioOutputDeviceId);}});onChange(this.store.settings,"cameraInputDeviceId",async()=>{if(this.localSession&&this.state.cameraTrack){await this.toggleVideo("camera",{force:true,refreshStream:true});}});this.store.env.bus.addEventListener("RTC-SERVICE:PLAY_MEDIA",()=>{const channel=this.state.channel;if(!channel){return;} 11919for(const session of channel.rtc_session_ids){session.playAudio();}});browser.addEventListener("blur",()=>this.onBlur());browser.addEventListener("keydown",(ev)=>{this.onKeyDown(ev);},{capture:true});browser.addEventListener("keyup",(ev)=>{this.onKeyUp(ev);},{capture:true});browser.addEventListener("pagehide",()=>{if(this.state.channel){const data=JSON.stringify({params:{channel_id:this.state.channel.id,session_id:this.selfSession.id},});const blob=new Blob([data],{type:"application/json"});browser.navigator.sendBeacon("/mail/rtc/channel/leave_call",blob);this.sfuClient?.disconnect();}});browser.setInterval(async()=>{if(!this.localSession||!this.state.channel){return;} 11920this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.PING,hostedSessionId:this.localSession.id,});await this.ping();if(!this.localSession||!this.state.channel){return;} 11921this.call();},PING_INTERVAL);} 11922get displaySurface(){return this.state.sourceScreenStream?.getVideoTracks()[0]?.getSettings().displaySurface;} 11923isPushToTalkRelease(ev){if(!this.state.channel||!this.store.settings.use_push_to_talk||(ev instanceof KeyboardEvent&&!this.store.settings.isPushToTalkKey(ev))||!this.localSession.isTalking||this.pttExtService.voiceActivated){return false;} 11924return true;} 11925onKeyDown(ev){if(!this.store.settings.isPushToTalkKey(ev)){return;} 11926this.onPushToTalk();} 11927onKeyUp(ev){if(!this.isPushToTalkRelease(ev)){return;} 11928this.setPttReleaseTimeout();} 11929onBlur(){if(!this.isPushToTalkRelease()){return;} 11930this.setPttReleaseTimeout();} 11931showMirroringWarning(){this.state.screenTrack.enabled=false;const trackEndedFn=()=>this.removeMirroringWarning?.();this.removeMirroringWarning=this.overlay.add(CallInfiniteMirroringWarning,{onClose:({stopScreensharing}={})=>{this.removeMirroringWarning({stopScreensharing});},},{onRemove:({stopScreensharing}={})=>
11931{if(stopScreensharing){this.toggleVideo("screen",false);} 11932this.state.screenTrack?.removeEventListener("ended",trackEndedFn);this.removeMirroringWarning=null;},});this.state.screenTrack.addEventListener("ended",trackEndedFn,{once:true});} 11933setPttReleaseTimeout(duration=PTT_RELEASE_DURATION){this.state.pttReleaseTimeout=browser.setTimeout(()=>{this.setTalking(false);if(!this.localSession?.isMute){this.soundEffectsService.play("ptt-release");}},Math.max(this.store.settings.voice_active_duration||0,duration));} 11934onPushToTalk(){if(!this.state.channel||this.store.settings.isRegisteringKey||!this.store.settings.use_push_to_talk){return;} 11935browser.clearTimeout(this.state.pttReleaseTimeout);if(!this.localSession.isTalking&&!this.localSession.isMute){this.soundEffectsService.play("ptt-press");} 11936this.setTalking(true);} 11937async openPip(options){if(this.isHost){this.exitFullscreen();await this.pipService.openPip(options);return;} 11938this.notification.add(UNAVAILABLE_AS_REMOTE,{type:"warning",});} 11939closePip(){if(this.isHost){this.pipService.closePip();}else{this._remoteAction({pip:false});}} 11940addCallNotification({id,text,delay=3000}){if(this.notifications.has(id)){return;} 11941this.notifications.set(id,{id,text});this.timeouts.set(id,browser.setTimeout(()=>{this.notifications.delete(id);this.timeouts.delete(id);},delay));} 11942removeCallNotification(id){browser.clearTimeout(this.timeouts.get(id));this.notifications.delete(id);this.timeouts.delete(id);} 11943async leaveCall(channel=this.state.channel){this.store.fullscreenChannel=null;this.state.hasPendingRequest=true;await this.rpcLeaveCall(channel);this.endCall(channel);this.state.hasPendingRequest=false;} 11944endCall(channel=this.state.channel){this._endHost();if(channel.self_member_id){channel.self_member_id.rtc_inviting_session_id=undefined;} 11945channel.activeRtcSession=undefined;if(channel.eq(this.state.channel)){this.state.logs.end=new Date().toISOString();this.dumpLogs();this.pttExtService.unsubscribe();this.network?.disconnect();this.clear();this.soundEffectsService.play("call-leave");}} 11946async deafen(){if(this.isRemote){this._remoteAction({is_deaf:true});return;} 11947await this.setDeaf(true);this.soundEffectsService.play("earphone-off");} 11948setRemoteRaiseHand(session,active){if(Boolean(session.raisingHand)===active){return;} 11949Object.assign(session,{raisingHand:active?new Date():undefined,});const notificationId="raise_hand_"+session.id;if(session.raisingHand){this.addCallNotification({id:notificationId,text:_t("%s raised their hand",session.name),});}else{this.removeCallNotification(notificationId);}} 11950setVolume(session,volume){session.volume=volume;this.store.settings.saveVolumeSetting({guestId:session?.guest_id?.id,partnerId:session?.partner_id?.id,volume,});this._postToTabs({type:CROSS_TAB_CLIENT_MESSAGE.UPDATE_VOLUME,changes:{sessionId:session.id,volume},});} 11951async mute(){if(this.isRemote){this._remoteAction({is_muted:true});return;} 11952await this.setMute(true);this.soundEffectsService.play("mic-off");} 11953async enterFullscreen(props){const Meeting=registry.category("discuss.call/components").get("Meeting");this.store.fullscreenChannel=this.channel;await this.fullscreen.enter(Meeting,{id:CALL_FULLSCREEN_ID,keepBrowserHeader:true,props,rootId:this.rootEl?.getRootNode()?.host?.id,});} 11954async exitFullscreen(){this.store.fullscreenChannel=null;await this.fullscreen.exit(CALL_FULLSCREEN_ID);} 11955async toggleCall(channel,{audio=true,camera}={}){if(channel.id===this._remotelyHostedChannelId){this._postToTabs({type:CROSS_TAB_CLIENT_MESSAGE.LEAVE});this.clear();return;} 11956await Promise.resolve(()=>loadJS(url("/mail/static/lib/selfie_segmentation/selfie_segmentation.js")).catch(()=>{}));if(this.state.hasPendingRequest){return;} 11957const isActiveCall=channel.eq(this.state.channel);if(this.state.channel){await this.leaveCall(this.state.channel);} 11958if(!isActiveCall){const joinCallOpts={audio,camera};if(this.microphonePermission!=="granted"){joinCallOpts.audio=false;} 11959await this.joinCall(channel,joinCallOpts);}} 11960async toggleCameraFacingMode(){this.store.settings.cameraFacingMode=this.store.settings.cameraFacingMode==="user"?"environment":"user";await this.toggleVideo("camera",{force:true,refreshStream:true});} 11961async toggleDeafen(){if(this.selfSession.is_deaf){await this.undeafen();if(this.selfSession.is_muted){await this.unmute();}}else{await this.deafen();}} 11962async toggleMicrophone(){if(this.selfSession.isMute){if(this.selfSession.is_muted){await this.unmute();} 11963if(this.selfSession.is_deaf){await this.undeafen();}}else{await this.mute();}} 11964async undeafen(){if(this.isRemote){this._remoteAction({is_deaf:false});return;} 11965await this.setDeaf(false);this.soundEffectsService.play("earphone-on");} 11966showMediaPermissionDialog(media){this.closeCallPermissionDialog=this.dialog.add(CallPermissionDialog,{media,useMicrophone:()=>this.unmute(),useCamera:()=>this.toggleVideo("camera",{force:true,refreshStream:true}),},{context:{root:{el:this.rootEl}}});} 11967showMediaUnavailableWarning({microphone,camera,screen}){let errorMessage;if(microphone&&camera){errorMessage=_t("Camera and microphone access blocked. Enable in browser settings.");}else if(camera){errorMessage=_t("Camera access blocked. Enable in browser settings.");}else if(microphone){errorMessage=_t("Microphone access blocked. Enable in browser settings.");}else if(screen){errorMessage=_t("Screen sharing access blocked. Enable in browser settings.");} 11968this.notification.add(errorMessage,{type:"warning"});} 11969async askForBrowserPermission({audio,video,deviceId}){try{const stream=await browser.navigator.mediaDevices.getUserMedia({audio:audio?{...this.store.settings.audioConstraints,...(deviceId&&{deviceId})}:false,video:video?{...this.store.settings.cameraConstraints,...(deviceId&&{deviceId})}:false,});if(isBrowserSafari()||isMobileOS()){if(audio){this.microphonePermission="granted";} 11970if(video){this.cameraPermission="granted";}} 11971closeStream(stream);}catch{this.showMediaUnavailableWarning({microphone:audio,camera:video}
11971);return false;} 11972if(audio&&video){return this.microphonePermission==="granted"&&this.cameraPermission==="granted";} 11973return audio?this.microphonePermission==="granted":this.cameraPermission==="granted";} 11974async unmute(){if(this.isRemote){this._remoteAction({is_muted:false});return;} 11975if(this.microphonePermission==="prompt"){this.showMediaPermissionDialog("microphone");return;} 11976if(this.state.micAudioTrack){await this.setMute(false);}else{await this.resetMicAudioTrack({force:true});} 11977this.soundEffectsService.play("mic-on");} 11978async _loadSfu(){const load=async()=>{await loadSfuAssets();const sfuModule=odoo.loader.modules.get("@mail/../lib/odoo_sfu/odoo_sfu");this.SFU_CLIENT_STATE=sfuModule.SFU_CLIENT_STATE;this.sfuClient=new sfuModule.SfuClient();};try{await load();}catch{await new Promise((resolve,reject)=>{browser.setTimeout(async()=>{try{await load();}catch(error){reject(error);} 11979resolve();},1000);});}} 11980updateUpload(){this.network?.updateUpload("audio",this.state.audioTrack);this.network?.updateUpload("camera",this.state.cameraTrack);this.network?.updateUpload("screen",this.state.screenTrack);} 11981async _initConnection(){this.localSession.connectionState="selecting network type";this.state.connectionType=CONNECTION_TYPES.P2P;this.network?.disconnect();this.p2pService.connect(this.localSession.id,this.state.channel.id,{info:this.formatInfo(),iceServers:this.iceServers,});this.network=new Network(this.p2pService);this.updateUpload();if(this.serverInfo){this.log(this.localSession,"loading sfu server",{step:"loading sfu server",serverInfo:toRaw(this.serverInfo),});this.localSession.connectionState="loading SFU assets";try{await this._loadSfu();this.state.connectionType=CONNECTION_TYPES.SERVER;if(this.network){this.network.addSfu(this.sfuClient);}else{return;}}catch(e){this.state.fallbackMode=true;this.notification.add(_t("Failed to load the SFU server, falling back to peer-to-peer"),{type:"warning",});this.log(this.localSession,"failed to load sfu server",{error:e,important:true,});} 11982this.selfSession.connectionState="initializing";}else{this.log(this.localSession,"no sfu server info, using peer-to-peer");} 11983this.network.addEventListener("stateChange",this._handleSfuClientStateChange);this.network.addEventListener("update",this._handleNetworkUpdates);this.network.addEventListener("log",({detail:{id,level,message}})=>{const session=this.store["discuss.channel.rtc.session"].get(id);if(session){this.log(session,message,{step:"p2p",level,important:true});}});if(this.state.channel){await this.call();this.updateUpload();}} 11984_remoteAction(changes){this._postToTabs({type:CROSS_TAB_CLIENT_MESSAGE.REQUEST_ACTION,changes,});} 11985_updateInfo(){if(!this.isHost){return;} 11986const info=toRaw(this.formatInfo());this.network?.updateInfo(info);this._updateRemoteTabs({[this.localSession.id]:info});} 11987_host(){this._remotelyHostedChannelId=undefined;this._remotelyHostedSessionId=this.localSession.id;this._updateRemoteTabs({[this.localSession.id]:toRaw(this.formatInfo())});} 11988_endHost(){this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.CLOSE,hostedSessionId:this._remotelyHostedSessionId,});} 11989_updateRemoteTabs(changes){this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.UPDATE_REMOTE,hostedChannelId:this.state.channel.id,hostedSessionId:this.localSession.id,changes,});} 11990_postToTabs(message){if(!this._broadcastChannel){this.log(this.selfSession,"broadcast channel not available");return;} 11991try{this._broadcastChannel.postMessage(message);}catch(error){this.log(this.selfSession,"failed to post message to broadcast channel",{error});}} 11992_refreshCrossTabTimeout(){browser.clearTimeout(this._crossTabTimeoutId);this._crossTabTimeoutId=browser.setTimeout(()=>{this.clear();},PING_INTERVAL+10_000);} 11993async _onBroadcastChannelMessage({data:{type,hostedChannelId,hostedSessionId,changes},}){switch(type){case CROSS_TAB_HOST_MESSAGE.UPDATE_REMOTE:if(this.isHost){return;} 11994this._remotelyHostedSessionId=hostedSessionId;this._remotelyHostedChannelId=hostedChannelId;this._refreshCrossTabTimeout();this.updateSessionInfo(changes);return;case CROSS_TAB_HOST_MESSAGE.CLOSE:{if(this._remotelyHostedSessionId!==hostedSessionId){return;} 11995this.clear();return;} 11996case CROSS_TAB_HOST_MESSAGE.PIP_CHANGE:{if(this.isHost){return;}
11997this.state.isPipMode=changes.isPipMode;return;} 11998case CROSS_TAB_HOST_MESSAGE.PING:{this._refreshCrossTabTimeout();return;} 11999case CROSS_TAB_CLIENT_MESSAGE.INIT:{if(!this.isHost){return;} 12000this._updateRemoteTabs({[this.localSession.id]:toRaw(this.formatInfo())});this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.PIP_CHANGE,changes:{isPipMode:this.state.isPipMode},});return;} 12001case CROSS_TAB_CLIENT_MESSAGE.REQUEST_ACTION:{if(!this.isHost){return;} 12002await this._localAction(changes);this._updateRemoteTabs({[this.localSession.id]:toRaw(this.formatInfo())});return;} 12003case CROSS_TAB_CLIENT_MESSAGE.LEAVE:{if(!this.isHost){return;} 12004await this.leaveCall(this.channel);return;} 12005case CROSS_TAB_CLIENT_MESSAGE.UPDATE_VOLUME:{const session=this.store["discuss.channel.rtc.session"].get(changes.sessionId);if(!session){return;} 12006session.volume=changes.volume;return;}}} 12007async _localAction(actions={}){const promises=[];for(const[key,value]of Object.entries(actions)){switch(key){case"is_muted":if(value===this.localSession.is_muted){break;} 12008promises.push(value?this.mute():this.unmute());break;case"is_deaf":if(value===this.localSession.is_deaf){break;} 12009value?promises.push(this.deafen()):promises.push(this.undeafen());break;case"raisingHand":if(value===Boolean(this.localSession.raisingHand)){break;} 12010promises.push(this.raiseHand(value));break;
12010case"pip":if(value===this.state.isPipMode){break;} 12011if(value){promises.push(this.openPip());}else{this.closePip();} 12012break;}} 12013await Promise.all(promises);} 12014log(session,entry,param2={}){if(!session){return;} 12015const{error,step,state,important,...data}=param2;session.logStep=entry;if(!this.store.settings.logRtc&&!important){return;} 12016console.debug(`%c${new Date().toLocaleString()} - [${entry}]`,"color: #e36f17; font-weight: bold;",toRaw(session)._raw,param2);if(!this.state.logs){return;} 12017let sessionEntry=this.state.logs.entriesBySessionId[session.id];if(!sessionEntry){this.state.logs.entriesBySessionId[session.id]=sessionEntry={step:"",state:"",logs:[],};} 12018if(step){sessionEntry.step=step;} 12019if(state){sessionEntry.state=state;} 12020sessionEntry.logs.push({event:`${new Date().toISOString()}: ${entry}`,error:error&&{name:error.name,message:error.message,stack:error.stack&&error.stack.split("\n"),},...data,});} 12021async _handleNetworkUpdates({detail:{name,payload}}){if(!this.state.channel){return;} 12022switch(name){case"broadcast":{const{senderId,message:{sequence},}=payload;if(!sequence){return;} 12023const session=await this.store["discuss.channel.rtc.session"].getWhenReady(senderId);if(!session){return;} 12024if(!session.sequence||session.sequence<sequence){session.sequence=sequence;}} 12025return;case"connection_change":{const{id,state}=payload;const session=this.store["discuss.channel.rtc.session"].get(id);if(!session){return;} 12026session.connectionState=state;} 12027return;case"disconnect":{const{sessionId}=payload;const session=this.store["discuss.channel.rtc.session"].get(sessionId);if(!session){return;} 12028this.disconnect(session);} 12029return;case"info_change":this.updateSessionInfo(payload);return;case"track":{const{sessionId,type,track,active,sequence}=payload;const session=await this.store["discuss.channel.rtc.session"].getWhenReady(sessionId);if(!session||!this.state.channel){this.log(this.selfSession,`track received for unknown session ${sessionId} (${this.state.connectionType})`);return;} 12030if(sequence&&sequence<session.sequence){this.log(session,`track received for old sequence ${sequence} (${this.state.connectionType})`);return;} 12031this.log(session,`${type} track received (${this.state.connectionType})`);try{await this.handleRemoteTrack({session,track,type,active});}catch{} 12032setTimeout(()=>{this.updateVideoDownload(session);},2000);} 12033return;case"recovery":{const{id}=payload;const session=this.store["discuss.channel.rtc.session"].get(id);if(this.selfSession?.persona.main_user_id?.share!==false||this.serverInfo||this.state.fallbackMode||!session?.channel.eq(this.state.channel)){return;} 12034this._p2pRecoveryCount++;if(this._p2pRecoveryCount>1||!hasTurn(this.iceServers)){this.upgradeConnectionDebounce();}}}} 12035async _handleSfuClientStateChange({detail:{state,cause}}){this.log(this.localSession,`connection state change: ${state}`,{state,cause});this.localSession.connectionState=state;switch(state){case this.SFU_CLIENT_STATE.AUTHENTICATED:this.p2pService.removeALlPeers();this.sfuClient.broadcast({sequence:getSequence()});break;case this.SFU_CLIENT_STATE.CONNECTED:browser.clearTimeout(this.sfuTimeout);this.sfuClient.updateInfo(this.formatInfo(),{needRefresh:true,});this.sfuClient.updateUpload("audio",this.state.audioTrack);this.sfuClient.updateUpload("camera",this.state.cameraTrack);this.sfuClient.updateUpload("screen",this.state.screenTrack);return;case this.SFU_CLIENT_STATE.CLOSED:{if(!this.state.channel){return;} 12036let text;if(cause==="full"){text=_t("Channel full");this.leaveCall();}else{text=_t("Connection to SFU server closed by the server, falling back to peer-to-peer");this.log(this.localSession,text,{important:true});this._downgradeConnection();} 12037this.notification.add(text,{type:"warning",});} 12038return;}} 12039async _upgradeConnection(){const channelId=this.state.channel?.id;if(this.serverInfo||this.state.fallbackMode||!channelId){return;} 12040await rpc("/mail/rtc/channel/upgrade_connection",{channel_id:channelId},{silent:true});} 12041updateSessionInfo(payload){if(!payload){return;} 12042if(this.isHost){this._updateRemoteTabs(payload);} 12043for(const[id,info]of Object.entries(payload)){(async()=>{const session=await this.store["discuss.channel.rtc.session"].getWhenReady(Number(id));if(!session||session.eq(this.localSession)||!this.channel){return;} 12044this.setRemoteRaiseHand(session,info.isRaisingHand);delete info.isRaisingHand;assignDefined(session,{is_muted:info.isSelfMuted??info.is_muted,is_deaf:info.isDeaf??info.is_deaf,isTalking:info.isTalking,is_camera_on:info.isCameraOn??info.is_camera_on,is_screen_sharing_on:info.isScreenSharingOn??info.is_screen_sharing_on,});})();}} 12045async _downgradeConnection(){this.serverInfo=undefined;this.state.fallbackMode=true;this.state.connectionType=CONNECTION_TYPES.P2P;this.network.removeSfu();await this.call();this.updateUpload();} 12046async call({asFallback=false}={}){if(asFallback&&!this.state.fallbackMode){return;} 12047if(this.state.connectionType===CONNECTION_TYPES.SERVER){if(this.sfuClient.state===this.SFU_CLIENT_STATE.DISCONNECTED){browser.clearTimeout(this.sfuTimeout);this.sfuTimeout=browser.setTimeout(()=>{this.log(this.selfSession,"sfu connection timeout",{important:true});this._downgradeConnection();},10000);await this.sfuClient.connect(this.serverInfo.url,this.serverInfo.jsonWebToken,{channelUUID:this.serverInfo.channelUUID,iceServers:this.iceServers,});} 12048return;} 12049if(this.state.channel.rtc_session_ids.length===0){return;} 12050const sequence=getSequence();for(const session of this.state.channel.rtc_session_ids){if(session.eq(this.localSession)){continue;} 12051this.p2pService.addPeer(session.id,{sequence});}} 12052async handleRemoteTrack({session,track,type,active=true}){session.updateStreamState(type,active);await this.updateStream(session,track,{mute:this.localSession.is_deaf,videoType:type,});this.updateActiveSession(session,type,{addVideo:true});} 12053async joinCall(channel,{audio=true,camera=false}={}){if(!IS_CLIENT_RTC_COMPATIBLE){this.notification.add(_t("Your browser does not support webRTC."),{type:"warning"});return;} 12054this.pttExtService.subscribe();this.state.hasPendingRequest=true;const data=await rpc("/mail/rtc/channel/join_call",{camera,channel_id:channel.i
12054d,check_rtc_session_ids:channel.rtc_session_ids.map((session)=>session.id),},{silent:true});this.state.hasPendingRequest=false;this.clear();this.state.channel=channel;this.store.insert(data);this.newLogs();this.state.updateAndBroadcastDebounce=debounce(async()=>{if(!this.localSession){return;} 12055await rpc("/mail/rtc/session/update_and_broadcast",{session_id:this.localSession.id,values:pick(this.localSession,"is_camera_on","is_deaf","is_muted","is_screen_sharing_on"),},{silent:true});},3000,{leading:true,trailing:true});if(this.state.channel.self_member_id){this.state.channel.self_member_id.rtc_inviting_session_id=undefined;} 12056if(camera){await this.toggleVideo("camera");} 12057if(!this.selfSession){return;} 12058await this._initConnection();await this.resetMicAudioTrack({force:audio});if(!this.state.channel?.id){return;} 12059this.soundEffectsService.play("call-join");this._host();this.cleanups.push(subscribe(browser,"beforeunload",(event)=>{event.preventDefault();}));this.channel?.focusAvailableVideo();} 12060newLogs(){this.state.logs={channelId:this.state.channel.id,selfSessionId:this.localSession.id,start:new Date().toISOString(),hasTurn:hasTurn(this.iceServers),entriesBySessionId:{},};} 12061dumpLogs({download=false}={}){const logs=[];if(this.state.logs){logs.push({type:"timeline",entry:this.state.logs.start,value:toRaw(this.state.logs),});} 12062if(this.state.channel){logs.push(this.buildSnapshot());} 12063if(logs.length||download){browser.navigator.serviceWorker?.controller?.postMessage({name:SW_MESSAGE_TYPE.POST_RTC_LOGS,logs,download,});}} 12064buildSnapshot(){const server={};if(this.state.connectionType===CONNECTION_TYPES.SERVER){server.info=toRaw(this.serverInfo);server.state=this.sfuClient?.state;server.errors=this.sfuClient?.errors.map((error)=>error.message);} 12065const sessions=this.state.channel.rtc_session_ids.map((session)=>{const sessionInfo={id:session.id,channelMemberId:session.channel_member_id?.id,state:session.connectionState,audioError:session.audioError,videoError:session.videoError,sfuConsumers:this.network?.getSfuConsumerStats(session.id),};if(session.eq(this.selfSession)){sessionInfo.isSelf=true;} 12066const audioEl=session.audioElement;if(audioEl){sessionInfo.audio={state:audioEl.readyState,muted:audioEl.muted,paused:audioEl.paused,networkState:audioEl.networkState,};} 12067const peer=this.p2pService?.peers.get(session.id);if(peer){sessionInfo.peer={id:peer.id,state:peer.connection.connectionState,iceState:peer.connection.iceConnectionState,};} 12068return sessionInfo;});return{type:"snapshot",entry:new Date().toISOString(),value:{server,sessions,connectionType:this.state.connectionType,fallback:this.state.fallbackMode,},};} 12069logSnapshot(){if(!this.state.channel){return;} 12070browser.navigator.serviceWorker?.controller?.postMessage({name:SW_MESSAGE_TYPE.POST_RTC_LOGS,logs:[this.buildSnapshot()],});} 12071async rpcLeaveCall(channel){await rpc("/mail/rtc/channel/leave_call",{channel_id:channel.id,},{silent:true});} 12072async ping(){const data=await rpc("/discuss/channel/ping",{channel_id:this.state.channel.id,check_rtc_session_ids:this.state.channel.rtc_session_ids.map((session)=>session.id),rtc_session_id:this.localSession.id,},{silent:true});this.store.insert(data);} 12073disconnect(session){const downloadTimeout=this.downloadTimeouts.get(session.id);if(downloadTimeout){clearTimeout(downloadTimeout);this.downloadTimeouts.delete(session.id);} 12074this.removeCallNotification("raise_hand_"+session.id);session.raisingHand=undefined;session.logStep=undefined;session.audioError=undefined;session.videoError=undefined;session.connectionState=undefined;session.isTalking=false;session.mainVideoStreamType=undefined;this.removeAudioFromSession(session);this.removeVideoFromSession(session);this.p2pService?.removePeer(session.id);this.log(session,"peer removed",{step:"peer removed"});} 12075clear(){if(this.state.channel){for(const session of this.state.channel.rtc_session_ids){this.removeAudioFromSession(session);this.removeVideoFromSession(session);session.isTalking=false;}} 12076this.exitFullscreen();this._remotelyHostedSessionId=undefined;this._remotelyHostedChannelId=undefined;browser.clearTimeout(this._crossTabTimeoutId);
12076this.cleanups.splice(0).forEach((cleanup)=>cleanup());browser.clearTimeout(this.sfuTimeout);this.sfuClient=undefined;this.network=undefined;this.audioContext?.close();this.audioContext=undefined;this._p2pRecoveryCount=0;this.closeCallPermissionDialog?.();this.state.updateAndBroadcastDebounce?.cancel();this.state.disconnectAudioMonitor?.();this.state.micAudioTrack?.stop();this.state.screenAudioTrack?.stop();this.state.audioTrack?.stop();this.state.cameraTrack?.stop();this.state.screenTrack?.stop();this.state.fallbackMode=undefined;this.state.isPipMode=false;closeStream(this.state.sourceCameraStream);this.state.sourceCameraStream=null;closeStream(this.state.sourceScreenStream);this.state.sourceScreenStream=null;if(this.blurManager){this.blurManager.close();this.blurManager=undefined;} 12077this.update({localSession:undefined,serverInfo:undefined,});Object.assign(this.state,{updateAndBroadcastDebounce:undefined,connectionType:undefined,disconnectAudioMonitor:undefined,cameraTrack:undefined,screenTrack:undefined,screenAudioTrack:undefined,micAudioTrack:undefined,audioTrack:undefined,sendCamera:false,sendScreen:false,channel:undefined,fallbackMode:false,});this.pipService?.closePip();} 12078async setDeaf(is_deaf){this.updateAndBroadcast({is_deaf});for(const session of this.state.channel.rtc_session_ids){if(!session.audioElement){continue;} 12079session.audioElement.muted=is_deaf;} 12080await this.refreshMicAudioStatus();} 12081async setOutputDevice(deviceId){const promises=[];for(const session of this.state.channel.rtc_session_ids){if(!session.audioElement){continue;} 12082promises.push(session.audioElement.setSinkId(deviceId));} 12083await Promise.all(promises);} 12084async setMute(is_muted){this.updateAndBroadcast({is_muted});await this.refreshMicAudioStatus();} 12085async raiseHand(raise){if(this.isRemote){this._remoteAction({raisingHand:raise});return;} 12086if(!this.localSession||!this.state.channel){return;} 12087this.localSession.raisingHand=raise?new Date():undefined;await this._updateInfo();} 12088async setTalking(isTalking){if(!this.localSession||isTalking===this.localSession.isTalking){return;} 12089this.localSession.isTalking=isTalking;
12089if(!this.localSession.isMute){this.pttExtService.notifyIsTalking(isTalking);await this.refreshMicAudioStatus();}} 12090async applyBlurEffect(videoStream){return new BlurManager(videoStream,{backgroundBlur:this.store.settings.backgroundBlurAmount,edgeBlur:this.store.settings.edgeBlurAmount,});} 12091async toggleVideo(type,options){let force;let env;let refreshStream;if(typeof options==="boolean"){force=options;}else{force=options?.force;env=options?.env;refreshStream=options?.refreshStream;} 12092if(this.isRemote){this.notification.add(UNAVAILABLE_AS_REMOTE,{type:"warning",});return;} 12093if(!this.state.channel?.id){return;} 12094switch(type){case"camera":{if(this.cameraPermission==="prompt"&&!this.state.cameraTrack){this.showMediaPermissionDialog("camera");return;} 12095const track=this.state.cameraTrack;const sendCamera=force??!this.state.sendCamera;this.state.sendCamera=false;await this.setVideo(track,type,{activateVideo:sendCamera,env,refreshStream});break;} 12096case"screen":{const track=this.state.screenTrack;const sendScreen=force??!this.state.sendScreen;this.state.sendScreen=false;await this.setVideo(track,type,{activateVideo:sendScreen,env});break;}} 12097if(!this.localSession){return;} 12098switch(type){case"camera":{this.removeVideoFromSession(this.localSession,{type:"camera",cleanup:false,});if(this.state.cameraTrack){this.updateStream(this.localSession,this.state.cameraTrack);} 12099this.updateAndBroadcast({is_camera_on:!!this.state.sendCamera,});break;} 12100case"screen":{if(!this.state.screenTrack){this.removeVideoFromSession(this.localSession,{type:"screen",cleanup:false,});}else{this.updateStream(this.localSession,this.state.screenTrack);} 12101this.updateAndBroadcast({is_screen_sharing_on:!!this.state.sendScreen,});break;}} 12102const updatedTrack=type==="camera"?this.state.cameraTrack:this.state.screenTrack;await this.network?.updateUpload(type,updatedTrack);} 12103updateAndBroadcast(data){this._updateRemoteTabs({[this.localSession.id]:data});assignDefined(this.localSession,data);this.state.updateAndBroadcastDebounce?.();} 12104async refreshMicAudioStatus(){if(!this.state.micAudioTrack){return;} 12105this.state.micAudioTrack.enabled=!this.localSession.isMute&&this.localSession.isTalking;this._updateInfo();} 12106async setVideo(track,type,options){let activateVideo;let env;if(typeof options==="boolean"){activateVideo=options??false;}else{activateVideo=options?.activateVideo??false;env=options?.env;} 12107const stopVideo=()=>{if(track){track.stop();} 12108switch(type){case"camera":{this.state.cameraTrack=undefined;closeStream(this.state.sourceCameraStream);this.state.sourceCameraStream=null;break;} 12109case"screen":{this.state.screenTrack=undefined;closeStream(this.state.sourceScreenStream);this.state.sourceScreenStream=null;break;}}};if(!activateVideo){if(type==="screen"){this.soundEffectsService.play("screen-sharing");} 12110if(type==="camera"&&this.blurManager){this.blurManager.close();this.blurManager=undefined;} 12111stopVideo();return;} 12112let sourceStream;const sourceWindow=env?.pipWindow??browser;try{if(type==="camera"){if(this.state.sourceCameraStream&&!options?.refreshStream){sourceStream=this.state.sourceCameraStream;}else{closeStream(this.state.sourceCameraStream);sourceStream=await sourceWindow.navigator.mediaDevices.getUserMedia({video:this.store.settings.cameraConstraints,});}} 12113if(type==="screen"){if(this.state.sourceScreenStream){sourceStream=this.state.sourceScreenStream;}else{sourceStream=await sourceWindow.navigator.mediaDevices.getDisplayMedia({video:SCREEN_CONFIG,audio:true,});} 12114this.soundEffectsService.play("screen-sharing");}}catch{this.showMediaUnavailableWarning({camera:type==="camera",screen:type==="screen",});stopVideo();return;} 12115if(!this.selfSession){closeStream(sourceStream);return;} 12116let outputTrack=sourceStream?sourceStream.getVideoTracks()[0]:undefined;const screenAudioTrack=sourceStream?sourceStream.getAudioTracks()[0]:undefined;if(outputTrack){outputTrack.addEventListener("ended",async()=>{await this.toggleVideo(type,{force:false});});if(type==="camera"&&isMobileOS()){const settings=outputTrack.getSettings();if(settings?.facingMode){this.store.settings.cameraFacingMode=settings.facingMode;}else if(!this.store.settings.cameraFacingMode){this.store.settings.cameraFacingMode="user";}}} 12117if(this.store.settings.useBlur&&type==="camera"){this.blurManager?.close();this.blurManager=undefined;try{this.blurManager=await this.applyBlurEffect(sourceStream);const blurredStream=await this.blurManager.stream;outputTrack=blurredStream.getVideoTracks()[0];}catch(_e){this.notification.add(_e.message,{type:"warning"});this.store.settings.setUseBlur(false);outputTrack=sourceStream.getVideoTracks()[0];}}else if(!this.store.settings.useBlur&&type==="camera"){this.blurManager?.close();this.blurManager=undefined;} 12118switch(type){case"camera":{Object.assign(this.state,{sourceCameraStream:sourceStream,cameraTrack:outputTrack,sendCamera:Boolean(outputTrack),isCameraSourceExternal:Boolean(sourceStream)&&env?.pipWindow,});break;} 12119case"screen":{Object.assign(this.state,{sourceScreenStream:sourceStream,screenTrack:outputTrack,screenAudioTrack:screenAudioTrack,sendScreen:Boolean(outputTrack),isScreenSourceExternal:Boolean(sourceStream)&&env?.pipWindow,});break;}} 12120if(this.state.screenAudioTrack){this.updateAudioTrack();}} 12121async updateAudioTrack(){const{micAudioTrack,screenAudioTrack}=this.state;if(!micAudioTrack&&!screenAudioTrack){return;} 12122if(micAudioTrack&&screenAudioTrack){await this.audioContext?.close();this.audioContext=undefined;this.audioContext=new AudioContext();const micSource=this.audioContext.createMediaStreamSource(new MediaStream([micAudioTrack]));const screenSource=this.audioContext.createMediaStreamSource(new MediaStream([screenAudioTrack]));const destination=this.audioContext.createMediaStreamDestination();micSource.connect(destination);screenSource.connect(destination);this.state.audioTrack=destination.stream.getAudioTracks()[0];}else{this.state.audioTrack=micAudioTrack??screenAudioTrack;} 12123await this.network?.updateUpload("audio",this.state.audioTrack);} 12124async resetMicAudioTrack({force=false}){this.state.micAudioTrack?.stop();this.state.micAudioTrack=undefined;this.state.audioTrack?.stop();this.state.audioTrack=undefined;if(!this.state.channel){return;} 12125if(this.localSession){this.setMute(true);} 12126if(force){let micAudioTrack;try{const audioStream=await browser.navigator.mediaDevices.getUserMedia({audio:this.store.settings.audioConstraints,});micAudioTrack=audioStream.getAudioTracks()[0];if(this.localSession){this.setMute(false);}}catch{this.showMediaUnavailableWarning({microphone:true});return;} 12127if(!this.localSession){micAudioTrack.stop();return;} 12128micAudioTrack.addEventListener("ended",async()=>{await this.resetMicAudioTrack({force:false});this.setMute(true);});micAudioTrack.enabled=!this.localSession.isMute&&this.localSession.isTalking;this.state.micAudioTrack=micAudioTrack;this.linkVoiceActivationDebounce();this.updateAudioTrack();}} 12129async linkVoiceActivation(){this.state.disconnectAudioMonitor?.();if(!this.localSession){return;} 12130if(this.store.settings.use_push_to_talk||!this.state.channel||!this.state.micAudioTrack){this.localSession.isTalking=false;await this.refreshMicAudioStatus();return;} 12131try{this.state.disconnectAudioMonitor=await monitorAudio(this.state.micAudioTrack,{onThreshold:async(isAboveThreshold)=>{this.setTalking(isAboveThreshold);},volumeThreshold:this.store.settings.voiceActivationThreshold,});}catch{this.notification.add(_t("Your browser does not support voice activation"),{type:"warning",});this.localSession.isTalking=true;} 12132await this.refreshMicAudioStatus();} 12133deleteSession(id){const session=this.store["discuss.channel.rtc.session"].get(id);if(session){if(this.localSession&&session.eq(this.localSession)){this.notifyServerDisconnect();this.endCall();} 12134this.disconnect(session);session.delete();}} 12135notifyServerDisconnect(){this.log(this.localSession,"self session deleted by the server, ending call",{important:true,});this.notification.add(_t("Disconnected from the call by the server"),{type:"warning",});} 12136formatInfo(){this.localSession.is_camera_on=Boolean(this.state.cameraTrack);this.localSession.is_screen_sharing_on=Boolean(this.state.screenTrack);return this.localSession.info;} 12137async updateStream(session,track,{mute,videoType}={}){const stream=new window.MediaStream();stream.addTrack(track);if(track.kind==="audio"){const audioElement=session.audioElement||new window.Audio();audioElement.srcObject=stream;audioElement.load();audioElement.muted=mute;audioElement.volume=this.store.settings.getVolume(session);audioElement.autoplay=true;session.audioElement=audioElement;session.audioStream=stream;session.is_muted=false;session.isTalking=false;await session.playAudio();} 12138if(track.kind==="video"){videoType=videoType?videoType:track.id===this.state.cameraTrack?.id?"camera":"screen";session.videoStreams.set(videoType,stream);this.updateActiveSession(session,videoType,{addVideo:true});}} 12139removeVideoFromSession(session,{type,cleanup=true}={}){if(type){this.updateActiveSession(session,type);if(cleanup){closeStream(session.videoStreams.get(type));} 12140session.videoStreams.delete(type);if(this.selfSession.videoStreams.size===0&&this.selfSession.eq(this.state.channel.activeRtcSession)){this.state.channel.activeRtcSession=undefined;}}else{if(cleanup){for(const stream of session.videoStreams.values()){closeStream(stream);}} 12141session.videoStreams.clear();}} 12142removeAudioFromSession(session){closeStream(session.audioStream);if(session.audioElement){session.audioElement.pause();try{session.audioElement.srcObject=undefined;}catch{}} 12143session.audioStream=undefined;} 12144updateActiveSession(session,videoType,{addVideo=false}={}){const activeRtcSession=this.state.channel.activeRtcSession;if(addVideo){if(videoType==="screen"){this.state.channel.activeRtcSession=session;session.mainVideoStreamType=videoType;return;} 12145if(activeRtcSession&&session.hasVideo&&!session.isMainVideoStreamA
12145ctive){session.mainVideoStreamType=videoType;} 12146return;} 12147if(!activeRtcSession||activeRtcSession.notEq(session)){return;} 12148if(activeRtcSession.isMainVideoStreamActive){if(videoType===session.mainVideoStreamType){if(videoType==="screen"){session.mainVideoStreamType="camera";}else if(this.actionsStack.includes("camera-on")&&this.actionsStack.includes("share-screen")){session.mainVideoStreamType="screen";}}}} 12149updateVideoDownload(rtcSession,{viewCountIncrement=0}={}){rtcSession.videoComponentCount+=viewCountIncrement;const downloadTimeout=this.downloadTimeouts.get(rtcSession.id);if(downloadTimeout){this.downloadTimeouts.delete(rtcSession.id);browser.clearTimeout(downloadTimeout);} 12150if(rtcSession.videoComponentCount>0){this.network?.updateDownload(rtcSession.id,{camera:true,screen:true,});}else{this.downloadTimeouts.set(rtcSession.id,browser.setTimeout(()=>{this.downloadTimeouts.delete(rtcSession.id);this.network?.updateDownload(rtcSession.id,{camera:false,screen:false,});},1000));}}} 12151Rtc.register();const rtcService=__exports.rtcService={dependencies:["bus_service","discuss.p2p","discu
12151ss.pip_service","discuss.ptt_extension","mail.fullscreen","mail.sound_effects","mail.store","legacy_multi_tab","notification","presence",],start(env,services){const store=env.services["mail.store"];const rtc=store.rtc;rtc.pipService=services["discuss.pip_service"];onChange(rtc.pipService.state,"active",()=>{const isPipMode=rtc.pipService.state.active;if(!isPipMode){rtc.channel?.openChatWindow();} 12152rtc.state.isPipMode=isPipMode;rtc._postToTabs({type:CROSS_TAB_HOST_MESSAGE.PIP_CHANGE,changes:{isPipMode},});});rtc.fullscreen=services["mail.fullscreen"];onChange(rtc.fullscreen,"id",()=>{const wasFullscreen=rtc.state.isFullscreen;rtc.state.isFullscreen=rtc.fullscreen.id===CALL_FULLSCREEN_ID;if(rtc.state.screenTrack&&rtc.displaySurface!=="browser"&&rtc.fullscreen.id===CALL_FULLSCREEN_ID){rtc.showMirroringWarning();}else if(!rtc.state.isFullscreen){rtc.removeMirroringWarning?.();if(wasFullscreen&&rtc.state.screenTrack){rtc.state.screenTrack.enabled=true;}}});browser.navigator.permissions?.query({name:"microphone"}).then((status)=>{rtc.microphonePermission=status.state;status.onchange=()=>(rtc.microphonePermission=status.state);});browser.navigator.permissions?.query({name:"camera"}).then((status)=>{rtc.cameraPermission=status.state;status.onchange=()=>(rtc.cameraPermission=status.state);});rtc.p2pService=services["discuss.p2p"];rtc.p2pService.acceptOffer=async(id,sequence)=>{const session=await store["discuss.channel.rtc.session"].getWhenReady(Number(id));return sequence>=session?.sequence;};services["bus_service"].subscribe("discuss.channel.rtc.session/sfu_hot_swap",async({serverInfo})=>{if(!rtc.localSession){return;} 12153if(rtc.serverInfo?.channelUUID===serverInfo.channelUUID){rtc.p2pService.removeALlPeers();return;} 12154rtc.serverInfo=serverInfo;await rtc._initConnection();});services["bus_service"].subscribe("discuss.channel.rtc.session/ended",({sessionId})=>{if(rtc.localSession?.id===sessionId){rtc.notifyServerDisconnect();rtc.endCall();}});services["bus_service"].subscribe("res.users.settings.volumes",(payload)=>{if(payload){rtc.store.Volume.insert(payload);}});services["bus_service"].subscribe("discuss.channel.rtc.session/update_and_broadcast",(payload)=>{const{data,channelId}=payload;if(channelId!==rtc.channel?.id){rtc.store.insert(data);}});services["presence"].bus.addEventListener("presence",()=>{env.bus.trigger("RTC-SERVICE:PLAY_MEDIA");},{once:true});return rtc;},};registry.category("services").add("discuss.rtc",rtcService);return __exports;});; 12155 12156/* /mail/static/src/discuss/call/common/rtc_session_model.js */ 12157odoo.define('@mail/discuss/call/common/rtc_session_model',['@mail/core/common/record','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const{Deferred}=require("@web/core/utils/concurrency");const RtcSession=__exports.RtcSession=class RtcSession extends Record{static _name="discuss.channel.rtc.session";static id="id";static awaitedRecords=new Map();static _insert(){const session=super._insert(...arguments);session.channel?.rtc_session_ids.add(session);return session;} 12158static async getWhenReady(id){const session=this.get(id);if(!session){let deferred=this.awaitedRecords.get(id);if(!deferred){deferred=new Deferred();this.awaitedRecords.set(id,deferred);setTimeout(()=>{deferred.resolve();this.awaitedRecords.delete(id);},120_000);} 12159return deferred;} 12160return session;} 12161static new(){const record=super.new(...arguments);this.awaitedRecords.get(record.id)?.resolve(record);this.awaitedRecords.delete(record.id);return record;} 12162channel_member_id=fields.One("discuss.channel.member",{inverse:"rtcSession"});partner_id=fields.One("res.partner",{compute(){return this.channel_member_id?.partner_id;},});guest_id=fields.One("mail.guest",{compute(){return this.channel_member_id?.guest_id;},});get persona(){return this.partner_id||this.guest_id;} 12163is_camera_on;is_screen_sharing_on=fields.Attr(undefined,{onUpdate(){if(this.eq(this.channel?.activeRtcSession)&&this.mainVideoStreamType==="screen"&&!this.is_screen_sharing_on){this.channel.activeRtcSession=undefined;}},});id;is_deaf;is_muted;audioElement;audioStream;dataChannel;audioError;videoError;isTalking=fields.Attr(false,{onUpdate(){if(this.isTalking&&!this.isMute){this.talkingTime=this.store.nextTalkingTime++;} 12164this.channel?.updateCallFocusStack(this);},});isActuallyTalking=fields.Attr(false,{compute(){return this.isTalking&&!this.isMute;},});isVideoStreaming=fields.Attr(false,{compute(){return this.is_screen_sharing_on||this.is_camera_on;},onUpdate(){if(this.isVideoStreaming&&this.channel?.channel_type==="chat"&&this.store.rtc.selfSession?.in(this.channel.rtc_session_ids)){this.channel.focusAvailableVideo();}},});shortStatus=fields.Attr(undefined,{compute(){if(this.is_screen_sharing_on){return"live";} 12165if(this.is_deaf){return"deafen";} 12166if(this.isMute){return"mute";}},});talkingTime=0;localVolume;peerConnection;raisingHand;videoComponentCount=0;videoStreams=new Map();mainVideoStreamType;sequence=0;connectionState;logStep;get channel(){return this.channel_member_id?.channel_id;} 12167get isMute(){return this.is_muted||this.is_deaf;}
12168get mainVideoStream(){return this.isMainVideoStreamActive&&this.videoStreams.get(this.mainVideoStreamType);} 12169get isMainVideoStreamActive(){if(!this.mainVideoStreamType){return false;} 12170return this.mainVideoStreamType==="camera"?this.is_camera_on:this.is_screen_sharing_on;} 12171get hasVideo(){return this.is_screen_sharing_on||this.is_camera_on;} 12172getStream(type){const isActive=type==="camera"?this.is_camera_on:this.is_screen_sharing_on;return isActive&&this.videoStreams.get(type);} 12173get info(){return{isSelfMuted:this.is_muted,isRaisingHand:Boolean(this.raisingHand),isDeaf:this.is_deaf,isTalking:this.isTalking,isCameraOn:this.is_camera_on,isScreenSharingOn:this.is_screen_sharing_on,};} 12174get name(){return this.channel_member_id?.name;} 12175get volume(){return this.audioElement?.volume||this.localVolume;} 12176set volume(value){if(this.audioElement){this.audioElement.volume=value;} 12177this.localVolume=value;} 12178async playAudio(){if(!this.audioElement){return;} 12179if(this.store.settings.audioOutputDeviceId){await this.audioElement.setSinkId(this.store.settings.audioOutputDeviceId).catch();} 12180try{await this.audioElement.play();this.audioError=undefined;}catch(error){this.audioError=error.name;}} 12181updateStreamState(type,state){if(type==="camera"){this.is_camera_on=state;}else if(type==="screen"){this.is_screen_sharing_on=state;}}} 12182RtcSession.register();return __exports;});; 12183 12184/* /mail/static/src/discuss/call/common/settings_model_patch.js */ 12185odoo.define('@mail/discuss/call/common/settings_model_patch',['@mail/core/common/settings_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Settings}=require("@mail/core/common/settings_model");const{patch}=require("@web/core/utils/patch");const SettingsPatch={setup(){super.setup(...arguments);},getVolume(rtcSession){return(rtcSession.volume??this.volumes.find((volume)=>volume.partner_id?.eq(rtcSession.partner_id)||volume.guest_id?.eq(rtcSession.guest_id))?.volume??0.5);},};patch(Settings.prototype,SettingsPatch);return __exports;});; 12186 12187/* /mail/static/src/discuss/call/common/store_service_patch.js */ 12188odoo.define('@mail/discuss/call/common/store_service_patch',['@mail/core/common/record','@mail/core/common/store_service','@web/core/browser/router','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{fields}=require("@mail/core/common/record");const{Store}=require("@mail/core/common/store_service");const{router}=require("@web/core/browser/router");const{patch}=require("@web/core/utils/patch");const StorePatch={setup(){super.setup(...arguments);this.rtc=fields.One("Rtc",{compute(){return{};},});this.ringingThreads=fields.Many("Thread",{onUpdate(){if(this.ringingThreads.length>0){this.env.services["mail.sound_effects"].play("call-invitation",{loop:true,});}else{this.env.services["mail.sound_effects"].stop("call-invitation");}},});this.allActiveRtcSessions=fields.Many("discuss.channel.rtc.session");this.nextTalkingTime=1;this.fullscreenChannel=fields.One("Thread");this._hasFullscreenUrl=fields.Attr(false,{compute(){return this.discuss?.thread?.eq(this.fullscreenChannel);},onUpdate(){if(!this.discuss?.hasRestoredThread){return;} 12189this._hasFullscreenUrlOnUpdate();},eager:true,});this.meetingViewOpened=false;},_hasFullscreenUrlOnUpdate(){router.pushState({fullscreen:this._hasFullscreenUrl?true:undefined,});},onStarted(){super.onStarted(...arguments);this.rtc.start();},sortMembers(m1,m2){const m1HasRtc=Boolean(m1.rtcSession);const m2HasRtc=Boolean(m2.rtcSession);if(m1HasRtc===m2HasRtc){const m1RaisingValue=m1.rtcSession?.raisingHand||Infinity;const m2RaisingValue=m2.rtcSession?.raisingHand||Infinity;if(m1HasRtc&&m1RaisingValue!==m2RaisingValue){return m1RaisingValue-m2RaisingValue;}else{return super.sortMembers(m1,m2);}}else{return m2HasRtc-m1HasRtc;}},};patch(Store.prototype,StorePatch);return __exports;});; 12190 12191/* /mail/static/src/discuss/call/common/thread_actions.js */ 12192odoo.define('@mail/discuss/call/common/thread_actions',['@mail/core/common/action','@mail/core/common/thread_actions','@mail/discuss/call/common/call_settings','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{ACTION_TAGS}=require("@mail/core/common/action");const{registerThreadAction}=require("@mail/core/common/thread_actions");const{CallSettings}=require("@mail/discuss/call/common/call_settings");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);registerThreadAction("call",{condition:({store,thread})=>
12192thread?.allowCalls&&!thread?.eq(store.rtc.channel),icon:"fa fa-fw fa-phone",name:({thread})=>thread.rtc_session_ids.length>0?_t("Join the Call"):_t("Start Call"),open:({store,thread})=>store.rtc.toggleCall(thread),sequence:10,sequenceQuick:30,tags:[ACTION_TAGS.SUCCESS,ACTION_TAGS.JOIN_LEAVE_CALL],});registerThreadAction("camera-call",{condition:({store,thread})=>thread?.allowCalls&&!thread?.eq(store.rtc.channel),icon:"fa fa-fw fa-video-camera",name:({thread})=>thread.rtc_session_ids.length>0?_t("Join the Call with Camera"):_t("Start Video Call"),open:({store,thread})=>store.rtc.toggleCall(thread,{camera:true}),sequence:5,sequenceQuick:({owner})=>(owner.env.inDiscussApp?25:35),tags:[ACTION_TAGS.SUCCESS,ACTION_TAGS.JOIN_LEAVE_CALL],});registerThreadAction("call-settings",{actionPanelComponent:CallSettings,actionPanelComponentProps:()=>({isCompact:true}),condition:({owner,store,thread})=>thread?.allowCalls&&(owner.props.chatWindow?.isOpen||store.inPublicPage)&&!owner.isDiscussSidebarChannelActions,icon:"fa fa-fw fa-gear",name:_t("Call Settings"),sequence:20,sequenceGroup:30,toggle:true,});registerThreadAction("disconnect",{condition:({owner,store,thread})=>store.rtc.selfSession?.in(thread?.rtc_session_ids)&&owner.isDiscussSidebarChannelActions,open:({store,thread})=>store.rtc.toggleCall(thread),icon:"fa fa-fw fa-phone",name:_t("Disconnect"),sequence:30,sequenceGroup:10,tags:[ACTION_TAGS.DANGER,ACTION_TAGS.JOIN_LEAVE_CALL],});return __exports;});; 12193 12194/* /mail/static/src/discuss/call/common/thread_model_patch.js */ 12195odoo.define('@mail/discuss/call/common/thread_model_patch',['@mail/core/common/record','@mail/core/common/thread_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{fields}=require("@mail/core/common/record");const{Thread}=require("@mail/core/common/thread_model");const{patch}=require("@web/core/utils/patch");const CALL_PROMOTE_FULLSCREEN=__exports.CALL_PROMOTE_FULLSCREEN=Object.freeze({INACTIVE:"INACTIVE",ACTIVE:"ACTIVE",DISCARDED:"DISCARDED",});const ThreadPatch={setup(){super.setup(...arguments);this.activeRtcSession=fields.One("discuss.channel.rtc.session",{onAdd(r){this.store.allActiveRtcSessions.add(r);},onDelete(r){this.store.allActiveRtcSessions.delete(r);},});this.promoteFullscreen=CALL_PROMOTE_FULLSCREEN.DISABLED;this.hadSelfSession=false;this.lastSessionIds=new Set();this.cancelRtcInvitationTimeout;this.rtc_session_ids=fields.Many("discuss.channel.rtc.session",{onDelete(r){this.store.env.services["discuss.rtc"].deleteSession(r.id);},async onUpdate(){const hadSelfSession=this.hadSelfSession;const lastSessionIds=this.lastSessionIds;this.hadSelfSession=Boolean(this.store.rtc.selfSession?.in(this.rtc_session_ids));this.lastSessionIds=new Set(this.rtc_session_ids.map((s)=>s.id));const shouldPlayJoinSound=[...this.lastSessionIds].some((id)=>!lastSessionIds.has(id));const shouldPlayLeaveSound=[...lastSessionIds].some((id)=>!this.lastSessionIds.has(id));if(!hadSelfSession||!this.hadSelfSession||!(await this.store.env.services["multi_tab"].isOnMainTab())){return;} 12196if(shouldPlayJoinSound){this.store.env.services["mail.sound_effects"].play("call-join");this.store.rtc.call({asFallback:true});} 12197if(shouldPlayLeaveSound){this.store.env.services["mail.sound_effects"].play("member-leave");}},});this.videoCountNotSelf=fields.Attr(0,{compute(){return this.rtc_session_ids.filter((s)=>s.hasVideo&&s.notEq(this.store.rtc.selfSession)).length;},onUpdate(){if(this.promoteFullscreen===CALL_PROMOTE_FULLSCREEN.DISCARDED){return;} 12198this.promoteFullscreen=this.videoCountNotSelf>0&&this.chat_window?.isOpen?CALL_PROMOTE_FULLSCREEN.ACTIVE:CALL_PROMOTE_FULLSCREEN.INACTIVE;},});this.videoCount=fields.Attr(0,{compute(){return this.rtc_session_ids.filter((s)=>s.hasVideo).length;},});this.focusStack=fields.Many("discuss.channel.rtc.session");this.visibleCards=fields.Attr([],{compute(){const raisingHandCards=[];const sessionCards=[];const invitationCards=[];const filterVideos=this.store.settings.showOnlyVideo&&this.videoCount>0;for(const session of this.rtc_session_ids){const target=session.raisingHand?raisingHandCards:sessionCards;
12198const cameraStream=session.is_camera_on?session.videoStreams.get("camera"):undefined;if(!filterVideos||cameraStream){target.push({key:"session_main_"+session.id,session,type:"camera",videoStream:cameraStream,});} 12199const screenStream=session.is_screen_sharing_on?session.videoStreams.get("screen"):undefined;if(screenStream){target.push({key:"session_secondary_"+session.id,session,type:"screen",videoStream:screenStream,});}} 12200if(!filterVideos){for(const member of this.invited_member_ids){invitationCards.push({key:"member_"+member.id,member});}} 12201raisingHandCards.sort((c1,c2)=>c1.session.raisingHand-c2.session.raisingHand);sessionCards.sort((c1,c2)=>c1.session.channel_member_id?.persona?.name?.localeCompare(c2.session.channel_member_id?.persona?.name)??1);invitationCards.sort((c1,c2)=>c1.member.persona?.name?.localeCompare(c2.member.persona?.name)??1);return raisingHandCards.concat(sessionCards,invitationCards);},});this.useCameraByDefault=fields.Attr(null,{compute(){if(this.channel_type==="chat"&&this.store.rtc.selfSession?.channel?.eq(this)){return this.store.rtc.selfSession.is_camera_on;} 12202return JSON.parse(localStorage.getItem(`discuss_channel_camera_default_${this.id}`));},onUpdate(){if(this.useCameraByDefault!==null){localStorage.setItem(`discuss_channel_camera_default_${this.id}`,JSON.stringify(this.useCameraByDefault));}},});},get isCallDisplayedInChatWindow(){return this.chat_window?.isOpen&&!this.store.meetingViewOpened;},get isSelfInCall(){return this.store.rtc.selfSession&&this.eq(this.store.rtc.channel);},get showCallView(){return!this.store.rtc.state.isFullscreen&&this.rtc_session_ids.length>0;},focusAvailableVideo(){if(!this.store.settings.useCallAutoFocus||!(this.store.env.services.ui.isSmall||this.store.rtc.state.isPipMo
12202de||this.isCallDisplayedInChatWindow)){return;} 12203const otherStreamingSession=this.rtc_session_ids.find((session)=>session.notEq(this.store.rtc.selfSession)&&session.hasVideo);if(!otherStreamingSession){return;} 12204this.activeRtcSession=otherStreamingSession;otherStreamingSession.mainVideoStreamType=otherStreamingSession.is_screen_sharing_on?"screen":"camera";},open(options){if(this.store.fullscreenChannel?.notEq(this)){this.store.rtc.exitFullscreen();} 12205return super.open(...arguments);},updateCallFocusStack(session){if(this.notEq(this.store.rtc?.channel)||session.eq(this.store.rtc.selfSession)||!this.activeRtcSession||!this.store.settings.useCallAutoFocus||this.activeRtcSession?.mainVideoStreamType==="screen"){return;} 12206this.focusStack.delete(session);if(session.isTalking&&!session.isMute){this.focusStack.push(session);} 12207const activeSession=this.focusStack.at(-1);if(!activeSession){return;} 12208this.activeRtcSession=activeSession;activeSession.mainVideoStreamType="camera";},};patch(Thread.prototype,ThreadPatch);return __exports;});; 12209 12210/* /mail/static/src/discuss/call/common/tick_worker.js */ 12211odoo.define('@mail/discuss/call/common/tick_worker',[],function(require){'use strict';let __exports={};let intervalId=null;let awaitingTock=false;let isRunning=false;function reset(){if(intervalId){clearInterval(intervalId);intervalId=null;} 12212awaitingTock=false;isRunning=false;} 12213function startProcessing(fps){if(isRunning){return;} 12214isRunning=true;intervalId=setInterval(()=>{if(awaitingTock){return;} 12215awaitingTock=true;self.postMessage({command:"tick"});},Math.floor(1000/(fps||30)));} 12216self.onmessage=(e)=>{if(!e.data?.command){return;} 12217const{command,fps}=e.data;switch(command){case"start":startProcessing(fps);break;case"tock":awaitingTock=false;break;case"stop":reset();break;default:break;}};self.onmessageerror=()=>{awaitingTock=false;};self.onerror=reset;return __exports;});; 12218 12219/* /mail/static/src/discuss/typing/common/composer_patch.js */ 12220odoo.define('@mail/discuss/typing/common/composer_patch',['@mail/core/common/composer','@mail/discuss/typing/common/typing','@web/core/network/rpc','@odoo/owl','@web/core/browser/browser','@web/core/registry','@web/core/utils/patch','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Composer}=require("@mail/core/common/composer");const{Typing}=require("@mail/discuss/typing/common/typing");const{rpc}=require("@web/core/network/rpc");const{onWillDestroy}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{patch}=require("@web/core/utils/patch");const{useDebounced}=require("@web/core/utils/timing");const commandRegistry=registry.category("discuss.channel_commands");const SHORT_TYPING=__exports.SHORT_TYPING=5000;const LONG_TYPING=__exports.LONG_TYPING=50000;patch(Composer,{components:{...Composer.components,Typing},});patch(Composer.prototype,{setup(){super.setup();this.typingNotified=false;this.stopTypingDebounced=useDebounced(this.stopTyping.bind(this),SHORT_TYPING);onWillDestroy(()=>{this.stopTyping();});},notifyIsTyping(is_typing=true){if(this.thread?.model==="discuss.channel"&&this.thread.id>0){rpc("/discuss/channel/notify_typing",{channel_id:this.thread.id,is_typing,},{silent:true});}},onInput(ev){super.onInput(ev);this.detectTyping(ev);},detectTyping(){if(this.props.composer.message){return;} 12221const value=this.props.composer.composerText;if(this.thread?.model==="discuss.channel"&&value.startsWith("/")){const[firstWord]=value.substring(1).split(/\s/);const command=commandRegistry.get(firstWord,false);if(value==="/"||this.hasSuggestions||(command&&(!command.condition||command.condition({store:this.store,thread:this.thread}))&&(!command.channel_types||command.channel_types.includes(this.thread.channel_type)))){this.stopTyping();return;}} 12222if(!this.typingNotified&&value){this.typingNotified=true;this.notifyIsTyping();browser.setTimeout(()=>(this.typingNotified=false),LONG_TYPING);} 12223this.stopTypingDebounced();},async sendMessage(){await super.sendMessage();this.stopTyping();},stopTyping(){if(this.typingNotified){this.typingNotified=false;this.notifyIsTyping(false);}},addEmoji(str){const res=super.addEmoji(str);this.detectTyping();return res;},});return __exports;});; 12224 12225/* /mail/static/src/discuss/typing/common/thread_icon_patch.js */ 12226odoo.define('@mail/discuss/typing/common/thread_icon_patch',['@mail/core/common/thread_icon','@mail/discuss/typing/common/typing','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ThreadIcon}=require("@mail/core/common/thread_icon");const{Typing}=require("@mail/discuss/typing/common/typing");const{patch}=require("@web/core/utils/patch");patch(ThreadIcon,{components:{...ThreadIcon.components,Typing},});return __exports;});; 12227 12228/* /mail/static/src/discuss/typing/common/typing.js */ 12229odoo.define('@mail/discuss/typing/common/typing',['@odoo/owl','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const Typing=__exports.Typing=class Typing extends Component{static defaultProps={size:"small",displayText:true,};static props=["channel?","size?","displayText?","member?"];static template="discuss.Typing";get text(){const typingMemberNames=this.props.member?[this.props.member.name]:this.props.channel.otherTypingMembers.map(({name})=>name);if(typingMemberNames.length===1){return _t("%s is typing...",typingMemberNames[0]);} 12230if(typingMemberNames.length===2){return _t("%(user1)s and %(user2)s are typing...",{user1:typingMemberNames[0],user2:typingMemberNames[1],});} 12231return _t("%(user1)s, %(user2)s and more are typing...",{user1:typingMemberNames[0],user2:typingMemberNames[1],});}} 12232return __exports;});; 12233 12234/* /mail/static/src/utils/common/dates.js */ 12235odoo.define('@mail/utils/common/dates',[],function(require){'use strict';let __exports={};const{DateTime}=luxon;__exports.computeDelay=computeDelay;function computeDelay(datetime){if(!datetime){return 0;} 12236const today=DateTime.now().startOf("day");return datetime.diff(today,"days").days;} 12237__exports.getMsToTomorrow=getMsToTomorrow;function getMsToTomorrow(){const now=new Date();const night=new Date(now.getFullYear(),now.getMonth(),now.getDate()+1,0,0,0);return night.getTime()-now.getTime();} 12238__exports.isToday=isToday;function isToday(datetime){if(!datetime){return false;}
12239return(datetime.toLocaleString(DateTime.DATE_FULL)===DateTime.now().toLocaleString(DateTime.DATE_FULL));} 12240return __exports;});; 12241 12242/* /mail/static/src/utils/common/format.js */ 12243odoo.define('@mail/utils/common/format',['@odoo/owl','@web/core/browser/router','@web/core/emoji_picker/emoji_picker','@web/core/l10n/utils','@web/core/utils/html','@web/core/utils/strings','@web/core/utils/urls','@web/core/utils/xml'],function(require){'use strict';let __exports={};const{htmlEscape,markup}=require("@odoo/owl");const{router}=require("@web/core/browser/router");const{loadEmoji,loader}=require("@web/core/emoji_picker/emoji_picker");const{normalize}=require("@web/core/l10n/utils");const{createDocumentFragmentFromContent,createElementWithContent,htmlFormatList,htmlJoin,htmlReplace,htmlReplaceAll,htmlTrim,isHtmlEmpty,setElementContent,}=require("@web/core/utils/html");const{escapeRegExp}=require("@web/core/utils/strings");const{getOrigin}=require("@web/core/utils/urls");const{setAttributes}=require("@web/core/utils/xml");const urlRegexp=/\b(?:https?:\/\/\d{1,3}(?:\.\d{1,3}){3}|(?:https?:\/\/|(?:www\.))[-a-z0-9@:%._+~#=\u00C0-\u024F\u1E00-\u1EFF]{1,256}(?:\.{1})?(?:[a-z]{2,13}))\b(?:[-a-z0-9@:%_+~#?&[\]^|{}`\\'$//=\u00C0-\u024F\u1E00-\u1EFF]|[.]*[-a-z0-9@:%_+~#?&[\]^|{}`\\'$//=\u00C0-\u024F\u1E00-\u1EFF]|,(?!$| )|\.(?!$| |\.)|;(?!$| ))*/gi;const messageUrlRegExp=new RegExp(`^${escapeRegExp(getOrigin())}/mail/message/(\\d+)$`);__exports.prettifyMessageText=prettifyMessageText;function prettifyMessageText(rawBody,{validMentions={},thread}={}){if(rawBody instanceof markup().constructor){return rawBody;} 12244let body=htmlTrim(rawBody);body=htmlReplace(body,/(\r|\n){2,}/g,()=>markup`<br/><br/>`);body=htmlReplace(body,/(\r|\n)/g,()=>markup`<br/>`);body=htmlReplace(body,/ /g,()=>" ");body=htmlTrim(body);body=generateMentionsLinks(body,{...validMentions,thread});body=parseAndTransform(body,addLink);return body;} 12245__exports.generateEmojisOnHtml=generateEmojisOnHtml;async function generateEmojisOnHtml(htmlBody,{allowEmojiLoading=true}={}){let body=htmlBody;
12245if(allowEmojiLoading||odoo.loader.modules.get("@web/core/emoji_picker/emoji_data")){body=await _generateEmojisOnHtml(body);} 12246return body;} 12247__exports.prettifyMessageContent=prettifyMessageContent;async function prettifyMessageContent(rawBody,{validMentions=[],allowEmojiLoading=true}={}){let body=prettifyMessageText(rawBody,{validMentions});body=await generateEmojisOnHtml(body,{allowEmojiLoading});return body;} 12248__exports.parseAndTransform=parseAndTransform;function parseAndTransform(htmlString,transformFunction){const div=document.createElement("div");try{setElementContent(div,htmlString);}catch{div.appendChild(createElementWithContent("pre",htmlString));} 12249return _parseAndTransform(Array.from(div.childNodes),transformFunction);} 12250function _parseAndTransform(nodes,transformFunction){if(!nodes){return;} 12251return htmlJoin(Object.values(nodes).map((node)=>transformFunction(node,function(){return _parseAndTransform(node.childNodes,transformFunction);})));} 12252function linkify(text){let curIndex=0;let result="";let match;while((match=urlRegexp.exec(text))!==null){const url=match[0];const fixedUrl=!/^https?:\/\//i.test(url)?`http://${url}`:url;if(!URL.canParse(fixedUrl)){continue;} 12253result=htmlJoin([result,text.slice(curIndex,match.index)]);const{href}=URL.parse(fixedUrl);const link=document.createElement("a");setAttributes(link,{target:"_blank",rel:"noreferrer noopener",href,});link.textContent=url;const messageMatch=messageUrlRegExp.exec(fixedUrl);if(messageMatch!==null){setAttributes(link,{"data-oe-id":messageMatch[1],"data-oe-model":"mail.message",});link.classList.add("o_message_redirect");} 12254result=htmlJoin([result,markup(link.outerHTML)]);curIndex=match.index+match[0].length;} 12255return htmlJoin([result,text.slice(curIndex)]);} 12256__exports.addLink=addLink;function addLink(node,transformChildren){if(node.nodeType===3){const linkified=linkify(node.textContent);if(linkified.toString()!==node.textContent){const div=createElementWithContent("div",linkified);for(const childNode of[...div.childNodes]){node.parentNode.insertBefore(childNode,node);} 12257node.parentNode.removeChild(node);return linkified;} 12258return node.textContent;} 12259if(node.tagName==="A"){return markup(node.outerHTML);} 12260transformChildren();return markup(node.outerHTML);} 12261function generateMentionElement({className,id,model,text}){const link=document.createElement("a");setAttributes(link,{href:router.stateToUrl({model:model,resId:id}),class:className,"data-oe-id":id,"data-oe-model":model,target:"_blank",contenteditable:"false",});link.textContent=text;return link;} 12262__exports.generatePartnerMentionElement=generatePartnerMentionElement;function generatePartnerMentionElement(partner,thread){return generateMentionElement({className:"o_mail_redirect",id:partner.id,model:"res.partner",text:`@${thread?.getPersonaName(partner) ?? partner.name}`,});} 12263__exports.generateRoleMentionElement=generateRoleMentionElement;function generateRoleMentionElement(role){return generateMentionElement({className:"o-discuss-mention",id:role.id,model:"res.role",text:`@${role.name}`,});} 12264__exports.generateSpecialMentionElement=generateSpecialMentionElement;function generateSpecialMentionElement(label){const link=document.createElement("a");setAttributes(link,{class:"o-discuss-mention",contenteditable:"false",});link.textContent=`@${label}`;return link;} 12265__exports.generateThreadMentionElement=generateThreadMentionElement;function generateThreadMentionElement(thread){return generateMentionElement({className:`o_channel_redirect${ 12266 thread.parent_channel_id ? " o_channel_redirect_asThread" : "" 12267 }`,id:thread.id,model:"discuss.channel",text:`#${thread.fullNameWithParent}`,});} 12268function generateMentionsLinks(body,{partners=[],roles=[],threads=[],specialMentions=[],thread}){const mentions=[];for(const partner of partners){const placeholder=`@-mention-partner-${partner.id}!`;const text=`@${thread?.getPersonaName(partner) ?? partner.name}`;mentions.push({link:generatePartnerMentionElement(partner,thread),placeholder,text,});} 12269for(const thread of threads){const placeholder=`#-mention-channel-${thread.id}!`;const text=`#${thread.fullNameWithParent}`;mentions.push({link:generateThreadMentionElement(thread),placeholder,text,});} 12270for(const mention of mentions.sort((m1,m2)=>m2.text.length-m1.text.length)){body=htmlReplace(body,mention.text,mention.placeholder);} 12271for(const special of specialMentions){const text=`@${special}`;const placeholder=`@-mention-special-${special}`;mentions.push({link:generateSpecialMentionElement(special),placeholder,});body=htmlReplace(body,text,placeholder);} 12272for(const role of roles){const placeholder=`@-mention-role-${role.i
12272d}`;const text=`@${role.name}`;mentions.push({link:generateRoleMentionElement(role),placeholder,});body=htmlReplace(body,text,placeholder);} 12273for(const mention of mentions){const link=mention.link;body=htmlReplace(body,mention.placeholder,markup(link.outerHTML));} 12274return htmlEscape(body);} 12275async function _generateEmojisOnHtml(htmlString){const{emojis}=await loadEmoji();for(const emoji of emojis){for(const source of[...emoji.shortcodes,...emoji.emoticons]){const escapedSource=htmlEscape(String(source));const regexp=new RegExp("(\\s|^)("+escapeRegExp(escapedSource)+")(?=\\s|$|<)","g");htmlString=htmlReplace(htmlString,regexp,(_,group1)=>group1+emoji.codepoints);}} 12276return htmlEscape(htmlString);} 12277__exports.getNonEditableMentions=getNonEditableMentions;function getNonEditableMentions(body){const doc=createDocumentFragmentFromContent(body);for(const block of doc.body.querySelectorAll(".o_mail_reply_hide")){block.classList.remove("o_mail_reply_hide");} 12278for(const mention of doc.body.querySelectorAll(".o_mail_redirect")){mention.setAttribute("contenteditable",false);} 12279for(const mention of doc.body.querySelectorAll(".o_channel_redirect")){mention.setAttribute("contenteditable",false);} 12280for(const mention of doc.body.querySelectorAll(".o-discuss-mention")){mention.setAttribute("contenteditable",false);} 12281return markup(doc.body.innerHTML);} 12282__exports.htmlToTextContentInline=htmlToTextContentInline;function htmlToTextContentInline(htmlString){htmlString=htmlReplace(htmlString,/<br\s*\/?>/gi,()=>" ");const div=document.createElement("div");try{setElementContent(div,htmlString);}catch{div.appendChild(createElementWithContent("pre",htmlString));} 12283return div.textContent.trim().replace(/[\n\r]/g,"").replace(/\s\s+/g," ");} 12284__exports.convertBrToLineBreak=convertBrToLineBreak;function convertBrToLineBreak(str){str=htmlReplace(str,/<br\s*\/?>/gi,()=>"\n");return createDocumentFragmentFromContent(str).body.textContent;} 12285__exports.trimEmptyBlocksAround=trimEmptyBlocksAround;function trimEmptyBlocksAround(content){if(isHtmlEmpty(content)){return content;} 12286const body=createDocumentFragmentFromContent(content).body;let changed=false;const removeNode=(node)=>{node.remove();changed=true;};const getBoundaryChild=(element,side)=>{if(!element){return null;} 12287return side==="start"?element.firstChild:element.lastChild;};const getBoundaryElement=(element,side)=>{if(!element){return null;} 12288return side==="start"?element.firstElementChild:element.lastElementChild;};const trimTextNodes=(element,side)=>{let node=getBoundaryChild(element,side);while(node?.nodeType===Node.TEXT_NODE&&!node.textContent.trim()){removeNode(node);node=getBoundaryChild(element,side);}};const trimEmptyParagraphs=(side)=>{trimTextNodes(body,side);let paragraph=getBoundaryElement(body,side);while(["P","DIV"].includes(paragraph?.tagName)&&isHtmlEmpty(paragraph.innerHTML)){removeNode(paragraph);trimTextNodes(body,side);paragraph=getBoundaryElement(body,side);}};const trimBoundaryParagraph=(side)=>{trimEmptyParagraphs(side);const paragraph=getBoundaryElement(body,side);if(!paragraph||!["P","DIV"].includes(paragraph.tagName)){return;} 12289trimTextNodes(paragraph,side);let node=getBoundaryChild(paragraph,side);while(node?.nodeName==="BR"){removeNode(node);trimTextNodes(paragraph,side);node=getBoundaryChild(paragraph,side);} 12290trimEmptyParagraphs(side);if(getBoundaryElement(body,side)!==paragraph){trimBoundaryParagraph(side);}};trimBoundaryParagraph("start");trimBoundaryParagraph("end");return changed?markup(body.innerHTML):content;} 12291__exports.cleanTerm=cleanTerm;function cleanTerm(term){return typeof term==="string"?normalize(term):"";} 12292__exports.parseEmail=parseEmail;function parseEmail(text){if(!text){return;} 12293let result=text.match(/"?(.*?)"? <(.*@.*)>/);if(result){const name=(result[1]||"").trim().replace(/(^"|"$)/g,"");return[name,(result[2]||"").trim()];} 12294result=text.match(/(.*@.*)/);if(result){return[String(result[1]||"").trim(),String(result[1]||"").trim()];} 12295return[text,false];} 12296const r=String.raw;const SUBDIVISION_FLAG=r`ð´[\u{E0020}-\u{E007E}]+\u{E007F}`;const KEYCAP=r`[#*\d]\uFE0F\u20E3`;const EMOJI_WITH_SKIN_TONE=r`\p{Emoji_Modifier_Base}\p{Emoji_Modifier}`;const EMOJI_PRESENTATION=r`\p{Emoji_Presentation}\uFE0F?`;const QUALIFIED_TEXT=r`(?![#*\d])\p{Emoji}\uFE0F`;const EMOJI=r`(?:${SUBDIVISION_FLAG}|${KEYCAP}|${EMOJI_WITH_SKIN_TONE}|${EMOJI_PRESENTATION}|${QUALIFIED_TEXT})`;const EMOJI_REGEX=__exports.EMOJI_REGEX=new RegExp(r`\p{Regional_Indicator}{2}|`+ 12297r`${EMOJI}(?:\u200D${EMOJI})*`,"gu");__exports.decorateEmojis=decorateEmojis;function decorateEmojis(content){if(!loader.loaded||!content){return content;} 12298const doc=createDocumentFragmentFromContent(content);const nodes=doc.evaluate(".//text()",doc.body,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);for(let i=0;i<nodes.snapshotLength;i++){const node=nodes.snapshotItem(i);const span=document.createElement("span");setElementContent(span,htmlReplaceAll(node.textContent,loader.loaded.emojiRegex,(codepoints)=>markup(`<span class="o-mail-emoji" title="${htmlFormatList( 12299 loader.loaded.emojiValueToShortcodes[codepoints], 12300 { style: "unit-narrow" } 12301 )}">${htmlEscape(codepoints)}</span>`)));node.replaceWith(...span.childNodes);} 12302return markup(doc.body.innerHTML);} 12303__exports.attClassObjectToString=attClassObjectToString;function attClassObjectToString(obj){return Object.entries(obj).filter(([_,val])=>val).map(([key,_])=>key).join(" ");} 12304return __exports;});; 12305 12306/* /mail/static/src/utils/common/hooks.js */ 12307odoo.define('@mail/utils/common/hooks',['@odoo/owl','@mail/utils/common/media_monitoring','@web/core/browser/browser','@web/core/overlay/overlay_container','@web/core/utils/concurrency','@web/core/utils/draggable_hook_builder_owl','@web/core/l10n/translation','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onMounted,onPatched,onWillUnmount,toRaw,useComponent,useEffect,useRef,useState,useSubEnv,xml,}=require("@odoo/owl");const{monitorAudio}=require("@mail/utils/common/media_monitoring");const{browser}=require("@web/core/browser/browser");const{OVERLAY_SYMBOL}=require("@web/core/overlay/overlay_container");const{Deferred}=require("@web/core/utils/concurrency");const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"mail",...args);const{useService}=require("@web/core/utils/hooks");__exports.useLazyExternalListener=useLazyExternalListener;function useLazyExternalListener(target,eventName,handler,eventParam
12307s){const boundHandler=handler.bind(useComponent());let t;onMounted(()=>{t=target();if(!t){return;} 12308t.addEventListener(eventName,boundHandler,eventParams);});onPatched(()=>{const t2=target();if(t!==t2){if(t){t.removeEventListener(eventName,boundHandler,eventParams);} 12309if(t2){t2.addEventListener(eventName,boundHandler,eventParams);} 12310t=t2;}});onWillUnmount(()=>{if(!t){return;} 12311t.removeEventListener(eventName,boundHandler,eventParams);});} 12312__exports.onExternalClick=onExternalClick;function onExternalClick(refName,cb){let downTarget,upTarget;const ref=useRef(refName);function onClick(ev){if(ref.el&&!ref.el.contains(ev.composedPath()[0])){cb(ev,{downTarget,upTarget});upTarget=downTarget=null;}} 12313function onMousedown(ev){downTarget=ev.target;} 12314function onMouseup(ev){upTarget=ev.target;} 12315onMounted(()=>{document.body.addEventListener("mousedown",onMousedown,true);document.body.addEventListener("mouseup",onMouseup,true);document.body.addEventListener("click",onClick,true);});onWillUnmount(()=>{document.body.removeEventListener("mousedown",onMousedown,true);document.body.removeEventListener("mouseup",onMouseup,true);document.body.removeEventListener("click",onClick,true);});} 12316__exports.useHover=useHover;function useHover(refNames,{onHover,onAway,stateObserver,onHovering}={}){refNames=Array.isArray(refNames)?refNames:[refNames];const targets=[];let wasHovering=false;let hoveringTimeout;let awayTimeout;let lastHoveredTarget;for(const refName of refNames){if(typeof refName==="function"){targets.push({ref:refName});continue;} 12317targets.push({ref:useRef(refName)});} 12318const state=useState({set isHover(newIsHover){if(this._isHover!==newIsHover){this._isHover=newIsHover;this._count++;}},get isHover(){void this._count;return this._isHover;},_contains:[],_count:0,_isHover:false,_targets:targets,addTarget(target){state._targets.push(target);const handleMouseenter=(ev)=>onmouseenter(ev);const handleMouseleave=(ev)=>onmouseleave(ev);target.ref.el.addEventListener("mouseenter",handleMouseenter,true);target.ref.el.addEventListener("mouseleave",handleMouseleave,true);return()=>{target.ref.el.removeEventListener("mouseenter",handleMouseenter,true);target.ref.el.removeEventListener("mouseleave",handleMouseleave,true);const idx=state._targets.findIndex((t)=>t===target);if(idx){state._targets.splice(idx,1);}};},});function setHover(hovering){if(hovering&&!wasHovering){state.isHover=true;clearTimeout(awayTimeout);clearTimeout(hoveringTimeout);if(typeof onHover==="function"){onHover();} 12319if(Array.isArray(onHovering)){const[delay,cb]=onHovering;hoveringTimeout=setTimeout(()=>{cb();},delay);}}else if(!hovering){state.isHover=false;clearTimeout(awayTimeout);if(typeof onAway==="function"){awayTimeout=setTimeout(()=>{clearTimeout(hoveringTimeout);onAway();},100);}} 12320wasHovering=hovering;} 12321function onmouseenter(ev){if(state.isHover){return;} 12322for(const target of toRaw(state)._targets){if(!target.ref.el){continue;} 12323if(target.ref.el.contains(ev.target)){setHover(true);lastHoveredTarget=target;return;}} 12324for(const contains of state._contains){if(contains(ev.target)){setHover(true);return;}}} 12325function onmouseleave(ev){if(!state.isHover){return;} 12326for(const target of toRaw(state._targets)){if(!target.ref.el){continue;} 12327if(target.ref.el.contains(ev.relatedTarget)){return;}} 12328for(const contains of state._contains){if(contains(ev.relatedTarget)){return;}} 12329setHover(false);lastHoveredTarget=null;} 12330for(const target of targets){useLazyExternalListener(()=>target.ref.el,"mouseenter",(ev)=>onmouseenter(ev),true);useLazyExternalListener(()=>target.ref.el,"mouseleave",(ev)=>onmouseleave(ev),true);} 12331if(stateObserver){useEffect((open)=>{if((lastHoveredTarget&&!lastHoveredTarget.ref.el)||!open){setHover(false);lastHoveredTarget=null;}},stateObserver);} 12332return state;} 12333const UseHoverOverlay=__exports.UseHoverOverlay=class UseHoverOverlay extends Component{static props=["slots","hover"];static template=xml`<div t-ref="root"><t t-slot="default"/></div>`;setup(){super.setup();this.root=useRef("root");const overlayContains=toRaw(this.env[OVERLAY_SYMBOL].contains);let removeTarget;onMounted(()=>{this.props.hover._contains.push(overlayContains);removeTarget=this.props.hover.addTarget({ref:{el:this.root.el.closest(".o-overlay-item")},});});onWillUnmount(()=>{const idx=this.props.hover._contains.find((c)=>c===overlayContains);if(idx){this.props.hover._contains.splice(idx,1);} 12334removeTarget?.();});}} 12335__exports.useOnBottomScrolled=useOnBottomScrolled;function useOnBottomScrolled(refName,callback,threshold=1){const ref=useRef(refName);function onScroll(){if(Math.abs(ref.el.scrollTop+ref.el.clientHeight-ref.el.scrollHeight)<threshold){callback();}} 12336onMounted(()=>{ref.el?.addEventListener("scroll",onScroll);});onWillUnmount(()=>{ref.el?.removeEventListener("scroll",onScroll);});} 12337__exports.useVisible=useVisible;function useVisible(refName,cb,{ready=true}={}){const ref=useRef(refName);const state=useState({isVisible:undefined,ready,});function setValue(value){state.isVisible=value;cb?.(state.isVisible);} 12338const observer=new IntersectionObserver((entries)=>{setValue(entries.at(-1).isIntersecting);});useEffect((el,ready)=>
12338{if(el&&ready){observer.observe(el);return()=>{setValue(undefined);observer.unobserve(el);};}},()=>[ref.el,state.ready]);return state;} 12339__exports.useMessageScrolling=useMessageScrolling;function useMessageScrolling(duration=2000){let timeout;const state=useState({clear(){if(this.highlightedMessageId){browser.clearTimeout(timeout);timeout=null;this.highlightedMessageId=null;}},async highlightMessage(message,thread){state.initiated=true;let messageScrollDirection;if(message.notIn(thread.messages)){messageScrollDirection=message.id<thread.messages[0]?.id?"top":"bottom";await thread.loadAround(message.id);} 12340const lastHighlightedMessageId=state.highlightedMessageId;this.clear();if(lastHighlightedMessageId===message.id){await new Promise(setTimeout);} 12341thread.scrollTop=messageScrollDirection==="top"?"bottom":undefined;if(thread.scrollTop==="bottom"){state.startupDeferred=new Deferred();await state.startupDeferred;state.startupDeferred=null;} 12342state.highlightedMessageId=message.id;state.initiated=false;timeout=browser.setTimeout(()=>this.clear(),duration);},initiated:false,startupDeferred:null,scrollPromise:null,scrollTo(el){state.scrollPromise?.resolve();const scrollPromise=new Deferred();state.scrollPromise=scrollPromise;if("onscrollend"in window){document.addEventListener("scrollend",scrollPromise.resolve,{capture:true,once:true,});}else{setTimeout(scrollPromise.resolve,250);} 12343el.scrollIntoView({behavior:"smooth",block:"center"});return scrollPromise;},highlightedMessageId:null,});return state;} 12344__exports.useMicrophoneVolume=useMicrophoneVolume;function useMicrophoneVolume(){let isClosed=false;let audioTrack=null;let disconnectAudioMonitor;let audioMonitorPromise;const store=useService("mail.store");const state=useState({isReady:true,isActive:false,value:0,toggle:async()=>{if(!state.isReady){return;} 12345state.isReady=false;disconnectAudioMonitor?.();disconnectAudioMonitor=undefined;if(audioTrack){audioTrack.stop();audioTrack=null;state.isReady=true;state.isActive=false;state.value=0;return;} 12346let track;try{const audioStream=await browser.navigator.mediaDevices.getUserMedia({audio:store.settings.audioConstraints,});track=audioStream.getAudioTracks()[0];}catch{store.env.services.notification.add(_t('"%(hostname)s" requires microphone access',{hostname:browser.location.host,}),{type:"warning"});return;} 12347if(isClosed){track.stop();return;} 12348audioMonitorPromise=monitorAudio(track,{onTic:(value)=>{state.value=value;},processInterval:100,});disconnectAudioMonitor=await audioMonitorPromise;audioTrack=track;state.isActive=true;state.isReady=true;},});onWillUnmount(async()=>{isClosed=true;await audioMonitorPromise;audioTrack?.stop();disconnectAudioMonitor?.();});return state;} 12349__exports.useSelection=useSelection;function useSelection({refName,model,preserveOnClickAwayPredicate=()=>false}){const ui=useService("ui");const ref=useRef(refName);function onSelectionChange(){const activeElement=ref.el?.getRootNode().activeElement;if(activeElement&&activeElement===ref.el){Object.assign(model,{start:ref.el.selectionStart,end:ref.el.selectionEnd,direction:ref.el.selectionDirection,});}} 12350onExternalClick(refName,async(ev)=>{if(await preserveOnClickAwayPredicate(ev)){return;} 12351if(!ref.el){return;} 12352Object.assign(model,{start:ref.el.value.length,end:ref.el.value.length,direction:ref.el.selectionDirection,});});onMounted(()=>{document.addEventListener("selectionchange",onSelectionChange);document.addEventListener("input",onSelectionChange);});onWillUnmount(()=>{document.removeEventListener("selectionchange",onSelectionChange);document.removeEventListener("input",onSelectionChange);});return{restore(){ref.el?.setSelectionRange(model.start,model.end,model.direction);},moveCursor(position){model.start=model.end=position;if(ref.el&&!ui.isSmall){ref.el.selectionStart=ref.el.selectionEnd=position;}},};} 12353__exports.useSequential=useSequential;function useSequential(){let inProgress=false;let nextFunction;let nextResolve;let nextReject;async function call(){const resolve=nextResolve;const reject=nextReject;const func=nextFunction;nextResolve=undefined;nextReject=undefined;nextFunction=undefined;inProgress=true;try{const data=await func();resolve(data);}catch(e){reject(e);} 12354inProgress=false;if(nextFunction&&nextResolve){call();}} 12355return(func)=>{nextResolve?.();const prom=new Promise((resolve,reject)=>{nextResolve=resolve;nextReject=reject;});nextFunction=func;if(!inProgress){call();} 12356return prom;};}
12357__exports.useDiscussSystray=useDiscussSystray;function useDiscussSystray(dropdownState){const ui=useService("ui");if(dropdownState){useEffect((isOpen)=>{if(isOpen){document.body.classList.add("o-mail-discuss-systray-menu-open");return()=>{document.body.classList.remove("o-mail-discuss-systray-menu-open");};}},()=>[dropdownState.isOpen]);} 12358return{class:"o-mail-DiscussSystray-class",get contentClass(){return`d-flex flex-column flex-grow-1 ${ 12359 ui.isSmall ? "overflow-auto o-scrollbar-thin w-100 mh-100" : "" 12360 }`;},get menuClass(){return`p-0 o-mail-DiscussSystray ${ 12361 ui.isSmall 12362 ? "o-mail-systrayFullscreenDropdownMenu start-0 w-100 mh-100 d-flex flex-column mt-0 border-0 shadow-lg" 12363 : "" 12364 }`;},};} 12365const useMovable=__exports.useMovable=makeDraggableHook({name:"useMovable",onWillStartDrag({ctx,addCleanup,addStyle,getRect}){ctx.current.container=document.createElement("div");addStyle(ctx.current.container,{position:"fixed",top:0,bottom:0,left:0,right:0,});ctx.current.element.after(ctx.current.container);addCleanup(()=>ctx.current.container.remove());},onDragStart:()=>true,onDragEnd:()=>true,onDrop({ctx,getRect}){const{top,left}=getRect(ctx.current.element);return{top,left};},});const LONG_PRESS_DELAY=__exports.LONG_PRESS_DELAY=400;__exports.useLongPress=useLongPress;function useLongPress(refName,{action,predicate=()=>true}={}){const MOVE_TRESHOLD=10;const ref=useRef(refName);let timer=null;let startX=0;let startY=0;function reset(){clearTimeout(timer);timer=null;} 12366useLazyExternalListener(()=>ref.el,"touchstart",(ev)=>{if(!predicate()){return;} 12367const touch=ev.touches[0];startX=touch.clientX;startY=touch.clientY;timer=setTimeout(()=>{action();reset();},LONG_PRESS_DELAY);});useLazyExternalListener(()=>ref.el,"touchmove",(ev)=>{if(!timer){return;} 12368const touch=ev.touches[0];const dx=touch.screenX-startX;const dy=touch.screenY-startY;if(Math.hypot(dx,dy)>MOVE_TRESHOLD){reset();}});useLazyExternalListener(()=>ref.el,"touchend",reset);useLazyExternalListener(()=>ref.el,"touchcancel",reset);} 12369const inDiscussCallViewProps=__exports.inDiscussCallViewProps=["isPip?"];__exports.useInDiscussCallView=useInDiscussCallView;function useInDiscussCallView(){const component=useComponent();useSubEnv({inDiscussCallView:{get isPip(){return component.props.isPip;},},});} 12370return __exports;});; 12371 12372/* /mail/static/src/utils/common/media_monitoring.js */ 12373odoo.define('@mail/utils/common/media_monitoring',[],function(require){'use strict';let __exports={};const HUMAN_VOICE_FREQUENCY_RANGE=[80,1000];__exports.monitorAudio=monitorAudio;async function monitorAudio(track,processorOptions){const monitoredTrack=track.clone();monitoredTrack.enabled=true;const stream=new window.MediaStream([monitoredTrack]);const AudioContext=window.AudioContext||window.webkitAudioContext;if(!AudioContext){throw"missing audio context";} 12374const audioContext=new AudioContext();const source=audioContext.createMediaStreamSource(stream);let processor;try{processor=await _loadAudioWorkletProcessor(source,audioContext,processorOptions);}catch{processor=_loadScriptProcessor(source,audioContext,processorOptions);} 12375return async()=>{processor.disconnect();source.disconnect();monitoredTrack.stop();try{await audioContext.close();}catch(e){if(e.name==="InvalidStateError"){return;} 12376throw e;}};} 12377function _loadScriptProcessor(source,audioContext,{frequencyRange=HUMAN_VOICE_FREQUENCY_RANGE,minimumActiveCycles=30,onThreshold,onTic,volumeThreshold=0.3,}={}){const bitSize=1024;const analyser=audioContext.createAnalyser();source.connect(analyser);const scriptProcessorNode=audioContext.createScriptProcessor(bitSize,1,1);analyser.connect(scriptProcessorNode);analyser.fftsize=bitSize;scriptProcessorNode.connect(audioContext.destination);const processInterval=50;const intervalInFrames=(processInterval/1000)*analyser.context.sampleRate;let nextUpdateFrame=processInterval;let activityBuffer=0;let wasAboveThreshold=undefined;let isAboveThreshold=false;scriptProcessorNode.onaudioprocess=()=>{nextUpdateFrame-=bitSize;if(nextUpdateFrame>=0){return;} 12378nextUpdateFrame+=intervalInFrames;const normalizedVolume=getFrequencyAverage(analyser,frequencyRange[0],frequencyRange[1]);if(normalizedVolume>=volumeThreshold){activityBuffer=minimumActiveCycles;}else if(normalizedVolume<volumeThreshold&&activityBuffer>0){activityBuffer--;} 12379isAboveThreshold=activityBuffer>0;onTic?.(normalizedVolume);if(wasAboveThreshold!==isAboveThreshold){wasAboveThreshold=isAboveThreshold;onThreshold?.(isAboveThreshold);}};return{disconnect:()=>{analyser.disconnect();scriptProcessorNode.disconnect();scriptProcessorNode.onaudioprocess=null;},};} 12380async function _loadAudioWorkletProcessor(source,audioContext,{frequencyRange=HUMAN_VOICE_FREQUENCY_RANGE,minimumActiveCycles=10,onThreshold,onTic,volumeThreshold=0.3,normalizationParameters={boost:1,shift:0.6},}={}){await audioContext.resume();await audioContext.audioWorklet.addModule("/mail/rtc/audio_worklet_processor_v2");const thresholdProcessor=new window.AudioWorkletNode(audioContext,"audio-processor",{processorOptions:{minimumActiveCycles,volumeThreshold,frequencyRange,normalizationParameters,postAllTics:!!onTic,},});source.connect(thresholdProcessor);thresholdProcessor.port.onmessage=(event)=>{const{isAboveThreshold,volume}=event.data;if(isAboveThreshold!==undefined){onThreshold?.(isAboveThreshold);} 12381if(volume!==undefined){onTic?.(volume);}};return{disconnect:()=>{thresholdProcessor.port.onmessage=null;thresholdProcessor.disconnect();},};} 12382function getFrequencyAverage(analyser,lowerFrequency,higherFrequency){const frequencies=new window.Uint8Array(analyser.frequencyBinCount);analyser.getByteFrequencyData(frequencies);const sampleRate=analyser.context.sampleRate;const startIndex=_getFrequencyIndex(lowerFrequency,sampleRate,analyser.frequencyBinCount);const endIndex=_getFrequencyIndex(higherFrequency,sampleRate,analyser.frequencyBinCount);const count=endIndex-startIndex;let sum=0;for(let index=startIndex;index<endIndex;index++){sum+=frequencies[index]/255;} 12383if(!count){return 0;} 12384return sum/count;} 12385function _getFrequencyIndex(targetFrequency,sampleRate,binCount){const index=Math.round((targetFrequency/(sampleRate/2))*binCount);return Math.min(Math.max(0,index),binCount);} 12386return __exports;});; 12387 12388/* /mail/static/src/utils/common/misc.js */ 12389odoo.define('@mail/utils/common/misc',['@odoo/owl','@web/core/assets','@web/core/utils/functions','@web/core/network/rpc','@web/core/utils/reactive'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{AssetsLoadingError,getBundle}=require("@web/core/assets");const{memoize}=require("@web/core/utils/functions");const{rpc}=require("@web/core/network/rpc");const{effect}=require("@web/core/utils/reactive");__exports.assignDefined=assignDefined;function assignDefined(obj,data,keys=Object.keys(data)){for(const key of keys){if(data[key]!==undefined){obj[key]=data[key];}} 12390return obj;} 12391__exports.assignGetter=assignGetter;function assignGetter(obj,data){const properties=Object.fromEntries(Object.entries(data).map(([getterName,getterFn])=>[getterName,{get:getterFn,set:()=>{},},]));Object.defineProperties(obj,properties);} 12392__exports.assignIn=assignIn;function assignIn(obj,data,keys=Object.keys(data)){for(const key of keys){if(key in data){obj[key]=data[key];}} 12393return obj;} 12394__exports.nearestGreaterThanOrEqual=nearestGreaterThanOrEqual;function nearestGreaterThanOrEqual(list,target,itemToCompareVal){const findNext=(left,right,next)=>{if(left>right){return next;} 12395const index=Math.floor((left+right)/2);const item=list[index];const val=itemToCompareVal?.(item)??item;if(val===target){return item;}else if(val>target){return findNext(left,index-1,item);}else{return findNext(index+1,right,next);}};return findNext(0,list.length-1,null);} 12396const mailGlobal=__exports.mailGlobal={isInTest:false,};__exports.rpcWithEnv=rpcWithEnv;function rpcWithEnv(){return rpc;} 12397__exports.isDragSourceExternalFile=isDragSourceExternalFile;function isDragSourceExternalFile(dataTransfer){const dragDataType=dataTransfer.types;if(dragDataType.constructor===window.DOMStringList){return dragDataType.contains("Files");} 12398if(dragDataType.constructor===Array){return dragDataType.includes("Files");} 12399return false;} 12400__exports.onChange=onChange;function onChange(target,key,callback){let proxy;function _observe(){const val=proxy[key];if(typeof val==="object"&&val!==null){void Object.keys(val);} 12401if(Array.isArray(val)){void val.length;void val.forEach((i)=>i);}} 12402if(Array.isArray(key)){for(const k of key){onChange(target,k,callback);} 12403return;} 12404proxy=reactive(target,()=>{_observe();callback();});_observe();return proxy;} 12405__exports.closeStream=closeStream;
12405function closeStream(stream){stream?.getTracks?.().forEach((track)=>track.stop());} 12406__exports.compareDatetime=compareDatetime;function compareDatetime(date1,date2){if(date1?.ts===date2?.ts){return 0;} 12407if(!date1){return-1;} 12408if(!date2){return 1;} 12409return date1.ts-date2.ts;} 12410function compareVersion(v1,v2){const parts1=v1.split(".");const parts2=v2.split(".");for(let i=0;i<Math.max(parts1.length,parts2.length);i++){const num1=parseInt(parts1[i])||0;const num2=parseInt(parts2[i])||0;if(num1<num2){return-1;} 12411if(num1>num2){return 1;}} 12412return 0;} 12413__exports.parseVersion=parseVersion;function parseVersion(v){return{isLowerThan(other){return compareVersion(v,other)<0;},};} 12414__exports.convertToEmbedURL=convertToEmbedURL;function convertToEmbedURL(url){const ytRegex=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|live\/|watch\?v=|&v=)([^#&?]*).*/;const ytMatch=url.match(ytRegex);if(ytMatch?.length===3){const youtubeURL=new URL(`/embed/${ytMatch[2]}`,"https://www.youtube.com");youtubeURL.searchParams.set("autoplay","1");return{url:youtubeURL.toString(),provider:"youtube"};} 12415const gdriveRegex=/(?:drive\.google\.com\/(?:file\/d\/|open\?id=|uc\?id=))([^/?&]+)/;const gdriveMatch=url.match(gdriveRegex);if(gdriveMatch?.length===2){const gdriveURL=new URL(`/file/d/${gdriveMatch[1]}/preview`,"https://drive.google.com");return{url:gdriveURL.toString(),provider:"google-drive"};} 12416return{url:null,provider:null};} 12417const hasHardwareAcceleration=__exports.hasHardwareAcceleration=memoize(()=>{const canvas=document.createElement("canvas");const gl=canvas.getContext("webgl2")||canvas.getContext("webgl")||canvas.getContext("experimental-webgl");if(!gl){return false;} 12418const debugInfo=gl.getExtension("WEBGL_debug_renderer_info");if(debugInfo){const renderer=gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);if(/swiftshader|llvmpipe|software/i.test(renderer)){return false;}} 12419return true;});__exports.effectWithCleanup=effectWithCleanup;function effectWithCleanup({effect:effectFn,dependencies,reactiveTargets}){let cleanup;let prevDependencies;effect((...deps)=>{const nextDependencies=dependencies(...deps);const changed=!prevDependencies||(Array.isArray(nextDependencies)?nextDependencies.some((v,i)=>v!==prevDependencies[i]):Object.keys(nextDependencies).some((key)=>nextDependencies[key]!==prevDependencies[key]));if(changed){prevDependencies=Array.isArray(nextDependencies)?[...nextDependencies]:{...nextDependencies};cleanup?.();cleanup=Array.isArray(nextDependencies)?effectFn(...nextDependencies):effectFn({...nextDependencies});}},reactiveTargets);} 12420__exports.effectWithDebouncedCleanup=effectWithDebouncedCleanup;function effectWithDebouncedCleanup({delay,dependencies,effect:effectFn,predicate,reactiveTargets,}){let timeout;let active=false;let cleanup;effectWithCleanup({effect(ctx){const{predicate,...deps}=ctx;if(!predicate){return;} 12421clearTimeout(timeout);if(!active){cleanup=effectFn(deps);active=true;} 12422return()=>{timeout=setTimeout(()=>{cleanup();active=false;},delay);};},dependencies:(...targets)=>({predicate:predicate(...targets),...dependencies(...targets),}),reactiveTargets,});} 12423__exports.loadCssFromBundle=loadCssFromBundle;async function loadCssFromBundle(targetNode,bundleName){try{const res=await getBundle(bundleName);for(const url of res.cssLibs){const link=document.createElement("link");link.rel="stylesheet";link.href=url;targetNode.appendChild(link);await new Promise((res,rej)=>{link.addEventListener("load",res);link.addEventListener("error",rej);});}}catch(e){if(e instanceof AssetsLoadingError&&e.cause instanceof TypeError){return new Promise(()=>{});}else{throw e;}}} 12424return __exports;});; 12425 12426/* /mail/static/src/utils/common/pdf_thumbnail.js */ 12427odoo.define('@mail/utils/common/pdf_thumbnail',['@web/core/utils/pdfjs'],function(require){'use strict';let __exports={};const{loadPDFJSAssets}=require("@web/core/utils/pdfjs");__exports.generatePdfThumbnail=generatePdfThumbnail;async function generatePdfThumbnail(pdfUrl,options={height:256,width:256}){let initialWorkerSrc=false,isPdfValid,pdf,thumbnail;try{await loadPDFJSAssets();initialWorkerSrc=globalThis.pdfjsLib.GlobalWorkerOptions.workerSrc;globalThis.pdfjsLib.GlobalWorkerOptions.workerSrc="/web/static/lib/pdfjs/build/pdf.worker.js";}catch{return{thumbnail,pdfEnabled:false};} 12428try{if(pdfUrl.startsWith("blob:")){pdfUrl=URL.createObjectURL(pdfUrl);pdf=await globalThis.pdfjsLib.getDocument(pdfUrl).promise;URL.revokeObjectURL(pdfUrl);}else{pdf=await globalThis.pdfjsLib.getDocument(pdfUrl).promise;}}
12428catch(_error){if(_error.status===415){isPdfValid=false;}else if(_error.name!=="UnexpectedResponseException"&&_error.status&&_error.status!==403){pdf=undefined;}}finally{globalThis.pdfjsLib.GlobalWorkerOptions.workerSrc=initialWorkerSrc;} 12429if(pdf){isPdfValid=true;const page=await pdf.getPage(1);const viewPort=page.getViewport({scale:1});const canvas=document.createElement("canvas");canvas.width=options.width;canvas.height=options.height;const scale=canvas.width/viewPort.width;await page.render({canvasContext:canvas.getContext("2d"),viewport:page.getViewport({scale}),}).promise;thumbnail=canvas.toDataURL("image/jpeg").replace("data:image/jpeg;base64,","");} 12430return{isPdfValid,thumbnail,pdfEnabled:true};} 12431return __exports;});; 12432 12433/* /rating/static/src/core/common/message_model_patch.js */ 12434odoo.define('@rating/core/common/message_model_patch',['@mail/core/common/message_model','@mail/core/common/record','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message_model");const{fields}=require("@mail/core/common/record");const{patch}=require("@web/core/utils/patch");patch(Message.prototype,{setup(){super.setup(...arguments);this.rating_id=fields.One("rating.rating");},computeIsEmpty(){return super.computeIsEmpty()&&!this.rating_id&&!this.rating_value;},get removeParams(){return{...super.removeParams,rating_value:false};},});return __exports;});; 12435 12436/* /rating/static/src/core/common/rating_model.js */ 12437odoo.define('@rating/core/common/rating_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const Rating=__exports.Rating=class Rating extends Record{static _name="rating.rating";static id="id";id;rating;rating_image_url;rating_text;} 12438Rating.register();return __exports;});; 12439 12440/* /im_livechat/static/src/core/common/chat_bubble_patch.js */ 12441odoo.define('@im_livechat/core/common/chat_bubble_patch',['@mail/core/common/chat_bubble','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChatBubble}=require("@mail/core/common/chat_bubble");const{patch}=require("@web/core/utils/patch");patch(ChatBubble.prototype,{get showImStatus(){if(this.thread?.self_member_id?.livechat_member_type==="visitor"){return false;} 12442return super.showImStatus;},});return __exports;});; 12443 12444/* /im_livechat/static/src/core/common/chat_window_model_patch.js */ 12445odoo.define('@im_livechat/core/common/chat_window_model_patch',['@mail/core/common/chat_window_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChatWindow}=require("@mail/core/common/chat_window_model");const{patch}=require("@web/core/utils/patch");const CW_LIVECHAT_STEP=__exports.CW_LIVECHAT_STEP={NONE:undefined,CONFIRM_CLOSE:"CONFIRM_CLOSE",FEEDBACK:"FEEDBACK",};const chatWindowPatch={setup(){super.setup(...arguments);this.livechatStep=CW_LIVECHAT_STEP.NONE;},close(options={}){if(this.thread?.channel_type!=="livechat"){return super.close(...arguments);} 12446if(options.force){this.livechatStep=CW_LIVECHAT_STEP.NONE;return super.close(...arguments);} 12447const isSelfVisitor=this.thread.livechatVisitorMember?.persona?.eq(this.store.self);switch(this.livechatStep){case CW_LIVECHAT_STEP.NONE:{if(this.thread.isTransient){this.thread.delete();super.close(...arguments);break;} 12448if(!this.thread.hasSelfAsMember){super.close(...arguments);break;} 12449if(this.thread.livechat_end_dt){if(isSelfVisitor){this.livechatStep=CW_LIVECHAT_STEP.FEEDBACK;this.open({focus:true,notifyState:this.thread?.state!=="open"});}else{super.close(...arguments);} 12450break;} 12451this.actionsDisabled=true;this.livechatStep=CW_LIVECHAT_STEP.CONFIRM_CLOSE;if(!isSelfVisitor&&this.thread.channel_member_ids.length>2){super.close(...arguments);break;} 12452if(!this.hubAsOpened){this.open({focus:true});} 12453break;} 12454case CW_LIVECHAT_STEP.CONFIRM_CLOSE:{this.actionsDisabled=false;if(isSelfVisitor){this.open({focus:true,notifyState:this.thread?.state!=="open"});this.livechatStep=CW_LIVECHAT_STEP.FEEDBACK;}else{this.livechatStep=CW_LIVECHAT_STEP.NONE;super.close(...arguments);} 12455break;} 12456case CW_LIVECHAT_STEP.FEEDBACK:{this.livechatStep=CW_LIVECHAT_STEP.NONE;super.close(...arguments);break;}}},};patch(ChatWindow.prototype,chatWindowPatch);return __exports;});; 12457 12458/* /im_livechat/static/src/core/common/chat_window_patch.js */ 12459odoo.define('@im_livechat/core/common/chat_window_patch',['@im_livechat/core/common/close_confirmation','@mail/core/common/chat_window','@web/core/utils/patch','@im_livechat/core/common/chat_window_model_patch'],function(require){'use strict';let __exports={};const{CloseConfirmation}=require("@im_livechat/core/common/close_confirmation");const{ChatWindow}=require("@mail/core/common/chat_window");const{patch}=require("@web/core/utils/patch");const{CW_LIVECHAT_STEP}=require("@im_livechat/core/common/chat_window_model_patch");Object.assign(ChatWindow.components,{CloseConfirmation});patch(ChatWindow.prototype,{setup(){super.setup(...arguments);this.CW_LIVECHAT_STEP=CW_LIVECHAT_STEP;},onCloseConfirmationDialog(){this.props.chatWindow.autofocus++;this.props.chatWindow.actionsDisabled=false;this.props.chatWindow.livechatStep=CW_LIVECHAT_STEP.NONE;},});return __exports;});; 12460 12461/* /im_livechat/static/src/core/common/chatbot_model.js */ 12462odoo.define('@im_livechat/core/common/chatbot_model',['@mail/core/common/record','@web/core/network/rpc','@web/core/browser/browser','@web/core/utils/timing','@im_livechat/core/common/expirable_storage'],function(require){'use strict';let __exports={};const{AND,fields,Record}=require("@mail/core/common/record");const{rpc}=require("@web/core/network/rpc");const{browser}=require("@web/core/browser/browser");const{debounce}=require("@web/core/utils/timing");const{expirableStorage}=require("@im_livechat/core/common/expirable_storage");const Chatbot=__exports.Chatbot=class Chatbot extends Record{static id=AND("script","thread");static MESSAGE_DELAY=400;static TYPING_DELAY=500;static MULTILINE_STEP_DEBOUNCE_DELAY=10000;forwarded;isTyping=false;isProcessingAnswer=false;script=fields.One("chatbot.script");currentStep=fields.One("ChatbotStep",{onUpdate(){if(this.currentStep?.operatorFound){this.forwarded=true;}},});steps=fields.Many("ChatbotStep");thread=fields.One("Thread",{inverse:"chatbot",onDelete(){this.delete();},});tmpAnswer="";typingMessage=fields.One("mail.message",{compute(){if(this.isTyping&&this.thread){return{id:-0.1-this.thread.id,thread:this.thread,author_id:this.script.operator_partner_id,};}},});_processAnswerDebounced=fields.Attr(null,{compute(){return debounce(this._processAnswer,Chatbot.MULTILINE_STEP_DEBOUNCE_DELAY);},});
12462async start(){if(this.completed){return;} 12463if(this.thread.isLastMessageFromCustomer){await this.processAnswer(this.thread.newestPersistentOfAllMessage);} 12464if(!this.currentStep?.expectAnswer||this.currentStep?.completed){this._runUntilUserInputStep();}} 12465stop(){clearTimeout(this.nextStepTimeout);} 12466async restart(){if(!this.completed){return;} 12467const{store_data,message_id}=await rpc("/chatbot/restart",{channel_id:this.thread.id,chatbot_script_id:this.script.id,});this.store.insert(store_data);this.thread.messages.add(message_id);this.thread.livechat_end_dt=false;if(this.currentStep){this.currentStep.isLast=false;}} 12468async processAnswer(message){if(this.forwarded||this.thread.notEq(message.thread)||!this.currentStep?.expectAnswer){return;} 12469if(this.currentStep.step_type==="free_input_multi"){await this._processAnswerDebounced(message);}else{await this._processAnswer(message);} 12470this.isProcessingAnswer=false;} 12471async _triggerNextStep(){if(this.currentStep){await this._simulateTyping();} 12472await this._goToNextStep();if(!this.currentStep||this.currentStep.completed||!this.thread){return;} 12473if(this.thread.isTransient){this.currentStep.message=this.store["mail.message"].insert({id:this.store.getNextTemporaryId(),author_id:this.script.operator_partner_id,body:this.currentStep.scriptStep.message,thread:this.thread,});} 12474if(this.currentStep.message){this.thread.messages.add(this.currentStep.message);}} 12475get completed(){return(this.currentStep?.isLast||this.currentStep?.operatorFound||this.thread.livechat_end_dt);} 12476get canRestart(){return this.currentStep?.isLast&&!this.currentStep.operatorFound;} 12477async _goToNextStep(){if(!this.thread){return;} 12478if(this.steps.at(-1)?.eq(this.currentStep)){const dataRequest=this.store.DataResponse.createRequest();await rpc("/chatbot/step/trigger",{channel_id:this.thread.id,chatbot_script_id:this.script.id,data_id:dataRequest.id,});await dataRequest._resultDef;if(this.currentStep.isLast){return;} 12479this.steps.push(dataRequest.chatbot_step);}else{const nextStepIndex=this.steps.lastIndexOf(this.currentStep)+1;this.currentStep=this.steps[nextStepIndex];this.currentStep.selectedAnswer=null;}} 12480async _runUntilUserInputStep(){await this._triggerNextStep();if(!this.currentStep||this.completed||(this.currentStep.expectAnswer&&!this.currentStep.completed)){return;} 12481this.nextStepTimeout=browser.setTimeout(async()=>this._runUntilUserInputStep(),Chatbot.TYPING_DELAY);} 12482async _simulateTyping(duration=Chatbot.MESSAGE_DELAY){this.isTyping=true;await new Promise((res)=>setTimeout(()=>{this.isTyping=false;res();},duration));} 12483async _processAnswer(message){if(this.currentStep.step_type==="free_input_multi"&&this.thread.composer.composerText&&this.tmpAnswer!==this.thread.composer.composerText){return await this._delayThenProcessAnswerAgain(message);} 12484this.tmpAnswer="";let stepCompleted=true;if(this.currentStep.step_type==="question_email"){stepCompleted=await this._processAnswerQuestionEmail();}else if(this.currentStep.step_type==="question_selection"){stepCompleted=await this._processAnswerQuestionSelection(message);} 12485this.currentStep.completed=stepCompleted;if(this.currentStep.completed){await this._runUntilUserInputStep();}} 12486async _delayThenProcessAnswerAgain(message){this.tmpAnswer=this.thread.composer.composerText;await Promise.resolve();return this._processAnswerDebounced(message);} 12487async _processAnswerQuestionSelection(message){const answer=this.currentStep.selectedAnswer;if(!answer?.redirect_link){return true;} 12488let isRedirecting=false;if(answer.redirect_link&&URL.canParse(answer.redirect_link,window.location.href)){const url=new URL(window.location.href);const nextURL=new URL(answer.redirect_link,window.location.href);isRedirecting=url.pathname!==nextURL.pathname||url.origin!==nextURL.origin;} 12489const redirects=JSON.parse(expirableStorage.getItem("im_livechat.chatbot_redirect")??"[]");const targetURL=new URL(answer.redirect_link,window.location.origin);const redirectionAlreadyDone=targetURL.href===location.href||redirects.includes(message.id);redirects.push(message.id);const ONE_DAY_TTL=60*60*24;expirableStorage.setItem("im_livechat.chatbot_redirect",JSON.stringify([...new Set(redirects)]),ONE_DAY_TTL);if(!redirectionAlreadyDone){browser.location.assign(answer.redirect_link);}else if(this.store.env.services.ui.isSmall){await this.store.chatHub.initPromise;this.store.ChatWindow.get({thread:this.thread})?.fold();} 12490return redirectionAlreadyDone||!isRedirecting;} 12491async _processAnswerQuestionEmail(){const{success,data}=await rpc("/chatbot/step/validate_email",{channel_id:this.thread.id,});this.store.insert(data);return success;}} 12492Chatbot.register();return __exports;});; 12493 12494/* /im_livechat/static/src/core/common/chatbot_script_model.js */ 12495odoo.define('@im_livechat/core/common/chatbot_script_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record,fields}=require("@mail/core/common/record");const ChatbotScript=__exports.ChatbotScript=class ChatbotScript extends Record{static _name="chatbot.script";static id="id";id;title;isLivechatTourRunning=false;operator_partner_id=fields.One("res.partner");} 12496ChatbotScript.register();return __exports;});; 12497 12498/* /im_livechat/static/src/core/common/chatbot_script_step_answer_model.js */ 12499odoo.define('@im_livechat/core/common/chatbot_script_step_answer_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const ChatbotScriptStepAnswer=__exports.ChatbotScriptStepAnswer=class ChatbotScriptStepAnswer extends Record{static id="id";static _name="chatbot.script.answer";id;label;redirect_link;} 12500ChatbotScriptStepAnswer.register();return __exports;});; 12501 12502/* /im_livechat/static/src/core/common/chatbot_script_step_model.js */ 12503odoo.define('@im_livechat/core/common/chatbot_script_step_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const ChatbotScriptStep=__exports.ChatbotScriptStep=class ChatbotScriptStep extends Record{static id="id";static _name="chatbot.script.step";id;message;step_type;isLast=false;answer_ids=fields.Many("chatbot.script.answer");} 12504ChatbotScriptStep.register();return __exports;});; 12505 12506/* /im_livechat/static/src/core/common/chatbot_step_model.js */ 12507odoo.define('@im_livechat/core/common/chatbot_step_model',['@mail/core/common/record','@web/core/utils/html'],function(require){'use strict';let __exports={};const{AND,fields,Record}=require("@mail/core/common/record");const{createDocumentFragmentFromContent}=require("@web/core/utils/html");const ChatbotStep=__exports.ChatbotStep=class ChatbotStep extends Record{static id=AND("scriptStep","message");operatorFound=false;scriptStep=fields.One("chatbot.script.step");message=fields.One("mail.message",{inverse:"chatbotStep"});answer_ids=fields.Many("chatbot.script.answer",{compute(){return this.scriptStep?.answer_ids;},});selectedAnswer=fields.One("chatbot.script.answer");rawAnswer=fields.Html("");step_type=fields.Attr("",{compute(){return this.scriptStep?.step_type;},});isLast=false;get expectAnswer(){return["free_input_multi","free_input_single","question_selection","question_email","question_phone",].includes(this.step_type);} 12508get answer(){switch(this.step_type){case"free_input_multi":case"free_input_single":case"question_email":case"question_phone":return createDocumentFragmentFromContent(this.rawAnswer).body.textContent;case"question_selection":return this.selectedAnswer?.label;default:return"";}}} 12509ChatbotStep.register();return __exports;});; 12510 12511/* /im_livechat/static/src/core/common/close_confirmation.js */ 12512odoo.define('@im_livechat/core/common/close_confirmation',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useAutofocus}=require("@web/core/utils/hooks");const CloseConfirmation=__exports.CloseConfirmation=class CloseConfirmation extends Component{static template="im_livechat.CloseConfirmation";static props=["onCloseConfirmationDialog","onClickLeaveConversation"];setup(){useAutofocus({refName:"confirm"});} 12513onKeydown(ev){if(ev.key==="Escape"){this.props.onCloseConfirmationDialog();}else if(ev.key==="Enter"){this.props.onClickLeaveConversation();}}} 12514return __exports;});; 12515 12516/* /im_livechat/static/src/core/common/data_response_model_patch.js */ 12517odoo.define('@im_livechat/core/common/data_response_model_patch',['@mail/core/common/data_response_model','@mail/model/misc','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{DataResponse}=require("@mail/core/common/data_response_model");const{fields}=require("@mail/model/misc");const{patch}=require("@web/core/utils/patch");patch(DataResponse.prototype,{setup(){super.setup(...arguments);this.chatbot_step=fields.One("ChatbotStep");},});return __exports;});; 12518 12519/* /im_livechat/static/src/core/common/expirable_storage.js */ 12520odoo.define('@im_livechat/core/common/expirable_storage',['@odoo/owl','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{EventBus}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const BASE_STORAGE_KEY="EXPIRABLE_STORAGE_";const CLEAR_INTERVAL=24*60*60*1000;function cleanupExpirableStorage(){const now=Date.now();const keys=browser.localStorage.items?.keys()??Object.keys(browser.localStorage);for(const key of keys){if(key.startsWith(BASE_STORAGE_KEY)){const item=JSON.parse(browser.localStorage.getItem(key));if(item.expires&&item.expires<now){browser.localStorage.removeItem(key);}}}} 12521const storageBus=new EventBus();const storageFnToWrapper=new Map();browser.addEventListener("storage",({key,newValue})=>{if(key?.startsWith(BASE_STORAGE_KEY)){const actualKey=key.slice(BASE_STORAGE_KEY.length);storageBus.trigger(actualKey,newValue?JSON.parse(newValue).value:null);}});const expirableStorage=__exports.expirableStorage={getItem(key){cleanupExpirableStorage();const item=browser.localStorage.getItem(`${BASE_STORAGE_KEY}${key}`);if(item){return JSON.parse(item).value;} 12522return null;},setItem(key,value,ttl){let expires;if(ttl){expires=Date.now()+ttl*1000;} 12523browser.localStorage.setItem(`${BASE_STORAGE_KEY}${key}`,JSON.stringify({value,expires}));},removeItem(key){browser.localStorage.removeItem(`${BASE_STORAGE_KEY}${key}`);},onChange(key,fn){storageFnToWrapper.set(fn,({detail})=>fn(detail));storageBus.addEventListener(key,storageFnToWrapper.get(fn));},offChange(key,fn){storageBus.removeEventListener(key,storageFnToWrapper.get(fn));storageFnToWrapper.delete(fn);},};cleanupExpirableStorage();setInterval(cleanupExpirableStorage,CLEAR_INTERVAL);return __exports;});; 12524 12525/* /im_livechat/static/src/core/common/livechat_channel_model.js */ 12526odoo.define('@im_livechat/core/common/livechat_channel_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const LivechatChannel=__exports.LivechatChannel=class LivechatChannel extends Record{static _name="im_livechat.channel";static id="id";are_you_inside;id;
12526name;} 12527LivechatChannel.register();return __exports;});; 12528 12529/* /im_livechat/static/src/core/common/livechat_channel_rule_model.js */ 12530odoo.define('@im_livechat/core/common/livechat_channel_rule_model',['@mail/model/misc','@mail/model/record'],function(require){'use strict';let __exports={};const{fields}=require("@mail/model/misc");const{Record}=require("@mail/model/record");const LivechatChannelRule=__exports.LivechatChannelRule=class LivechatChannelRule extends Record{static id="id";static _name="im_livechat.channel.rule";action;autopopup_timer;chatbot_script_id=fields.One("chatbot.script");id;} 12531LivechatChannelRule.register();return __exports;});; 12532 12533/* /im_livechat/static/src/core/common/livechat_command_dialog.js */ 12534odoo.define('@im_livechat/core/common/livechat_command_dialog',['@mail/discuss/core/common/action_panel','@odoo/owl','@web/core/utils/hooks','@web/core/registry'],function(require){'use strict';let __exports={};const{ActionPanel}=require("@mail/discuss/core/common/action_panel");const{Component,useState}=require("@odoo/owl");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const commandRegistry=registry.category("discuss.channel_commands");const LivechatCommandDialog=__exports.LivechatCommandDialog=class LivechatCommandDialog extends Component{static template="im_livechat.LivechatCommandDialog";static components={ActionPanel};static props=["thread","close","commandName","placeholderText","title","icon"];setup(){this.state=useState({inputText:""});this.store=useService("mail.store");useAutofocus();} 12535onKeydown(ev){if(ev.key==="Enter"&&this.state.inputText.trim().length>0){this.executeCommand();}} 12536executeCommand(){const command=commandRegistry.get(this.props.commandName,false);if(command){this.props.thread.executeCommand(command,`/${this.props.commandName} ${this.state.inputText}`);this.props.close();}}} 12537return __exports;});; 12538 12539/* /im_livechat/static/src/core/common/livechat_conversation_tag_model.js */ 12540odoo.define('@im_livechat/core/common/livechat_conversation_tag_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const LivechatConversationTag=__exports.LivechatConversationTag=class LivechatConversationTag extends Record{static _name="im_livechat.conversation.tag";static id="id";id;name;color;} 12541LivechatConversationTag.register();return __exports;});; 12542 12543/* /im_livechat/static/src/core/common/livechat_expertise_model.js */ 12544odoo.define('@im_livechat/core/common/livechat_expertise_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const LivechatExpertise=__exports.LivechatExpertise=class LivechatExpertise extends Record{static id="id";static _name="im_livechat.expertise";id;name;} 12545LivechatExpertise.register();return __exports;});; 12546 12547/* /im_livechat/static/src/core/common/message_model_patch.js */ 12548odoo.define('@im_livechat/core/common/message_model_patch',['@mail/core/common/message_model','@mail/core/common/record','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message_model");const{fields}=require("@mail/core/common/record");const{patch}=require("@web/core/utils/patch");const messagePatch={setup(){super.setup(...arguments);this.chatbotStep=fields.One("ChatbotStep",{inverse:"message"});},canReplyTo(thread){return(super.canReplyTo(thread)&&(thread?.channel_type!=="livechat"||!thread.composerDisabled));},isTranslatable(thread){return(super.isTranslatable(thread)||(this.store.hasMessageTranslationFeature&&thread?.channel_type==="livechat"&&this.store.self?.main_user_id?.share===false));},};patch(Message.prototype,messagePatch);return __exports;});; 12549 12550/* /im_livechat/static/src/core/common/misc.js */ 12551odoo.define('@im_livechat/core/common/misc',[],function(require){'use strict';let __exports={};__exports.isValidEmail=isValidEmail;function isValidEmail(val){const re=/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;return re.test(val);} 12552return __exports;});; 12553 12554/* /im_livechat/static/src/core/common/res_partner_model_patch.js */ 12555odoo.define('@im_livechat/core/common/res_partner_model_patch',['@mail/core/common/res_partner_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ResPartner}=require("@mail/core/common/res_partner_model");const{patch}=require("@web/core/utils/patch");const resPartnerPatch={setup(){super.setup();this.livechat_languages=[];this.livechat_expertise=[];},_computeDisplayName(){return super._computeDisplayName()||this.user_livechat_username;},};patch(ResPartner.prototype,resPartnerPatch);return __exports;});; 12556 12557/* /im_livechat/static/src/core/common/res_users_model_patch.js */ 12558odoo.define('@im_livechat/core/common/res_users_model_patch',['@mail/core/common/res_users_model','@mail/model/misc','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ResUsers}=require("@mail/core/common/res_users_model");const{fields}=require("@mail/model/misc");const{patch}=require("@web/core/utils/patch");const resUsersPatch={setup(){super.setup(...arguments);this.is_livechat_manager=false;this.livechat_expertise_ids=fields.Many("im_livechat.expertise");},};patch(ResUsers.prototype,resUsersPatch);return __exports;});; 12559 12560/* /im_livechat/static/src/core/common/suggestion_service_patch.js */ 12561odoo.define('@im_livechat/core/common/suggestion_service_patch',['@mail/core/common/suggestion_service','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{SuggestionService}=require("@mail/core/common/suggestion_service");const{patch}=require("@web/core/utils/patch");patch(SuggestionService.prototype,{getSupportedDelimiters(thread){const res=super.getSupp
12561ortedDelimiters(...arguments);return thread?.channel_type==="livechat"&&!this.store.self_partner?res.filter((delimiter)=>delimiter.at(0)!=="@"):res;},});return __exports;});; 12562 12563/* /im_livechat/static/src/core/common/thread_actions_patch.js */ 12564odoo.define('@im_livechat/core/common/thread_actions_patch',['@mail/core/common/thread_actions','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ThreadAction,threadActionsRegistry}=require("@mail/core/common/thread_actions");const{patch}=require("@web/core/utils/patch");patch(ThreadAction.prototype,{_condition({action,store,thread}){const visitorActions=["fold-chat-window","close","restart","call-settings","meeting-chat",];if(thread?.channel_type==="livechat"&&store.self_partner?.main_user_id?.share!==false&&!visitorActions.includes(action.id)){return false;} 12565return super._condition(...arguments);},});patch(threadActionsRegistry.get("invite-people"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12566return super.condition(...arguments);},});patch(threadActionsRegistry.get("notification-settings"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12567return super.condition(...arguments);},});patch(threadActionsRegistry.get("camera-call"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12568return super.condition(...arguments);},});patch(threadActionsRegistry.get("call"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12569return super.condition(...arguments);},});return __exports;});; 12570 12571/* /im_livechat/static/src/core/common/thread_model_patch.js */ 12572odoo.define('@im_livechat/core/common/thread_model_patch',['@mail/core/common/record','@mail/core/common/thread_model','@web/core/l10n/translation','@web/core/utils/patch','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{fields}=require("@mail/core/common/record");const{Thread}=require("@mail/core/common/thread_model");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"im_livechat",...args);const{patch}=require("@web/core/utils/patch");const{url}=require("@web/core/utils/urls");patch(Thread.prototype,{setup(){super.setup();this.livechat_end_dt=fields.Datetime();this.livechat_lang_id=fields.One("res.lang");this.livechat_operator_id=fields.One("res.partner");this.livechat_conversation_tag_ids=fields.Many("im_livechat.conversation.tag");this.chatbot=fields.One("Chatbot");this.livechatVisitorMember=fields.One("discuss.channel.member",{compute(){if(this.channel_type!=="livechat"){return;} 12573const orderedChannelMembers=[...this.channel_member_ids].sort((a,b)=>a.id-b.id);const isFirstMemberOperator=orderedChannelMembers[0]?.partner_id?.eq(this.livechat_operator_id);const visitor=isFirstMemberOperator?orderedChannelMembers[1]:orderedChannelMembers[0];return visitor;},});this.open_chat_window=fields.Attr(undefined,{onUpdate(){if(this.open_chat_window){this.open_chat_window=undefined;this.openChatWindow({focus:true});}},});},get autoOpenChatWindowOnNewMessage(){return((this.channel_type==="livechat"&&!this.store.chatHub.compact&&this.self_member_id)||super.autoOpenChatWindowOnNewMessage);},get showCorrespondentCountry(){if(this.channel_type==="livechat"){return(this.correspondent?.livechat_member_type==="visitor"&&Boolean(this.correspondentCountry));} 12574return super.showCorrespondentCountry;}
12574,get typesAllowingCalls(){return super.typesAllowingCalls.concat(["livechat"]);},get isChatChannel(){return this.channel_type==="livechat"||super.isChatChannel;},get allowDescription(){return this.channel_type==="livechat"||super.allowDescription;},get composerDisabled(){return this.channel_type==="livechat"&&this.livechat_end_dt;},get composerDisabledText(){return this.channel_type==="livechat"&&this.livechat_end_dt?_t("This livechat conversation has ended."):"";},get transcriptUrl(){return url(`/im_livechat/download_transcript/${this.id}`);},getPersonaName(persona){if(this.channel_type==="livechat"&&persona?.user_livechat_username){return persona.user_livechat_username;} 12575return super.getPersonaName(persona);},});return __exports;});; 12576 12577/* /im_livechat/static/src/core/common/thread_patch.js */ 12578odoo.define('@im_livechat/core/common/thread_patch',['@mail/core/common/thread','@odoo/owl','@web/core/l10n/translation','@web/core/user','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Thread}=require("@mail/core/common/thread");const{useEffect}=require("@odoo/owl");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"im_livechat",...args);const{user}=require("@web/core/user");const{patch}=require("@web/core/utils/patch");const{DateTime}=luxon;patch(Thread.prototype,{setup(){super.setup(...arguments);this.IM_STATUS_DELAY=1500;Object.assign(this.state,{isVisitorOffline:false});useEffect(()=>{if(!this.props.thread.livechatVisitorMember?.im_status){return;} 12579clearTimeout(this.imStatusTimeoutId);if(this.props.thread.livechatVisitorMember.im_status.includes("offline")){this.imStatusTimeoutId=setTimeout(()=>(this.state.isVisitorOffline=true),this.IM_STATUS_DELAY);}else{this.state.isVisitorOffline=false;} 12580return()=>clearTimeout(this.imStatusTimeoutId);},()=>[this.props.thread.livechatVisitorMember?.im_status]);},get showVisitorDisconnected(){return(this.store.self.notEq(this.props.thread.livechatVisitorMember?.persona)&&!this.props.thread.livechat_end_dt&&this.props.thread.livechatVisitorMember&&this.state.isVisitorOffline);},get disconnectedText(){const offlineSince=this.props.thread.livechatVisitorMember.persona.offline_since;if(!offlineSince){return _t("Visitor is disconnected");} 12581const userLocale={locale:user.lang};if(offlineSince.hasSame(DateTime.now(),"day")){return _t("Visitor is disconnected since %(time)s",{time:offlineSince.toLocaleString(DateTime.TIME_SIMPLE,userLocale),});} 12582if(offlineSince.hasSame(DateTime.now().minus({day:1}),"day")){return _t("Visitor is disconnected since yesterday at %(time)s",{time:offlineSince.toLocaleString(DateTime.TIME_SIMPLE,userLocale),});} 12583return _t("Visitor is disconnected");},});return __exports;});; 12584 12585/* /im_livechat/static/src/core/common/transcript_sender.js */ 12586odoo.define('@im_livechat/core/common/transcript_sender',['@im_livechat/core/common/misc','@odoo/owl','@web/core/network/rpc','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{isValidEmail}=require("@im_livechat/core/common/misc");const{Component,onWillUpdateProps,useEffect,useState}=require("@odoo/owl");const{rpc}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const TranscriptSender=__exports.TranscriptSender=class TranscriptSender extends Component{static template="im_livechat.TranscriptSender";static props=["thread","disableOnSend?"];STATUS=Object.freeze({IDLE:"idle",SENDING:"sending",SENT:"sent",FAILED:"failed",});setup(){this.isValidEmail=isValidEmail;this.state=useState({email:this.props.thread.livechatVisitorMember?.persona.email,status:this.STATUS.IDLE,});this.store=useService("mail.store");onWillUpdateProps((newProps)=>{if(this.props.thread?.notEq(newProps.thread)){this.state.email=newProps.thread.livechatVisitorMember?.persona.email;this.state.status=this.STATUS.IDLE;}});useEffect(()=>{this.state.status=this.STATUS.IDLE;},()=>[this.state.email]);} 12587get isButtonDisabled(){return([this.STATUS.SENDING,this.STATUS.SENT].includes(this.state.status)||!this.isValidEmail(this.state.email));} 12588get isInputDisabled(){return(!(this.store.self_partner?.main_user_id?.share===false)||this.state.status===this.STATUS.SENDING||(this.props.disableOnSend&&this.state.status===this.STATUS.SENT));} 12589onKeydown(ev){if(ev.key=="Enter"&&!this.isButtonDisabled){this.onClickSend();}} 12590clear(){this.state.status=this.STATUS.IDLE;this.state.email="";} 12591async onClickSend(){this.state.status=this.STATUS.SENDING;
12591try{await rpc("/im_livechat/email_livechat_transcript",{channel_id:this.props.thread.id,email:this.state.email,});this.state.status=this.STATUS.SENT;}catch{this.state.status=this.STATUS.FAILED;}}} 12592return __exports;});; 12593 12594/* /im_livechat/static/src/embed/common/attachment_model_patch.js */ 12595odoo.define('@im_livechat/embed/common/attachment_model_patch',['@mail/core/common/attachment_model','@web/core/browser/browser','@web/core/utils/patch','@web/session'],function(require){'use strict';let __exports={};const{Attachment}=require("@mail/core/common/attachment_model");const{browser}=require("@web/core/browser/browser");const{patch}=require("@web/core/utils/patch");const{session}=require("@web/session");patch(Attachment.prototype,{get isViewable(){if(this.isPdf&&browser.location.origin!==session.origin){return false;} 12596return super.isViewable;}});return __exports;});; 12597 12598/* /im_livechat/static/src/embed/common/attachment_upload_service_patch.js */ 12599odoo.define('@im_livechat/embed/common/attachment_upload_service_patch',['@mail/core/common/attachment_upload_service','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{AttachmentUploadService}=require("@mail/core/common/attachment_upload_service");const{patch}=require("@web/core/utils/patch");patch(AttachmentUploadService.prototype,{async upload(thread,composer,file,options){if(thread.channel_type==="livechat"&&thread.isTransient){thread=await this.env.services["im_livechat.livechat"].persist(thread);if(!thread){return;} 12600thread.readyToSwapDeferred.resolve();composer=thread.composer;} 12601return super.upload(thread,composer,file,options);},});return __exports;});; 12602 12603/* /im_livechat/static/src/embed/common/autopopup_service.js */ 12604odoo.define('@im_livechat/embed/common/autopopup_service',['@im_livechat/core/common/expirable_storage','@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{expirableStorage}=require("@im_livechat/core/common/expirable_storage");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const AutopopupService=__exports.AutopopupService=class AutopopupService{static STORAGE_KEY="im_livechat_auto_popup";constructor(env,{"im_livechat.livechat":livechatService,"mail.store":storeService,ui}){this.storeService=storeService;this.livechatService=livechatService;this.ui=ui;storeService.isReady.then(()=>{browser.setTimeout(async()=>{await storeService.chatHub.initPromise;if(this.allowAutoPopup){expirableStorage.setItem(AutopopupService.STORAGE_KEY,true);livechatService.open();}},storeService.livechat_rule?.auto_popup_timer*1000);});} 12605get allowAutoPopup(){return Boolean(!expirableStorage.getItem(AutopopupService.STORAGE_KEY)&&!this.ui.isSmall&&this.storeService.livechat_rule?.action==="auto_popup"&&this.storeService.livechat_available&&this.storeService.activeVisitorLivechats.length===0);}} 12606const autoPopupService=__exports.autoPopupService={dependencies:["im_livechat.livechat","mail.store","ui"],start(env,services){return new AutopopupService(env,services);},};registry.category("services").add("im_livechat.autopopup",autoPopupService);return __exports;});; 12607 12608/* /im_livechat/static/src/embed/common/boot_helpers.js */ 12609odoo.define('@im_livechat/embed/common/boot_helpers',['@web/core/utils/urls'],function(require){'use strict';let __exports={};const{url}=require("@web/core/utils/urls");async function loadFont(name,url,targetDocument){await targetDocument.fonts.ready;if([...targetDocument.fonts].some(({family})=>family===name)){return;} 12610const link=document.createElement("link");link.rel="preload";link.as="font";link.href=url;link.crossOrigin="";const style=document.createElement("style");style.appendChild(document.createTextNode(` 12611 @font-face { 12612 font-family: ${name}; 12613 src: url('${url}') format('woff2'); 12614 font-weight: normal; 12615 font-style: normal; 12616 font-display: block; 12617 } 12618 `));const loadPromise=new Promise((res,rej)=>{link.addEventListener("load",res);link.addEventListener("error",rej);});targetDocument.head.appendChild(link);targetDocument.head.appendChild(style);return loadPromise;} 12619function loadStyle(target){const link=document.createElement("link");link.rel="stylesheet";link.href=url("/im_livechat/assets_embed.css");
12619const stylesLoadedPromise=new Promise((res,rej)=>{link.addEventListener("load",res);link.addEventListener("error",rej);});target.appendChild(link);return stylesLoadedPromise;} 12620__exports.makeRoot=makeRoot;function makeRoot(target){const root=document.createElement("div");root.classList.add("o-livechat-root");root.setAttribute("id",`o-livechat-root-${luxon.DateTime.now().ts + Math.random()}`);root.style.zIndex="calc(9e999)";root.style.position="relative";root.style.display="block";target.appendChild(root);return root;} 12621__exports.loadAssets=loadAssets;async function loadAssets(styleTarget){const document=styleTarget.ownerDocument;await Promise.all([loadStyle(styleTarget),loadFont("FontAwesome",url("/im_livechat/font-awesome"),document),loadFont("odoo_ui_icons",url("/im_livechat/odoo_ui_icons"),document),]);} 12622__exports.makeShadow=makeShadow;async function makeShadow(root){const shadow=root.attachShadow({mode:"open"});await loadAssets(shadow);return shadow;} 12623return __exports;});; 12624 12625/* /im_livechat/static/src/embed/common/chat_hub_patch.js */ 12626odoo.define('@im_livechat/embed/common/chat_hub_patch',['@im_livechat/embed/common/livechat_button','@mail/core/common/chat_hub','@odoo/owl','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{LivechatButton}=require("@im_livechat/embed/common/livechat_button");const{ChatHub}=require("@mail/core/common/chat_hub");const{useExternalListener}=require("@odoo/owl");const{patch}=require("@web/core/utils/patch");ChatHub.components={...ChatHub.components,LivechatButton};patch(ChatHub.prototype,{setup(){super.setup(...arguments);useExternalListener(document,"scroll",this._onScroll);},_onScroll(ev){if(this.position.dragged){return;} 12627const container=document.querySelector("html");this.position.bottom=container.scrollHeight-container.scrollTop===container.clientHeight?`${this.chatHub.BUBBLE_OUTER * 5}px`:`${this.chatHub.BUBBLE_OUTER}px`;},});return __exports;});; 12628 12629/* /im_livechat/static/src/embed/common/chat_window_model_patch.js */ 12630odoo.define('@im_livechat/embed/common/chat_window_model_patch',['@web/core/utils/patch','@mail/core/common/chat_window_model','@im_livechat/core/common/chat_window_model_patch'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{ChatWindow}=require("@mail/core/common/chat_window_model");const{CW_LIVECHAT_STEP}=require("@im_livechat/core/common/chat_window_model_patch");patch(ChatWindow.prototype,{close(){super.close(...arguments);if(this.livechatStep===CW_LIVECHAT_STEP.FEEDBACK){this.store.env.services["im_livechat.livechat"].leave(this.thread);this.thread.chatbot?.stop();}},});return __exports;});; 12631 12632/* /im_livechat/static/src/embed/common/chat_window_patch.js */ 12633odoo.define('@im_livechat/embed/common/chat_window_patch',['@im_livechat/core/common/chat_window_model_patch','@im_livechat/embed/common/feedback_panel/feedback_panel','@mail/core/common/chat_window','@odoo/owl','@web/core/utils/hooks','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{CW_LIVECHAT_STEP}=require("@im_livechat/core/common/chat_window_model_patch");const{FeedbackPanel}=require("@im_livechat/embed/common/feedback_panel/feedback_panel");const{ChatWindow}=require("@mail/core/common/chat_window");const{useState}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{patch}=require("@web/core/utils/patch");Object.assign(ChatWindow.components,{FeedbackPanel});patch(ChatWindow.prototype,{setup(){super.setup(...arguments);this.livechatService=useService("im_livechat.livechat");this.livechatState=useState({showCloseConfirmation:false});},async onClickNewSession(){await this.close();await this.livechatService.open();},onClickFeedback(){this.props.chatWindow.livechatStep=CW_LIVECHAT_STEP.CONFIRM_CLOSE;this.close();},get showGiveFeedbackBtn(){const thread=this.props.chatWindow.thread;if(thread?.channel_type!=="livechat"){return false;} 12634return thread.chatbot?.completed||thread.livechat_end_dt;},});return __exports;});; 12635 12636/* /im_livechat/static/src/embed/common/composer_patch.js */ 12637odoo.define('@im_livechat/embed/common/composer_patch',['@mail/core/common/composer','@web/core/l10n/translation','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Composer}=require("@mail/core/common/composer");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"im_livechat",...args);const{patch}=require("@web/core/utils/patch");patch(Composer.prototype,{get placeholder(){if(this.thread?.channel_type!=="livechat"){return super.placeholder;} 12638return _t("Say something...");},});return __exports;});; 12639 12640/* /im_livechat/static/src/embed/common/disabled_features.js */ 12641odoo.define('@im_livechat/embed/common/disabled_features',['@mail/core/common/thread_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Thread}=require("@mail/core/common/thread_model");const{patch}=require("@web/core/utils/patch");patch(Thread.prototype,{get hasMemberList(){return false;},get hasAttachmentPanel(){return this.channel_type!=="livechat"&&super.hasAttachmentPanel;},});return __exports;});; 12642 12643/* /im_livechat/static/src/embed/common/feedback_panel/feedback_panel.js */ 12644odoo.define('@im_livechat/embed/common/feedback_panel/feedback_panel',['@im_livechat/embed/common/livechat_service','@im_livechat/core/common/transcript_sender','@odoo/owl','@web/core/utils/hooks','@web/session','@web/core/utils/urls','@web/core/network/rpc'],function(require){'use strict';let __exports={};const{RATING}=require("@im_livechat/embed/common/livechat_service");const{TranscriptSender}=require("@im_livechat/core/common/transcript_sender");const{Component,useState}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{session}=require("@web/session");const{url}=require("@web/core/utils/urls");const{rpc}=require("@web/core/network/rpc");const FeedbackPanel=__exports.FeedbackPanel=class FeedbackPanel extends Component{static template="im_livechat.FeedbackPanel";static props=["onClickClose?","onClickNewSession","thread"];static components={TranscriptSender};STEP=Object.freeze({RATING:"rating",THANKS:"thanks",});RATING=RATING;setup(){this.session=session;this.livechatService=useService("im_livechat.livechat");this.store=useService("mail.store");this.state=useState({step:this.STEP.RATING,rating:null,feedback:"",});this.url=url;} 12645select(rating){this.state.rating=rating;} 12646get allowNewSession(){return(this.store.livechat_rule?.action!=="hide_button"&&this.livechatService.options.channel_id);} 12647get transcriptUrl(){return this.props.thread.transcriptUrl;} 12648onClickSendFeedback(){rpc("/im_livechat/feedback",{reason:this.state.feedback,rate:this.state.rating,channel_id:this.props.thread.id,});this.state.step=this.STEP.THANKS;const link=this.livechatService.options.review_link;if(this.state.rating===this.RATING.GOOD&&link){window.open(link,"_blank","noopener");}}} 12649return __exports;});; 12650 12651/* /im_livechat/static/src/embed/common/history_service.js */ 12652odoo.define('@im_livechat/embed/common/history_service',['@im_livechat/core/common/expirable_storage','@web/core/browser/browser','@web/core/network/rpc','@web/core/registry'],function(require){'use strict';let __exports={};const{expirableStorage}=require("@im_livechat/core/common/expirable_storage");const{browser}=require("@web/core/browser/browser");const{rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const HistoryService=__exports.HistoryService=class HistoryService{static HISTORY_STORAGE_KEY="im_livechat_history";static HISTORY_LIMIT=15;constructor(env,services){this.busService=services.bus_service;this.storeService=services["mail.store"];} 12653setup(){this.updateHistory();this.busService.subscribe("im_livechat.history_command",async(payload)=>{const thread=await this.storeService.Thread.getOrFetch({id:payload.id,model:"discuss.channel",});if(thread?.channel_type!=="livechat"){return;} 12654const data=expirableStorage.getItem(HistoryService.HISTORY_STORAGE_KEY);const history=data?JSON.parse(data):[];rpc("/im_livechat/history",{pid:payload.partner_id,channel_id:thread.id,page_history:history,});});} 12655updateHistory(){const page=browser.location.href.replace(/^.*\/\/[^/]+/,"");const pageHistory=expirableStorage.getItem(HistoryService.HISTORY_STORAGE_KEY);const urlHistory=pageHistory?JSON.parse(pageHistory):[];if(!urlHistory.includes(page)){urlHistory.push(page);if(urlHistory.length>HistoryService.HISTORY_LIMIT){urlHistory.shift();} 12656expirableStorage.setItem(HistoryService.HISTORY_STORAGE_KEY,JSON.stringify(urlHistory),60*60*24);}}} 12657const historyService=__exports.historyService={dependencies:["bus_service","mail.store"],start(env,services){const history=new HistoryService(env,services);history.setup();},};registry.category("services").add("im_livechat.history_service",historyService);return __exports;});; 12658 12659/* /im_livechat/static/src/embed/common/livechat_button.js */ 12660odoo.define('@im_livechat/embed/common/livechat_button',['@odoo/owl','@web/core/utils/hooks','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Component,useRef,useState,useEffect}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{debounce}=require("@web/core/utils/timing");const LivechatButton=__exports.LivechatButton=class LivechatButton extends Component{static template="im_livechat.LivechatButton";static props={};static DEBOUNCE_DELAY=500;setup(){this.store=useService("mail.store");this.livechatService=useService("im_livechat.livechat");this.onClick=debounce(this.onClick.bind(this),LivechatButton.DEBOUNCE_DELAY,{leading:true,});this.ref=useRef("button");this.state=useState({animateNotification:this.isShown});useEffect((isShown,rootNodeClassList)=>{if(isShown&&rootNodeClassList){rootNodeClassList.add("o-livechat-LivechatButton-isVisible");return()=>{rootNodeClassList.remove("o-livechat-LivechatButton-isVisible");};}},()=>[this.isShown,this.ref.el?.getRootNode().host?.classList]);} 12661onClick(){this.state.animateNotification=false;this.livechatService.open();}
12662get isShown(){return(this.store.livechat_available&&this.store.activeVisitorLivechats.length===0&&this.livechatService.options.channel_id);}} 12663return __exports;});; 12664 12665/* /im_livechat/static/src/embed/common/livechat_service.js */ 12666odoo.define('@im_livechat/embed/common/livechat_service',['@im_livechat/core/common/expirable_storage','@odoo/owl','@web/core/network/rpc','@web/core/l10n/translation','@web/core/registry','@web/core/utils/concurrency','@web/session','@im_livechat/embed/common/misc'],function(require){'use strict';let __exports={};const{expirableStorage}=require("@im_livechat/core/common/expirable_storage");const{reactive}=require("@odoo/owl");const{rpc}=require("@web/core/network/rpc");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"im_livechat",...args);const{registry}=require("@web/core/registry");const{Deferred}=require("@web/core/utils/concurrency");const{session}=require("@web/session");const{canLoadLivechat}=require("@im_livechat/embed/common/misc");const RATING=__exports.RATING=Object.freeze({GOOD:5,OK:3,BAD:1,});const ODOO_VERSION_KEY=__exports.ODOO_VERSION_KEY=`${location.origin.replace( 12667 /:\/{0,2}/g, 12668 "_" 12669)}_im_livechat.odoo_version`;const OPERATOR_STORAGE_KEY="im_livechat_previous_operator";const LivechatService=__exports.LivechatService=class LivechatService{initialized=false;constructor(env,services){this.setup(env,services);} 12670setup(env,services){this.env=env;this.notificationService=services.notification;this.store=services["mail.store"];} 12671async initialize(){this.store.fetchStoreData("init_livechat",this.options.channel_id,{readonly:false});if(this.options.chatbot_test_store){await this.store.chatHub.initPromise;this.store.insert(this.options.chatbot_test_store);}} 12672async open(options={}){const thread=await this._createThread({persist:false,options});await thread?.openChatWindow({focus:true});return thread;} 12673async persist(thread){if(!thread.isTransient){return thread;} 12674if(this._persistDeferred){return this._persistDeferred;} 12675this._persistDeferred=new Deferred();try{const temporaryThread=thread;const deleteTemporary=async()=>{await this.store.chatHub.initPromise;await this.store.ChatWindow.get({thread:temporaryThread})?.close({force:true,});temporaryThread?.delete();};const savedThread=await this._createThread({originThread:thread,persist:true});if(!savedThread){await deleteTemporary();return;} 12676savedThread.fetchNewMessages();this.env.services["mail.store"].initialize();savedThread.readyToSwapDeferred.then(async()=>{if(!savedThread?.exists()){return;} 12677savedThread.scrollUnread=false;deleteTemporary();savedThread.openChatWindow({focus:true});});this._persistDeferred.resolve(savedThread);return savedThread;}catch(error){this._persistDeferred.reject(error);throw error;}finally{this._persistDeferred=null;}} 12678async leave(thread){await rpc("/im_livechat/visitor_leave_session",{channel_id:thread.id});} 12679async _createThread({originThread,persist=false,options={}}){const{store_data,channel_id}=await rpc("/im_livechat/get_session",{channel_id:options.channel_id??this.options.channel_id,previous_operator_id:expirableStorage.getItem(OPERATOR_STORAGE_KEY),chatbot_script_id:originThread?.chatbot?.script.id??this.store.livechat_rule?.chatbot_script_id?.id,persisted:options.persist??persist,...this.getSessionExtraParams(originThread,options),},{silent:true});if(!channel_id){this.notificationService.add(_t("No available collaborator, please try again later."));return;} 12680this.store.insert(store_data);const thread=this.store.Thread.get({id:channel_id,model:"discuss.channel"});const ONE_DAY_TTL=60*60*24;expirableStorage.setItem("im_livechat_previous_operator",thread.livechat_operator_id.id,ONE_DAY_TTL*7);return thread;} 12681getSessionExtraParams(thread,options){return{};} 12682get options(){return session.livechatData?.options??{};}} 12683const livechatService=__exports.livechatService={dependencies:["mail.store","notification"],start(env,services){const livechat=reactive(new LivechatService(env,services));if(canLoadLivechat()){livechat.initialize();} 12684return livechat;},};registry.category("services").add("im_livechat.livechat",livechatService);return __exports;});; 12685 12686/* /im_livechat/static/src/embed/common/mail_popout_service_patch.js */ 12687odoo.define('@im_livechat/embed/common/mail_popout_service_patch',['@web/core/utils/patch','@im_livechat/embed/common/boot_helpers','@mail/core/common/mail_popout_service'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{loadAssets}=require("@im_livechat/embed/common/boot_helpers");const{mailPopoutService}=require("@mail/core/common/mail_popout_service");const popoutPatch={async addAssets(window){await super.addAssets(...arguments);await new Promise((resolve)=>{if(window.document.readyState==="complete"){resolve();}else{window.addEventListener("load",resolve,{once:true});}});await window.document.fonts.ready;await loadAssets(window.document.head);},};
12687patch(mailPopoutService,popoutPatch);return __exports;});; 12688 12689/* /im_livechat/static/src/embed/common/message_model_patch.js */ 12690odoo.define('@im_livechat/embed/common/message_model_patch',['@mail/core/common/message_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message_model");const{patch}=require("@web/core/utils/patch");const messagePatch={setup(){super.setup(...arguments);this.disableChatbotAnswers=false;},get notificationHidden(){if(this.thread.channel_type!=="livechat"||!this.notificationType){return super.notificationHidden;} 12691return["channel-joined","channel-left"].includes(this.notificationType);},};patch(Message.prototype,messagePatch);return __exports;});; 12692 12693/* /im_livechat/static/src/embed/common/message_patch.js */ 12694odoo.define('@im_livechat/embed/common/message_patch',['@mail/core/common/message','@web/core/utils/patch','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message");const{patch}=require("@web/core/utils/patch");const{url}=require("@web/core/utils/urls");Message.props.push("isTypingMessage?");patch(Message.prototype,{setup(){super.setup();this.url=url;},answerChatbot(answer){if(this.props.message.disableChatbotAnswers){return;} 12695this.props.message.disableChatbotAnswers=true;return this.props.message.thread.post(answer.name,{},{selected_answer_id:answer.id});},});return __exports;});; 12696 12697/* /im_livechat/static/src/embed/common/misc.js */ 12698odoo.define('@im_livechat/embed/common/misc',['@web/session'],function(require){'use strict';let __exports={};const{session}=require("@web/session");__exports.canLoadLivechat=canLoadLivechat;function canLoadLivechat(){const sessionData=session.livechatData??{};return"can_load_livechat"in sessionData?sessionData.can_load_livechat:sessionData.isAvailable;} 12699return __exports;});; 12700 12701/* /im_livechat/static/src/embed/common/store_service_patch.js */ 12702odoo.define('@im_livechat/embed/common/store_service_patch',['@im_livechat/core/common/expirable_storage','@mail/core/common/store_service','@mail/model/export','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{expirableStorage}=require("@im_livechat/core/common/expirable_storage");const{Store}=require("@mail/core/common/store_service");const{fields}=require("@mail/model/export");const{patch}=require("@web/core/utils/patch");const GUEST_TOKEN_STORAGE_KEY=__exports.GUEST_TOKEN_STORAGE_KEY="im_livechat_guest_token";const StorePatch={setup(){super.setup(...arguments);this.activeLivechats=fields.Many("Thread",{inverse:"storeAsActiveLivechats"});this.activeVisitorLivechats=fields.Many("Thread",{inverse:"storeAsActiveVisitorLivechats",});expirableStorage.onChange(GUEST_TOKEN_STORAGE_KEY,(value)=>(this.guest_token=value));this.guest_token=fields.Attr(null,{compute(){return expirableStorage.getItem(GUEST_TOKEN_STORAGE_KEY);},onUpdate(){if(this.guest_token){expirableStorage.setItem(GUEST_TOKEN_STORAGE_KEY,this.guest_token);this.store.env.services.bus_service.addChannel(`mail.guest_${this.guest_token}`);return;} 12703expirableStorage.removeItem(GUEST_TOKEN_STORAGE_KEY);this.store.env.services.bus_service.deleteChannel(`mail.guest_${this.guest_token}`);},eager:true,});this.livechat_rule=fields.One("im_livechat.channel.rule");this.livechat_available=false;},};patch(Store.prototype,StorePatch);return __exports;});; 12704 12705/* /im_livechat/static/src/embed/common/thread_actions.js */ 12706odoo.define('@im_livechat/embed/common/thread_actions',['@im_livechat/core/common/chat_window_model_patch','@mail/core/common/thread_actions','@mail/discuss/call/common/thread_actions','@web/core/l10n/translation','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{CW_LIVECHAT_STEP}=require("@im_livechat/core/common/chat_window_model_patch");const{registerThreadAction,threadActionsRegistry}=require("@mail/core/common/thread_actions");require("@mail/discuss/call/common/thread_actions");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"im_livechat",...args);const{patch}=require("@web/core/utils/patch");registerThreadAction("restart",{condition:({owner,thread})=>thread?.chatbot?.canRestart&&!owner.isDiscussSidebarChannelActions,icon:"fa fa-fw fa-refresh",name:_t("Restart Conversation"),open:({owner,thread})=>{owner.props.chatWindow.livechatStep=CW_LIVECHAT_STEP.NONE;thread.chatbot.restart();owner.props.chatWindow.open({focus:true});}
12706,sequence:99,sequenceQuick:15,});const callSettingsAction=threadActionsRegistry.get("call-settings");patch(callSettingsAction,{condition({store,thread}){return thread?.channel_type==="livechat"?store.rtc.state.channel?.eq(thread):super.condition(...arguments);},});return __exports;});; 12707 12708/* /im_livechat/static/src/embed/common/thread_model_patch.js */ 12709odoo.define('@im_livechat/embed/common/thread_model_patch',['@mail/core/common/record','@mail/core/common/thread_model','@mail/discuss/core/common/thread_model_patch','@mail/utils/common/format','@web/core/utils/patch','@web/core/l10n/translation','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{fields}=require("@mail/core/common/record");const{Thread}=require("@mail/core/common/thread_model");require("@mail/discuss/core/common/thread_model_patch");const{generateEmojisOnHtml}=require("@mail/utils/common/format");const{patch}=require("@web/core/utils/patch");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"im_livechat",...args);const{Deferred}=require("@web/core/utils/concurrency");const threadStaticPatch={async getOrFetch(data,fieldNames=[]){const thread=await super.getOrFetch(...arguments);if(thread){return thread;} 12710await this.store.isReady;return super.getOrFetch(...arguments);},};patch(Thread,threadStaticPatch);patch(Thread.prototype,{setup(){super.setup();this.livechat_operator_id=fields.One("res.partner");this.chatbotTypingMessage=fields.One("mail.message",{compute(){if(this.chatbot){return{id:-0.1-this.id,thread:this,author_id:this.livechat_operator_id,};}},});this.livechatWelcomeMessage=fields.One("mail.message",{compute(){if(this.hasWelcomeMessage){const livechatService=this.store.env.services["im_livechat.livechat"];return{id:-0.2-this.id,body:livechatService.options.default_message,thread:this,author_id:this.livechat_operator_id,};}},});this.readyToSwapDeferred=new Deferred();this._toggleChatbot=fields.Attr(false,{compute(){return Boolean(this.chatbot&&!this.chatbot.completed&&!this.livechat_end_dt);},onUpdate(){const shouldToggle=this._toggleChatbot;this.isLoadedDeferred.then(()=>{if(shouldToggle){this.chatbot.start();}else{this.chatbot?.stop();}});},eager:true,});this.storeAsActiveLivechats=fields.One("Store",{compute(){return this.channel_type==="livechat"&&!this.livechat_end_dt?this.store:null;},});this.storeAsActiveVisitorLivechats=fields.One("Store",{compute(){return!this.livechat_end_dt&&(this.self_member_id?.eq(this.livechatVisitorMember)||this.isTransient)?this.store:null;},inverse:"activeVisitorLivechats",});this.requested_by_operator=false;},get isLastMessageFromCustomer(){return this.newestPersistentOfAllMessage?.isSelfAuthored;},get membersThatCanSeen(){return super.membersThatCanSeen.filter((member)=>member.livechat_member_type!=="bot");},get avatarUrl(){if(this.channel_type==="livechat"){return this.livechat_operator_id.avatarUrl;} 12711return super.avatarUrl;},get displayName(){if(this.channel_type==="livechat"&&this.livechat_operator_id){return this.getPersonaName(this.livechat_operator_id);} 12712return super.displayName;},get hasWelcomeMessage(){return this.channel_type==="livechat"&&!this.chatbot&&!this.requested_by_operator;},async post(body,postData,extraData={}){if(this.chatbot&&!this.chatbot.forwarded&&this.chatbot.currentStep?.step_type!=="free_input_multi"){this.chatbot.isProcessingAnswer=true;} 12713if(this.channel_type==="livechat"&&this.isTransient){if(this.chatbot&&extraData.selected_answer_id){this.chatbot.currentStep.selectedAnswer=this.store["chatbot.script.answer"].get(extraData.selected_answer_id);} 12714const authorModelName=this.store.self?.Model.getName();const temporaryMsg=this.store["mail.message"].insert({author_id:authorModelName==="res.partner"?this.store.self:undefined,author_guest_id:authorModelName==="mail.guest"?this.store.self:undefined,body:await generateEmojisOnHtml(body,{allowEmojiLoading:false}),id:this.store.getNextTemporaryId(),model:"discuss.channel",res_id:this.id,thread:this,});this.messages.push(temporaryMsg);this?.chatbot?._simulateTyping(2**31-1);const thread=await this.store.env.services["im_livechat.livechat"].persist(this);if(this.store.self_partner){temporaryMsg.author_id=this.store.self_partner;}else{temporaryMsg.author_guest_id=this.store.self_guest;} 12715if(!thread){return;} 12716await thread.isLoadedDeferred;return thread.post(...arguments).then(()=>thread.readyToSwapDeferred.resolve());} 12717const message=await super.post(...arguments);await this.chatbot?.processAnswer(message);return message;},get composerDisabled(){const step=this.chatbot?.currentStep;if(this.chatbot?.forwarded&&!this.livechat_end_dt){return false;} 12718return(super.composerDisabled||this.chatbot?.isProcessingAnswer||(step&&!step.operatorFound&&(step.completed||!step.expectAnswer||step.answer_ids.length>0)));},get composerDisabledText(){const text=super.composerDisabledText;if(text||!this.chatbot){return text;} 12719if(this.chatbot.completed){return _t("This livechat conversation has ended.");} 12720if(this.chatbot.currentStep?.step_type==="question_selection"&&!this.chatbot.currentStep.selectedAnswer){return _t("Select an option above");} 12721return _t("Say something");},});return __exports;});; 12722 12723/* /website/static/src/common/website_model.js */ 12724odoo.define('@website/common/website_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const Website=__exports.Website=class Website extends Record{static id="id";static _name="website";id;
12724name;} 12725Website.register();return __exports;});; 12726 12727/* /website/static/src/common/website_visitor_model.js */ 12728odoo.define('@website/common/website_visitor_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{fields,Record}=require("@mail/core/common/record");const WebsiteVisitor=__exports.WebsiteVisitor=class WebsiteVisitor extends Record{static _name="website.visitor";static id="id";country=fields.One("res.country",{compute(){return this.partner_id?.country_id||this.country_id;},});country_id=fields.One("res.country");discuss_channel_ids=fields.Many("Thread");display_name;lang_id=fields.One("res.lang");partner_id=fields.One("res.partner");website_id=fields.One("website");} 12729WebsiteVisitor.register();return __exports;});; 12730 12731/* /website_livechat/static/src/common/thread_model_patch.js */ 12732odoo.define('@website_livechat/common/thread_model_patch',['@mail/core/common/record','@mail/core/common/thread_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{fields}=require("@mail/core/common/record");const{Thread}=require("@mail/core/common/thread_model");const{patch}=require("@web/core/utils/patch");patch(Thread.prototype,{setup(){super.setup(...arguments);this.livechat_visitor_id=fields.One("website.visitor");},});return __exports;});; 12733 12734/* /ai_livechat/static/src/discuss/core/common/chat_window_patch.js */ 12735odoo.define('@ai_livechat/discuss/core/common/chat_window_patch',['@mail/core/common/chat_window','@web/core/network/rpc','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChatWindow}=require("@mail/core/common/chat_window");const{rpc}=require("@web/core/network/rpc");const{patch}=require("@web/core/utils/patch");patch(ChatWindow.prototype,{get showForwardOperatorButton(){const thread=this.props.chatWindow.thread;return thread.channel_type==='livechat'&&thread.ai_agent_id;},async forwardOperator(ev){let thread=this.props.chatWindow.thread;if(thread.channel_type!=="livechat"){return;} 12736if(thread.isTransient){thread=await this.store.env.services["im_livechat.livechat"].persist(thread) 12737if(!thread){return;}} 12738const result=await rpc("/ai_livechat/forward_operator",{channel_id:thread.id,});if(result['store_data']){this.store.insert(result['store_data']);} 12739if(result['notification']){this.store.env.services.notification.add(result['notification'],{type:result['notification_type']});} 12740if(result['success']===true){thread.readyToSwapDeferred.resolve();}}});return __exports;});; 12741 12742/* /ai_livechat/static/src/discuss/embed/common/livechat_service_patch.js */ 12743odoo.define('@ai_livechat/discuss/embed/common/livechat_service_patch',['@im_livechat/embed/common/livechat_service','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{LivechatService}=require("@im_livechat/embed/common/livechat_service");const{patch}=require("@web/core/utils/patch");patch(LivechatService.prototype,{getSessionExtraParams(thread,options){let extraParams=super.getSessionExtraParams(thread,options);extraParams['ai_agent_id']=options.ai_agent_id??this.store.livechat_rule?.ai_agent_id;return extraParams;},});return __exports;});; 12744 12745/* /ai_website_livechat/static/src/discuss/core/common/chat_window_model_patch.js */ 12746odoo.define('@ai_website_livechat/discuss/core/common/chat_window_model_patch',['@mail/core/common/chat_window_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChatWindow}=require("@mail/core/common/chat_window_model");const{patch}=require("@web/core/utils/patch");patch(ChatWindow.prototype,{_onClose(options={}){const channel=this.thread;super._onClose(...arguments);if(channel?.model==="discuss.channel"){this.store.env.bus.trigger("CHATWINDOW_CLOSED",{channel});}},});return __exports;});; 12747 12748/* /im_livechat/static/src/embed/external/boot.js */ 12749odoo.define('@im_livechat/embed/external/boot',['@im_livechat/embed/common/boot_helpers','@im_livechat/embed/common/misc','@odoo/owl','@web/core/assets','@web/core/l10n/translation','@web/core/main_components_container','@web/core/templates','@web/env','@web/session'],function(require){'use strict';let __exports={};const{makeRoot,makeShadow}=require("@im_livechat/embed/common/boot_helpers");const{canLoadLivechat}=require("@im_livechat/embed/common/misc");const{mount,whenReady}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const{appTranslateFn}=require("@web/core/l10n/translation");const{MainComponentsContainer}=require("@web/core/main_components_container");const{getTemplate}=require("@web/core/templates");const{makeEnv,startServices}=require("@web/env");const{session}=require("@web/session");(async function boot(){if(!canLoadLivechat()){return;} 12750session.origin=session.livechatData.serverUrl;await whenReady();if(session.test_mode){await loadBundle("im_livechat.assets_livechat_support_tours");} 12751const env=makeEnv();await startServices(env);odoo.isReady=true;const root=makeRoot(document.body);const target=await makeShadow(root);env.services["discuss.rtc"].rootEl=target;await mount(MainComponentsContainer,target,{env:Object.assign(Object.create(env),{rootId:root.getAttribute("id"),}),getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,dev:env.debug,});})();return __exports;});; 12752 12753/* /im_livechat/static/src/embed/external/bus_parameters_service_patch.js */ 12754odoo.define('@im_livechat/embed/external/bus_parameters_service_patch',['@bus/bus_parameters_service','@web/core/utils/patch','@web/session'],function(require){'use strict';let __exports={};const{busParametersService}=require("@bus/bus_parameters_service");const{patch}=require("@web/core/utils/patch");const{session}=require("@web/session");patch(busParametersService,{start(){return{...super.start(...arguments),serverURL:session.livechatData.serverUrl.replace(/\/+$/,""),};},});return __exports;});; 12755 12756/* /im_livechat/static/src/embed/external/emoji_loader_patch.js */ 12757odoo.define('@im_livechat/embed/external/emoji_loader_patch',['@web/core/emoji_picker/emoji_picker','@web/core/assets','@web/core/utils/patch','@web/core/utils/urls','@web/session'],function(require){'use strict';let __exports={};const{loader}=require("@web/core/emoji_picker/emoji_picker");const{loadJS}=require("@web/core/assets");const{patch}=require("@web/core/utils/patch");const{url}=require("@web/core/utils/urls");const{session}=require("@web/session");patch(loader,{loadEmoji:()=>loadJS(url("/im_livechat/emoji_bundle",undefined,{origin:session.livechatData.serverUrl,})),});return __exports;}); 12758 12759 /******************************************* 12760 * Templates * 12761 *******************************************/ 12762 12763 odoo.define("im_livechat.assets_embed_external.bundle.xml", ["@web/core/templates"], function(require) { 12764 "use strict"; 12765 const { checkPrimaryTemplateParents, registerTemplate, registerTemplateExtension } = require("@web/core/templates"); 12766 /* im_livechat.assets_embed_external */ 12767 registerTemplate("web.ActionSwiper", `/web/static/src/core/action_swiper/action_swiper.xml`, `<t t-name="web.ActionSwiper" xml:space="preserve"> 12768 <t t-if="props.onRightSwipe || props.onLeftSwipe"> 12769 <div class="o_actionswiper" t-on-touchend="_onTouchEndSwipe" t-on-touchmove="_onTouchMoveSwipe" t-on-touchstart="_onTouchStartSwipe" t-ref="root"> 12770 <div class="o_actionswiper_overflow_container position-relative overflow-hidden"> 12771 <div class="o_actionswiper_target_container" t-ref="targetContainer" t-att-style="state.containerStyle" t-att-class="{ o_actionswiper_swiping: state.isSwiping }"> 12772 <t t-slot="default"/> 12773 <t t-if="localizedProps.onRightSwipe and (localizedProps.onRightSwipe.icon or localizedProps.onRightSwipe.bgColor)"> 12774 <div t-att-style="'max-width: ' + swipedDistance + 'px;'" class="o_actionswiper_right_swipe_area position-absolute overflow-hidden w-100 h-100 d-flex align-items-center justify-content-center rounded-end" t-att-class="localizedProps.onRightSwipe.bgColor">
12775 <span><i class="fa fa-2x" t-att-class="localizedProps.onRightSwipe.icon"/></span> 12776 </div> 12777 </t> 12778 <t t-if="localizedProps.onLeftSwipe and (localizedProps.onLeftSwipe.icon or localizedProps.onLeftSwipe.bgColor)"> 12779 <div t-att-style="'max-width: ' + -swipedDistance + 'px;'" class="o_actionswiper_left_swipe_area position-absolute overflow-hidden w-100 h-100 d-flex align-items-center justify-content-center rounded-start" t-att-class="localizedProps.onLeftSwipe.bgColor"> 12780 <span><i class="fa fa-2x" t-att-class="localizedProps.onLeftSwipe.icon"/></span> 12781 </div> 12782 </t> 12783 </div> 12784 </div> 12785 </div> 12786 </t> 12787 <t t-else=""> 12788 <t t-slot="default"/> 12789 </t> 12790 </t> 12791`); 12792registerTemplate("web.AutoComplete", `/web/static/src/core/autocomplete/autocomplete.xml`, `<t t-name="web.AutoComplete" xml:space="preserve"> 12793 <div class="o-autocomplete" t-ref="root" t-att-class="autoCompleteRootClass"> 12794 <input type="text" t-att-id="props.id" class="o-autocomplete--input o_input pe-3 text-truncate" t-att-autocomplete="props.autocomplete" t-att-placeholder="props.placeholder" t-att-title="props.title" role="combobox" t-att-aria-activedescendant="activeSourceOptionId" t-att-aria-expanded="displayOptions ? 'true' : 'false'" aria-autocomplete="list" aria-haspopup="listbox" t-model="state.value" t-on-blur="onInputBlur" t-on-click="onInputClick" t-on-change="onInputChange" t-on-input="onInput" t-on-keydown="onInputKeydown" t-on-focus="onInputFocus" t-ref="input"/> 12795 <t t-if="displayOptions"> 12796 <ul role="menu" class="o-autocomplete--dropdown-menu ui-widget show" t-att-class="ulDropdownClass" t-ref="sourcesList"> 12797 <t t-foreach="sources" t-as="source" t-key="source.id"> 12798 <t t-if="source.isLoading"> 12799 <li class="ui-menu-item" t-att-class="{ 'o-autocomplete--dropdown-item': props.dropdown, 'd-block': !props.dropdown }"> 12800 <a t-attf-id="{{props.id or 'autocomplete'}}_{{source_index}}_loading" role="option" href="#" class="o_loading dropdown-item ui-menu-item-wrapper" aria-selected="true"> 12801 <i class="fa fa-spin fa-circle-o-notch"/>
12801 <t t-esc="source.placeholder"/> 12802 </a> 12803 </li> 12804 </t> 12805 <t t-else=""> 12806 <t t-foreach="source.options" t-as="option" t-key="option.id"> 12807 <li class="o-autocomplete--dropdown-item ui-menu-item d-block" t-att-class="option.cssClass" t-on-mouseenter="() => this.onOptionMouseEnter([source_index, option_index])" t-on-mouseleave="() => this.onOptionMouseLeave([source_index, option_index])" t-on-click="() => this.onOptionClick(option)" t-on-pointerdown="(ev) => this.onOptionPointerDown(option, ev)"> 12808 <t t-tag="option.unselectable ? 'span' : 'a'" class="dropdown-item ui-menu-item-wrapper text-truncate" t-attf-id="{{props.id or 'autocomplete'}}_{{source_index}}_{{option_index}}" t-att-role="!option.unselectable and 'option'" t-att-href="!option.unselectable and '#'" t-att-class="{ 'ui-state-active': isActiveSourceOption([source_index, option_index]) }" t-att-aria-selected="isActiveSourceOption([source_index, option_index]) ? 'true' : 'false'"> 12809 <t t-slot="{{ source.optionSlot }}" label="option.label" data="option.data"> 12810 <t t-if="!option.labelTermOrder" t-out="option.label"/> 12811 <t t-else=""> 12812 <t t-foreach="option.labelTermOrder.labelBits" t-as="bit" t-key="bit.id"> 12813 <t t-if="!option.labelTermOrder.searchTermIndexes.includes(bit.id)" t-esc="bit.bit"/> 12814 <mark t-else="" class="o-autocomplete--mark" t-esc="bit.bit"/> 12815 </t> 12816 </t> 12817 </t> 12818 </t> 12819 </li> 12820 </t> 12821 </t> 12822 </t> 12823 </ul> 12824 </t> 12825 </div> 12826 </t> 12827 12828`); 12829registerTemplate("web.BarcodeDialog", `/web/static/src/core/barcode/barcode_dialog.xml`, `<t t-name="web.BarcodeDialog" xml:space="preserve"> 12830 <Dialog title.translate="Barcode Scanner" fullscreen="true" footer="false" contentClass="'o-barcode-modal'"> 12831 <BarcodeVideoScanner t-if="state.barcodeScannerSupported" t-props="props" onError.bind="onError" onResult.bind="onResult"/> 12832 <div t-else="" t-ref="videoPreview" class="h-100 d-flex flex-column justify-content-center align-items-center gap-1"> 12833 <i class="fa fa-2x fa-camera text-muted"/> 12834 <strong>Unable to access camera</strong> 12835 <span class="text-muted" t-out="state.errorMessage"/> 12836 </div> 12837 </Dialog> 12838 </t> 12839`); 12840registerTemplate("web.BarcodeVideoScanner", `/web/static/src/core/barcode/barcode_video_scanner.xml`, `<t t-name="web.BarcodeVideoScanner" xml:space="preserve"> 12841 <CropOverlay onResize.bind="this.onResize" isReady="state.isReady"> 12842 <video t-ref="videoPreview" muted="true" autoplay="true" playsinline="true" t-att-class="props.cssClass"/> 12843 </CropOverlay> 12844 </t> 12845`); 12846registerTemplate("web.CropOverlay", `/web/static/src/core/barcode/crop_overlay.xml`, `<t t-name="web.CropOverlay" xml:space="preserve"> 12847 <div t-ref="crop-container" t-on-mousedown="pointerDown" t-on-touchstart="pointerDown" t-on-mousemove="pointerMove" t-on-touchmove="pointerMove" t-on-mouseup="pointerUp" t-on-touchend="pointerUp" class="d-grid align-content-center justify-content-center h-100 o_crop_container"> 12848 <t t-slot="default"/> 12849 <t t-if="props.isReady"> 12850 <div class="o_crop_overlay" t-att-class="{'o_crop_overlay_ios': isIOS}"/> 12851 <img class="o_crop_icon" src="/web/static/img/transform.svg" draggable="false"/> 12852 </t> 12853 </div> 12854 </t> 12855`); 12856registerTemplate("web.BottomSheet", `/web/static/src/core/bottom_sheet/bottom_sheet.xml`, `<t t-name="web.BottomSheet" xml:space="preserve"> 12857 <div class="o_bottom_sheet" t-att-class="{ 'o_bottom_sheet_ready': state.isPositionedReady, 'o_bottom_sheet_dismissing': state.isDismissing, 'o_bottom_sheet_snapping': state.isSnappingEnabled, }" t-attf-style="--BottomSheet-progress: {{state.progress}}" t-ref="container"> 12858 12859 <div class="o_bottom_sheet_rail" t-att-class="{ o_bottom_sheet_rail_prevent_overscroll : props.preventDism
12859issOnContentScroll }" t-ref="scrollRail"> 12860 12861 <div class="o_bottom_sheet_backdrop" t-on-click="slideOut"/> 12862 12863 12864 <div class="o_bottom_sheet_dismiss"/> 12865 12866 12867 <div class="o_bottom_sheet_spacer"/> 12868 12869 12870 <div class="o_bottom_sheet_sheet offcanvas position-relative overflow-hidden" role="dialog" t-ref="sheet"> 12871 12872 12873 <div tabindex="-1" role="button" class="o_bottom_sheet_handle text-center d-flex align-items-center justify-content-center opacity-50 py-2" t-on-click.stop="slideOut"> 12874 <div class="o_bottom_sheet_handle_bar pt-1 mx-auto rounded-pill d-inline-block px-5 bg-dark"/> 12875 </div> 12876 12877 12878 <div class="o_bottom_sheet_body offcanvas-body" role="menu" t-att-class="props.class" t-ref="ref"> 12879 12880 12881 <t t-if="props.component"> 12882 <t t-component="props.component" t-props="props.componentProps || {}"/> 12883 </t> 12884 12885 12886 <t t-else=""> 12887 <t t-slot="default" close="close" back="back"/> 12888 </t> 12889 </div> 12890 </div> 12891 </div> 12892 </div> 12893 </t> 12894`); 12895registerTemplate("web.CheckBox", `/web/static/src/core/checkbox/checkbox.xml`, `<t t-name="web.CheckBox" xml:space="preserve"> 12896 <div class="o-checkbox form-check" t-attf-class="{{ props.slots ? 'form-check' : '' }}" t-att-class="props.className" t-on-click="onClick" t-ref="root"> 12897 <input t-att-id="props.id or id" type="checkbox" class="form-check-input" t-att-disabled="props.disabled" t-att-checked="props.value" t-att-name="props.name" t-att-indeterminate="props.indeterminate" t-on-change="onChange"/> 12898 <label t-att-for="props.id or id" class="form-check-label"> 12899 <t t-slot="default"/> 12900 </label> 12901 </div> 12902</t> 12903 12904`); 12905registerTemplate("web.CodeEditor", `/web/static/src/core/code_editor/code_editor.xml`, `<t t-name="web.CodeEditor" xml:space="preserve"> 12906 <div t-ref="editorRef" class="w-100" t-att-class="props.class" t-att-data-mode="state.activeMode"/> 12907 </t> 12908 12909`); 12910registerTemplate("web.ColorPicker", `/web/static/src/core/color_picker/color_picker.xml`, `<t t-name="web.ColorPicker" xml:space="preserve"> 12911 <div t-attf-class="o_font_color_selector user-select-none {{this.props.className}}" t-on-pointerdown.stop="() => {}" data-prevent-closing-overlay="true" t-ref="root"> 12912 <div class="px-1 mb-1 pt-2 d-flex"> 12913 <t t-foreach="this.tabs" t-as="tab" t-key="tab.id"> 12914 <button t-attf-class="btn btn-sm text-truncate btn-tab me-1 #{tab.id}-tab #{ isDarkTheme ? 'btn-secondary' : 'btn-light'} #{state.activeTab === tab.id ? 'active' : ''}" t-on-click="() => this.setTab(tab.id)"> 12915 <t t-out="tab.name"/> 12916 </button> 12917 </t> 12918 <div class="flex-grow-1"/>
12919 <button t-attf-class="btn btn-sm fa fa-trash o_color_picker_reset #{ isDarkTheme ? 'btn-secondary' : 'btn-light'}" title="Reset" t-on-click="onColorApply" t-on-mouseover="onColorHover" t-on-mouseout="onColorHoverOut" t-on-focusin="onColorFocusin" t-on-focusout="onColorFocusout"/> 12920 </div> 12921 <t t-set="activeTab" t-value="this.tabs.find((tab) => state.activeTab === tab.id)"/> 12922 <t t-component="activeTab.component" t-props="{ applyColor: this.applyColor.bind(this), onColorClick: this.onColorApply.bind(this), onColorPointerOver: this.onColorHover.bind(this), onColorPointerOut: this.onColorHoverOut.bind(this), onColorPointerLeave: this.applyColorResetPreview.bind(this), onFocusin: this.onColorFocusin.bind(this), onFocusout: this.onColorFocusout.bind(this), colorPickerNavigation: this.colorPickerNavigation.bind(this), onColorPreview: this.onColorPreview.bind(this), setOnCloseCallback: this.props.setOnCloseCallback.bind(this), setOperationCallbacks: this.setOperationCallbacks.bind(this), editColorCombination: this.props.editColorCombination, selectedColorCombination: this.props.state.selectedColorCombination, defaultOpacity: this.props.defaultOpacity, noTransparency: this.props.noTransparency, defaultThemeColorVars: this.DEFAULT_THEME_COLOR_VARS, defaultColorSet: this.defaultColorSet, cssVarColorPrefix: this.props.cssVarColorPrefix, defaultColors: this.DEFAULT_COLORS, getUsedCustomColors: this.props.getUsedCustomColors, grayscales: this.grayscales, currentCustomColor: this.state.currentCustomColor, currentColorPreview: this.state.currentColorPreview, selectedColor: this.props.state.selectedColor, }"/> 12923 </div> 12924</t> 12925 12926`); 12927registerTemplate("web.CustomColorPicker", `/web/static/src/core/color_picker/custom_color_picker/custom_color_picker.xml`, `<t t-name="web.CustomColorPicker" xml:space="preserve"> 12928 <div class="o_colorpicker_widget" t-ref="el" t-on-click="onClick" t-on-keydown="onKeydown"> 12929 <div class="d-flex justify-content-between align-items-stretch mb-2"> 12930 <div t-ref="colorPickerArea" role="application" aria-label="Saturation and brightness color picker." aria-roledescription="Use up and down arrow keys to adapt the brightness. Use left and right arrow keys to adapt the saturation. Press the Control or Command key at the same time to have finer control." aria-activedescendant="picker_pointer" class="o_color_pick_area position-relative w-75" t-att-style="props.noTransparency ? 'width: 89%;' : None" t-on-pointerdown="onPointerDownPicker"> 12931 <div t-ref="colorPickerPointer" id="picker_pointer" class="o_picker_pointer rounded-circle p-1 position-absolute" tabindex="0" t-on-keydown="onPickerKeydown"/> 12932 </div> 12933 <div t-ref="colorSlider" class="o_color_slider position-relative" t-on-pointerdown="onPointerDownSlider"> 12934 <div t-ref="colorSliderPointer" class="o_slider_pointer" tabindex="0" t-on-keydown="onSliderKeydown" role="slider" aria-label="Hue" aria-orientation="vertical" aria-valuemin="0" aria-valuemax="360"/> 12935 </div> 12936 <div t-ref="opacitySlider" class="o_opacity_slider position-relative" t-if="!props.noTransparency" t-on-pointerdown="onPointerDownOpacitySlider"> 12937 <div t-ref="opacitySliderPointer" class="o_opacity_pointer" tabindex="0" t-on-keydown="onOpacitySliderKeydown" role="slider" aria-label="Opacity" aria-orientation="vertical" aria-valuemin="0" aria-valuemax="100"/> 12938 </div> 12939 </div> 12940 <div class="o_color_picker_inputs d-flex justify-content-between mb-2" t-on-change="debouncedOnChangeInputs"> 12941 <t t-set="input_classes" t-value="'p-0 border-0 text-center font-monospace bg-transparent'"/> 12942 12943 <div class="o_hex_div d-flex align-items-baseline me-1"> 12944 <input type="text" t-attf-class="o_hex_input {{input_classes}}
12944" data-color-method="hex" size="1" t-on-input="onHexColorInput"/> 12945 <label class="flex-grow-0 ms-1 mb-0">hex</label> 12946 </div> 12947 </div> 12948 </div> 12949</t> 12950 12951`); 12952registerTemplate("web.ColorPickerCustomTab", `/web/static/src/core/color_picker/tabs/color_picker_custom_tab.xml`, `<t t-name="web.ColorPickerCustomTab" xml:space="preserve"> 12953 <div class="d-flex flex-column align-items-start p-2 pb-0" t-on-keydown="props.colorPickerNavigation"> 12954 <div class="o_colorpicker_section" t-on-click="props.onColorClick" t-on-mouseover="props.onColorPointerOver" t-on-mouseout="props.onColorPointerOut" t-on-focusin="props.onFocusin" t-on-focusout="props.onColorPointerOut"> 12955 <t t-foreach="usedCustomColors" t-as="color" t-key="color_index"> 12956 <button t-if="color.toLowerCase() !== props.currentCustomColor?.toLowerCase()" class="o_color_button o_color_picker_button btn p-0" t-att-data-color="color" t-attf-style="background-color: {{color}}"/> 12957 </t> 12958 <button t-if="!props.defaultColorSet and isValidCustomColor(props.currentCustomColor)" class="o_color_button o_color_picker_button btn p-0" t-att-class="{'selected': props.defaultColorSet === false and !props.currentColorPreview}" t-attf-style="background-color: {{props.currentCustomColor}}" t-att-data-color="props.currentCustomColor"/> 12959 <button t-if="!!props.currentColorPreview" class="o_color_button o_color_picker_button btn p-0" t-att-class="{ 'selected': !!props.currentColorPreview }" t-attf-style="background-color: {{props.currentColorPreview}}" t-att-data-color="props.currentColorPreview"/> 12960 </div> 12961 <t t-foreach="Object.values(props.grayscales)" t-as="grayscaleColors" t-key="grayscaleColors"> 12962 <div class="o_colorpicker_section" t-on-click="props.onColorClick" t-on-mouseover="props.onColorPointerOver" t-on-mouseout="props.onColorPointerOut" t-on-focusin="props.onFocusin" t-on-focusout="props.onColorPointerOut"> 12963 <t t-foreach="grayscaleColors" t-as="color" t-key="color"> 12964 <button t-att-data-color="color" class="o_color_button o_color_picker_button btn p-0" t-att-class="{'selected': color === props.defaultColorSet and !props.currentColorPreview}" t-attf-style="background-color: var(--{{props.cssVarColorPrefix+color}})"/> 12965 </t> 12966 </div> 12967 </t> 12968 <CustomColorPicker selectedColor="props.currentCustomColor" setOnCloseCallback.bind="props.setOnCloseCallback" setOperationCallbacks.bind="props.setOperationCallbacks" onColorSelect.bind="(color) => this.props.applyColor(color.hex)" onColorPreview.bind="props.onColorPreview" noTransparency="props.noTransparency" defaultOpacity="props.defaultOpacity"/> 12969 </div> 12970</t> 12971`); 12972registerTemplate("web.ColorPickerSolidTab", `/web/static/src/core/color_picker/tabs/color_picker_solid_tab.xml`, `<t t-name="web.ColorPickerSolidTab" xml:space="preserve"> 12973 <div class="d-flex flex-column align-items-center p-1" t-on-click="props.onColorClick" t-on-mouseover="props.onColorPointerOver" t-on-mouseout="props.onColorPointerOut" t-on-focusin="props.onFocusin" t-on-focusout="props.onFocusout" t-ref="solidTabRef" t-on-keydown="props.colorPickerNavigation"> 12974 <div class="o_colorpicker_section"> 12975 <t t-foreach="props.defaultThemeColorVars" t-as="color" t-key="color"> 12976 <button t-att-data-color="color" t-att-class="{'selected': color === props.defaultColorSet}" t-att-style="\`background-color: var(--\${props.cssVarColorPrefix + color})\` + (color_index === 3 ? '; grid-column: 5' : '')" class="btn p-0 o_color_button o_color_picker_button"/> 12977 </t> 12978 </div> 12979 12980 <div class="o_color_section"> 12981 <t t-foreach="props.defaultColors" t-as="line" t-key="line_index"> 12982 <t t-foreach="line" t-as="color" t-key="color_index"> 12983 <button class="o_color_button o_color_picker_button btn p-0" t-att-class="{'selected': color === props.currentCustomColor.toUpperCase() and !props.defaultColorSet}" t-att-data-color="color" t-attf-style="background-color: {{color}}"/> 12984 </t> 12985 </t> 12986 </div> 12987 </div> 12988</t> 12989`); 12990registerTemplate("web.ColorList", `/web/static/src/core/colorlist/colorlist.xml`, `<t t-name="web.ColorList" xml:space="preserve"> 12991 <div class="o_colorlist d-grid gap-3 gap-md-2" aria-atomic="true" t-ref="colorlist"> 12992 <t t-if="!props.forceExpanded and !state.isExpanded"> 12993 <button t-on-click="onToggle" role="menuitem" t-att-title="colors[props.selectedColor]" t-att-data-color="props.selectedColor" t-att-aria-label="colors[props.selectedColor]" t-attf-class="border-0 rounded-circle o_colorlist_toggler o_colorlist_item_color_{{ props.selectedColor }}"/> 12994 </t> 12995 <t t-else="" t-foreach="props.colors" t-as="colorId" t-key="colorId"> 12996 <button t-on-click.prevent.stop="() => this.onColorSelected(colorId)" role="menuitem" t-att-title="colors[colorId]" t-att-data-color="colorId" t-att-aria-label="colors[colorId]" t-attf-class="border-0 rounded-circle o_colorlist_item_color_{{ colorId }} {{ colorId === props.selectedColor ? 'active' : '' }}"/> 12997 </t> 12998 </div> 12999 </t> 13000 13001`); 13002registerTemplate("web.DefaultFooter", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.DefaultFooter" owl="1" xml:space="preserve"> 13003 <span>
13004 <span class="fw-bolder text-primary">TIP</span> â search for 13005 <t t-foreach="elements" t-as="element" t-key="element.namespace"> 13006 <t t-if="!(element_first || element_last)">, </t> 13007 <t t-if="element_last and !element_first"> and </t> 13008 <span class="o_namespace btn-link text-primary cursor-pointer" t-on-click="() => this.onClick(element.namespace)"> 13009 <span t-out="element.namespace" class="fw-bolder text-primary"/><t t-out="element.name"/> 13010 </span> 13011 </t> 13012 </span> 13013 </t> 13014 13015 `); 13016registerTemplate("web.DefaultCommandItem", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.DefaultCommandItem" xml:space="preserve"> 13017 <div class="o_command_default d-flex align-items-center justify-content-between px-4 py-2 cursor-pointer"> 13018 <t t-slot="name"/> 13019 <t t-slot="focusMessage"/> 13020 </div> 13021 </t> 13022 13023 `); 13024registerTemplate("web.HotkeyCommandItem", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.HotkeyCommandItem" xml:space="preserve"> 13025 <div class="o_command_hotkey d-flex align-items-center justify-content-between px-4 py-2 cursor-pointer"> 13026 <t t-slot="name"/> 13027 <span> 13028 <t t-foreach="getKeysToPress(props)" t-as="key" t-key="key_index"> 13029 <kbd t-out="key" class="d-inline-block px-3 py-1"/> 13030 <span t-if="!key_last"> + </span> 13031 </t> 13032 </span> 13033 </div> 13034 </t> 13035 13036`); 13037registerTemplate("web.CommandPalette", `/web/static/src/core/commands/command_palette.xml`, `<t t-name="web.CommandPalette" xml:space="preserve"> 13038 <Dialog header="false" footer="false" size="'md'" contentClass="'o_command_palette'"> 13039 <div t-ref="root"> 13040 <div class="o_command_palette_search input-group mb-2 px-4 py-3 border-bottom"> 13041 <span t-if="state.namespace !== 'default'" class="o_namespace d-flex align-items-center me-1 fs-4 text-muted opacity-75" t-out="state.namespace"/> 13042 <input class="form-control border-0 p-0" type="text" data-allow-hotkeys="true" t-att-value="state.searchValue" t-ref="autofocus" t-att-placeholder="state.placeholder" t-on-input="onSearchInput" t-on-keydown="onKeyDown" role="combobox" t-attf-aria-activedescendant="o_command_{{state.commands.length ? state.commands.indexOf(state.selectedCommand) : 'empty'}}" aria-expanded="true" aria-autocomplete="list" aria-haspopup="listbox"/> 13043 <div class="input-group-text border-0 bg-transparent"> 13044 <i t-if="state.isLoading" title="Loading..." role="img" aria-label="Loading..." class="fa fa-circle-o-notch fa-spin"/> 13045 <i t-else="" t-att-title="state.placeholder" role="img" t-att-aria-label="state.placeholder" class="oi oi-search"/> 13046 </div> 13047 </div> 13048 13049 <div t-ref="listbox" role="listbox" class="o_command_palette_listbox position-relative overflow-auto"> 13050 <div t-if="!state.commands.length" id="o_command_empty" role="option" aria-selected="true" class="o_command_palette_listbox_empty px-4 py-3 fst-italic" t-out="state.emptyMessage"/> 13051 <t t-if="!isFuzzySearch" t-foreach="commandsByCategory" t-as="category" t-key="category.keyId"> 13052 <div class="o_command_category px-0"> 13053 <span t-if="category.name" class="text-uppercase fw-bold px-3 text-muted smaller opacity-50" t-out="category.name"/> 13054 <t t-foreach="category.commands" t-as="command" t-key="command.keyId"> 13055 <t t-set="commandIndex" t-value="state.commands.indexOf(command)"/> 13056 <div t-attf-id="o_command_{{commandIndex}}" class="o_command" role="option" t-att-aria-selected="state.selectedCommand === command ? 'true' : 'false'" t-att-class="{ focused: state.selectedCommand === command }" t-on-click="(event) => this.onCommandClicked(event, commandIndex)" t-on-mouseenter="() => this.onCommandMouseEnter(commandIndex)" t-on-close="() => this.props.closeMe()"> 13057 <a t-att-href="command.href" t-att-class="command.className"> 13058 <t t-component="command.Component || DefaultCommandItem" name="command.name" searchValue="state.searchValue" t-props="command.props" executeCommand="() => this.executeCommand(command)"> 13059 <t t-set-slot="name">
13060 <span class="o_command_name text-ellipsis" t-att-title="command.name" t-out="command.text"/> 13061 </t> 13062 <t t-set-slot="focusMessage"> 13063 <small t-if="!isMobileOS and command.href and state.selectedCommand === command" class="o_command_focus text-muted"><kbd><t t-if="isMacOS">CMD</t><t t-else="">CTRL</t></kbd>+<kbd>â</kbd><span class="ms-1">new tab</span></small> 13064 </t> 13065 </t> 13066 </a> 13067 </div> 13068 </t> 13069 </div> 13070 13071 <hr class="my-2 mx-0" t-if="!category_last"/> 13072 </t> 13073 </div> 13074 13075 <div t-if="state.FooterComponent" class="o_command_palette_footer mt-2 px-4 py-2 border-top rounded-bottom bg-100 text-muted"> 13076 <t t-component="state.FooterComponent" switchNamespace="(namespace) => this.debounceSearch(namespace.concat(this.state.searchValue))"/> 13077 </div> 13078 </div> 13079 </Dialog> 13080 </t> 13081 13082`); 13083registerTemplate("web.ConfirmationDialog", `/web/static/src/core/confirmation_dialog/confirmation_dialog.xml`, `<t t-name="web.ConfirmationDialog" xml:space="preserve"> 13084 <Dialog size="'md'" title="props.title" modalRef="modalRef"> 13085 <p t-out="props.body" class="text-prewrap"/> 13086 <t t-set-slot="footer"> 13087 <button class="btn" t-att-class="props.confirmClass" t-on-click="_confirm" t-esc="props.confirmLabel" data-hotkey="q"/> 13088 <button t-if="props.cancel" class="btn btn-secondary" t-on-click="_cancel" t-esc="props.cancelLabel" data-hotkey="x"/> 13089 </t> 13090 </Dialog> 13091 </t> 13092 13093 `); 13094registerTemplate("web.AlertDialog", `/web/static/src/core/confirmation_dialog/confirmation_dialog.xml`, `<t t-name="web.AlertDialog" xml:space="preserve"> 13095 <Dialog size="'sm'" title="props.title" contentClass="props.contentClass"> 13096 <p t-out="props.body" class="text-prewrap"/> 13097 <t t-set-slot="footer"> 13098 <button class="btn" t-att-class="props.confirmClass" t-on-click="_confirm" t-esc="props.confirmLabel"/> 13099 <button t-if="props.cancel" class="btn btn-secondary" t-on-click="_cancel" t-esc="props.cancelLabel"/> 13100 </t> 13101 </Dialog> 13102 </t> 13103 13104`); 13105registerTemplate("web.CopyButton", `/web/static/src/core/copy_button/copy_button.xml`, `<t t-name="web.CopyButton" xml:space="preserve"> 13106 <button type="button" class="text-nowrap" t-ref="button" t-att-disabled="props.disabled" t-attf-class="btn o_clipboard_button {{ props.className || '' }}" t-on-click.stop="onClick"> 13107 <span class="mx-1" t-attf-class="fa {{ props.icon || 'fa-clipboard' }}"/> 13108 <span t-if="props.copyText" t-esc="props.copyText"/> 13109 </button> 13110 </t> 13111 13112`); 13113registerTemplate("web.DateTimeInput", `/web/static/src/core/datetime/datetime_input.xml`, `<t t-name="web.DateTimeInput" xml:space="preserve"> 13114 <input type="text" t-ref="start-date" t-att-id="props.id" class="o_datetime_input o_input cursor-pointer" t-att-class="props.class" autocomplete="off" t-att-placeholder="props.placeholder" t-att-disabled="props.disabled"/> 13115 </t> 13116`); 13117registerTemplate("web.DateTimePicker.Days", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Days" xml:space="preserve"> 13118 <div class="d-flex gap-3"> 13119 <t t-foreach="items" t-as="month" t-key="month.id"> 13120 <div class="o_date_picker d-grid flex-grow-1 rounded overflow-auto" t-on-pointerleave="() => (state.hoveredDate = null)"> 13121 <t t-foreach="month.daysOfWeek" t-as="dayOfWeek" t-key="dayOfWeek[0]"> 13122 <div class="o_day_of_week_cell fw-bolder d-flex align-items-center justify-content-center" t-att-title="dayOfWeek[1]"> 13123 <div class="text-nowrap overflow-hidden" t-esc="props.daysOfWeekFormat === 'narrow' ? dayOfWeek[2] : dayOfWeek[0]"/> 13124 </div> 13125 </t> 13126 <t t-foreach="month.weeks" t-as="week" t-key="week.number"> 13127 <t t-if="props.showWeekNumbers"> 13128 <div class="o_week_number_cell d-flex justify-content-end align-items-center pe-3 fw-bolder" t-esc="week.number"/> 13129 </t> 13130 <t t-foreach="week.days" t-as="itemInfo" t-key="itemInfo.id"> 13131 <t t-set="arInfo" t-value="getActiveRangeInfo(itemInfo)"/> 13132 <div class="o_date_item_cell o_datetime_button o_center" t-att-class="{ 'o_out_of_range text-muted': itemInfo.isOutOfRange, o_selected: arInfo.isSelected, o_select_start: arInfo.isSelectStart, o_select_end: arInfo.isSelectEnd, o_highlighted: arInfo.isHighlighted, 'o_today fw-bolder': itemInfo.includesToday, [itemInfo.extraClass]: true, 'opacity-50': !itemInfo.isValid, 'cursor-pointer': itemInfo.isValid, }
13132" t-att-disabled="!itemInfo.isValid" t-on-pointerenter="() => (state.hoveredDate = itemInfo.range[0])" t-on-click="() => this.zoomOrSelect(itemInfo)"> 13133 <div t-att-class="{'w-75 align-content-center text-center rounded-circle': itemInfo.includesToday}"> 13134 <t t-esc="itemInfo.label"/> 13135 </div> 13136 </div> 13137 </t> 13138 </t> 13139 </div> 13140 </t> 13141 </div> 13142 <div t-if="props.type === 'datetime'" class="d-flex gap-3 justify-content-between"> 13143 <div class="d-flex gap-1 align-items-center"> 13144 <TimePicker t-if="state.timeValues[0]" value="state.timeValues[0]" onChange="(newTime) => this.onTimeChange(0, newTime)" minutesRounding="props.rounding" showSeconds="props.rounding === 0" inputCssClass="'o_input'"/> 13145 <i t-if="state.timeValues[0] and state.timeValues[1]" class="fa fa-long-arrow-right"/> 13146 <TimePicker t-if="state.timeValues[1]" value="state.timeValues[1]" onChange="(newTime) => this.onTimeChange(1, newTime)" minutesRounding="props.rounding" showSeconds="props.rounding === 0" inputCssClass="'o_input'"/> 13147 </div> 13148 <t t-slot="buttons"/> 13149 </div> 13150 </t> 13151 13152 `); 13153registerTemplate("web.DateTimePicker.Grid", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Grid" xml:space="preserve"> 13154 <div class="o_date_item_picker d-grid"> 13155 <t t-foreach="items" t-as="itemInfo" t-key="itemInfo.id"> 13156 <t t-set="arInfo" t-value="getActiveRangeInfo(itemInfo)"/> 13157 <div class="o_date_item_cell o_datetime_button o_center cursor-pointer" t-att-class="{ o_selected: arInfo.isSelected, o_select_start: arInfo.isSelectStart, o_select_end: arInfo.isSelectEnd, o_highlighted: arInfo.isHighlighted, o_today: itemInfo.includesToday, 'opacity-50': !itemInfo.isValid, }" t-att-disabled="!itemInfo.isValid" t-on-click="() => this.zoomOrSelect(itemInfo)"> 13158 <t t-esc="itemInfo.label"/> 13159 </div> 13160 </t> 13161 </div> 13162 </t> 13163 13164 `); 13165registerTemplate("web.DateTimePicker", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker" xml:space="preserve"> 13166 <div class="o_datetime_picker d-flex flex-column gap-2 user-select-none p-2" t-attf-style="--DateTimePicker__Day-template-columns: {{ props.showWeekNumbers ? 8 : 7 }}"> 13167 <nav class="o_datetime_picker_header d-flex"> 13168 <button class="o_previous btn btn-sm opacity-75 opacity-100-hover" t-on-click="previous" tabindex="-1"> 13169 <i class="oi oi-chevron-left" t-att-title="activePrecisionLevel.prevTitle"/> 13170 </button> 13171 <button class="o_next btn btn-sm opacity-75 opacity-100-hover" t-on-click="next" tabindex="-1"> 13172 <i class="oi oi-chevron-right" t-att-title="activePrecisionLevel.nextTitle"/> 13173 </button> 13174 <button class="o_zoom_out o_datetime_button btn opacity-75 opacity-100-hover text-truncate" tabindex="-1" t-att-class="{ 'disabled': isLastPrecisionLevel }" t-att-title="!isLastPrecisionLevel and activePrecisionLevel.mainTitle" t-on-click="zoomOut"> 13175 <t t-foreach="titles" t-as="title" t-key="title"> 13176 <strong class="o_header_part" t-esc="title"/> 13177 </t> 13178 </button> 13179 <button t-if="props.showRangeToggler" class="o_toggle_range btn btn-secondary btn-sm ms-auto" tabindex="-1" title="Toggle date range mode" t-on-click="props.onToggleRange" t-att-class="{'active': props.range}"> 13180 <i class="fa fa-calendar-plus-o"/> 13181 </button> 13182 </nav> 13183 <t t-if="state.precision === 'days'"> 13184 <t t-call="web.DateTimePicker.Days"/> 13185 </t> 13186 <t t-else=""> 13187 <t t-call="web.DateTimePicker.Grid"/> 13188 </t> 13189 </div> 13190 </t> 13191`); 13192registerTemplate("web.DateTimePickerPopover", `/web/static/src/core/datetime/datetime_picker_popover.xml`, `<t t-name="web.DateTimePickerPopover" xml:space="preserve">
13193 <DateTimePicker t-props="props.pickerProps"> 13194 <t t-set-slot="buttons"> 13195 <div class="o_datetime_buttons d-flex gap-2"> 13196 <button class="btn btn-sm btn-secondary" title="Clear" tabindex="-1" t-on-click="props.pickerProps.onReset"> 13197 <i class="fa fa-eraser"/> 13198 </button> 13199 <button class="btn btn-sm btn-primary" tabindex="-1" t-on-click="props.close"> 13200 <span>Apply</span> 13201 </button> 13202 </div> 13203 </t> 13204 </DateTimePicker> 13205 </t> 13206`); 13207registerTemplate("web.DebugMenu", `/web/static/src/core/debug/debug_menu.xml`, `<t t-name="web.DebugMenu" xml:space="preserve"> 13208 <div class="o_debug_manager"> 13209 <Dropdown beforeOpen.bind="loadGroupedItems" position="'bottom-end'"> 13210 <button t-att-class="\`o-dropdown--narrow \${env.inDialog?'btn btn-link':''}\`"> 13211 <i class="fa fa-bug" role="img" aria-label="Open developer tools"/> 13212 </button> 13213 <t t-set-slot="content"> 13214 <t t-foreach="sectionEntries" t-as="entry" t-key="entry[0]"> 13215 <div class="dropdown-menu_group dropdown-header"> 13216 <t t-esc="getSectionLabel(entry[0])"/> 13217 </div> 13218 <t t-foreach="entry[1]" t-as="element" t-key="element_index"> 13219 <DropdownItem t-if="element.type == 'item'" onSelected="element.callback" attrs="{ href: element.href }"> 13220 <span t-att-class="entry[0] and 'ps-3'" t-esc="element.description"/> 13221 </DropdownItem> 13222 <t t-if="element.type == 'component'" t-component="element.Component" t-props="element.props"/> 13223 </t> 13224 </t> 13225 </t> 13226 </Dropdown> 13227 </div> 13228 </t> 13229 13230`); 13231registerTemplate("web.DebugMenu.SetDefaultDialog", `/web/static/src/core/debug/debug_menu_items.xml`, `<t t-name="web.DebugMenu.SetDefaultDialog" xml:space="preserve"> 13232 <Dialog title.translate="Set Default Values"> 13233 <table style="width: 100%"> 13234 <tr> 13235 <td> 13236 <label for="formview_default_fields" class="oe_label oe_align_right"> 13237 Default: 13238 </label> 13239 </td> 13240 <td class="oe_form_required"> 13241 <select id="formview_default_fields" class="o_input" t-model="state.fieldToSet"> 13242 <option value=""/> 13243 <option t-foreach="defaultFields" t-as="field" t-att-value="field.name" t-key="field.name"> 13244 <t t-esc="field.string"/> = <t t-esc="field.displayed"/> 13245 </option> 13246 </select> 13247 </td> 13248 </tr> 13249 <tr t-if="conditions.length"> 13250 <td> 13251 <label for="formview_default_conditions" class="oe_label oe_align_right"> 13252 Condition: 13253 </label> 13254 </td> 13255 <td> 13256 <select id="formview_default_conditions" class="o_input" t-model="state.condition"> 13257 <option value=""/> 13258 <option t-foreach="conditions" t-as="cond" t-att-value="cond.name + '=' + cond.value" t-key="cond.name"> 13259 <t t-esc="cond.string"/>=<t t-esc="cond.displayed"/> 13260 </option> 13261 </select> 13262 </td> 13263 </tr> 13264 <tr> 13265 <td colspan="2"> 13266 <input type="radio" id="formview_default_self" value="self" name="scope" t-model="state.scope"/> 13267 <label for="formview_default_self" class="oe_label" style="display: inline;"> 13268 Only you 13269 </label> 13270 <br/> 13271 <input type="radio" id="formview_default_all" value="all" name="scope" t-model="state.scope"/> 13272 <label for="formview_default_all" class="oe_label" style="display: inline;"> 13273 All users 13274 </label> 13275 </td> 13276 </tr> 13277 </table> 13278 <t t-set-slot="footer"> 13279 <button class="btn btn-secondary" t-on-click="props.close">Close</button> 13280 <button class="btn btn-secondary" t-on-click="saveDefault">Save default</button> 13281 </t> 13282 </Dialog> 13283 </t> 13284 13285 `); 13286registerTemplate("web.DebugMenu.GetMetadataDialog", `/web/static/src/core/debug/debug_menu_items.xml`, `<t t-name="web.DebugMenu.GetMetadataDialog" xml:space="preserve"> 13287 <Dialog title.translate="Metadata"> 13288 <table class="table table-sm table-striped"> 13289 <tr> 13290 <th>ID:</th> 13291 <td><t t-esc="state.id"/></td> 13292 </tr> 13293 <tr> 13294 <th>XML ID:</th> 13295 <td> 13296 <t t-if="state.xmlids.length > 1"> 13297 <t t-foreach="state.xmlids" t-as="imd" t-key="imd['xmlid']"> 13298 <div t-att-class=""p-0 " + (imd["xmlid"] === state.xmlid ? "fw-bolder " : "") + (imd["noupdate"] === true ? "fst-italic " : "")" t-esc="imd['xmlid']"/> 13299 </t> 13300 </t> 13301 <t t-elif="state.xmlid" t-esc="state.xmlid"/> 13302 <t t-else=""> 13303 / <a t-on-click="onClickCreateXmlid"> (create)</a> 13304 </t> 13305 </td> 13306 </tr> 13307 <tr> 13308 <th>No Update:</th> 13309 <td> 13310 <t t-esc="state.noupdate"/> 13311 <t t-if="state.xmlid"> 13312 <a t-on-click="toggleNoupdate"> (change)</a> 13313 </t> 13314 </td> 13315 </tr> 13316 <tr> 13317 <th>Creation User:</th> 13318 <td><t t-esc="state.creator"/></td> 13319 </tr> 13320 <tr> 13321 <th>Creation Date:</th> 13322 <td><t t-esc="state.createDate"/></td> 13323 </tr> 13324 <tr> 13325 <th>Latest Modification by:</th> 13326 <td><t t-esc="state.lastModifiedBy"/></td> 13327 </tr> 13328 <tr> 13329 <th>Latest Modification Date:</th> 13330 <td><t t-esc="state.writeDate"/></td> 13331 </tr> 13332 </table> 13333 </Dialog> 13334 </t> 13335 13336 `); 13337registerTemplate("web.DebugMenu.GetViewDialog", `/web/static/src/core/debug/debug_menu_items.xml`, `<t t-name="web.DebugMenu.GetViewDialog" xml:space="preserve"> 13338 <Dialog title.translate="Computed Arch"> 13339 <pre t-esc="props.arch"/> 13340 <t t-set-slot="footer"> 13341 <button class="btn btn-primary" t-on-click="() => props.close()">Close</button>
13342 <CopyButton className="'btn-secondary'" copyText.translate="Copy Arch" successText.translate="Copied" content="props.arch"/> 13343 </t> 13344 </Dialog> 13345 </t> 13346`); 13347registerTemplate("web.Dialog", `/web/static/src/core/dialog/dialog.xml`, `<t t-name="web.Dialog" xml:space="preserve"> 13348 <div class="o_dialog" t-att-id="id" t-att-class="{ o_inactive_modal: !data.isActive }"> 13349 <div role="dialog" class="modal d-block" tabindex="-1" t-att-class="{ o_technical_modal: props.technical, o_modal_full: isFullscreen, o_inactive_modal: !data.isActive }" t-ref="modalRef"> 13350 <div class="modal-dialog modal-dialog-centered" t-attf-class="modal-{{props.size}}"> 13351 <div class="modal-content" t-att-class="props.contentClass" t-att-style="contentStyle"> 13352 <header t-if="props.header" class="modal-header"> 13353 <t t-slot="header" close="data.close" isFullscreen="isFullscreen"> 13354 <t t-call="web.Dialog.header"> 13355 <t t-set="fullscreen" t-value="isFullscreen"/> 13356 <t t-set="onExpand" t-value="props.onExpand"/> 13357 </t> 13358 </t> 13359 </header> 13360 <main class="modal-body" t-attf-class="{{ props.bodyClass }} {{ !props.withBodyPadding ? 'p-0': '' }}" t-att-tabindex="this.bodyTabIndex"> 13361 <t t-slot="default" close="() => this.data.close()"/> 13362 </main> 13363 <footer t-if="props.footer" class="modal-footer d-empty-none justify-content-around justify-content-md-start flex-wrap gap-1 w-100"> 13364 <t t-slot="footer" close="() => this.data.close()"/> 13365 </footer> 13366 </div> 13367 </div> 13368 </div> 13369 </div> 13370 </t> 13371 13372 `); 13373registerTemplate("web.Dialog.header", `/web/static/src/core/dialog/dialog.xml`, `<t t-name="web.Dialog.header" xml:space="preserve"> 13374 <t t-if="fullscreen"> 13375 <button class="btn oi oi-arrow-left" aria-label="Close" tabindex="-1" t-on-click="dismiss"/> 13376 </t> 13377 <h4 class="modal-title text-break flex-grow-1" t-att-class="{ 'me-auto': fullscreen }"> 13378 <t t-esc="props.title"/> 13379 </h4> 13380 <t t-if="onExpand"> 13381 <button type="button" class="fa fa-expand btn opacity-75 opacity-100-hover o_expand_button" aria-label="Expand" tabindex="-1" t-on-click="onExpand"/> 13382 </t> 13383 <t t-if="!fullscreen"> 13384 <button type="button" class="btn-close" aria-label="Close" tabindex="-1" t-on-click="dismiss"/> 13385 </t> 13386 </t> 13387`); 13388registerTemplate("web.DomainSelector", `/web/static/src/core/domain_selector/domain_selector.xml`, `<t t-name="web.DomainSelector" xml:space="preserve"> 13389 <div class="o_domain_selector w-100" aria-atomic="true" t-att-class="props.className"> 13390 <t t-if="tree"> 13391 <TreeEditor resModel="props.resModel" tree="tree" update.bind="update" readonly="props.readonly" isDebugMode="props.isDebugMode" defaultConnector="props.defaultConnector" getDefaultCondition.bind="getDefaultCondition" getOperatorEditorInfo.bind="getOperatorEditorInfo" getDefaultOperator.bind="getDefaultOperator" getPathEditorInfo.bind="getPathEditorInfo"> 13392 <CheckBox t-if="showArchivedCheckbox" value="includeArchived" disabled="props.readonly" className="'form-switch'" onChange.bind="toggleIncludeArchived"> 13393 Include archived 13394 </CheckBox> 13395 </TreeEditor> 13396 </t> 13397 <t t-else=""> 13398 <div class="o_domain_selector_row d-flex align-items-center"> 13399 This domain is not supported. 13400 <t t-if="!props.readonly"> 13401 <button class="btn btn-sm btn-primary ms-2" t-on-click="() => this.resetDomain()">Reset domain</button> 13402 </t> 13403 </div> 13404 </t> 13405 <t t-if="props.isDebugMode and (!tree or !props.readonly)"> 13406 <label class="o_domain_selector_debug_container d-block mt-3 border rounded p-3 bg-100 text-muted font-monospace">
13407 <span class="small"># Code editor</span> 13408 <textarea class="pt-2 border-0 bg-transparent text-body" type="text" t-att-readonly="props.readonly" spellcheck="false" t-att-value="props.domain" t-on-input="(ev) => this.onDomainInput(ev.target.value)" t-on-change="(ev) => this.onDomainChange(ev.target.value)"/> 13409 </label> 13410 </t> 13411 </div> 13412 </t> 13413 13414`); 13415registerTemplate("web.DomainSelectorDialog", `/web/static/src/core/domain_selector_dialog/domain_selector_dialog.xml`, `<t t-name="web.DomainSelectorDialog" xml:space="preserve"> 13416 <Dialog title="dialogTitle" size="'xl'"> 13417 <div t-if="props.text" class="mb-3" t-out="props.text"/> 13418 <DomainSelector t-props="domainSelectorProps"/> 13419 <t t-set-slot="footer"> 13420 <t t-if="props.readonly"> 13421 <button class="btn btn-secondary" t-on-click="() => props.close()">Close</button> 13422 </t> 13423 <t t-else=""> 13424 <button class="btn btn-primary" t-att-disabled="disabled" t-on-click="onConfirm" t-ref="confirm"><t t-esc="confirmButtonText"/></button> 13425 <button class="btn btn-secondary" t-on-click="onDiscard"><t t-esc="discardButtonText"/></button> 13426 </t> 13427 </t> 13428 </Dialog> 13429 </t> 13430 13431`); 13432registerTemplate("web.AccordionItem", `/web/static/src/core/dropdown/accordion_item.xml`, `<t t-name="web.AccordionItem" xml:space="preserve"> 13433 <div class="o_accordion position-relative"> 13434 <button class="o_menu_item o_accordion_toggle dropdown-item o-navigable" tabindex="0" t-att-class="{'selected': props.selected, 'open': state.open}" t-attf-class="{{ props.class }}" t-att-aria-expanded="state.open ? 'true' : 'false'" t-esc="props.description" t-on-click="() => state.open = !state.open"/> 13435 <t t-if="state.open"> 13436 <div class="o_accordion_values ms-4 border-start"> 13437 <t t-slot="default"/> 13438 </div> 13439 </t> 13440 </div> 13441 </t> 13442 13443`); 13444registerTemplate("web.DropdownItem", `/web/static/src/core/dropdown/dropdown_item.xml`, `<t t-name="web.DropdownItem" xml:space="preserve"> 13445 <t t-tag="props.tag ?? (props.attrs and props.attrs.href ? 'a' : 'span')" class="o-dropdown-item dropdown-item o-navigable" t-att-class="props.class" t-on-click.stop="onClick" t-on-mouseenter="() => this.dropdownControl.closeChildren()" role="menuitem" tabindex="0" t-att="props.attrs"> 13446 <t t-slot="default"/> 13447 </t> 13448 </t> 13449 13450 13451 `); 13452registerTemplate("web.CheckboxItem", `/web/static/src/core/dropdown/dropdown_item.xml`, `<t t-name="web.CheckboxItem" t-inherit="web.DropdownItem" t-inherit-mode="primary" xml:space="preserve"> 13453 <xpath expr="//t[@role='menuitem']" position="attributes"> 13454 <attribute name="role">menuitemcheckbox</attribute> 13455 <attribute name="t-att-aria-checked">props.checked ? 'true' : 'false'</attribute> 13456 </xpath> 13457 </t> 13458 13459`); 13460registerTemplate("web.Dropzone", `/web/static/src/core/dropzone/dropzone.xml`, `<t t-name="web.Dropzone" xml:space="preserve"> 13461 <div class="o-Dropzone position-fixed align-items-center justify-content-center d-flex border-primary bg-100 text-primary opacity-75" t-att-class="{ 'o-dragging-inside': state.isDraggingInside }" t-attf-class="{{ props.extraClass }}" t-on-dragenter="() => state.isDraggingInside = true" t-on-dragleave="() => state.isDraggingInside = false" t-on-drop="props.onDrop" t-ref="root"> 13462 <t t-slot="default"> 13463 <h4>Drag Files Here <i class="fa fa-download"/></h4> 13464 </t> 13465 </div> 13466</t> 13467 13468`); 13469registerTemplate("web.RainbowMan", `/web/static/src/core/effects/rainbow_man.xml`, `<t t-name="web.RainbowMan" xml:space="preserve"> 13470 <div class="o_reward position-fixed top-0 start-0 w-100 h-100" t-att-class="{ o_reward_fading: state.isFading }" t-on-animationend="onAnimationEnd"> 13471 <svg class="o_reward_rainbow_man position-absolute top-0 bottom-0 start-0 end-0 m-auto overflow-visible" viewBox="0 0 400 400"> 13472 <defs> 13473 <radialGradient id="o_reward_gradient_bg" cx="200" cy="200" r="200" gradientUnits="userSpaceOnUse"> 13474 <stop offset="0.3" stop-color="#edeff4"/> 13475 <stop offset="1" stop-color="#edeff4" stop-opacity="0"/> 13476 </radialGradient> 13477 <symbol id="o_reward_star"> 13478 <path d="M33 15.9C26.3558 13.6951 21.1575 8.4597 19 1.8 19 1.2477 18.5523.8 18 .8 17.4477.8 17 1.2477 17 1.8 14.6431 8.6938 9.0262 13.9736 2 15.9 1.3649 15.9.85 16.4149.85 17.05.85 17.6851 1.3649 18.2 2 18.2 8.6215 20.3845 13.8155 25.5785 16 32.2 16 32.7523 16.4477 33.2 17 33.2 17.5523 33.2 18 32.7523 18 32.2 20.3569 25.3062 25.9738 20.0264 33 18.1 33.6351 18.1 34.15 17.5851 34.15 16.95 34.15 16.3149 33.6351 15.8 33 15.8" fill="#FFFFFF"/> 13479 </symbol> 13480 <symbol id="o_reward_thumb"> 13481 <path d="M10 52C6 51 3 48 3 44 2 42 3 39 5 38 3 36 2 34 2 32 2 29 3 27 5 26 3 24 2 21 2 19 2 15 7 12 10 12L23 12C23 11 23 11 23 11L23 10C23 8 24 6 25 4 27 2 29 2 31 2 33 2 35 2 36 4 38 5 39 7 39 10L39 38C39 41 37 45 35 47 32 50 28 51 25 52L10 52 10 52Z" fill="#FBFBFC"/> 13482 <polygon fill="#ECF1FF" points="25 11 25 51 5 52 5 12"/> 13483 <path d="M31 0C28 0 26 1 24 3 22 5 21 7 21 10L10 10C8 10 6 11 4 12 2 14 1 16 1 19 1 21 1 24 2 26 1 27 1 29 1 32 1 34 1 36 2 38 1 40 0 42 1 45 1 50 5 53 10 54L25 54C29 54 33 52 36 49 39 46 41 42 41 38L41 10C41 4 36 0 31 0M31 4C34 4 37 6 37 10L37 38C37 41 35 44 33 46 31 48 28 49 25 50L10 50C7 49 5 47 5 44 4 41 6 38 9 37L9 37C6 37 5 35 5 32 5 28 6 26 9 26L9 26C6 26 5 22 5 19 5 16 8 14 11 14L23 14C24 14 25 12 25 11L25 10C25 7 28 4 31 4" fill="#A1ACBA"/> 13484 </symbol> 13485 </defs> 13486 <rect width="400" height="400" fill="url(#o_reward_gradient_bg)"/> 13487 <g transform="translate(47 45) scale(0.9)" class="o_reward_rainbow"> 13488 <path d="M270,170a100,100,0,0,0-200,0" class="o_reward_rainbow_line" stroke="#FF9E80" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/> 13489 <path d="M290,170a120,120,0,0,0-240,0" class="o_reward_rainbow_line" stroke="#FFE57F" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/> 13490 <path d="M310,170a140,140,0,0,0-280,0" class="o_reward_rainbow_line" stroke="#80D8FF" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/> 13491 <path d="M330,170a160,160,0,0,0-320,0" class="o_reward_rainbow_line" stroke="#C794BA" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/> 13492 </g> 13493 <g transform="translate(80 125)"> 13494 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_01"/> 13495 </g> 13496 <g transform="translate(140 75)"> 13497 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_02"/> 13498 </g> 13499 <g transform="translate(230 90)"> 13500 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_03"/> 13501 </g> 13502 <g transform="translate(275 120)"> 13503 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_04"/> 13504 </g> 13505 <g class="o_reward_face_group o_reward_box" transform-origin="center top"> 13506 <g class="o_reward_shadow_container o_reward_box"> 13507 <ellipse class="o_reward_shadow o_reward_box" cx="200" cy="105%" rx="100" ry="6" fill="#000" opacity="0.25" transform-origin="center"/> 13508 </g> 13509 <g class="o_reward_face_wrap o_reward_box" transform-origin="center"> 13510 <image class="o_reward_face" x="132" y="125" width="136" height="136" t-attf-href="{{props.imgUrl}}"/> 13511 </g> 13512 <g transform="translate(258 174)"> 13513 <use href="#o_reward_thumb" class="o_reward_box o_reward_thumbup" transform-origin="center"/> 13514 </g> 13515 </g> 13516 </svg> 13517 <div class="o_reward_rainbow_man o_reward_msg_container position-absolute top-0 bottom-0 start-0 end-0 m-auto"> 13518 <div class="o_reward_face_group h-100 w-75 mx-auto"> 13519 <svg viewBox="0 0 42 60" preserveAspectRatio="xMinYMax meet" width="37" height="65%" class="overflow-visible position-relative ms-5"> 13520 <g class="o_reward_box"> 13521 <use href="#o_reward_thumb" x="-60%" y="0" transform="rotate(-90) scale(1 -1)" transform-origin="center"/> 13522 </g> 13523 </svg> 13524 <div class="o_reward_msg mx-4"> 13525 <div class="o_reward_msg_card"> 13526 <div class="o_reward_msg_content text-muted px-3 py-4 bg-view d-inline-block border border-light border-top-0"> 13527 <t t-if="!props.Component"> 13528 <t t-out="props.message"/> 13529 </t> 13530 <t t-else="" t-component="props.Component" t-props="props.props"/> 13531 </div> 13532 </div> 13533 </div> 13534 </div> 13535 </div> 13536 </div> 13537 </t> 13538`); 13539registerTemplate("web.EmojiPicker", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker" xml:space="preserve"> 13540 <div class="o-EmojiPicker bg-100 d-flex flex-column justify-content-center rounded-3" t-att-class="{ 'align-items-center': emojis.length === 0, 'h-100': props.mobile }" t-attf-class="{{props.class}}" t-on-click="onClick" t-on-keydown="onKeydown"> 13541 <t t-if="emojis.length === 0">
13542 <span class="o-EmojiPicker-empty">ðµâð«</span> 13543 <span class="fs-5 text-muted">Failed to load emojis...</span> 13544 </t> 13545 <t t-else=""> 13546 <div class="o-EmojiPicker-search d-flex align-items-center mx-2 mt-2 rounded"> 13547 <span class="o-EmojiPicker-searchContour d-flex mx-1 w-100 rounded o-active align-items-center justify-content-center border border-secondary bg-view"> 13548 <t t-call="web.EmojiPicker.searchInput"> 13549 <t t-if="props.state" t-set="localState" t-value="props.state"/> 13550 <t t-else="" t-set="localState" t-value="state"/> 13551 </t> 13552 <i class="oi oi-search px-2 py-1 fs-7 rounded-start-0 rounded-3 o-active opacity-50" title="Search..." role="img" aria-label="Search..."/> 13553 </span> 13554 </div> 13555 <t t-set="itemIndex" t-value="0"/> 13556 <t t-set="emojisFromSearch" t-value="getEmojisFromSearch()"/> 13557 <div class="o-EmojiPicker-content overflow-auto d-flex flex-grow-1 w-100 flex-wrap align-items-center user-select-none mt-1" t-att-class="emojisFromSearch.length === 0 ? 'flex-column justify-content-center' : 'align-content-start'" t-ref="emoji-grid" t-on-scroll="highlightActiveCategory"> 13558 <t t-if="searchTerm and emojisFromSearch.length === 0" class="d-flex flex-column"> 13559 <span class="o-EmojiPicker-empty">ð¢</span> 13560 <span class="fs-5 text-muted">No emojis match your search</span> 13561 </t> 13562 <t t-if="recentEmojis.length > 0"> 13563 <t t-if="!searchTerm" t-call="web.EmojiPicker.section"> 13564 <t t-set="category" t-value="recentCategory"/> 13565 </t> 13566 <t t-foreach="recentEmojis" t-as="emoji" t-key="'recent_' + emoji_index"> 13567 <t t-call="web.EmojiPicker.emoji"> 13568 <t t-set="inRecent" t-value="true"/> 13569 <t t-set="emoji" t-value="emoji"/> 13570 </t> 13571 <t t-set="itemIndex" t-value="itemIndex + 1"/> 13572 </t> 13573 </t> 13574 <t t-set="current" t-value=""/> 13575 <t t-foreach="getEmojis()" t-as="emoji" t-key="emoji_index"> 13576 <t t-if="!searchTerm and current !== emoji.category"> 13577 <t t-set="current" t-value="emoji.category"/> 13578 <t t-set="category" t-value="categories.find(c => c.name === current)"/> 13579 <t t-call="web.EmojiPicker.section"> 13580 <t t-set="category" t-value="category"/> 13581 </t> 13582 </t> 13583 <t t-elif="searchTerm" t-set="categorySortId" t-value="null"/> 13584 <t t-call="web.EmojiPicker.emoji"> 13585 <t t-set="emoji" t-value="emoji"/> 13586 </t> 13587 <t t-set="itemIndex" t-value="itemIndex + 1"/> 13588 </t> 13589 </div> 13590 <div class="o-EmojiPicker-navbar d-flex flex-shrink-0 w-100 align-items-center justify-content-center overflow-auto px-1 gap-1 border-top border-secondary" t-att-class="{ 'opacity-0': !state.emojiNavbarRepr }" t-ref="navbar"> 13591 <t t-if="currentNavbarPanel"> 13592 <t t-set="allCategories" t-value="getAllCategories()"/> 13593 <t t-foreach="currentNavbarPanel" t-as="navbarItemId" t-key="navbarItemId"> 13594 <t t-if="navbarItemId === 'next'" t-call="web.EmojiPicker.tabNext"/> 13595 <t t-elif="navbarItemId === 'previous'" t-call="web.EmojiPicker.tabPrev"/> 13596 <t t-elif="typeof navbarItemId === 'string' and navbarItemId.startsWith('empty')" t-call="web.EmojiPicker.tabEmpty"/> 13597 <t t-else=""> 13598 <t t-set="category" t-value="allCategories.find(cat => cat.sortId === navbarItemId)"/> 13599 <t t-if="category" t-call="web.EmojiPicker.tab"> 13600 <t t-set="category" t-value="category"/> 13601 </t> 13602 </t> 13603 </t> 13604 </t> 13605 </div> 13606 </t> 13607 </div> 13608</t> 13609 13610`); 13611registerTemplate("web.EmojiPicker.tab", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tab" xml:space="preserve"> 13612 <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch" t-att-class="{'o-active': category.sortId === state.categoryId}" t-att-title="category.name" t-att-data-id="category.sortId" t-on-click="() => this.selectCategory(category.sortId)">
13613 <span t-esc="category.title"/> 13614 </span> 13615</t> 13616 13617`); 13618registerTemplate("web.EmojiPicker.tabNext", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabNext" xml:space="preserve"> 13619 <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch" title="To previous categories" t-on-click="onClickToNextCategories"> 13620 <span class="position-relative"> 13621 <i class="oi oi-chevron-right fa-fw smaller opacity-0"/> 13622 <i class="oi oi-chevron-right fa-fw smaller position-absolute opacity-75" style="left: 3px; transform: translateY(75%);"/> 13623 <i class="oi oi-chevron-right fa-fw smaller position-absolute opacity-75" style="left: -3px; transform: translateY(75%);"/> 13624 </span> 13625 </span> 13626</t> 13627 13628`); 13629registerTemplate("web.EmojiPicker.tabPrev", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabPrev" xml:space="preserve"> 13630 <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch" title="To next categories" t-on-click="onClickToPreviousCategories"> 13631 <span class="position-relative"> 13632 <i class="oi oi-chevron-left fa-fw smaller opacity-0"/> 13633 <i class="oi oi-chevron-left fa-fw smaller position-absolute opacity-75" style="left: 3px; transform: translateY(75%);"/> 13634 <i class="oi oi-chevron-left fa-fw smaller position-absolute opacity-75" style="left: -3px; transform: translateY(75%);"/> 13635 </span> 13636 </span> 13637</t> 13638 13639`); 13640registerTemplate("web.EmojiPicker.tabEmpty", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabEmpty" xml:space="preserve"> 13641 <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch opacity-0"> 13642 <span>ð«¥</span> 13643 </span> 13644</t> 13645 13646`); 13647registerTemplate("web.EmojiPicker.section", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.section" xml:space="preserve"> 13648 <span class="w-100 fs-7 px-2 py-1 position-sticky top-0 bg-100 align-self-stretch" t-att-data-category="category.sortId"><span class="o-EmojiPicker-sectionIcon fs-5 opacity-50" t-esc="category.title"/><span class="ms-2 text-muted text-uppercase fs-7 opacity-50" t-esc="category.displayName"/></span> 13649 <span class="o-EmojiPicker-category opacity-100 fs-7 py-2" t-att-data-category="category.sortId"/> 13650</t> 13651 13652`); 13653registerTemplate("web.EmojiPicker.emoji", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.emoji" xml:space="preserve"> 13654 <span class="o-Emoji cursor-pointer d-flex justify-content-center rounded-3 align-items-center align-self-stretch" t-att-class="{ 'o-active': state.activeEmojiIndex === itemIndex, 'fs-2': !ui.isSmall, 'fs-1': ui.isSmall }" t-att-title="emoji.name" t-att-data-codepoints="emoji.codepoints" t-att-data-index="itemIndex" t-att-data-category="inRecent ? recentCategory.sortId : categories.find(c => c.name === emoji.category).sortId" t-on-click="selectEmoji" t-on-mouseenter="(ev) => this.onMouseenterEmoji(ev, emoji)" t-on-mouseleave="(ev) => this.onMouseleaveEmoji(ev, emoji)"> 13655 <span t-esc="emoji.codepoints"/> 13656 </span> 13657</t> 13658 13659`); 13660registerTemplate("web.EmojiPicker.searchInput", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.searchInput" xml:space="preserve"> 13661 <input class="form-control border-0 flex-grow-1 rounded-3 rounded-end-0 o-active lh-1" t-att-placeholder="placeholder" t-model="localState.searchTerm" t-ref="autofocus" t-att-model="localState.searchTerm" t-on-input="() => this.state.activeEmojiIndex = 0" t-att-tabindex="isMobileOS ? -1 : 0"/> 13662</t> 13663 13664`); 13665registerTemplate("web.WarningDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.WarningDialog" xml:space="preserve"> 13666 <Dialog title="title" size="'xl'" contentClass="'o_error_dialog'"> 13667 <div role="alert"> 13668 <p t-esc="message" class="text-prewrap"/> 13669 </div> 13670 <t t-set-slot="footer"> 13671 <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button> 13672 </t> 13673 </Dialog> 13674 </t> 13675 13676 `); 13677registerTemplate("web.RedirectWarningDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.RedirectWarningDialog" xml:space="preserve"> 13678 <Dialog title="title" size="'xl'" contentClass="'o_error_dialog'"> 13679 <div role="alert"> 13680 <p t-esc="message" class="text-prewrap"/> 13681 </div> 13682 <t t-set-slot="footer"> 13683 <button class="btn btn-primary" t-on-click="onClick" t-esc="buttonText"/> 13684 <button class="btn btn-secondary" t-on-click="props.close">Close</button> 13685 </t> 13686 </Dialog> 13687 </t> 13688 13689 `); 13690registerTemplate("web.Error504Dialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.Error504Dialog" xml:space="preserve"> 13691 <Dialog title.translate="Request timeout" size="'xl'" contentClass="'o_error_dialog'"> 13692 <div role="alert"> 13693 <p class="text-prewrap"> 13694 The operation was interrupted. This usually means that the current operation is taking too much time. 13695 </p> 13696 </div> 13697 <t t-set-slot="footer"> 13698 <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button> 13699 </t> 13700 </Dialog> 13701 </t> 13702 13703 `); 13704registerTemplate("web.SessionExpiredDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.SessionExpiredDialog" xml:space="preserve"> 13705 <Dialog title.translate="Odoo Session Expired" size="'xl'" contentClass="'o_error_dialog'"> 13706 <div role="alert"> 13707 <p class="text-prewrap"> 13708 Your Odoo session expired. The current page is about to be refreshed. 13709 </p> 13710 </div> 13711 <t t-set-slot="footer"> 13712 <button class="btn btn-primary o-default-button" t-on-click="onClick">Close</button> 13713 </t> 13714 </Dialog> 13715 </t> 13716 13717 `); 13718registerTemplate("web.ErrorDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.ErrorDialog" xml:space="preserve"> 13719 <Dialog title.translate="Oops!" size="'xl'" contentClass="'o_error_dialog'"> 13720 <div role="alert"> 13721 <p class="text-prewrap"> 13722 Something went wrong... If you really are stuck, share the report with your friendly support service 13723 </p> 13724 <button class="btn btn-link p-0" t-on-click="() => { state.showTraceback = !state.showTraceback }" t-esc="state.showTraceback ? this.constructor.hideTracebackButtonText : this.constructor.showTracebackButtonText"/> 13725 <div t-if="state.showTraceback" class="bg-100 mb-0 clearfix mt-3 position-relative o_error_detail"> 13726 <button class="btn position-absolute bg-100" t-ref="copyButton" t-on-click="onClickClipboard">
13727 <span class="fa fa-clipboard"/> 13728 </button> 13729 <div class="ps-3 pt-3"> 13730 <p class="m-0"><b t-esc="title or this.constructor.title"/></p> 13731 <code t-if="props.name" t-esc="props.name"/> 13732 <p class="m-0" t-if="props.message" t-esc="props.message"/> 13733 <p class="m-0" t-if="contextDetails" t-esc="contextDetails"/> 13734 <pre class="m-0 p-0 mt-2" t-esc="traceback or props.traceback"/> 13735 </div> 13736 </div> 13737 </div> 13738 <t t-set-slot="footer"> 13739 <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button> 13740 </t> 13741 </Dialog> 13742 </t> 13743 13744`); 13745registerTemplate("web.ExpressionEditor", `/web/static/src/core/expression_editor/expression_editor.xml`, `<t t-name="web.ExpressionEditor" xml:space="preserve"> 13746 <div class="o_expression_editor w-100" aria-atomic="true"> 13747 <t t-if="tree"> 13748 <TreeEditor resModel="props.resModel" tree="tree" isDebugMode="isDebugMode" update.bind="update" getDefaultCondition.bind="getDefaultCondition" getDefaultOperator.bind="getDefaultOperator" getOperatorEditorInfo.bind="getOperatorEditorInfo" getPathEditorInfo.bind="getPathEditorInfo"/> 13749 </t> 13750 <t t-else=""> 13751 This expression is not supported. 13752 <button t-on-click="() => this.resetExpression()">Reset expression</button> 13753 </t> 13754 <t t-if="isDebugMode"> 13755 <div class="o_expression_editor_debug_container d-block mt-3 border rounded p-3 bg-100 text-muted font-monospace"> 13756 <span class="small"># Code editor</span> 13757 <textarea class="pt-2 border-0 bg-transparent text-body" type="text" spellcheck="false" t-att-value="props.expression" t-on-change="(ev) => this.onExpressionChange(ev.target.value)"/> 13758 </div> 13759 </t> 13760 </div> 13761 </t> 13762 13763`); 13764registerTemplate("web.ExpressionEditorDialog", `/web/static/src/core/expression_editor_dialog/expression_editor_dialog.xml`, `<t t-name="web.ExpressionEditorDialog" xml:space="preserve"> 13765 <Dialog title.translate="Edit Condition" size="'xl'"> 13766 <ExpressionEditor t-props="expressionEditorProps"/> 13767 <t t-set-slot="footer"> 13768 <button class="btn btn-primary" t-on-click="onConfirm" t-ref="confirm">Confirm</button> 13769 <button class="btn btn-secondary" t-on-click="onDiscard">Discard</button> 13770 </t> 13771 </Dialog> 13772 </t> 13773 13774`); 13775registerTemplate("web.FileInput", `/web/static/src/core/file_input/file_input.xml`, `<t t-name="web.FileInput" xml:space="preserve"> 13776 <span class="o_file_input" t-att-class="{ 'd-none': props.hidden, 'show opacity-50 pe-none': state.isDisable}" aria-atomic="true"> 13777 <span t-if="!props.hidden" class="o_file_input_trigger" t-on-click.prevent="onTriggerClicked"> 13778 <t t-slot="default"> 13779 <button class="btn btn-primary">Choose File</button> 13780 </t> 13781 </span> 13782 <input type="file" name="ufile" class="o_input_file d-none" t-att-multiple="props.multiUpload" t-att-accept="props.acceptedFileExtensions" t-ref="file-input" t-att-disabled="state.isDisable" t-on-change="onFileInputChange"/> 13783 </span> 13784 </t> 13785 13786`); 13787registerTemplate("web.FileUploadProgressBar", `/web/static/src/core/file_upload/file_upload_progress_bar.xml`, `<t t-name="web.FileUploadProgressBar" xml:space="preserve"> 13788 <div class="position-absolute top-0 start-0 h-100 w-100"> 13789 <div class="o-file-upload-progress-bar-value h-100" t-ref="bar" t-att-style="'width: ' + (this.props.fileUpload.progress * 100) + '%;'"/> 13790 <span class="position-absolute top-0 end-0 cursor-pointer o-file-upload-progress-bar-abort fa fa-times-circle" title="Cancel Upload" aria-label="Cancel Upload" t-on-click.stop.prevent="onCancel"/> 13791 </div> 13792 </t> 13793`); 13794registerTemplate("web.FileUploadProgressContainer", `/web/static/src/core/file_upload/file_upload_progress_container.xml`, `<t t-name="web.FileUploadProgressContainer" xml:space="preserve"> 13795 <t t-foreach="Object.values(props.fileUploads)" t-as="fileUpload" t
13795-key="fileUpload.id"> 13796 <t t-if="!props.shouldDisplay || props.shouldDisplay(fileUpload)" t-component="props.Component" fileUpload="fileUpload" selector="props.selector"/> 13797 </t> 13798 </t> 13799`); 13800registerTemplate("web.FileUploadProgressKanbanRecord", `/web/static/src/core/file_upload/file_upload_progress_record.xml`, `<t t-name="web.FileUploadProgressKanbanRecord" xml:space="preserve"> 13801 <t t-set="progressTexts" t-value="getProgressTexts()"/> 13802 <div class="o_kanban_record d-flex flex-grow-1 flex-md-shrink-1 flex-shrink-0"> 13803 <div class="o_kanban_progress_card o_kanban_attachment position-relative p-0 cursor-pointer"> 13804 <div class="o_kanban_image_wrapper"> 13805 <div class="o_image o_image_thumbnail" t-att-data-mimetype="props.fileUpload.type"/> 13806 </div> 13807 <div t-att-title="props.fileUpload.title" t-att-aria-label="props.fileUpload.title" class="fw-bold fs-5 mb-2 p-2"> 13808 <span t-esc="props.fileUpload.title"/> 13809 </div> 13810 <div class="o_kanban_record_body"/> 13811 <div class="d-flex p-2 text-dark"> 13812 <div class="o_file_upload_progress_text_left" t-esc="progressTexts.left"/> 13813 <span class="o_file_upload_progress_text_right ms-auto" t-esc="progressTexts.right"/> 13814 </div> 13815 <FileUploadProgressBar fileUpload="props.fileUpload"/> 13816 </div> 13817 </div> 13818 </t> 13819 13820 `); 13821registerTemplate("web.FileUploadProgressDataRow", `/web/static/src/core/file_upload/file_upload_progress_record.xml`, `<t t-name="web.FileUploadProgressDataRow" xml:space="preserve"> 13822 <t t-set="progressTexts" t-value="getProgressTexts()"/> 13823 <div class="o_data_row o_list_progress_card position-relative align-middle p-0"> 13824 <span class="o_file_upload_upload_title" t-esc="props.fileUpload.title"/> 13825 <span class="o_file_upload_progress_text_left" t-esc="progressTexts.left"/> 13826 <span class="o_file_upload_progress_text_right" t-esc="progressTexts.right"/> 13827 <FileUploadProgressBar fileUpload="props.fileUpload"/> 13828 </div> 13829 </t> 13830 13831`); 13832registerTemplate("web.FileViewer", `/web/static/src/core/file_viewer/file_viewer.xml`, `<t t-name="web.FileViewer" xml:space="preserve"> 13833 <div class="d-flex justify-content-center" t-att-class="{ 'modal modal-fullscreen': props.modal }"> 13834 <div class="o-FileViewer flex-column align-items-center d-flex w-100 h-100" tabindex="0" t-ref="autofocus" t-on-keydown.stop="(ev) => this.onKeydown(ev)"> 13835 <div class="o-FileViewer-header position-absolute top-0 d-flex w-100" t-on-click.stop=""> 13836 <div t-if="isViewable" class="d-flex align-items-center ms-4 me-2"> 13837 <i t-if="state.file.isImage" class="fa fa-picture-o" role="img" title="Image"/> 13838 <i t-if="state.file.isPdf" class="fa fa-file-text" role="img" title="PDF file"/> 13839 <i t-if="state.file.isText" class="fa fa-file-text" role="img" title="Text file"/> 13840 <i t-if="state.file.isVideo" class="fa fa-video-camera" role="img" title="Video"/> 13841 </div> 13842 <div class="d-flex align-items-center ms-4 overflow-auto"> 13843 <span class="text-truncate" t-out="state.file.name"/> 13844 </div> 13845 <div class="flex-grow-1"/> 13846 <div class="o-FileViewer-download o-FileViewer-headerButton d-flex align-items-center px-3 cursor-pointer" role="button" title="Download" t-on-click.stop="onClickDownload"> 13847 <span class="text-reset d-flex align-items-baseline"> 13848 <i class="fa fa-download fa-fw me-1" role="img"/> 13849 <span>Download</span> 13850 </span> 13851 </div> 13852 13853 <div t-on-click.stop="close" class="o-FileViewer-headerButton d-flex align-items-center mb-0 px-3 h4 text-reset cursor-pointer" role="button" title="Close (Esc)" aria-label="Close"> 13854 <i class="fa fa-fw fa-times" role="img"/> 13855 </div> 13856 </div> 13857 <div t-on-click.stop="close" t-on-mousemove="onMousemoveView" class="o-FileViewer-main position-absolute top-0 bottom-0 start-0 end-0 align-items-center justify-content-center d-flex" t-att-class="{ 'o_with_img overflow-hidden': state.file.isImage }"> 13858 <div t-if="state.file.isImage" class="o-FileViewer-zoomer position-absolute align-items-center justify-content-center d-flex w-100 h-100" t-ref="zoomer"> 13859 <div t-if="!state.imageLoaded" class="position-absolute"> 13860 <i class="fa fa-3x fa-circle-o-notch fa-fw fa-spin text-white" role="img" title="Loading"/> 13861 </div> 13862 <img t-on-click.stop="" t-on-load="onImageLoaded" t-on-wheel="onWheelImage" t-on-mousedown.stop="onMousedownImage" t-on-mouseup.stop="onMouseupImage" class="o-FileViewer-view o-FileViewer-viewImage mw-100 mh-100 transition-base" t-att-src="state.file.defaultSource" t-att-style="imageStyle" draggable="false" alt="Viewer" t-ref="image"/> 13863 </div> 13864 <iframe t-if="state.file.isPdf" class="o-FileViewer-view w-75 h-100 border-0" t-ref="iframeViewerPdf" t-att-class="{ 'w-100': ui.isSmall }" t-att-src="state.file.defaultSource"/> 13865 <iframe t-if="state.file.isText" class="o-FileViewer-view o-isText o_text w-75 h-100 border-0" t-att-class="{ 'w-100': ui.isSmall, 'o-FileViewer-loading': !this.state.isIframeLoaded }" t-att-src="state.file.defaultSource" t-on-load="this.onIframeLoaded" loading="lazy"/> 13866 <iframe t-if="state.file.isUrlYoutube" allow="autoplay; encrypted-media" class="o-FileViewer-view w-75 h-100 border-0" t-att-src="state.file.defaultSource" height="315" width="560"/> 13867 <video t-if="state.file.isVideo" class="o-FileViewer-view w-75 h-75" t-att-class="{ 'w-100 h-100': ui.isSmall }" t-on-click.stop="" controls="controls"> 13868 <source t-att-data-type="state.file.mimetype" t-att-src="state.file.defaultSource"/> 13869 </video> 13870 </div> 13871 <div t-if="state.file.isImage" class="position-absolute bottom-0 d-flex" role="toolbar"> 13872 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="zoomIn" title="Zoom In (+)" role="button"> 13873 <i class="fa fa-fw fa-plus" role="img"/> 13874 </div> 13875 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': state.scale === 1 }" t-on-click.stop="resetZoom" role="button" title="Reset Zoom (0)"> 13876 <i class="fa fa-fw fa-search" role="img"/> 13877 </div> 13878 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': state.scale === minScale }" t-on-click.stop="zoomOut" title="Zoom Out (-)" role="button"> 13879 <i class="fa fa-fw fa-minus" role="img"/> 13880 </div> 13881 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="rotate" title="Rotate (r)" role="button"> 13882 <i class="fa fa-fw fa-repeat" role="img"/> 13883 </div> 13884 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="onClickPrint" title="Print" role="button"> 13885 <i class="fa fa-fw fa-print" role="img"/> 13886 </div> 13887 <div class="o-FileViewer-download o-FileViewer-toolbarButton p-3 rounded-0 cursor-pointer" title="Download" role="button" t-on-click.stop="onClickDownload"> 13888 <i class="fa fa-download fa-fw" role="img"/> 13889 </div> 13890 </div> 13891 <t t-if="props.files.length > 1"> 13892 <div class="o-FileViewer-navigation position-absolute top-0 bottom-0 start-0 align-items-center justify-content-center d-flex my-auto ms-3 rounded-circle bg-dark text-white" t-on-click.stop="previous" title="Previous (Left-Arrow)" aria-label="Previous" role="button">
13893 <span class="oi oi-chevron-left" role="img"/> 13894 </div> 13895 <div class="o-FileViewer-navigation position-absolute top-0 bottom-0 end-0 align-items-center justify-content-center d-flex my-auto me-3 rounded-circle bg-dark text-white" t-on-click.stop="next" title="Next (Right-Arrow)" aria-label="Next" role="button"> 13896 <span class="oi oi-chevron-right" role="img"/> 13897 </div> 13898 </t> 13899 </div> 13900 </div> 13901 </t> 13902 13903`); 13904registerTemplate("web.InstallScopedApp", `/web/static/src/core/install_scoped_app/install_scoped_app.xml`, `<t t-name="web.InstallScopedApp" xml:space="preserve"> 13905 <div class="o_install_scoped_app o_home_menu_background h-100 w-100 d-flex align-items-center justify-content-center user-select-none"> 13906 <button class="btn btn-link m-1 position-absolute start-0 top-0" t-on-click="() => window.close()"> 13907 <svg xmlns="http://www.w3.org/2000/svg" style="transform:rotate(135deg);" width="28" height="28" viewBox="-7 -7 24 24" preserveAspectRatio="xMinYMin"> 13908 <path fill="#000" d="M8 8V1a1 1 0 1 1 2 0v8a1 1 0 0 1-1 1H1a1 1 0 1 1 0-2h7z"/> 13909 </svg> 13910 </button> 13911 <i t-if="!state.showInstallUI" class="fa fa-circle-o-notch fa-spin fa-2x text-primary position-absolute"/> 13912 <div t-attf-class="h-100 w-100 d-flex align-items-center justify-content-center flex-column fade {{state.showInstallUI ? 'show': ''}}"> 13913 <div class="d-flex align-items-center justify-content-center flex-wrap gap-3 m-4 mw-75 mw-md-50"> 13914 <img style="height:100px;width:100px;" class="rounded-4 p-4 bg-white shadow" t-att-src="state.manifest.icons?.[0]?.src"/> 13915 <div class="d-inline-block"> 13916 <div class="d-flex align-items-center"> 13917 <h1 class="mb-0" t-esc="state.manifest.name"/> 13918 <Dropdown t-if="pwa.isAvailable" menuClass="'p-2'"> 13919 <button class="btn btn-link fa fa-pencil"/> 13920 <t t-set-slot="content"> 13921 <label class="mb-1">Application name</label> 13922 <input class="form-control" t-att-value="state.manifest.name" t-on-change="onChangeName"/> 13923 </t> 13924 </Dropdown> 13925 </div> 13926 <a class="text-primary text-decoration-none" href="https://odoo.com" alt="Odoo" target="_blank">Odoo S.A.</a> 13927 </div> 13928 </div> 13929 <button t-if="pwa.isAvailable" class="btn btn-primary btn-lg rounded-5 shadow py-2 px-3" t-on-click="onInstall">Install</button> 13930 <div t-else="" class="p-2 px-4 overflow-hidden rounded-2 mw-75 bg-info text-white"> 13931 <t t-if="pwa.isSupportedOnBrowser"> 13932 <span t-if="pwa.hasScopeBeenInstalled()">The app seems to be installed on your device</span> 13933 <span t-else="">
13933You can install the app from the browser menu</span> 13934 </t> 13935 <span t-else="">The app cannot be installed with this browser</span> 13936 </div> 13937 </div> 13938 </div> 13939 </t> 13940`); 13941registerTemplate("web._ModelFieldSelector", `/web/static/src/core/model_field_selector/model_field_selector.xml`, `<t t-name="web._ModelFieldSelector" xml:space="preserve"> 13942 <div class="o_model_field_selector d-flex" aria-atomic="true" t-att-class="props.readonly ? 'o_read_mode' : 'o_edit_mode o_input'" t-on-click="(ev) => this.openPopover(ev.currentTarget)"> 13943 <div class="o_model_field_selector_value flex-grow-1 h-100" tabindex="0" t-att-data-tooltip="state.displayNames.join(' > ')" data-tooltip-position="top"> 13944 <t t-foreach="state.displayNames" t-as="displayName" t-key="displayName_index"> 13945 <t t-if="!displayName_first"> 13946 <i class="oi oi-chevron-right m-1" role="img" aria-label="Followed by" data-tooltip="Followed by"/> 13947 </t> 13948 <span t-attf-class="o_model_field_selector_chain_part mb-1 #{props.readonly ? 'border-0 fw-bolder' : 'px-1'} text-nowrap"> 13949 <t t-esc="displayName"/> 13950 </span> 13951 </t> 13952 </div> 13953 <div t-if="!props.readonly and state.isInvalid" class="o_model_field_selector_controls ms-2" tabindex="0"> 13954 <i class="fa fa-exclamation-triangle text-warning o_model_field_selector_warning" role="alert" aria-label="Invalid field chain" data-tooltip="Invalid field chain"/> 13955 </div> 13956 <div t-if="!props.readonly and props.allowEmpty and state.displayNames.length" class="o_model_field_selector_controls ms-2" tabindex="0"> 13957 <i class="fa fa-times" t-on-click.stop="clear" aria-label="Clear" data-tooltip="Clear"/> 13958 </div> 13959 </div> 13960 </t> 13961 13962`); 13963registerTemplate("web.ModelFieldSelectorPopover", `/web/static/src/core/model_field_selector/model_field_selector_popover.xml`, `<t t-name="web.ModelFieldSelectorPopover" xml:space="preserve"> 13964 <div class="o_model_field_selector_popover d-flex flex-column" tabindex="-1" t-ref="root" t-on-keydown="onInputKeydown"> 13965 <div class="border-bottom p-2 text-dark fw-bolder"> 13966 <div class="d-flex justify-content-between align-items-center"> 13967 <t t-if="state.page.previousPage"> 13968 <i class="o_model_field_selector_popover_prev_page btn btn-link oi oi-arrow-left ms-n2 text-dark" data-tooltip="Previous" role="img" aria-label="Previous" t-on-click="() => this.goToPreviousPage()"/> 13969 </t> 13970 <div class="o_model_field_selector_popover_title px-2 text-truncate"> 13971 <t t-esc="state.page.title"/> 13972 </div> 13973 <i class="o_model_field_selector_popover_close btn btn-link me-n2 fa fa-times text-dark" data-tooltip="Close" role="img" aria-label="Close" t-on-click="() => props.close()"/> 13974 </div> 13975 <t t-if="props.showSearchInput"> 13976 <div class="o_model_field_selector_popover_search mt-1"> 13977 <input type="text" placeholder="Search..." class="o_input p-1 border rounded-1 bg-view" t-att-value="state.page.query" t-on-input="(ev) => this.debouncedSearchFields(ev.target.value)"/> 13978 </div> 13979 </t> 13980 </div> 13981 <div class="o_model_field_selector_popover_body overflow-auto"> 13982 <ul class="o_model_field_selector_popover_page list-unstyled mb-0"> 13983 <t t-foreach="fieldNames" t-as="fieldName" t-key="fieldName"> 13984 <t t-set="fieldDef" t-value="state.page.fieldDefs[fieldName]"/> 13985 <li class="o_model_field_selector_popover_item d-flex border-bottom" t-att-class="{ 'active': fieldName === state.page.focusedFieldName }" t-att-data-name="fieldName"> 13986 <button t-attf-class="o_model_field_selector_popover_item_name btn btn-light flex-fill border-0 rounded-0 text-break text-start fw-normal" t-on-click="() => this.selectField(fieldDef)"> 13987 <t t-esc="fieldDef.string"/> 13988 <t t-if="fieldDef.record_name"> (<t t-esc="fieldDef.record_name"/>)</t> 13989 <div t-if="props.isDebugMode" class="o_model_field_selector_popover_item_title text-break text-muted small"><t t-esc="fieldName"/> (<t t-esc="fieldDef.type"/>)</div> 13990 </button> 13991 <t t-if="this.canFollowRelationFor(fieldDef)"> 13992 <t t-set="label"> 13993 <t t-if="fieldDef.relation">Relation to follow</t> 13994 <t t-else="">Show options</t> 13995 </t> 13996 <button class="o_model_field_selector_popover_item_relation btn btn-light border-0 border-start rounded-0" t-att-data-tooltip="label" t-att-aria-label="label" t-on-click.stop="() => this.followRelation(fieldDef)"> 13997 <i class="oi oi-chevron-right o_model_field_selector_popover_relation_icon" role="img"/> 13998 </button> 13999 </t> 14000 </li> 14001 </t> 14002 </ul> 14003 </div> 14004 <div t-if="showDebugInput" class="o_model_field_selector_popover_footer border-top py-1 px-2"> 14005 <input type="text" class="o_model_field_selector_debug o_input" t-att-value="state.page.path" t-on-change="(ev) => this.loadNewPath(ev.target.value)" t-on-keydown="onDebugInputKeydown" t-on-input="(ev) => this.props.update(ev.target.value, null, true)"/> 14006 </div> 14007 </div> 14008 </t> 14009 14010`); 14011registerTemplate("web.ModelSelector", `/web/static/src/core/model_selector/model_selector.xml`, `<t t-name="web.ModelSelector" xml:space="preserve"> 14012 <div class="o_model_selector" t-ref="autocomplete_container"> 14013 <input t-if="env.isSmall" type="text" class="o_input" readonly="" t-att-id="props.id" t-att-value="props.value"/> 14014 <AutoComplete t-else="" id="props.id" value="props.value || ''" sources="sources" placeholder="this.placeholder" autoSelect="props.autoSelect" autofocus="props.autofocus"/>
14015 <span class="o_dropdown_button"/> 14016 </div> 14017 </t> 14018`); 14019registerTemplate("web.Notebook", `/web/static/src/core/notebook/notebook.xml`, `<t t-name="web.Notebook" xml:space="preserve"> 14020 <div t-attf-class="o_notebook d-flex w-100 {{ props.orientation === 'horizontal' ? 'horizontal flex-column' : 'vertical flex-row' }} {{ props.className }}" t-if="state.currentPage"> 14021 <div class="o_notebook_headers" t-att-class="{ 'm-0': props.orientation === 'vertical' }"> 14022 <ul t-attf-class="nav nav-tabs {{ props.orientation === 'horizontal' ? 'flex-row flex-nowrap' : 'flex-column p-0' }}"> 14023 <li t-foreach="navItems" t-as="navItem" t-key="navItem[0]" class="nav-item flex-nowrap" t-if="navItem[1].isVisible" t-attf-class="{{ navItem[1].isDisabled ? 'disabled' : '' }}"> 14024 <a class="nav-link" t-att-class="{'active position-relative cursor-default z-1': navItem[0] === state.currentPage, 'p-3 rounded-0 w-100': props.orientation === 'vertical', 'o_page_invalid': invalidPages.has(navItem[0])}" t-attf-class="{{ navItem[1].className || '' }}" t-att-name="navItem[1].name" t-on-click.prevent="() => this.activatePage(navItem[0])" href="#" role="tab" tabindex="0"> 14025 <i t-if="props.icons and props.icons[navItem[0]]" t-attf-class="fa {{ props.icons[navItem[0]] }} me-2"/> 14026 <t t-esc="navItem[1].title"/> 14027 </a> 14028 </li> 14029 </ul> 14030 </div> 14031 <div class="o_notebook_content tab-content"> 14032 <div class="tab-pane active fade" t-ref="activePane"> 14033 <t t-if="page" t-component="page.Component" t-key="state.currentPage" t-props="page.props"/> 14034 <t t-else="" t-slot="{{ state.currentPage }}"/> 14035 </div> 14036 </div> 14037 </div> 14038 </t> 14039 14040`); 14041registerTemplate("web.NotificationWowl", `/web/static/src/core/notifications/notification.xml`, `<t t-name="web.NotificationWowl" xml:space="preserve"> 14042 <div t-on-mouseenter="freeze" t-on-mouseleave="refresh" t-attf-class="o_notification {{props.className}} d-flex mb-2 position-relative rounded shadow-lg" role="alert" aria-live="assertive" aria-atomic="true"> 14043 <span t-attf-class="o_notification_bar bg-{{props.type}} rounded-start"/> 14044 <div class="w-100 py-2 ps-3 pe-5 border border-start-0 rounded-end text-break"> 14045 <button type="button" class="o_notification_close btn-close position-absolute top-0 end-0 mt-2 me-2" aria-label="Close" t-on-click="close"/> 14046 <div class="o_notification_body d-flex align-items-center"> 14047 <span class="me-auto o_notification_content w-100"> 14048 14049 <t t-if="props.title"><t t-out="props.title"/>. </t> 14050 <t t-out="props.message"/> 14051 </span> 14052 <div t-if="props.buttons.length" class="o_notification_buttons justify-content-end w-50"> 14053 <button t-foreach="props.buttons" t-as="button" type="button" t-key="button_index" t-attf-class="btn btn-link" t-on-click="button.onClick"> 14054 <t t-if="button.icon"> 14055 <i t-if="button.icon.indexOf('fa-') === 0" role="img" t-att-aria-label="button.name" t-att-title="button.name" t-attf-class="fa fa-fw {{button.icon}} me-1"/> 14056 <img t-else="" t-att-src="button.icon" t-att-alt="button.name"/> 14057 </t> 14058 <span class="fw-bolder" t-esc="button.name"/> 14059 </button> 14060 </div> 14061 </div> 14062 <div t-ref="autoclose_progress_bar" t-attf-class="o_notification_progress opacity-75 bg-{{props.type}}"/> 14063 </div> 14064 </div> 14065 </t> 14066 14067`); 14068registerTemplate("web.OverlayContainer", `/web/static/src/core/overlay/overlay_container.xml`, `<t t-name="web.OverlayContainer" xml:space="preserve"> 14069 <div class="o-overlay-container" t-ref="root"> 14070 <t t-foreach="sortedOverlays" t-as="overlay" t-key="overlay.id"> 14071 <ErrorHandler t-if="isVisible(overlay)" onError="(error) => this.handleError(overlay, error)"> 14072 <OverlayItem env="overlay.env" component="overlay.component" props="overlay.props"/> 14073 </ErrorHandler> 14074 </t> 14075 </div> 14076 </t> 14077 14078 `); 14079registerTemplate("web.OverlayContainer.Item", `/web/static/src/core/overlay/overlay_container.xml`, `<t t-name="web.OverlayContainer.Item" xml:space="preserve"> 14080 <div t-ref="rootRef" class="o-overlay-item"> 14081 <t t-component="props.component" t-props="props.props"/> 14082 </div> 14083 </t> 14084 14085`); 14086registerTemplate("web.Pager", `/web/static/src/core/pager/pager.xml`, `<t t-name="web.Pager" xml:space="preserve"> 14087 <nav class="o_pager d-flex gap-2 h-100" aria-label="Pager">
14088 <span t-if="!env.isSmall" class="o_pager_counter align-self-center" t-on-click.stop=""> 14089 <t t-if="state.isEditing"> 14090 <input type="text" class="o_pager_value o_input d-inline-block w-auto text-end mb-n1" size="7" t-ref="autofocus" t-att-value="value" t-on-blur="onInputBlur" t-on-change="onInputChange" t-on-keydown.stop="onInputKeydown"/> 14091 </t> 14092 <t t-else=""> 14093 <span class="o_pager_value d-inline-block border-bottom border-transparent mb-n1" t-esc="value" t-on-click="onValueClick"/> 14094 </t> 14095 <span> / </span> 14096 <t t-if="props.updateTotal"> 14097 <span class="o_pager_limit o_pager_limit_fetch" t-att-class="{ 'disabled': state.isDisabled }" t-on-click.stop="updateTotal"><t t-esc="props.total"/>+</span> 14098 </t> 14099 <t t-else=""> 14100 <span class="o_pager_limit" t-esc="props.total"/> 14101 </t> 14102 </span> 14103 <span class="btn-group d-print-none" aria-atomic="true"> 14104 14105 <button type="button" class="btn btn-secondary o_pager_previous px-2 rounded-start" aria-label="Previous" data-tooltip="Previous" tabindex="-1" t-att-data-hotkey="props.withAccessKey ? 'p' : false" t-att-disabled="state.isDisabled or isSinglePage" t-on-click.stop="() => this.navigate(-1)"> 14106 <i class="oi oi-chevron-left"/> 14107 </button> 14108 <button type="button" class="btn btn-secondary o_pager_next px-2 rounded-end" aria-label="Next" data-tooltip="Next" tabindex="-1" t-att-data-hotkey="props.withAccessKey ? 'n' : false" t-att-disabled="state.isDisabled or isSinglePage" t-on-click.stop="() => this.navigate(1)"> 14109 <i class="oi oi-chevron-right"/> 14110 </button> 14111 </span> 14112 </nav> 14113 </t> 14114 14115`); 14116registerTemplate("web.PagerIndicator", `/web/static/src/core/pager/pager_indicator.xml`, `<t t-name="web.PagerIndicator" xml:space="preserve"> 14117 <Transition visible="state.show" name="'o-fade'" t-slot-scope="transition" leaveDuration="400"> 14118 <div class="o_pager_indicator position-fixed top-0 end-0 m-1 d-flex" t-att-class="transition.className"> 14119 <span class="o_pager_indicator_inner m-1 px-1 text-center shadow"> 14120 <span class="o_pager_value" t-esc="state.value"/> 14121 <span> / </span> 14122 <span class="o_pager_limit" t-esc="state.total"/> 14123 </span> 14124 </div> 14125 </Transition> 14126 </t> 14127 14128`); 14129registerTemplate("web.Popover", `/web/static/src/core/popover/popover.xml`, `<t t-name="web.Popover" xml:space="preserve"> 14130 <div t-ref="ref" t-att-class="defaultClassObj" t-attf-style="--animation-time: {{ constructor.animationTime }}ms" t-att-role="props.role" t-on-pointerenter="() => props.holdOnHover and position.lock()" t-on-pointerleave="() => props.holdOnHover and position.unlock()"> 14131 <t t-component="props.component" t-props="props.componentProps" close="props.close"/> 14132 <div t-if="props.arrow" class="popover-arrow position-absolute z-n1"/> 14133 </div> 14134 </t> 14135 14136`); 14137registerTemplate("web.InstallPrompt", `/web/static/src/core/pwa/install_prompt.xml`, `<t t-name="web.InstallPrompt" xml:space="preserve"> 14138 <Dialog contentClass="'o_install_prompt position-fixed px-2 py-3 m-2 user-select-none'" size="'md'" footer="false"> 14139 <t t-set-slot="header"> 14140 <div class="d-flex w-100"> 14141 <h4>How to get the application</h4> 14142 <div t-on-click="onClose" type="button" class="btn-close" aria-label="Close"/> 14143 </div> 14144 </t> 14145 <p>Install the app on your device to access it easily. Here are the steps to follow:</p> 14146 <t t-call="web.InstallStepsSafari"/> 14147 </Dialog> 14148 </t> 14149 `); 14150registerTemplate("web.InstallStepsSafari", `/web/static/src/core/pwa/install_prompt.xml`, `<t t-name="web.InstallStepsSafari" xml:space="preserve"> 14151 <t t-if="isMobileSafari"> 14152 <ul class="mb-0"> 14153 <li> 14154 Tap on the share icon 14155 </li> 14156 <li> 14157 Select "Add to home screen" 14158 </li> 14159 </ul> 14160 </t> 14161 <t t-else=""> 14162 <ul class="mb-0"> 14163 <li> 14164 Open "File" menu from your browser 14165 </li> 14166 <li> 14167 Select "Add to dock" 14168 </li> 14169 </ul> 14170 </t> 14171 </t> 14172`); 14173registerTemplate("web.MultiRecordSelector", `/web/static/src/core/record_selectors/multi_record_selector.xml`, `<t t-name="web.MultiRecordSelector" xml:space="preserve"> 14174 <div class="o_input d-flex flex-wrap gap-1 o_multi_record_selector" t-ref="multiRecordSelector"> 14175 <TagsList tags="tags"/> 14176 <RecordAutocomplete resModel="props.resModel" value="''" domain="props.domain" context="props.context" className="'o_record_autocomplete_with_caret flex-grow-1'" fieldString="props.fieldString" placeholder="placeholder" multiSelect="true" getIds.bind="getIds" update.bind="update"> 14177 <t t-set-slot="autoCompleteItem" t-slot-scope="autoCompleteItemScope">
14178 <span t-if="isAvatarModel" class="o_avatar_many2x_autocomplete o_avatar d-flex align-items-center"> 14179 <img class="rounded me-1" t-attf-src="/web/image/{{props.resModel}}/{{autoCompleteItemScope.data.record.id}}/avatar_128"/> 14180 <t t-esc="autoCompleteItemScope.label"/> 14181 </span> 14182 <t t-else="" t-esc="autoCompleteItemScope.label"/> 14183 </t> 14184 </RecordAutocomplete> 14185 </div> 14186 </t> 14187 14188`); 14189registerTemplate("web.RecordAutocomplete", `/web/static/src/core/record_selectors/record_autocomplete.xml`, `<t t-name="web.RecordAutocomplete" xml:space="preserve"> 14190 <AutoComplete placeholder="props.placeholder" value="props.value" autoSelect="true" resetOnSelect="props.multiSelect" class="props.className" sources="sources" onChange.bind="onChange"> 14191 <t t-set-slot="option" t-slot-scope="optionScope"> 14192 <t t-if="optionScope.data.record"> 14193 <t t-slot="autoCompleteItem" label="optionScope.label" data="optionScope.data"/> 14194 </t> 14195 <t t-else=""> 14196 <t t-esc="optionScope.label"/> 14197 </t> 14198 </t> 14199 </AutoComplete> 14200 </t> 14201 14202`); 14203registerTemplate("web.RecordSelector", `/web/static/src/core/record_selectors/record_selector.xml`, `<t t-name="web.RecordSelector" xml:space="preserve"> 14204 <div class="o_input d-flex flex-wrap gap-1 o_record_selector"> 14205 <span t-if="hasAvatarImg" class="o_avatar o_m2o_avatar"> 14206 <img class="rounded" t-attf-src="/web/image/{{props.resModel}}/{{props.resId}}/avatar_128"/> 14207 </span> 14208 <RecordAutocomplete resModel="props.resModel" value="displayName" domain="props.domain" context="props.context" className="'h-100 flex-grow-1'" fieldString="props.fieldString" placeholder="props.placeholder" multiSelect="false" getIds="() => []" update.bind="update"> 14209 <t t-set-slot="autoCompleteItem" t-slot-scope="autoCompleteItemScope"> 14210 <span t-if="isAvatarModel" class="o_avatar_many2x_autocomplete o_avatar d-flex align-items-center"> 14211 <img class="rounded me-1" t-attf-src="/web/image/{{props.resModel}}/{{autoCompleteItemScope.data.record.id}}/avatar_128"/> 14212 <t t-esc="autoCompleteItemScope.label"/> 14213 </span> 14214 <t t-else="" t-esc="autoCompleteItemScope.label"/> 14215 </t> 14216 </RecordAutocomplete> 14217 <span class="o_dropdown_button"/> 14218 </div> 14219 </t> 14220 14221`); 14222registerTemplate("web_studio.ResizablePanel", `/web/static/src/core/resizable_panel/resizable_panel.xml`, `<t t-name="web_studio.ResizablePanel" xml:space="preserve"> 14223 <div class="o_resizable_panel d-flex flex-column" t-att-class="class" t-ref="containerRef"> 14224 <t t-slot="default"/> 14225 <div class="o_resizable_panel_handle position-absolute top-0 bottom-0 end-0" t-att-class="props.handleSide === 'start' ? 'start-0' : 'end-0'" t-ref="handleRef"/> 14226 </div> 14227 </t> 14228 14229`); 14230registerTemplate("web.SelectMenu.search", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu.search" xml:space="preserve"> 14231 <input type="text" t-attf-class="o_input {{inputClass}}" t-ref="inputRef" t-on-input="onSearchInput" t-on-focus="onInputFocus" t-on-blur="onInputBlur" t-att-placeholder="placeholderValue" t-att-value="displayValue" t-att-id="props.id" t-att-name="props.name" t-att-disabled="props.disabled" t-on-click="onInputClick" autocomplete="off" autocorrect="off" spellcheck="false"/> 14232 </t> 14233 14234 `); 14235registerTemplate("web.SelectMenu", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu" xml:space="preserve"> 14236 <div t-att-class="\`o_select_menu w-auto position-relative \${props.multiSelect ? 'o_select_menu_multi_select' : ''} \${displayInputInToggler ? 'o_input_dropdown' : ''} \${props.class || ''}\`" t-att-data-id="selectMenuId"> 14237 <Dropdown menuClass="this.menuClass" menuRef="this.menuRef" position="'bottom-fit'" beforeOpen.bind="onBeforeOpen" focusToggleOnClosed="!isBottomSheet" onStateChanged.bind="onStateChanged" navigationOptions="navigationOptions" state="dropdownState"> 14238 <t t-if="displayInputInToggler"> 14239 <t t-set="inputClass" t-value="'o_select_menu_toggler ' + (!displayInputInDropdown ? 'o_select_menu_input ' : '') + props.togglerClass"/> 14240 <div class="w-100 d-flex flex-column"> 14241 <t t-if="props.multiSelect"> 14242 <div t-if="props.value.length" class="d-flex flex-wrap mb-1"> 14243 <TagsList tags="multiSelectChoices"/> 14244 </div> 14245 </t> 14246 <div class="position-relative d-flex"> 14247 <t t-call="web.SelectMenu.search"/>
14248 <span class="o_select_menu_caret align-self-center"/> 14249 </div> 14250 </div> 14251 </t> 14252 <t t-else=""> 14253 <button type="button" t-attf-class="o_select_menu_toggler d-flex border btn btn-light w-100 bg-light {{ props.togglerClass }}" t-att-disabled="props.disabled"> 14254 <span class="o_select_menu_toggler_slot text-start text-truncate"> 14255 <span t-if="props.placeholder and !props.value" class="text-muted" t-out="props.placeholder"/> 14256 <t t-slot="default"/> 14257 </span> 14258 <span t-if="canDeselect" t-on-click.stop="onInputClear" class="o_select_menu_toggler_clear position-absolute top-50 end-0 me-3"> 14259 <i class="fa fa-times"/> 14260 </span> 14261 <span class="o_select_menu_caret align-self-center"/> 14262 </button> 14263 </t> 14264 <t t-set-slot="content"> 14265 <button t-if="isBottomSheet and canDeselect" class="btn o_clear_button px-4 d-block ms-auto" t-on-click="onInputClear">Clear</button> 14266 <div class="o_select_menu_searchbox position-sticky start-0 d-empty-none" t-att-data-id="selectMenuId"> 14267 <t t-if="displayInputInDropdown"> 14268 <t t-set="inputClass" t-value="'o_select_menu_input dropdown-item'"/> 14269 <t t-call="web.SelectMenu.search"/> 14270 </t> 14271 </div> 14272 <t t-if="state.choices.length === 0"> 14273 <p class="text-muted fst-italic mx-4 my-1">No results</p> 14274 </t> 14275 <t t-foreach="state.displayedOptions" t-as="choice" t-key="choice_index"> 14276 <t t-call="{{ this.constructor.choiceItemTemplate }}"> 14277 <t t-set="choice" t-value="choice"/> 14278 <t t-set="choice_index" t-value="choice_index"/> 14279 </t> 14280 </t> 14281 <t t-if="props.slots and props.slots.bottomArea" t-slot="bottomArea" data="state"/> 14282 </t> 14283 </Dropdown> 14284 </div> 14285 </t> 14286 14287 `); 14288registerTemplate("web.SelectMenu.ChoiceItem", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu.ChoiceItem" xml:space="preserve"> 14289 <div t-if="choice.isGroup and choice.label" class="o_select_menu_group position-sticky start-0 px-1 fw-bolder user-select-none" t-att-class="{'o_select_menu_searchable_group': displayInputInDropdown, 'ms-2': !!choice.section }"> 14290 <span t-esc="choice.label"/> 14291 </div> 14292 <DropdownItem t-if="!choice.isGroup" onSelected="() => this.onItemSelected(choice.value)" class="getItemClass(choice) + ' text-wrap'" attrs="{ 'data-choice-index': choice_index }"> 14293 <t t-if="props.slots and props.slots.choice" t-slot="choice" data="choice"/> 14294 <t t-else=""> 14295 <div t-esc="choice.label || choice.value"/> 14296 </t> 14297 </DropdownItem> 14298 </t> 14299 14300`); 14301registerTemplate("web.sign_svg_text", `/web/static/src/core/signature/name_and_signature.xml`, `<t t-name="web.sign_svg_text" name="SVG Signature Text" xml:space="preserve"> 14302 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" t-att-width="width" t-att-height="height"> 14303 <defs> 14304 <style type="text/css"> 14305 @font-face { 14306 font-family: "font"; 14307 src: url(data:font/ttf;base64,<t t-esc="font"/>) format("woff"); 14308 font-weight: normal; 14309 font-style: normal; 14310 } 14311 </style> 14312 </defs> 14313 14314 <text t-esc="text" x="50%" t-att-y="height * 3 / 5" t-att-font-size="height * 3 / 5" t-att-textLength="width * 4 / 5 * (type === 'signature' ? Math.min(1, text.length / 7) : 1)" t
14314-att-lengthAdjust="'spacing' + (type === 'signature' ? 'AndGlyphs' : '')" t-attf-style="font-family:'font'; stroke: none; fill: {{color}};" text-anchor="middle"/> 14315 </svg> 14316 </t> 14317 14318 14319 `); 14320registerTemplate("web.NameAndSignature", `/web/static/src/core/signature/name_and_signature.xml`, `<t t-name="web.NameAndSignature" xml:space="preserve"> 14321 <div class="o_web_sign_name_and_signature"> 14322 <div t-if="!props.noInputName" class="o_web_sign_name_group"> 14323 <label class="col-form-label" t-att-for="'o_web_sign_name_input_' + htmlId">Full Name</label> 14324 <input type="text" name="signer" t-att-id="'o_web_sign_name_input_' + htmlId" class="o_web_sign_name_input form-control" t-on-input="onInputSignName" t-att-value="props.signature.name" t-ref="signNameInput" placeholder="Type your name to sign" required=""/> 14325 </div> 14326 14327 14328 <div t-if="state.showSignatureArea" class="o_web_sign_signature_group bg-100 card mt-3" style="overflow: hidden;"> 14329 <div class="card-header bg-transparent"> 14330 <div class="row g-0"> 14331 <div t-if="!props.noInputName or defaultName" class="col-auto"> 14332 <a role="button" href="#" t-on-click.prevent="onClickSignAuto" t-attf-class="o_web_sign_auto_button me-2 btn btn-light {{ state.signMode === 'auto' ? 'active': '' }}"> 14333 Auto 14334 </a> 14335 </div> 14336 <div class="col-auto"> 14337 <a role="button" href="#" t-on-click.prevent="() => this.setMode('draw')" t-attf-class="o_web_sign_draw_button me-2 btn btn-light {{ state.signMode === 'draw' ? 'active': '' }}"> 14338 Draw 14339 </a> 14340 </div> 14341 <div class="col-auto"> 14342 <a role="button" href="#" t-on-click.prevent="onClickSignLoad" t-attf-class="o_web_sign_load_button me-2 btn btn-light {{ state.signMode === 'load' ? 'active': '' }}"> 14343 Load 14344 </a> 14345 </div> 14346 14347 <div class="col-auto division ms-auto"/> 14348 14349 <div t-if="state.signMode === 'auto'" class="o_web_sign_auto_select_style col-auto"> 14350 <Dropdown> 14351 <button type="button" class="btn btn-link fa fa-font o-dropdown-caret"/> 14352 <t t-set-slot="content"> 14353 <t t-foreach="fonts" t-as="font" t-key="font_index"> 14354 <DropdownItem onSelected="() => this.onSelectFont(font_index)"> 14355 <img class="img-fluid" t-att-src="getSVGTextFont(font)"/> 14356 </DropdownItem> 14357 </t> 14358 </t> 14359 </Dropdown> 14360 </div> 14361 14362 <div t-if="state.signMode === 'draw'" t-attf-class="o_web_sign_draw_clear col-auto"> 14363 <a role="button" href="#" t-on-click.prevent="onClickSignDrawClear" class="btn btn-link fa fa-trash"/> 14364 </div> 14365 14366 <div t-if="state.signMode === 'load'" class="o_web_sign_load_file col-auto"> 14367 <button type="button" id="loadFileXml" t-on-click="uploadFile" class="btn btn-link fa fa-upload"/> 14368 <input t-ref="signInputLoad" type="file" role="button" name="files[]" class="d-none" t-on-change="onChangeSignLoadInput"/> 14369 </div> 14370 </div> 14371 </div> 14372 14373 <div class="o_web_sign_signature_container position-relative"> 14374 <div class="o_signature_stroke position-absolute"/> 14375 <canvas t-if="state.showSignatureArea" t-ref="signature" class="o_web_sign_signature z-1"/> 14376 </div> 14377 14378 <div t-if="loadIsInvalid" t-attf-class="o_web_sign_load_invalid card-footer d-none"> 14379 <div class="alert alert-danger mb-0" role="alert">
14380 This file is invalid. Please select an image. 14381 </div> 14382 </div> 14383 </div> 14384 </div> 14385 </t> 14386`); 14387registerTemplate("web.SignatureDialog", `/web/static/src/core/signature/signature_dialog.xml`, `<t t-name="web.SignatureDialog" xml:space="preserve"> 14388 <Dialog title.translate="Adopt Your Signature"> 14389 <div> 14390 <NameAndSignature t-props="nameAndSignatureProps"/> 14391 <div class="mt16 small">By clicking Adopt & Sign, I agree that the chosen signature/initials will be a valid electronic representation of my hand-written signature/initials for all purposes when it is used on documents, including legally binding contracts.</div> 14392 </div> 14393 <t t-set-slot="footer"> 14394 <button class="btn btn-primary" t-att-disabled="signature.isSignatureEmpty" t-on-click="onClickConfirm">Adopt & Sign</button> 14395 <button class="btn btn-secondary" t-on-click="props.close">Cancel</button> 14396 </t> 14397 </Dialog> 14398 </t> 14399 14400`); 14401registerTemplate("web.TagsList", `/web/static/src/core/tags_list/tags_list.xml`, `<t t-name="web.TagsList" xml:space="preserve"> 14402 <t t-foreach="visibleTags" t-as="tag" t-key="tag.id or tag_index"> 14403 <span class="o_tag position-relative d-inline-flex align-items-center user-select-none mw-100" t-att-class="{ 'o_avatar opacity-trigger-hover' : tag.img, 'o_badge badge rounded-pill': !tag.img, 'cursor-pointer': tag.canEdit, }" t-attf-class="{{ !tag.img ? 'o_tag_color_' + (tag.colorIndex ? tag.colorIndex : '0') : '' }}" tabindex="-1" t-att-data-color="tag.colorIndex" t-att-aria-label="tag.title || tag.text" t-att-data-tooltip="tag.title || tag.text" t-on-click="(ev) => tag.onClick and tag.onClick(ev)"> 14404 14405 14406 <span t-if="tag.img and props.displayText and tag.onDelete" class="o_avatar_backdrop position-absolute top-0 end-0 bottom-0 start-0 ms-n2 mt-n1 mb-n1 bg-view rounded border shadow opacity-0 opacity-100-hover"/> 14407 14408 <img t-if="tag.img" t-att-src="tag.img" class="o_avatar o_m2m_avatar position-relative rounded" t-att-class="tag.imageClass"/> 14409 14410 <i t-if="tag.icon" t-attf-class="p-1 fa {{ tag.icon }}" t-att-class="tag.className"/> 14411 14412 <div t-if="props.displayText" class="o_tag_badge_text text-truncate" t-att-class="{'position-relative ms-1' : tag.img}" t-out="tag.text"/> 14413 14414 <a t-if="tag.onDelete" t-on-click.stop.prevent="(ev) => tag.onDelete and tag.onDelete(ev)" class="o_delete d-flex align-items-center opacity-100-hover" t-att-class="{ 'btn btn-link position-relative py-0 px-1 text-danger opacity-0': tag.img, 'ps-1 opacity-75': !tag.img }" data-tooltip="Delete" aria-label="Delete" tabIndex="-1" href="#"> 14415 <i class="oi oi-close align-text-top"/> 14416 </a> 14417 </span> 14418 </t> 14419 <span t-if="otherTags.length" class="o_m2m_avatar_empty rounded text-center fw-bold cursor-default" data-tooltip-template="web.TagsList.Tooltip" data-tooltip-position="right" t-att-data-tooltip-info="tooltipInfo" t-on-click.stop=""> 14420 <span t-if="otherTags.length > 9" t-esc="'9+'"/> 14421 <span t-else="" t-esc="'+' + otherTags.length"/> 14422 </span> 14423 </t> 14424 14425 `); 14426registerTemplate("web.TagsList.Tooltip", `/web/static/src/core/tags_list/tags_list.xml`, `<t t-name="web.TagsList.Tooltip" xml:space="preserve"> 14427 <t t-foreach="tags" t-as="tag" t-key="tag.id or tag_index"> 14428 <div t-esc="tag.text"/> 14429 </t> 14430 </t> 14431 14432`); 14433registerTemplate("web.TimePicker", `/web/static/src/core/time_picker/time_picker.xml`, `<t t-name="web.TimePicker" xml:space="preserve"> 14434 <div class="o_time_picker d-flex align-items-center justify-content-center" t-att-class="cssClass"> 14435 <Dropdown state="dropdownState" menuRef="menuRef" manual="true" focusToggleOnClosed="false" position="'bottom-start'" menuClass="'o_time_picker_dropdown pt-0 mt-0'" navigationOptions="navigationOptions" onOpened.bind="onDropdownOpened">
14436 <input type="text" t-ref="inputRef" class="o_time_picker_input form-control px-0" t-att-class="inputCssClass" t-model="state.inputValue" t-on-input="onInput" t-on-focus="ensureOpen" t-on-click="ensureOpen" t-on-change="onChange" t-on-keydown.capture="onKeydown" t-att-placeholder="getPlaceholder()" tabindex="-1"/> 14437 <t t-set-slot="content"> 14438 <t t-foreach="suggestions" t-as="value" t-key="value_index"> 14439 <DropdownItem class="'o_time_picker_option'" t-out="value.toString()" onSelected="() => this.onItemSelected(value)" closingMode="'none'"/> 14440 </t> 14441 </t> 14442 </Dropdown> 14443 </div> 14444 </t> 14445`); 14446registerTemplate("web.Tooltip", `/web/static/src/core/tooltip/tooltip.xml`, `<t t-name="web.Tooltip" xml:space="preserve"> 14447 <div class="o-tooltip tooltip-inner d-print-none text-start"> 14448 <t t-if="props.template" t-call="{{props.template}}" t-call-context="{ env, ...props.info }"/> 14449 <span t-else="" t-esc="props.tooltip"/> 14450 </div> 14451 </t> 14452 14453`); 14454registerTemplate("web.TreeEditor", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor" xml:space="preserve"> 14455 <div class="o_tree_editor w-100" aria-atomic="true" t-att-class="className"> 14456 <div t-attf-class="o_tree_editor_node d-flex flex-column #{props.readonly ? (props.isSubTree ? 'gap-0' : 'gap-2') : 'gap-1'}"> 14457 <t t-set="ancestors" t-value="[]"/> 14458 <t t-set="node" t-value="tree"/> 14459 <div class="o_tree_editor_row o_tree_editor_connector d-flex align-items-center flex-wrap" t-att-class="{'ps-4': props.isSubTree}"> 14460 <div class="d-flex flex-grow-1 align-items-center"> 14461 <t t-if="node.children.length"> 14462 <span t-if="!props.isSubTree">Match</span> 14463 <t t-call="web.TreeEditor.connector.value"/> 14464 <span t-if="props.isSubTree">of:</span> 14465 <span t-else="">of the following rules:</span> 14466 </t> 14467 <t t-elif="node.value === '|' ? node.negate : !node.negate"> 14468 <span><span t-if="!props.isSubTree">Match </span><strong>all records</strong></span> 14469 </t> 14470 <t t-else=""> 14471 <span><span t-if="!props.isSubTree">Match </span><strong>no records</strong></span> 14472 </t> 14473 </div> 14474 <t t-slot="default"/> 14475 </div> 14476 <t t-if="node.children.length" t-call="web.TreeEditor.connector.children"/> 14477 <t t-if="!props.readonly"> 14478 <div class="o_tree_editor_row d-flex align-items-center" t-att-class="{ 'ps-4': addPadding || props.isSubTree }"> 14479 <a href="#" role="button" t-on-click="() => this.addNewCondition(node)">New Rule</a> 14480 </div> 14481 </t> 14482 </div> 14483 </div> 14484 </t> 14485 14486 `); 14487registerTemplate("web.TreeEditor.controls", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.controls" xml:space="preserve"> 14488 <div class="o_tree_editor_node_control_panel d-flex" role="toolbar" aria-label="Domain node"> 14489 <t t-if="node.type !== 'connector'"> 14490 <button t-if="ancestors.length === 1" class="btn px-2 fs-4" role="button" data-tooltip="Add nested rule" aria-label="Add nested rule" t-on-click="() => this.addNewConnector(parent, node)" t-on-mouseenter="(ev) => this.highlightNode(ev.target, true)" t-on-mouseleave="(ev) => this.highlightNode(ev.target, false)"> 14491 <i class="fa fa-sitemap"/> 14492 </button> 14493 <button t-else="" class="btn px-2 fs-4" role="button" data-tooltip="Add rule" aria-label="Add rule" t-on-click="() => this.addNewCondition(parent, node)" t-on-mouseenter="(ev) => this.highlightNode(ev.target, true)" t-on-mouseleave="(ev) => this.highlightNode(ev.target, false)"> 14494 <i class="fa fa-plus"/> 14495 </button> 14496 </t> 14497 <button class="btn btn-link px-2 text-danger fs-4" role="button" data-tooltip="Delete rule" aria-label="Delete rule" t-on-click="() => this.delete(ancestors, node)" t-on-mouseenter="(ev) => this.highlightNode(ev.target, true)" t-on-mouseleave="(ev) => this.highlightNode(ev.target, false)">
14498 <i class="fa fa-trash"/> 14499 </button> 14500 </div> 14501 </t> 14502 14503 `); 14504registerTemplate("web.TreeEditor.connector.value", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.value" xml:space="preserve"> 14505 <t t-set="title"> 14506 <t t-if="node.value === '|'"> 14507 <t t-if="node.negate">none</t> 14508 <t t-else="">any</t> 14509 </t> 14510 <t t-else=""> 14511 <t t-if="node.negate">not all</t> 14512 <t t-else="">all</t> 14513 </t> 14514 </t> 14515 <t t-if="props.readonly"> 14516 <div class="o_tree_editor_connector_value px-1"> 14517 <strong class="text-primary" t-esc="title"/> 14518 </div> 14519 </t> 14520 <t t-else=""> 14521 <div class="o_tree_editor_connector_value px-1" aria-atomic="true"> 14522 <button class="btn o-dropdown o-dropdown-caret p-0 opacity-75" t-on-click="() => this.updateConnector(node)"> 14523 <strong class="text-primary" t-esc="title"/> 14524 </button> 14525 </div> 14526 </t> 14527 </t> 14528 14529 `); 14530registerTemplate("web.TreeEditor.connector.children", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.children" xml:space="preserve"> 14531 <t t-foreach="node.children" t-as="child" t-key="child.type + '_' + child_index"> 14532 <div class="o_tree_editor_node" t-att-class="{ 'ps-4': addPadding || props.isSubTree }"> 14533 <t t-call="web.TreeEditor.{{ child.type }}"> 14534 <t t-set="ancestors" t-value="[...ancestors, node]"/> 14535 <t t-set="parent" t-value="node"/> 14536 <t t-set="node" t-value="child"/> 14537 </t> 14538 </div> 14539 </t> 14540 </t> 14541 14542 `); 14543registerTemplate("web.TreeEditor.connector", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector" xml:space="preserve"> 14544 <div class="o_tree_editor_row o_tree_editor_connector d-flex align-items-center"> 14545 <div class="d-flex flex-grow-1"> 14546 <t t-call="web.TreeEditor.connector.value"/> 14547 <span>of:</span> 14548 </div> 14549 <t t-if="!props.readonly"> 14550 <t t-call="web.TreeEditor.controls"/> 14551 </t> 14552 </div> 14553 <t t-call="web.TreeEditor.connector.children"> 14554 <t t-set="addPadding" t-value="true"/> 14555 </t> 14556 </t> 14557 14558 `); 14559registerTemplate("web.TreeEditor.condition", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition" xml:space="preserve"> 14560 <div class="o_tree_editor_row d-flex align-items-center"> 14561 <t t-if="props.readonly"> 14562 <t t-call="web.TreeEditor.condition:readonly"/> 14563 </t> 14564 <t t-else=""> 14565 <t t-call="web.TreeEditor.condition:editable"/> 14566 <t t-call="web.TreeEditor.controls"/> 14567 </t> 14568 </div> 14569 <t t-if="isTree(node.value)"> 14570 <TreeEditor t-props="props" update="(value) => this.updateLeafValue(node, value)" slots="{}" isSubTree="true" tree="node.value" resModel="getResModel(node)"/> 14571 </t> 14572 </t> 14573 14574 `); 14575registerTemplate("web.TreeEditor.condition:readonly", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition:readonly" xml:space="preserve"> 14576 <t t-set="description" t-value="getConditionDescription(node)"/> 14577 <div class="o_tree_editor_condition d-flex gap-1 px-2 border bg-100"> 14578 <div class="fw-bolder text-nowrap" t-esc="description.pathDescription"/> 14579 <div class="fst-italic text-nowrap" t-esc="description.operatorDescription"/> 14580 <t t-if="description.valueDescription"> 14581 <t t-set="values" t-value="description.valueDescription.values"/> 14582 <t t-set="join" t-value="description.valueDescription.join"/> 14583 <t t-set="addParenthesis" t-value="description.valueDescription.addParenthesis"/> 14584 <t t-if="addParenthesis">( </t> 14585 <t t-foreach="values" t-as="val" t-key="val_index">
14586 <span class="text-primary fw-bolder"><t t-esc="val"/></span> 14587 <t t-if="!val_last"> <t t-esc="join"/> </t> 14588 </t> 14589 <t t-if="addParenthesis"> )</t> 14590 </t> 14591 </div> 14592 </t> 14593 14594 `); 14595registerTemplate("web.TreeEditor.Editor", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.Editor" xml:space="preserve"> 14596 <t t-if="!info.isSupported(value)"> 14597 <div t-attf-class="o_tree_editor_editor #{_classes}"> 14598 <div class="o_input d-flex align-items-center"> 14599 <span class="flex-grow-1 text-truncate" t-esc="info.stringify(value)"/> 14600 <i role="alert" class="fa fa-exclamation-triangle text-warning mx-2" t-att-data-tooltip="(typeof info.message === 'function') ? info.message(value) : info.message"/> 14601 <i class="fa fa-times" data-tooltip="Clear" t-on-click="() => update(info.defaultValue())"/> 14602 </div> 14603 </div> 14604 </t> 14605 <t t-elif="info.component"> 14606 <div t-attf-class="o_tree_editor_editor #{_classes}"> 14607 <t t-component="info.component" t-props="info.extractProps({ update, value, displayPlaceholder })"/> 14608 </div> 14609 </t> 14610 </t> 14611 14612 `); 14613registerTemplate("web.TreeEditor.condition:editable", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition:editable" xml:space="preserve"> 14614 <div class="o_tree_editor_condition d-flex flex-grow-1 align-items-end gap-2"> 14615 <t t-call="web.TreeEditor.Editor"> 14616 <t t-set="_classes" t-value="'col col-md-4 pe-0'"/> 14617 <t t-set="info" t-value="getPathEditorInfo()"/> 14618 <t t-set="value" t-value="node.path"/> 14619 <t t-set="update" t-value="(path) => this.updatePath(node, path)"/> 14620 </t> 14621 <t t-call="web.TreeEditor.Editor"> 14622 <t t-set="_classes" t-value="'col col-md-2 px-3'"/> 14623 <t t-set="info" t-value="getOperatorEditorInfo(node)"/> 14624 <t t-set="value" t-value="[node.operator, node.negate]"/> 14625 <t t-set="update" t-value="(operator, negate) => this.updateLeafOperator(node, operator, negate)"/> 14626 </t> 14627 <t t-call="web.TreeEditor.Editor"> 14628 <t t-set="_classes" t-value="'col ps-0 overflow-hidden'"/> 14629 <t t-set="info" t-value="getValueEditorInfo(node)"/> 14630 <t t-set="value" t-value="node.value"/> 14631 <t t-set="update" t-value="(value) => this.updateLeafValue(node, value)"/> 14632 </t> 14633 </div> 14634 </t> 14635 14636 `); 14637registerTemplate("web.TreeEditor.complex_condition", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.complex_condition" xml:space="preserve"> 14638 <div class="o_tree_editor_row d-flex align-items-center"> 14639 <div class="o_tree_editor_complex_condition flex-grow-1"> 14640 <input class="o_input w-100" t-att-value="node.value" t-att-readonly="props.readonly or !isDebugMode" t-on-change="(ev) => this.updateComplexCondition(node, ev.target.value)"/> 14641 </div> 14642 <t t-call="web.TreeEditor.controls"/> 14643 </div> 14644 </t> 14645 14646 14647`); 14648registerTemplate("web.TreeEditor.Input", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Input" xml:space="preserve"> 14649 <input type="text" class="o_input" t-att-value="props.startEmpty ? '' : props.value" t-att-placeholder="props.placeholder" t-on-change="(ev) => props.update(ev.target.value)"/> 14650 </t> 14651 14652 `); 14653registerTemplate("web.TreeEditor.Select", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Select" xml:space="preserve"> 14654 <select class="o_input pe-3 text-truncate" t-on-change="(ev) => props.update(deserialize(ev.target.value))"> 14655 <option class="o_select_placeholder" t-if="props.addBlankOption" hidden="true" t-esc="props.placeholder ? props.placeholder : ''"/> 14656 <t t-foreach="props.options" t-as="option" t-key="serialize(option[0])"> 14657 <option class="text-black" t-att-value="serialize(option[0])" t-att-selected="!props.addBlankOption and option[0] === props.value" t-esc="option[1]"/> 14658 </t> 14659 </select> 14660 </t> 14661 14662 `); 14663registerTemplate("web.TreeEditor.Range", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Range" xml:space="preserve"> 14664 <div class="d-flex align-items-center"> 14665 <t t-call="web.TreeEditor.Editor"> 14666 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14667 <t t-set="info" t-value="props.editorInfo"/> 14668 <t t-set="value" t-value="props.value[0]"/> 14669 <t t-set="update" t-value="(val) => this.update(0, val)"/> 14670 </t> 14671 <i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow"/> 14672 <t t-call="web.TreeEditor.Editor"> 14673 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14674 <t t-set="info" t-value="props.editorInfo"/> 14675 <t t-set="value" t-value="props.value[1]"/> 14676 <t t-set="update" t-value="(val) => this.update(1, val)"/> 14677 </t> 14678 </div> 14679 </t> 14680 14681 `); 14682registerTemplate("web.TreeEditor.InRange", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.InRange" xml:space="preserve"> 14683 <div class="d-flex flex-column gap-2"> 14684 <t t-call="web.TreeEditor.Editor"> 14685 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14686 <t t-set="info" t-value="props.valueTypeEditorInfo"/> 14687 <t t-set="value" t-value="props.value[1]"/> 14688 <t t-set="update" t-value="(val) =>
14688 this.updateValueType(val)"/> 14689 </t> 14690 <t t-if="props.value[1] === 'custom range'"> 14691 <t t-call="web.TreeEditor.Editor"> 14692 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14693 <t t-set="info" t-value="props.betweenEditorInfo"/> 14694 <t t-set="value" t-value="props.value.slice(2)"/> 14695 <t t-set="update" t-value="(val) => this.updateValues(val)"/> 14696 </t> 14697 </t> 14698 </div> 14699 </t> 14700 14701 `); 14702registerTemplate("web.TreeEditor.List", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.List" xml:space="preserve"> 14703 <div class="o_input d-flex flex-wrap gap-1"> 14704 <TagsList tags="tags"/> 14705 <div class="flex-grow-1"> 14706 <t t-call="web.TreeEditor.Editor"> 14707 <t t-set="info" t-value="props.editorInfo"/> 14708 <t t-set="value" t-value="props.editorInfo.defaultValue()"/> 14709 <t t-set="update" t-value="(val) => this.update(val)"/> 14710 <t t-set="displayPlaceholder" t-value="!tags.length"/> 14711 </t> 14712 </div> 14713 </div> 14714 </t> 14715 14716`); 14717registerTemplate("web.BlockUI", `/web/static/src/core/ui/block_ui.xml`, `<t t-name="web.BlockUI" xml:space="preserve"> 14718 <t t-if="state.blockState === BLOCK_STATES.UNBLOCKED"> 14719 <div/> 14720 </t> 14721 <t t-else=""> 14722 <t t-set="visiblyBlocked" t-value="state.blockState === BLOCK_STATES.VISIBLY_BLOCKED"/> 14723 <div class="o_blockUI fixed-top d-flex justify-content-center align-items-center flex-column vh-100" t-att-class="visiblyBlocked ? '' : 'o_blockUI_invisible'"> 14724 <t t-if="visiblyBlocked"> 14725 <div class="o_spinner mb-4"> 14726 <img src="/web/static/img/spin.svg" alt="Loading..."/> 14727 </div> 14728 <div class="o_message text-center px-4"> 14729 <t t-esc="state.line1"/><br/> 14730 <t t-esc="state.line2"/> 14731 </div> 14732 </t> 14733 </div> 14734 </t> 14735</t> 14736`); 14737registerTemplate("web.login_user_switch", `/web/static/src/core/user_switch/user_switch.xml`, `<t t-name="web.login_user_switch" xml:space="preserve"> 14738 <t t-if="state.users.length"> 14739 <t t-if="state.displayUserChoice"> 14740 <div class="oe_login_form o_user_switch user-select-none my-4" t-ref="root"> 14741 <p>Choose a user</p> 14742 <div class="list-group my-3"> 14743 <t t-foreach="state.users" t-as="user" t-key="user_index"> 14744 <button type="button" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" t-on-click="() => this.fillForm(user.login)"> 14745 <span class="d-flex justify-content-begin align-items-center"> 14746 <img class="o_avatar o_user_avatar rounded me-2" t-attf-src="{{getAvatarUrl(user)}}" t-att-alt="user.login"/> 14747 <t t-esc="user.name"/> 14748 </span> 14749 <i class="fa fa-times" title="Remove user from switcher" t-on-click.stop="() => this.remove(user)"/> 14750 </button> 14751 </t> 14752 </div> 14753 <button type="button" class="btn btn-link btn-sm w-100" t-on-click="() => this.fillForm()"> 14754 <i class="fa fa-user-circle-o"/> <span class="ms-1">Use another user</span> 14755 </button> 14756 </div> 14757 </t> 14758 <t t-else="" t-portal="'label.form-label'"> 14759 <button type="button" class="o_user_switch_btn btn btn-sm btn-link m-0 p-0" tabindex="1" t-on-click="() => this.toggleFormDisplay()"> 14760 Choose a user 14761 </button> 14762 </t> 14763 </t> 14764 </t> 14765`); 14766registerTemplate("web.FileUploader", `/web/static/src/views/fields/file_handler.xml`, `<t t-name="web.FileUploader" xml:space="preserve"> 14767 <div class="d-contents" t-on-click.stop=""> 14768 <t t-if="state.isUploading and props.showUploadingText">Uploading...</t>
14769 <span t-else="" t-on-click.prevent="onSelectFileButtonClick" style="display:contents"> 14770 <t t-slot="toggler"/> 14771 </span> 14772 <t t-slot="default"/> 14773 <input type="file" t-att-name="props.inputName" t-ref="fileInput" t-attf-class="o_input_file d-none {{ props.fileUploadClass or '' }}" t-att-multiple="props.multiUpload ? 'multiple' : false" t-att-accept="props.acceptedFileExtensions or '*'" t-on-change="onFileChange"/> 14774 </div> 14775 </t> 14776 14777`); 14778registerTemplate("html_editor.AttachmentError", `/html_editor/static/src/main/media/media_dialog/attachment_error.xml`, `<t t-name="html_editor.AttachmentError" xml:space="preserve"> 14779 <Dialog title="title"> 14780 <div class="form-text"> 14781 <p>The image could not be deleted because it is used in the 14782 following pages or views:</p> 14783 <ul t-foreach="props.views" t-as="view" t-key="view.id"> 14784 <li> 14785 <a t-att-href="'/odoo/ir.ui.view/' + window.encodeURIComponent(view.id)"> 14786 <t t-esc="view.name"/> 14787 </a> 14788 </li> 14789 </ul> 14790 </div> 14791 <t t-set-slot="footer"> 14792 <button class="btn btn-primary" t-on-click="() => this.props.close()"> 14793 Ok 14794 </button> 14795 </t> 14796 </Dialog> 14797</t> 14798`); 14799registerTemplate("html_editor.DocumentAttachment", `/html_editor/static/src/main/media/media_dialog/document_selector.xml`, `<t t-name="html_editor.DocumentAttachment" xml:space="preserve"> 14800 <div class="o_existing_attachment_cell o_we_attachment_highlight card col-2 position-relative mb-2 p-2 opacity-trigger-hover" t-att-class="{ o_we_attachment_selected: props.selected }"> 14801 <RemoveButton remove="() => this.remove()"/> 14802 <div t-att-data-url="props.url" role="img" t-att-aria-label="props.name" t-att-title="props.name" t-att-data-mimetype="props.mimetype" class="o_image d-flex align-items-center justify-content-center"/> 14803 <button class="o_btn_reset o_button_area cursor-pointer" t-on-click="props.selectAttachment" t-att-aria-label="props.name"/> 14804 <small class="o_file_name d-block text-truncate" t-esc="props.name"/> 14805 </div> 14806</t> 14807 14808`); 14809registerTemplate("html_editor.DocumentsListTemplate", `/html_editor/static/src/main/media/media_dialog/document_selector.xml`, `<t t-name="html_editor.DocumentsListTemplate" xml:space="preserve"> 14810 <div class="o_we_existing_attachments o_we_documents" t-ref="existing-attachments"> 14811 <div t-if="!hasContent" class="o_nocontent_help"> 14812 <p class="o_empty_folder_image">No documents found.</p> 14813 <p class="o_empty_folder_subtitle">You can upload documents with the button located in the top left of the screen.</p> 14814 </div> 14815 <div t-else="" class="d-flex flex-wrap gap-2"> 14816 <t t-foreach="state.attachments" t-as="attachment" t-key="attachment.id"> 14817 <DocumentAttachment url="attachment.url" name="attachment.name" mimetype="attachment.mimetype" id="attachment.id" onRemoved="(attachmentId) => this.onRemoved(attachmentId)" selected="this.selectedAttachmentIds.includes(attachment.id)" selectAttachment="() => this.onClickDocument(attachment)"/> 14818 </t> 14819 </div> 14820 </div> 14821</t> 14822`); 14823registerTemplate("html_editor.FileSelectorControlPanel", `/html_editor/static/src/main/media/media_dialog/file_selector.xml`, `<t t-name="html_editor.FileSelectorControlPanel" xml:space="preserve"> 14824 <div class="o_we_file_selector_control_panel sticky-top d-flex flex-wrap gap-2 mb-1 p-3 align-items-end"> 14825 <SearchMedia searchPlaceholder="props.searchPlaceholder" needle="props.needle" search="props.search"/> 14826 <div class="d-flex gap-3 justify-content-start align-items-center"> 14827 <div t-if="props.showOptimizedOption" class="flex-shrink-0 form-check form-switch align-items-center" t-on-change="props.changeShowOptimized"> 14828 <input class="o_we_show_optimized form-check-input" type="checkbox" t-att-checked="props.showOptimized" id="o_we_show_optimized_switch"/> 14829 <label class="form-check-label" for="o_we_show_optimized_switch"> 14830 Show optimized images 14831 </label> 14832 </div> 14833 <select t-if="showSearchServiceSelect" class="o_input o_we_search_select form-select pe-5" t-on-change="ev => props.changeSearchService(ev.target.value)"> 14834 <option t-att-selected="props.searchService === 'all'" value="all">All</option> 14835 <option t-att-selected="props.searchService === 'database'" value="database">My Images</option> 14836 <option t-if="props.useMediaLibrary" t-att-selected="props.searchService === 'media-library'" value="media-library">Illustrations</option> 14837 </select> 14838 </div> 14839 <div class="col justify-content-end flex-nowrap input-group has-validation"> 14840 <input type="text" class="form-control o_input o_we_url_input o_we_transition_ease flex-grow-0" t-att-class="{ o_we_horizontal_collapse: !state.showUrlInput, 'w-auto': state.showUrlInput }" name="url" t-att-placeholder="props.urlPlaceholder" t-model="state.urlInput" t-on-input="onUrlInput" t-if="state.showUrlInput" t-ref="urlInput"/> 14841 <button type="button" class="btn o_upload_media_url_button text-nowrap" t-att-class="{ 'btn-primary': state.urlInput, 'btn-secondary': !state.urlInput}" t-on-click="onUrlUploadClick" t-att-disabled="!enableUrlUploadClick"> 14842 <t t-esc="props.addText"/> 14843 </button> 14844 <div class="d-flex align-items-center">
14845 <span t-if="state.urlInput and state.isValidatingUrl" class="o_we_url_loading mx-2 fa fa-lg fa-circle-o-notch fa-spin" title="Loading..."/> 14846 <span t-elif="state.urlInput and state.isValidUrl and state.isValidFileFormat" class="o_we_url_success text-success mx-2 fa fa-lg fa-check" title="The URL seems valid."/> 14847 <span t-elif="state.urlInput and !state.isValidUrl" class="o_we_url_error text-danger mx-2 oi oi-large oi-close" title="The URL does not seem to work."/> 14848 <span t-elif="props.urlWarningTitle and state.urlInput and state.isValidUrl and !state.isValidFileFormat" class="o_we_url_warning text-warning mx-2 fa fa-lg fa-warning" t-att-title="props.urlWarningTitle"/> 14849 </div> 14850 </div> 14851 <input type="file" class="d-none o_file_input" t-on-change="onChangeFileInput" t-ref="file-input" t-att-accept="props.accept" t-att-multiple="props.multiSelect and 'multiple'"/> 14852 <div class="col-auto btn-group"> 14853 <button type="button" class="btn btn-secondary o_upload_media_button" t-on-click="onClickUpload"> 14854 <t t-esc="props.uploadText"/> 14855 </button> 14856 </div> 14857 </div> 14858</t> 14859 14860`); 14861registerTemplate("html_editor.FileSelector", `/html_editor/static/src/main/media/media_dialog/file_selector.xml`, `<t t-name="html_editor.FileSelector" xml:space="preserve"> 14862 <div> 14863 <FileSelectorControlPanel uploadText="uploadText" accept="fileMimetypes" urlPlaceholder="urlPlaceholder" addText="addText" searchPlaceholder="searchPlaceholder" urlWarningTitle="urlWarningTitle" uploadUrl="(url) => this.uploadUrl(url)" uploadFiles="(files) => this.uploadFiles(files)" showOptimizedOption="showOptimizedOption" showOptimized="state.showOptimized" changeShowOptimized="showOptimized => this.state.showOptimized = !this.state.showOptimized" changeSearchService="service => this.state.searchService = service" searchService="state.searchService" needle="state.needle" search="(needle) => this.handleSearch(needle)" useMediaLibrary="props.useMediaLibrary" validateUrl="validateUrl" multiSelect="props.multiSelect"/> 14864 <t t-call="{{ constructor.attachmentsListTemplate }}"/> 14865 <div name="load_more_attachments" class="pt-3 pb-1 text-center mx-auto o_we_load_more" t-ref="load-more-button"> 14866 <button t-if="canLoadMore" class="btn btn-primary o_load_more" type="button" t-on-click="handleLoadMore"> 14867 Load more... 14868 </button> 14869 <div t-elif="hasContent" class="mt-2 o_load_done_msg"> 14870 <span><i t-esc="allLoadedText"/></span> 14871 </div> 14872 </div> 14873 <div t-if="this.state.canScrollAttachments" class="position-sticky d-flex align-items-center mx-auto btn btn-primary rounded-circle oi oi-chevron-down o_scroll_attachments" t-on-click="handleScrollAttachments"/> 14874 </div> 14875</t> 14876`); 14877registerTemplate("html_editor.IconSelector", `/html_editor/static/src/main/media/media_dialog/icon_selector.xml`, `<t t-name="html_editor.IconSelector" xml:space="preserve"> 14878 <div> 14879 <div class="o_we_file_selector_control_panel sticky-top d-flex gap-2 align-items-center mb-1 py-4 px-3"> 14880 <SearchMedia searchPlaceholder.translate="Search a pictogram" search.bind="this.search" needle="state.needle"/> 14881 </div> 14882 <div class="font-icons-icons"> 14883 <t t-foreach="state.fonts" t-as="font" t-key="font.base"> 14884 <div t-if="!font.icons.length" class="o_nocontent_help"> 14885 <p class="o_empty_folder_image">No pictograms found.</p> 14886 <p class="o_empty_folder_subtitle">Try searching with other keywords.</p> 14887 </div> 14888 <span t-foreach="font.icons" t-as="icon" t-key="icon.id" t-att-title="icon.names[0]" t-att-aria-label="icon.names[0]" role="img" class="font-icons-icon m-2 fs-2 p-3 cursor-pointer text-center" t-att-class="{ o_we_attachment_selected: this.selectedMediaIds.includes(icon.id) }" t-attf-class="{{ font.base }} {{ icon.names[0] }}" t-on-click="() => this.onClickIcon(font, icon)"/> 14889 </t> 14890 </div> 14891 </div> 14892</t> 14893`); 14894registerTemplate("html_editor.AutoResizeImage", `/html_editor/static/src/main/media/media_dialog/image_selector.xml`, `<t t-name="html_editor.AutoResizeImage" xml:space="preserve"> 14895 <div t-ref="auto-resize-image-container" class="o_existing_attachment_cell o_
14895we_image align-items-center justify-content-center me-1 mb-1 opacity-trigger-hover opacity-0" t-att-class="{ o_we_attachment_optimized: props.isOptimized, 'o_loaded position-relative opacity-100': state.loaded, o_we_attachment_selected: props.selected, 'position-fixed': !state.loaded, }"> 14896 <RemoveButton t-if="props.isRemovable" model="props.model" remove="() => this.remove()"/> 14897 <div class="o_we_media_dialog_img_wrapper" t-att-class="{ 'bg-light': props.unselectable }"> 14898 <t t-set="unselectable_attachment_title">You can not use this image in a field</t> 14899 <img t-ref="auto-resize-image" class="o_we_attachment_highlight img img-fluid w-100" t-att-class="{ 'opacity-25': props.unselectable}" t-att-src="props.src" t-att-alt="props.altDescription" loading="lazy" t-att-title="props.unselectable ? unselectable_attachment_title : props.title" t-on-load="onImageLoaded"/> 14900 <a t-if="props.author" class="o_we_media_author position-absolute start-0 bottom-0 end-0 text-truncate text-center text-primary fs-6 bg-white-50" t-att-href="props.authorLink" target="_blank" t-esc="props.author"/> 14901 </div> 14902 <button class="o_btn_reset o_button_area" t-att-class="{ 'cursor-pointer': !props.unselectable }" t-on-click="props.onImageClick" t-att-aria-label="props.unselectable ? unselectable_attachment_title : props.title"/> 14903 <span t-if="props.isOptimized" class="badge position-absolute bottom-0 end-0 m-1 text-bg-success">Optimized</span> 14904 </div> 14905</t> 14906 14907`); 14908registerTemplate("html_editor.ExternalImage", `/html_editor/static/src/main/media/media_dialog/image_selector.xml`, `<t t-name="html_editor.ExternalImage" xml:space="preserve"> 14909 <t t-if="record.mediaType == 'libraryMedia'"> 14910 <AutoResizeImage author="record.author" src="record.thumbnail_url" authorLink="record.author_link" title="record.tooltip" altDescription="record.tooltip" minRowHeight="MIN_ROW_HEIGHT" selected="this.selectedMediaIds.includes(record.id)" onImageClick="() => this.onClickMedia(record)" onLoaded="(imgEl) => this.onImageLoaded(imgEl, record)"/> 14911 </t> 14912</t> 14913 14914`); 14915registerTemplate("html_editor.ImagesListTemplate", `/html_editor/static/src/main/media/media_dialog/image_selector.xml`, `<t t-name="html_editor.ImagesListTemplate" xml:space="preserve"> 14916 <div class="o_we_existing_attachments o_we_images d-flex flex-wrap my-0" t-ref="existing-attachments"> 14917 <t t-if="!hasContent and !isFetching"> 14918 <div t-if="state.needle" class="o_nocontent_help"> 14919 <p class="o_empty_folder_image">No images found.</p> 14920 <p class="o_empty_folder_subtitle">Wow, it feels a bit empty in here. Upload from the button in the top right corner!</p> 14921 </div> 14922 <div t-else="" class="o_we_search_prompt"> 14923 <h2>Search the web for royalty-free images</h2> 14924 </div> 14925 </t> 14926 <t t-else=""> 14927 <t t-if="['all', 'database'].includes(state.searchService)"> 14928 <t t-foreach="state.attachments" t-as="attachment" t-key="attachment.id"> 14929 <AutoResizeImage t-if="!attachment.original_id or state.showOptimized" id="attachment.id" isOptimized="!!attachment.original_id" isRemovable="true" onRemoved="(attachmentId) => this.onRemoved(attachmentId)" selected="this.selectedAttachmentIds.includes(attachment.id)" src="attachment.thumbnail_src or attachment.image_src" name="attachment.name" title="attachment.name" unselectable="!!attachment.unselectable" altDescription="attachment.altDescription" model="attachment.res_model" minRowHeight="MIN_ROW_HEIGHT" onImageClick="() => this.onClickAttachment(attachment)" onLoaded="(imgEl) => this.onImageLoaded(imgEl, attachment)"/> 14930 </t> 14931 </t> 14932 <t id="o_we_media_library_images" t-if="['all', 'media-library'].includes(state.searchService)"> 14933 <t t-foreach="state.libraryMedia" t-as="record" t-key="record.id"> 14934 <t t-call="html_editor.ExternalImage"/> 14935 </t> 14936 </t> 14937 14938 <t t-foreach="[...Array(20).keys()]" t-as="i" t-key="i"> 14939 <div class="o_we_attachment_placeholder"/> 14940 </t> 14941 </t> 14942 </div> 14943</t> 14944`); 14945registerTemplate("html_editor.MediaDialog", `/html_editor/static/src/main/media/media_dialog/media_dialog.xml`, `<t t-name="html_editor.MediaDialog" xml:space="preserve"> 14946 <Dialog contentClass="contentClass" size="size" title="title" modalRef="modalRef"> 14947 <Notebook pages="notebookPages" onPageUpdate.bind="onTabChange" defaultPage="state.activeTab"/> 14948 <t t-set-slot="footer"> 14949 <button class="btn btn-primary" t-on-click="() => this.save()" t-ref="add-button">Add</button> 14950 <button class="btn btn-secondary" t-on-click="() => this.close()">Discard</button> 14951 </t> 14952 </Dialog> 14953</t> 14954`); 14955registerTemplate("html_editor.SearchMedia", `/html_editor/static/src/main/media/media_dialog/search_media.xml`, `<t t-name="html_editor.SearchMedia" xml:space="preserve"> 14956 <div class="position-relative mw-lg-25 flex-grow-1 me-auto"> 14957 <input type="text" class="o_we_search o_input form-control pe-4" t-att-placeholder="props.searchPlaceholder.trim()" t
14957-model="state.input" t-ref="autofocus"/> 14958 <i class="oi oi-search input-group-text position-absolute end-0 top-50 me-n3 px-2 py-1 translate-middle bg-transparent border-0" title="Search" role="img" aria-label="Search"/> 14959 </div> 14960</t> 14961`); 14962registerTemplate("html_editor.ProgressBar", `/html_editor/static/src/main/media/media_dialog/upload_progress_toast/upload_progress_toast.xml`, `<t t-name="html_editor.ProgressBar" xml:space="preserve"> 14963 <small class="text-info d-flex align-items-center me-2"> 14964 <span t-if="!props.hasError and !props.uploaded"><i class="fa fa-circle-o-notch fa-spin me-2"/></span> 14965 <span class="fst-italic fw-bold text-truncate flex-grow-1 me-2" t-esc="props.name"/> 14966 <span class="fw-bold text-nowrap" t-esc="props.size"/> 14967 </small> 14968 <small t-if="props.uploaded or props.hasError" class="d-flex align-items-center mt-1"> 14969 <span t-if="props.uploaded" class="text-success"><i class="fa fa-check my-1 me-1"/> File has been uploaded</span> 14970 <span t-else="" class="text-danger"><i class="oi oi-close float-start my-1 me-1"/> <span class="o_we_error_text" t-esc="errorMessage"/></span> 14971 </small> 14972 <div t-else="" class="progress mt-2"> 14973 <div class="progress-bar bg-info progress-bar-striped progress-bar-animated" role="progressbar" t-attf-style="width: {{this.progress}}%;" aria-label="Progress bar"><span t-esc="this.progress + '%'"/></div> 14974 </div> 14975 <hr/> 14976</t> 14977 14978`); 14979registerTemplate("html_editor.UploadProgressToast", `/html_editor/static/src/main/media/media_dialog/upload_progress_toast/upload_progress_toast.xml`, `<t t-name="html_editor.UploadProgressToast" xml:space="preserve"> 14980 <div class="editor_notification_manager o_notification_manager o_upload_progress_toast"> 14981 <div t-if="state.isVisible" class="o_notification position-relative show fade mb-2 border border-info bg-white d-flex justify-content-between" role="alert" aria-live="assertive" aria-atomic="true"> 14982 <div class="editor_notification_body o_notification_body ps-2 py-2"> 14983 <div class="me-auto o_notification_content"> 14984 <div t-foreach="state.files" t-as="file" t-key="file" class="o_we_progressbar"> 14985 <ProgressBar progress="file_value.progress" errorMessage="file_value.errorMessage" hasError="file_value.hasError" name="file_value.name" uploaded="file_value.uploaded" size="file_value.size"/> 14986 </div> 14987 </div> 14988 </div> 14989 <button type="button" class="btn btn-close o_notification_close p-2" aria-label="Close" t-on-click="props.close"/> 14990 </div> 14991 </div> 14992</t> 14993`); 14994registerTemplate("html_editor.VideoOption", `/html_editor/static/src/main/media/media_dialog/video_selector.xml`, `<t t-name="html_editor.VideoOption" xml:space="preserve"> 14995 <div class="mb-1" t-attf-class="{{ showStartAtInput ? 'd-flex align-items-start gap-2 cursor-pointer' : ''}}"> 14996 <Switch value="!!props.value" onChange="props.onChangeOption" label="props.label" description="props.description" extraClasses="'d-flex align-items-start cursor-pointer flex-shrink-0'"/> 14997 <t t-if="showStartAtInput"> 14998 <input type="text" placeholder="MM:SS" class="o_input w-lg-auto" t-att-value="props.value" t-on-input="props.onChangeStartAt"/> 14999 </t> 15000 </div> 15001</t> 15002 15003`); 15004registerTemplate("html_editor.VideoIframe", `/html_editor/static/src/main/media/media_dialog/video_selector.xml`, `<t t-name="html_editor.VideoIframe" xml:space="preserve"> 15005 <iframe t-att-src="this.props.src" class="o_video_dialog_iframe mw-100 mh-100 overflow-hidden shadow" width="1280" height="720" allowfullscreen="allowfullscreen" frameborder="0"/> 15006</t> 15007 15008`); 15009registerTemplate("html_editor.VideoSelector", `/html_editor/static/src/main/media/media_dialog/video_selector.xml`, `<t t-name="html_editor.VideoSelector" xml:space="preserve"> 15010 <div class="row"> 15011 <div class="col mt-4 o_video_dialog_form"> 15012 <div class="mb-2"> 15013 <label for="o_video_text"> 15014 <b>Video code </b>(URL or Embed) 15015 </label> 15016 <div class="text-start"> 15017 <small class="text-muted">Accepts <b><i>Youtube</i></b>, <b><i>Vimeo</i></b>, <b><i>Dailymotion</i></b> and <b><i>Instagram</i></b> videos</small> 15018 </div> 15019 <textarea t-ref="autofocus" t-model="state.urlInput" class="form-control" id="o_video_text" placeholder="Copy-paste your URL or embed code here" t-on-input="onChangeUrl" t-att-class="{ 'is-valid': state.urlInput and !this.state.errorMessage, 'is-invalid': state.urlInput and this.state.errorMessage }"/> 15020 </div> 15021 <div t-if="shownOptions.length" class="o_video_dialog_options"> 15022 <VideoOption t-foreach="shownOptions" t-as="option" t-key="option.id" name="option.id" value="value" onChangeOption="() => this.onChangeOption(option.id)" onChangeStartAt="(ev) => this.onChangeStartAt(ev, option.id)" label="option.label" description="option.description"/> 15023 </div> 15024 <t t-if="state.vimeoPreviews.length">
15025 <span class="fw-bold">Suggestions</span> 15026 <div id="video-suggestion" class="mt-4 d-flex flex-wrap mh-75 overflow-auto"> 15027 <t t-foreach="state.vimeoPreviews" t-as="vimeoPreview" t-key="vimeoPreview.id"> 15028 <div class="o_sample_video w-25 mh-100 cursor-pointer" t-on-click="() => this.onClickSuggestion(vimeoPreview.src)"> 15029 <img class="mw-100 mh-100 p-1" t-att-src="vimeoPreview.thumbnailSrc"/> 15030 </div> 15031 </t> 15032 </div> 15033 </t> 15034 </div> 15035 <div class="col-md-6"> 15036 <div class="o_video_preview position-relative border-0 p-3"> 15037 <div t-if="this.state.src and !this.state.errorMessage" class="o_video_dialog_preview_text mb-2">Preview</div> 15038 <div class="media_iframe_video"> 15039 <div class="media_iframe_video_size"/> 15040 <VideoIframe t-if="this.state.src and !this.state.errorMessage" src="this.state.src"/> 15041 <div t-if="this.state.errorMessage" class="alert alert-warning o_video_dialog_iframe mw-100 mh-100 mb-2 mt-2" t-esc="this.state.errorMessage"/> 15042 </div> 15043 </div> 15044 </div> 15045 </div> 15046</t> 15047`); 15048registerTemplateExtension("html_editor.ExternalImage", `/web_unsplash/static/src/media_dialog/media_dialog.xml`, `<t t-inherit="html_editor.ExternalImage" t-inherit-mode="extension" xml:space="preserve"> 15049 <xpath expr="//t[@t-if]" position="after"> 15050 <t t-elif="record.mediaType === 'unsplashRecord'"> 15051 <AutoResizeImage src="record.url" author="record.user.n
15051ame" authorLink="record.user.links.html" name="record.user.name" title="record.user.name" altDescription="record.alt_description" selected="this.selectedRecordIds.includes(record.id)" onImageClick="() => this.onClickRecord(record)" minRowHeight="MIN_ROW_HEIGHT" onLoaded="(imgEl) => this.onImageLoaded(imgEl, record)"/> 15052 </t> 15053 </xpath> 15054 </t> 15055 15056 `); 15057registerTemplateExtension("html_editor.ImagesListTemplate", `/web_unsplash/static/src/media_dialog/media_dialog.xml`, `<t t-inherit="html_editor.ImagesListTemplate" t-inherit-mode="extension" xml:space="preserve"> 15058 <xpath expr="//t[@id='o_we_media_library_images']" position="replace"> 15059 <t id="o_we_media_library_images" t-if="['all', 'unsplash', 'media-library'].includes(state.searchService)"> 15060 <t t-foreach="combinedRecords" t-as="record" t-key="record.id"> 15061 <t t-call="html_editor.ExternalImage"/> 15062 </t> 15063 </t> 15064 </xpath> 15065 </t> 15066 15067 `); 15068registerTemplateExtension("html_editor.FileSelector", `/web_unsplash/static/src/media_dialog/media_dialog.xml`, `<t t-inherit="html_editor.FileSelector" t-inherit-mode="extension" xml:space="preserve"> 15069 <xpath expr="//div[@name='load_more_attachments']" position="before"> 15070 <div t-if="unsplashState?.unsplashError" class="d-flex mt-2 unsplash_error"> 15071 <UnsplashError title="errorTitle" subtitle="errorSubtitle" showCredentials="['key_not_found', 401].includes(unsplashState.unsplashError)" submitCredentials="(key, appId) => this.submitCredentials(key, appId)" hasCredentialsError="unsplashState.unsplashError === 401"/> 15072 </div> 15073 </xpath> 15074 </t> 15075 15076 `); 15077registerTemplateExtension("html_editor.FileSelector", `/web_unsplash/static/src/media_dialog/media_dialog.xml`, `<t t-inherit="html_editor.FileSelector" t-inherit-mode="extension" xml:space="preserve"> 15078 <xpath expr="//FileSelectorControlPanel" position="attributes"> 15079 <attribute name="useUnsplash">unsplashState?.useUnsplash</attribute> 15080 </xpath> 15081 </t> 15082`); 15083registerTemplateExtension("html_editor.FileSelectorControlPanel", `/web_unsplash/static/src/media_dialog/media_dialog.xml`, `<t t-inherit="html_editor.FileSelectorControlPanel" t-inherit-mode="extension" xml:space="preserve"> 15084 <xpath expr="//option[@value='media-library']" position="after"> 15085 <option t-if="props.useUnsplash" t-att-selected="props.searchService === 'unsplash'" value="unsplash">Photos (via Unsplash)</option> 15086 </xpath> 15087 </t> 15088 15089 `); 15090registerTemplate("web_unsplash.UnsplashCredentials", `/web_unsplash/static/src/unsplash_credentials/unsplash_credentials.xml`, `<t t-name="web_unsplash.UnsplashCredentials" xml:space="preserve"> 15091 <div class="d-flex align-items-center flex-wrap"> 15092 <a href="https://www.odoo.com/documentation/latest/applications/websites/website/optimize/unsplash.html#generate-an-unsplash-access-key" class="me-1" target="_blank">Get an Access key</a> 15093 and paste it here: 15094 <input type="text" class="o_input o_required_modifier form-control w-auto mx-2" id="accessKeyInput" placeholder="Paste your access key here" t-model="state.key" t-on-input="() => this.state.hasKeyError = false" t-att-class="{ 'is-invalid': state.hasKeyError }"/> 15095 and paste 15096 <a href="https://www.odoo.com/documentation/latest/applications/websites/website/optimize/unsplash.html#generate-an-unsplash-application-id" class="mx-1" target="_blank">Application ID</a> 15097 here: 15098 <input type="text" class="o_input o_required_modifier form-control w-auto ms-2" placeholder="Paste your application ID here" t-model="state.appId" t-on-input="() => this.state.hasAppIdError = false" t-att-class="{ 'is-invalid': state.hasAppIdError }"/> 15099 <button type="button" class="btn btn-primary w-auto ms-3 p-auto save_unsplash" t-on-click="() => this.submitCredentials()">Apply</button> 15100 </div> 15101 </t> 15102`); 15103registerTemplate("web_unsplash.UnsplashError", `/web_unsplash/static/src/unsplash_error/unsplash_error.xml`, `<t t-name="web_unsplash.UnsplashError" xml:space="preserve"> 15104 <div class="alert alert-info w-100"> 15105 <h4><t t-esc="props.title"/></h4> 15106 <p><t t-esc="props.subtitle"/></p> 15107 <UnsplashCredentials t-if="props.showCredentials" submitCredentials="props.submitCredentials" hasCredentialsError="props.hasCredentialsError"/> 15108 </div> 15109 </t> 15110`); 15111registerTemplate("html_editor.HtmlViewer", `/html_editor/static/src/components/html_viewer/html_viewer.xml`, `<t t-name="html_editor.HtmlViewer" xml:space="preserve"> 15112 <t t-if="this.showIframe"> 15113 <iframe t-ref="iframe" t-att-class="{'d-none': !this.state.iframeVisible, 'o_readonly': true}" t-att-sandbox="props.config.hasFullHtml ? 'allow-same-origin allow-popups allow-popups-to-escape-sandbox' : false"/> 15114 </t> 15115 <t t-else="">
15116 <div t-ref="readonlyContent" class="o_readonly" t-out="state.value"/> 15117 </t> 15118 </t> 15119`); 15120registerTemplate("html_editor.LocalOverlayContainer", `/html_editor/static/src/local_overlay_container.xml`, `<t t-name="html_editor.LocalOverlayContainer" xml:space="preserve"> 15121 <div class="o-wysiwyg-local-overlay position-relative h-0 w-0" t-ref="localOverlay"/> 15122 <div class="o-wysiwyg-local-overlay position-relative h-0 w-0"> 15123 <t t-foreach="Components.entries" t-as="C" t-key="C[0]"> 15124 <div class="oe-local-overlay" t-att-data-oe-local-overlay-id="C[0]"> 15125 <ErrorHandler onError="error => this.handleComponentError(error, C)"> 15126 <t t-component="C[1].Component" t-props="C[1].props"/> 15127 </ErrorHandler> 15128 </div> 15129 </t> 15130 </div> 15131 </t> 15132`); 15133registerTemplate("html_editor.EmbeddedComponentToolbar", `/html_editor/static/src/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar.xml`, `<t t-name="html_editor.EmbeddedComponentToolbar" xml:space="preserve"> 15134 <span class="o_embedded_toolbar d-flex justify-content-end align-items-center"> 15135 <span t-attf-class="btn-group d-flex flex-wrap #{ props.buttonsGroupClass ? props.buttonsGroupClass : '' }"> 15136 <t t-slot="buttons"/> 15137 </span> 15138 </span> 15139 </t> 15140 `); 15141registerTemplate("html_editor.EmbeddedComponentToolbarButton", `/html_editor/static/src/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar.xml`, `<t t-name="html_editor.EmbeddedComponentToolbarButton" xml:space="preserve"> 15142 <button t-if="!props.hidden" t-ref="buttonRef" t-on-click="props.onClick" t-att-name="props.name" t-att-title="props.title" class="btn btn-primary btn-link btn-sm border-0 py-0 text-break text-start text-o-color-2 text-capitalize fw-bold border-transparent bg-transparent"> 15143 <i t-if="props.icon" t-attf-class="fa #{props.icon} me-1"/> 15144 <span class="o_embedded_toolbar_button_text" t-out="props.label"/> 15145 </button> 15146 </t> 15147`); 15148registerTemplate("html_editor.ReadonlyEmbeddedFile", `/html_editor/static/src/others/embedded_components/core/file/readonly_file.xml`, `<t t-name="html_editor.ReadonlyEmbeddedFile" t-inherit="html_editor.StaticFileBox" t-inherit-mode="primary" xml:space="preserve"> 15149 <xpath expr="//span[hasclass('o_file_image')]" position="inside"> 15150 <a t-att-href="fileModel.downloadUrl" t-on-click.prevent.stop="onClickFileImage" class="w-100"/> 15151 </xpath> 15152 15153 <xpath expr="//span[hasclass('o_file_name_container')]/a" position="replace"> 15154 <span class="o_file_name" t-out="fileModel.filename"/> 15155 </xpath> 15156 15157 <xpath expr="//span[hasclass('o_file_name_container')]" position="after"> 15158 <span class="flex-grow-1 d-flex justify-content-end"> 15159 15160 <EmbeddedComponentToolbar> 15161 <t t-set-slot="buttons"/> 15162 </EmbeddedComponentToolbar> 15163 </span> 15164 </xpath> 15165 15166 </t> 15167 15168`); 15169registerTemplate("html_editor.StaticFileBox", `/html_editor/static/src/others/embedded_components/core/file/static_file.xml`, `<t t-name="html_editor.StaticFileBox" xml:space="preserve"> 15170 <span class="d-flex flex-grow-1 align-items-center alert alert-info"> 15171 15172 <span class="o_file_image d-flex o_image user-select-none" t-att-title="fileModel.filename" t-att-data-mimetype="fileModel.mimetype"/> 15173 15174 <span class="o_file_name_container mx-2 d-flex flex-grow-1"> 15175 <a class="o_link_readonly w-100" t-att-href="fileModel.downloadUrl" t-out="fileModel.filename" contenteditable="false"/> 15176 </span> 15177 </span> 15178 </t> 15179`); 15180registerTemplate("html_editor.EmbeddedTableOfContent", `/html_editor/static/src/others/embedded_components/core/table_of_content/table_of_content.xml`, `<t t-name="html_editor.EmbeddedTableOfContent" xml:space="preserve"> 15181 <div class="px-1" t-att-class="{ 'pb-1' : !state.folded and state.toc.headings.length }"> 15182 <div class="d-flex align-items-center cursor-pointer user-select-none" t-on-click="() => { this.state.folded = !this.state.folded; }"> 15183 <div class="o_embedded_toc_label p-1 fw-bold"> 15184 Table of Contents 15185 <i t-attf-class="align-self-center fa fa-fw fa-caret-#{ state.folded ? 'right' : 'down' }"/> 15186 </div> 15187 </div> 15188 <div t-if="!state.folded" class="o_embedded_toc_content"> 15189 <t t-foreach="this.state.toc.headings" t-as="heading" t-key="heading_index"> 15190 <a href="#" contenteditable="false" t-out="heading.name" t-on-click.prevent="() => this.onTocLinkClick(heading)" t-attf-class="o_no_link_popover py-1 pe-1 d-block text-reset o_embedded_toc_link #{'o_embedded_toc_link_depth_' + heading.depth}"/> 15191 </t> 15192 </div> 15193 </div> 15194 <div class="p-1" t-if="displayTocHint()"> 15195 <i class="o_embedded_toc_hint px-1"> 15196 Add headings to fill the Table of Contents 15197 </i> 15198 </div> 15199</t> 15200`); 15201registerTemplate("html_editor.EmbeddedToggleBlock", `/html_editor/static/src/others/embedded_components/core/toggle_block/toggle_block.xml`, `<t t-name="html_editor.EmbeddedToggleBlock" xml:space="preserve"> 15202 <div class="d-flex flex-row align-items-center"> 15203 <button class="btn p-0 border-0 align-items-center justify-content-center btn-light" t-on-click="onToggle" t-on-pointerdown.prevent="" type="button"> 15204 <i t-attf-class="fa align-self-center fa-caret-{{this.state.showContent ? 'down' : 'right'}}"/> 15205 </button> 15206 <div class="flex-fill ms-1" t-ref="title"/> 15207 </div> 15208 <div class="ps-4 ms-1" t-att-class="{ 'd-none': !state.showContent }" t-ref="content"/> 15209 </t> 15210`); 15211registerTemplate("html_editor.EmbeddedVideo", `/html_editor/static/src/others/embedded_components/core/video/readonly_video.xml`, `<t t-name="html_editor.EmbeddedVideo" xml:space="preserve"> 15212 <iframe t-ref="iframeRef" t-att-src="url" title="Video player" frameborder="0" allowfullscreen="allowfullscreen" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"> 15213 Your browser does not support iframe. 15214 </iframe> 15215 </t> 15216`); 15217registerTemplate("html_editor.Wysiwyg", `/html_editor/static/src/wysiwyg.xml`, `<t t-name="html_editor.Wysiwyg" xml:space="preserve"> 15218 <div class="o-wysiwyg d-flex flex-column p-0" t-att-class="props.class" t-att-style="props.style"> 15219 <LocalOverlayContainer localOverlay="overlayRef" identifier="env.localOverlayContainerKey"/> 15220 <div class="flex-grow-1" t-att-class="{'overflow-auto': !props.iframe}"> 15221 <t t-if="props.iframe">
15222 <iframe t-ref="content" class="w-100 h-100" t-att-data-class="props.contentClass" t-on-focusout="props.onBlur"/> 15223 </t> 15224 <t t-else=""> 15225 <div t-att-class="props.contentClass" t-ref="content" t-on-focusout="props.onBlur" contenteditable="true"/> 15226 </t> 15227 </div> 15228 </div> 15229 </t> 15230`); 15231registerTemplate("html_editor.HistoryDialog", `/html_editor/static/src/components/history_dialog/history_dialog.xml`, `<t t-name="html_editor.HistoryDialog" xml:space="preserve"> 15232 <Dialog size="size" title="title" contentClass="'h-100 html-history-dialog-container'" t-on-close="props.close" t-on-cancel="props.close" t-on-confirm="_onRestoreRevisionClick" t-on-after-render="_onAfterRender"> 15233 <div t-attf-class="dialog-container html-history-dialog #{state.revisionLoading ? 'html-history-loading' : 'html-history-loaded'}"> 15234 <div class="revision-list d-flex flex-column align-content-stretch" t-attf-style="max-height: {{state.cssMaxHeight}}px;"> 15235 <t t-if="!state.revisionsData.length"> 15236 <div class="text-center w-100 pb-2 pt-0 px-0 fw-bolder">No history</div> 15237 </t> 15238 15239 <t t-foreach="state.revisionsData" t-as="rev" t-key="rev.revision_id"> 15240 <a type="object" href="#" role="button" t-attf-title="Show the document submited by #{rev.create_user_name}, on #{this.getRevisionDate(rev)}" t-att-class="this.getRevisionClasses(rev)" t-on-click="() => this.updateCurrentRevision(rev.revision_id )"> 15241 <small><t t-esc="this.getRevisionDate(rev)"/></small> 15242 <div class="o_avatar"> 15243 <img class="rounded" t-att-src="this.getRevisionAuthorAvatar(rev)" t-att-alt="rev.create_user_name" t-att-title="rev.create_user_name"/> 15244 </div> 15245 </a> 15246 </t> 15247 </div> 15248 <div class="history-container" t-attf-style="max-height: {{state.cssMaxHeight}}px;"> 15249 <div t-attf-class="history-content-view #{state.currentView === 'content' ? '' : 'd-none'}"> 15250 <div class="history-view-top-bar"> 15251 <div> 15252 <div class="text-info smaller"> 15253 <i class="fa fa-info-circle me-1" title="Version date"/> 15254 Showing the document as it was on <t t-esc="this.getRevisionDate(this.currentRevision)"/>, submited by <t t-esc="this.currentRevision.create_user_name"/> 15255 </div> 15256 </div> 15257 <div> 15258 <a type="object" href="#" role="button" class="btn btn-secondary" t-on-click="() => state.currentView = 'comparison'"> 15259 <i class="fa fa-exchange" title="View comparison"/> 15260 View comparison 15261 </a> 15262 </div> 15263 </div> 15264 <div class="history-view-inner" t-attf-style="max-height: {{state.cssMaxHeight-20}}px;"> 15265 <t t-if="state.revisionLoading"> 15266 <div class="d-flex flex-column justify-content-center align-items-center"> 15267 <img src="/web/static/img/spin.svg" alt="Loading..." class="me-2" style="filter: invert(1); opacity: 0.5; width: 30px; height: 30px;"/> 15268 <p class="m-0 text-muted loading-text"> 15269 <em>Loading...</em> 15270 </p> 15271 </div> 15272 </t> 15273 <t t-elif="state.revisionContent?.length"> 15274 <div class="pe-none"> 15275 <HtmlViewer config="getConfig('revisionContent')"/> 15276 </div> 15277 </t> 15278 <t t-else="" t-out="props.noContentHelper"/> 15279 </div> 15280 </div> 15281 <div t-attf-class="history-comparison-view #{state.currentView === 'comparison' ? '' : 'd-none'}"> 15282 <div class="history-view-top-bar"> 15283 <t t-if="env.debug"> 15284 <div class="toggle-view-btns"> 15285 <div class="btn-group" role="group"> 15286 <input type="radio" class="btn-check" name="vbtn-radio" id="unified-view-btn" t-on-click="() => state.isComparisonSplit = false" t-att-checked="state.isComparisonSplit ? '' : 'checked'"/> 15287 <label class="btn btn-secondary" for="unified-view-btn">Unified view</label> 15288 <input type="radio" class="btn-check" name="vbtn-radio" id="split-view-btn" t-on-click="() => state.isComparisonSplit = true" t-att-checked="state.isComparisonSplit ? 'checked' : ''"/> 15289 <label class="btn btn-secondary" for="split-view-btn">Split view</label> 15290 </div> 15291 </div> 15292 </t> 15293 <div> 15294 <div class="text-info smaller"> 15295 <i class="fa fa-info-circle me-1" title="Version date"/> 15296 Showing all differences between the current version and the selected one updated by <t t
15296-esc="this.currentRevision.create_user_name"/> on <t t-esc="this.getRevisionDate(this.currentRevision)"/> 15297 </div> 15298 </div> 15299 <div> 15300 <a type="object" href="#" role="button" class="btn btn-secondary" t-on-click="() => state.currentView = 'content'"> 15301 <i class="fa fa-eye" title="View Content"/> 15302 View content 15303 </a> 15304 </div> 15305 </div> 15306 <div class="history-view-inner" t-attf-style="max-height: {{state.cssMaxHeight-60}}px;"> 15307 <t t-if="state.revisionLoading"> 15308 <div class="d-flex flex-column justify-content-center align-items-center"> 15309 <img src="/web/static/img/spin.svg" alt="Loading..." class="me-2" style="filter: invert(1); opacity: 0.5; width: 30px; height: 30px;"/> 15310 <p class="m-0 text-muted loading-text"> 15311 <em>Loading...</em> 15312 </p> 15313 </div> 15314 </t> 15315 <t t-elif="state.revisionComparison?.length"> 15316 <div t-attf-class="history-comparison-split #{state.isComparisonSplit ? '' : 'd-none'}"> 15317 <HtmlViewer config="getConfig('revisionComparisonSplit')"/> 15318 </div> 15319 <div t-attf-class="pe-none history-comparison-unified #{state.isComparisonSplit ? 'd-none' : ''}"> 15320 <HtmlViewer config="getConfig('revisionComparison')"/> 15321 </div> 15322 </t> 15323 <t t-else=""> 15324 <span class="text-muted fst-italic">This is the current version, nothing to compare.</span> 15325 </t> 15326 </div> 15327 </div> 15328 </div> 15329 </div> 15330 <t t-set-slot="footer"> 15331 <button class="btn btn-primary" t-on-click="_onRestoreRevisionClick" t-att-disabled="state.revisionLoading || state.revisionId === -1">Restore history</button> 15332 <button class="btn btn-secondary" t-on-click="props.close">Discard</button> 15333 </t> 15334 </Dialog> 15335 </t> 15336`); 15337registerTemplate("html_editor.AlignSelector", `/html_editor/static/src/main/align/align_selector.xml`, `<t t-name="html_editor.AlignSelector" xml:space="preserve"> 15338 <Dropdown menuClass="'o-we-toolbar-dropdown'" bottomSheet="false" menuRef="menuRef"> 15339 <button class="btn btn-light" t-att-title="props.title" name="text_align"> 15340 <span class="px-1 d-flex align-items-center"> 15341 <i t-att-class="\`fa fa-align-\${state.displayName}\`"/> 15342 </span> 15343 </button> 15344 <t t-set-slot="content"> 15345 <div data-prevent-closing-overlay="true"> 15346 <t t-foreach="items" t-as="item" t-key="item_index"> 15347 <button t-attf-class="btn btn-light fa fa-align-{{item.mode}}" t-att-class="{ active: item.mode === state.displayName }" t-on-click="() => this.onSelected(item)" t-on-pointerdown.prevent="() => {}"/> 15348 </t> 15349 </div> 15350 </t> 15351 </Dropdown> 15352 </t> 15353`); 15354registerTemplate("html_editor.ChatGPTTranslateDialog", `/html_editor/static/src/main/chatgpt/chatgpt_translate_dialog.xml`, `<t t-name="html_editor.ChatGPTTranslateDialog" xml:space="preserve"> 15355 <Dialog size="'lg'" title.translate="Translate with AI"> 15356 <div t-if="state.translationInProgress" class="d-flex"> 15357 <img src="/web/static/img/spin.svg" alt="Loading..." class="me-2" style="filter:invert(1); opacity: 0.5; width: 30px; height: 30px;"/> 15358 <p class="m-0 text-muted align-self-center"> 15359 <em>Translating...</em> 15360 </p> 15361 </div> 15362 <t t-else=""> 15363 <t t-set="message" t-value="state.messages[0]"/> 15364 <div t-att-data-message-id="message.id" t-att-class="message.isError ? 'o-message-error border-danger bg-danger p-2' : ''" class="o-chatgpt-translated"> 15365 <t t-out="formatContent(message.text)"/> 15366 </div> 15367 </t> 15368 15369 15370 <t t-set-slot="footer"> 15371 <button class="btn btn-primary" t-on-click="_confirm" t-att-disabled="state.translationInProgress || state.messages[0].isError">Insert</button> 15372 <button class="btn btn-secondary" t-on-click="_cancel">Cancel</button> 15373 </t> 15374 </Dialog> 15375</t> 15376`); 15377registerTemplate("html_editor.LanguageSelector", `/html_editor/static/src/main/chatgpt/language_selector.xml`, `<t t-name="html_editor.LanguageSelector" xml:space="preserve"> 15378 <t t-if="state.languages.length === 1"> 15379 <t t-call="html_editor.translateButton"> 15380 <t t-set="onClick" t-value="() => this.onSelected(state.languages[0][1])"/> 15381 </t> 15382 </t> 15383 <Dropdown t-else="" menuRef="menuRef"> 15384 <t t-call="html_editor.translateButton"> 15385 <t t-set="onClick" t-value="() => {}"/> 15386 </t> 15387 <t t-set-slot="content"> 15388 <div data-prevent-closing-overlay="true"> 15389 <t t-foreach="state.languages" t-as="language" t-key="language[0]"> 15390 <DropdownItem class="'user-select-none'" onSelected="() => this.onSelected(language[1])"> 15391 <div class="lang" t-esc="language[1]"/> 15392 </DropdownItem> 15393 </t> 15394 </div> 15395 </t> 15396 </Dropdown> 15397 </t> 15398 15399 `); 15400registerTemplate("html_editor.translateButton", `/html_editor/static/src/main/chatgpt/language_selector.xml`, `<t t-name="html_editor.translateButton" xml:space="preserve"> 15401 <button class="btn btn-light" name="translate" t-att-title="props.title" t-att-disabled="props.isDisabled" t-on-click="onClick"> 15402 15403 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="oe-language-icon" version="1.1" id="Layer_1" viewBox="796 796 200 200" enable-background="new 796 796 200 200" xml:space="preserve"> 15404 <g> 15405 <path d="M973.166,818.5H818.833c-12.591,0-22.833,10.243-22.833,22.833v109.333c0,12.59,10.243,22.833,22.833,22.833h154.333 c12.59,0,22.834-10.243,22.834-22.833V841.333C996,828.743,985.756,818.5,973.166,818.5z M896,961.5h-77.167 c-5.973,0-10.833-4.859-10.833-10.833V841.333c0-5.974,4.86-10.833,10.833-10.833H896V961.5z M978.58,872.129 c-0.547,9.145-5.668,27.261-20.869,39.845c4.615,1.022,9.629,1.573,14.92,1.573v12c-10.551,0-20.238-1.919-28.469-5.325 c-7.689,3.301-16.969,5.325-28.125,5.325v-12c5.132,0,9.924-0.501,14.366-1.498c-8.412-7.016-13.382-16.311-13.382-26.78h11.999 c0,8.857,5.66,16.517,14.884,21.623c4.641-2.66,8.702-6.112,12.164-10.351c5.628-6.886,8.502-14.521,9.754-20.042h-49.785v-12 h22.297v-11.986h12V864.5h21.055c1.986,0,3.902,0.831,5.258,2.28C977.986,868.199,978.697,870.155,978.58,872.129z"/> 15406 <g> 15407 <g> 15408 <path d="M839.035,914.262l-4.45,11.258h-15.971l26.355-61.09h15.971l25.746,61.09h-16.583l-4.363-11.258H839.035z M852.475,879.876l-8.902,22.604h17.629L852.475,879.876z"/> 15409 </g> 15410 </g> 15411 </g> 15412 </svg> 15413 </button> 15414 </t> 15415 15416`); 15417registerTemplate("html_editor.ColorPickerGradientTab", `/html_editor/static/src/main/font/color_picker_gradient_tab.xml`, `<t t-name="html_editor.ColorPickerGradientTab" xml:space="preserve"> 15418 <t t-set="currentGradient" t-value="getCurrentGradientColor()"/> 15419 <div class="o_colorpicker_sections p-2 d-grid gap-1" style="grid-template-columns: 1fr 1fr;" t-on-click="props.onColorClick" t-on-mouseover="props.onColorPointerOver" t-on-mouseout="props.onColorPointerOut" t-on-focusin="props.onFocusin" t-on-focusout="props.onFocusout"> 15420 <t t-set="gradientsWithOpacity" t-value="DEFAULT_GRADIENT_COLORS.map((gradient) => applyOpacityToGradient(gradient, props.defaultOpacity))"/> 15421 <t t-foreach="gradientsWithOpacity" t-as="gradient" t-key="gradient"> 15422 <button class="w-100 m-0 o_color_button o_color_picker_button o_gradient_color_button btn p-0" t-att-class="{'selected': currentGradient?.includes(gradient)}" t-attf-style="background-image: #{gradient};" t-att-data-color="gradient"/> 15423 </t> 15424 </div> 15425 <div class="px-2"> 15426 <button t-attf-style="{{ currentGradient ? \`background-image: \${currentGradient}\` : '' }};" class="w-50 btn mb-2 o_custom_gradient_button o_color_picker_button" t-att-class="{'selected': currentGradient and !gradientsWithOpacity.includes(currentGradient)}" t-att-data-color="currentGradient" t-on-click="toggleGradientPicker" title="Define a custom gradient"> 15427 Custom 15428 </button> 15429 <GradientPicker t-if="state.showGradientPicker" onGradientChange.bind="props.applyColor" onGradientPreview.bind="props.onColorPreview" setOnCloseCallback.bind="props.setOnCloseCallback" setOperationCallbacks.bind="props.setOperationCallbacks" selectedGradient="getCurrentGradientColor()" noTransparency="props.noTransparency"/> 15430 </div> 15431</t> 15432`); 15433registerTemplate("html_editor.ColorSelector", `/html_editor/static/src/main/font/color_selector.xml`, `<t t-name="html_editor.ColorSelector" xml:space="preserve"> 15434 <button t-ref="root" class="btn btn-light" t-attf-class="o-select-color-{{props.type}} {{colorSelectorState.isOpen ? 'active' : ''}}" t-att-title="props.title" t-att-disabled="props.isDisabled"> 15435 <t t-if="props.type === 'foreground'"> 15436 <i class="fa fa-fw fa-font py-1" t-att-style="this.get
15436SelectedColorStyle()"/> 15437 </t> 15438 <t t-else=""> 15439 <i class="fa fa-fw fa-paint-brush py-1" t-att-style="this.getSelectedColorStyle()"/> 15440 </t> 15441 </button> 15442</t> 15443 15444`); 15445registerTemplate("html_editor.FontFamilySelector", `/html_editor/static/src/main/font/font_family_selector.xml`, `<t t-name="html_editor.FontFamilySelector" xml:space="preserve"> 15446 <Dropdown menuClass="'o_font_family_selector_menu'" menuRef="menuRef"> 15447 <button class="btn btn-light" t-att-title="props.title" name="font_family" t-att-disabled="props.isDisabled"> 15448 <span class="px-1" t-esc="props.currentFontFamily.displayName"/> 15449 </button> 15450 <t t-set-slot="content"> 15451 <div data-prevent-closing-overlay="true"> 15452 <t t-foreach="props.fontFamilyItems" t-as="item" t-key="item_index"> 15453 <DropdownItem attrs="{ name: item.nameShort }" onSelected="() => props.onSelected(item)" t-on-pointerdown.prevent="() => {}"> 15454 <t t-esc="item.name"/> 15455 </DropdownItem> 15456 </t> 15457 </div> 15458 </t> 15459 </Dropdown> 15460 </t> 15461`); 15462registerTemplate("html_editor.FontSelector", `/html_editor/static/src/main/font/font_selector.xml`, `<t t-name="html_editor.FontSelector" xml:space="preserve"> 15463 <Dropdown menuClass="'o_font_selector_menu'" menuRef="menuRef"> 15464 <button class="btn btn-light" t-att-title="props.title" name="font" t-att-disabled="props.isDisabled"> 15465 <span class="px-1" t-esc="state.displayName"/> 15466 </button> 15467 <t t-set-slot="content"> 15468 <div data-prevent-closing-overlay="true"> 15469 <t t-foreach="items" t-as="item" t-key="item_index"> 15470 <DropdownItem attrs="{ name: item.tagName }" onSelected="() => this.onSelected(item)" t-on-pointerdown.prevent="() => {}"> 15471 <t t-esc="item.name"/> 15472 </DropdownItem> 15473 </t> 15474 </div> 15475 </t> 15476 </Dropdown> 15477 </t> 15478`); 15479registerTemplate("html_editor.FontSizeSelector", `/html_editor/static/src/main/font/font_size_selector.xml`, `<t t-name="html_editor.FontSizeSelector" xml:space="preserve"> 15480 <Dropdown state="dropdown" menuClass="'o_font_size_selector_menu'" menuRef="menuRef"> 15481 <button class="btn btn-light" t-att-title="props.title" name="font_size_selector" t-att-disabled="props.isDisabled"> 15482 <iframe t-ref="iframeContent" style="width: 4ch; height:100%;"/> 15483 </button> 15484 <t t-set-slot="content"> 15485 <div data-prevent-closing-overlay="true"> 15486 <t t-foreach="items" t-as="item" t-key="item_index"> 15487 <DropdownItem onSelected="() => this.onSelected(item)" t-on-pointerdown.prevent="() => {}"> 15488 <t t-out="item.name"/> 15489 </DropdownItem> 15490 </t> 15491 </div> 15492 </t> 15493 </Dropdown> 15494 </t> 15495`); 15496registerTemplate("html_editor.GradientPicker", `/html_editor/static/src/main/font/gradient_picker/gradient_picker.xml`, `<t t-name="html_editor.GradientPicker" xml:space="preserve"> 15497 <div class="d-flex flex-column"> 15498 15499 <div class="align-items-center d-flex justify-content-between my-2 o_type_row"> 15500 Type 15501 <span class="d-flex justify-content-between"> 15502 <button t-attf-class="btn btn-sm btn-light {{ this.state.type === 'linear' ? 'active' : ''}}" t-on-click="() => this.selectType('linear')"> Linear </button> 15503 <button t-attf-class="btn btn-sm btn-light {{ this.state.type === 'radial' ? 'active' : ''}}" t-on-click="() => this.selectType('radial')"> Radial </button> 15504 </span> 15505 </div> 15506 15507 <div t-if="this.state.type === 'linear'" class="d-flex align-items-center justify-content-between mb-1"> 15508 Angle 15509 <span class="d-flex justify-content-between align-items-center"> 15510 <div class="d-flex justify-content-center align-items-center my-auto me-2 position-relative gradient-angle-knob" t-ref="gradientAngleKnob" t-attf-style="--angle: #{this.state.angle}deg;" t-on-mousedown="onKnobMouseDown"> 15511 <div class="position-absolute gradient-angle-thumb"/> 15512 </div> 15513 <div class="o_color_gradient_input d-flex align-items-center">
15514 <input name="angle" type="number" min="0" max="360" t-att-value="this.state.angle" t-on-change="onAngleChange"/> 15515 <label class="flex-grow-0 ms-1 mb-0">deg</label> 15516 </div> 15517 </span> 15518 </div> 15519 <div t-else="" class="d-flex flex-column gap-1 mb-1"> 15520 Size 15521 <div class="d-flex align-items-center justify-content-between"> 15522 <button t-on-click="() => this.onSizeChange('closest-side')" t-attf-class="btn btn-light p-0 {{ this.state.size === 'closest-side' ? \`active\` : ''}}" title="Extend to the closest side"> 15523 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15524 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15525 <path d="M3 4H9V8C9 8.55228 8.55228 9 8 9H4C3.44772 9 3 8.55228 3 8V4Z" fill="#8C8C92"/> 15526 <path d="M6 11C7.65685 11 9 9.65685 9 8C9 6.34315 7.65685 5 6 5C4.34315 5 3 6.34315 3 8C3 9.65685 4.34315 11 6 11Z" fill="#74747B"/> 15527 <path d="M6 10C7.10457 10 8 9.10457 8 8C8 6.89543 7.10457 6 6 6C4.89543 6 4 6.89543 4 8C4 9.10457 4.89543 10 6 10Z" fill="white"/> 15528 <rect x="2" y="3" width="12" height="1" fill="white"/> 15529 </svg> 15530 </button> 15531 <button t-on-click="() => this.onSizeChange('closest-corner')" t-attf-class="btn btn-light p-0 {{ this.state.size === 'closest-corner' ? \`active\` : ''}}" title="Extend to the closest corner"> 15532 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15533 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15534 <path d="M2 4H9V7C9 9.20914 7.20914 11 5 11H2V4Z" fill="#8C8C92"/> 15535 <path d="M6 11C7.65685 11 9 9.65685 9 8C9 6.34315 7.65685 5 6 5C4.34315 5 3 6.34315 3 8C3 9.65685 4.34315 11 6 11Z" fill="#74747B"/> 15536 <path d="M6 10C7.10457 10 8 9.10457 8 8C8 6.89543 7.10457 6 6 6C4.89543 6 4 6.89543 4 8C4 9.10457 4.89543 10 6 10Z" fill="white"/> 15537 <rect x="1" y="3" width="8" height="1" fill="white"/> 15538 <rect x="1" y="11" width="8" height="1" transform="rotate(-90 1 11)" fill="white"/> 15539 </svg> 15540 </button> 15541 <button t-on-click="() => this.onSizeChange('farthest-side')" t-attf-class="btn btn-light p-0 {{ this.state.size === 'farthest-side' ? \`active\` : ''}}" title="Extend to the farthest side"> 15542 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15543 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15544 <path d="M7 12C10.3137 12 14 10.2091 14 8C14 5.79086 10.3137 4 7 4C3.68629 4 2 5.79086 2 8C2 10.2091 3.68629 12 7 12Z" fill="#8C8C92"/> 15545 <path d="M6 11C7.65685 11 9 9.65685 9 8C9 6.34315 7.65685 5 6 5C4.34315 5 3 6.34315 3 8C3 9.65685 4.34315 11 6 11Z" fill="#74747B"/> 15546 <path d="M6 10C7.10457 10 8 9.10457 8 8C8 6.89543 7.10457 6 6 6C4.89543 6 4 6.89543 4 8C4 9.10457 4.89543 10 6 10Z" fill="white"/> 15547 <rect x="14" y="4" width="1" height="12" fill="white"/> 15548 </svg> 15549 </button> 15550 <button t-on-click="() => this.onSizeChange('farthest-corner')" t-attf-class="btn btn-light p-0 {{ this.state.size === 'farthest-corner' ? \`active\` : ''}}" title="Extend to the farthest corner"> 15551 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15552 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15553 <path d="M2 4H14V10C14 13.3137 11.3137 16 8 16H2V4Z" fill="#8C8C92"/> 15554 <path d="M6 11C7.65685 11 9 9.65685 9 8C9 6.34315 7.65685 5 6 5C4.34315 5 3 6.34315 3 8C3 9.65685 4.34315 11 6 11Z" fill="#74747B"/> 15555 <path d="M6 10C7.10457 10 8 9.10457 8 8C8 6.89543 7.10457 6 6 6C4.89543 6 4 6.89543 4 8C4 9.10457 4.89543 10 6 10Z" fill="white"/> 15556 <rect x="15" y="17" width="7" height="0.999999" transform="rotate(-180 15 17)" fill="white"/> 15557 <rect x="15" y="10" width="7" height="1" transform="rotate(90 15 10)" fill="white"/> 15558 </svg> 15559 </button> 15560 </div> 15561 <div class="d-flex align-items-center justify-content-between"> 15562 Position X
15563 <span class="o_color_gradient_input"> 15564 <input name="positionX" type="number" min="0" max="100" t-att-value="this.positions['x']" t-on-change="(ev) => this.onPositionChange('x', ev)"/> 15565 </span> 15566 </div> 15567 <div class="d-flex align-items-center justify-content-between"> 15568 Position Y 15569 <span class="o_color_gradient_input"> 15570 <input name="positionY" type="number" min="0" max="100" t-att-value="this.positions['y']" t-on-change="(ev) => this.onPositionChange('y', ev)"/> 15571 </span> 15572 </div> 15573 </div> 15574 15575 <div class="custom-gradient-configurator"> 15576 <div class="gradient-checkers"/> 15577 <div class="gradient-preview" t-attf-style="background-image: #{this.cssGradients.preview};" t-on-click="this.onGradientPreviewClick"> 15578 </div> 15579 <style><t t-out="this.cssGradients.sliderThumbStyle"/></style> 15580 <div class="gradient-colors"> 15581 <div t-foreach="this.colors" t-as="color" t-key="color_index"> 15582 <input type="range" min="0" max="100" t-att-value="color.percentage" t-att-class="{'active': this.state.currentColorIndex === color_index}" t-attf-name="custom gradient percentage color #{color_index+1}" t-on-click="() => this.state.currentColorIndex = color_index" t-on-change="(ev) => this.onColorPercentageChange(color_index, ev)"/> 15583 </div> 15584 </div> 15585 <div class="gradient-color-bin"> 15586 <t t-if="this.colors.length > 2"> 15587 <a t-on-click="() => this.removeColor(this.state.currentColorIndex)" t-attf-style="left: #{this.colors[this.state.currentColorIndex].percentage}%" type="button" class="btn btn-sm btn-light"><i class="fa fa-fw fa-trash" role="img"/></a> 15588 </t> 15589 </div> 15590 </div> 15591 15592 <ColorPicker onColorSelect.bind="onColorChange" onColorPreview.bind="onColorPreview" setOnCloseCallback.bind="props.setOnCloseCallback" setOperationCallbacks.bind="props.setOperationCallbacks" defaultColor="this.currentColorHex" selectedColor="this.currentColorHex" noTransparency="props.noTransparency"/> 15593 </div> 15594 </t> 15595`); 15596registerTemplate("html_editor.linkPopover", `/html_editor/static/src/main/link/link_popover.xml`, `<t t-name="html_editor.linkPopover" xml:space="preserve"> 15597 <div class="o-we-linkpopover d-flex bg-light overflow-auto shadow" t-on-keydown="onKeydown" role="dialog" aria-modal="true" aria-label="Link Popover"> 15598 <div t-if="state.editing" class="container-fluid d-flex vertical-center p-2" t-ref="editing-wrapper"> 15599 <div t-if="state.isImage" class="col p-2 o_link_popover_container"> 15600 <div class="input-group mb-1"> 15601 <input name="o_linkpopover_url_img" t-ref="url" class="o_we_href_input_link border-dark-subtle form-control form-control-sm" t-model="state.url" title="URL" placeholder="Type your URL" t-on-keydown="onKeydownEnter"/> 15602 <button class="o_we_apply_link btn btn-sm btn-primary" t-att-class="{'mx-1': state.type === ''}" t-on-click="onClickApply">Apply</button> 15603 </div> 15604 </div> 15605 <div t-else="" class="d-flex"> 15606 <t t-if="state.showAdvancedOptions"> 15607 <div class="o_advance_option_panel"> 15608 <div class="o_advance_options_grid" style="width: 200px;"> 15609 <button t-if="state.showAdvancedOptions" class="fa fa-angle-left btn btn-secondary border-10" t-on-click="toggleAdvancedOptions"/> 15610 <t t-foreach="Object.values(state.relAttributeOptions)" t-as="opt" t-key="opt.label"> 15611 <t t-if="opt.label !== 'noopener'"> 15612 <div class="o_seo_option_row d-flex justify-content-between align-items-center py-1 gap-2">
15613 <span t-att-title="opt.description"><t t-out="opt.label"/></span> 15614 <CheckBox value="opt.isChecked" onChange="toggleRelAttr.bind(this, opt.label)"/> 15615 </div> 15616 </t> 15617 </t> 15618 <div class="o_seo_option_row d-flex justify-content-between align-items-center py-1 gap-2"> 15619 <span>Open in new tab</span> 15620 <CheckBox value="state.linkTarget === '_blank'" onChange="onClickNewWindow.bind(this)" className="'target-blank-option'"/> 15621 </div> 15622 <t t-if="state.linkTarget === '_blank'"> 15623 <div class="o_seo_option_row o_seo_option_child d-flex justify-content-between align-items-center py-1 gap-2 ps-4"> 15624 <span>noopener</span> 15625 <CheckBox value="state.relAttributeOptions.noopener.isChecked" onChange="toggleRelAttr.bind(this, 'noopener')"/> 15626 </div> 15627 </t> 15628 </div> 15629 </div> 15630 </t> 15631 <t t-else=""> 15632 <div class="col p-2 o_link_popover_container"> 15633 <div class="input-group mb-2" t-att-class="{'d-none': !state.showLabel}"> 15634 <input t-ref="label" class="o_we_label_link border-dark-subtle form-control form-control-sm" t-model="state.label" title="Label" placeholder="Add a label for your link" t-on-input="onChange"/> 15635 </div> 15636 <div class="input-group mb-2"> 15637 <input t-ref="url" name="o_linkpopover_url" class="o_we_href_input_link border-dark-subtle form-control form-control-sm" t-model="state.url" title="URL" placeholder="e.g. https://www.odoo.com" t-on-keydown="onKeydownEnter" t-on-input="this.onChange"/> 15638 <span class="ms-1" t-if="props.canUpload"> 15639 or <button class="btn btn-light btn-sm" t-on-click="uploadFile"><i class="fa fa-upload"/></button> 15640 </span> 15641 15642 </div> 15643 <div class="input-group"> 15644 <select name="link_type" class="form-select form-select-sm border-dark-subtle w-100 mb-1" t-model="state.type" t-on-change="onChange"> 15645 <t t-foreach="this.colorsData" t-as="colorData" t-key="colorData.type"> 15646 <t t-if="props.allowCustomStyle or colorData.type !== 'custom'"> 15647 <option t-att-value="colorData.type" t-att-selected="state.type === colorData.type" t-attf-class="o_btn_preview" t-out="colorData.label"/> 15648 </t> 15649 </t> 15650 </select> 15651 </div> 15652 <div t-if="state.type" class="input-group"> 15653 <select name="link_style_size" class="form-select form-select-sm border-dark-subtle mb-1" t-model="state.buttonSize" t-on-change="onChange" aria-label="Select button size"> 15654 <option t-foreach="this.buttonSizesData" t-as="buttonSizesData" t-key="buttonSizesData.size" t-att-value="buttonSizesData.size" t-att-selected="state.buttonSize === buttonSizesData.size" t-out="buttonSizesData.label"/> 15655 </select> 15656 <select name="link_style_shape" class="form-select form-select-sm link-style border-dark-subtle mb-1" t-model="state.buttonShape" t-on-change="onChange" aria-label="Select button shape"> 15657 <option t-foreach="this.buttonShapeData" t-as="buttonShapeData" t-key="buttonShapeData.shape" t-att-value="buttonShapeData.shape" t-att-selected="state.buttonShape === buttonShapeData.shape" t-out="buttonShapeData.label"/> 15658 </select> 15659 </div> 15660 15661 <t t-if="state.type === 'custom'"> 15662 <div class="d-flex mb-1 custom-text-color"> 15663 <label>Text Color</label> 15664 <button class="o_we_color_preview custom-text-picker me-3" t-att-data-color="this.customTextColorState.selectedColor" t-ref="customTextColorButton" t-attf-style="background-color: {{this.props.formatColor(this.customTextColorState.selectedColor)}}"/> 15665 <label>Fill Color</label> 15666 <button class="o_we_color_preview custom-fill-picker" t-att-data-color="this.customFillColorState.selectedColor" t-ref="customFillColorButton" t-attf-style="{{this.customFillColorState.selectedColor?.includes('gradient') ? 'background-image' : 'background-color'}}: {{this.props.formatColor(this.customFillColorState.selectedColor)}}"/> 15667 </div> 15668 <div class="d-flex mb-1 custom-border align-items-center"> 15669 <label class="flex-shrink-0">Border</label> 15670 <div class="input-group me-1"> 15671 <input type="number" min="0" class="form-control form-control-sm custom-border-size flex-grow-0" t-model="state.customBorderSize" placeholder="Border Size" t-on-keydown="onKeydownEnter" t-on-input="onInput"/>
15672 <span class="input-group-text">px</span> 15673 </div> 15674 <div class="d-flex align-items-center" t-if="state.customBorderSize > 0"> 15675 <select name="link_style_border" class="form-select form-select-sm custom-border-style me-1" t-model="state.customBorderStyle" t-on-change="onChange"> 15676 <t t-foreach="this.borderData" t-as="borderData" t-key="borderData.style"> 15677 <option t-att-value="borderData.style" t-att-selected="state.customBorderStyle === borderData.style"> 15678 <span t-esc="borderData.label"/> 15679 </option> 15680 </t> 15681 </select> 15682 <button class="o_we_color_preview custom-border-picker" t-att-data-color="this.customBorderColorState.selectedColor" t-ref="customBorderColorButton" t-attf-style="background-color: {{this.props.formatColor(this.customBorderColorState.selectedColor)}}"/> 15683 </div> 15684 </div> 15685 </t> 15686 <t t-if="props.allowTargetBlank"> 15687 <t t-if="state.isDocument"> 15688 <CheckBox value="state.directDownload" onChange="onClickDirectDownload.bind(this)" className="'direct-download-option'"> 15689 Direct download 15690 </CheckBox> 15691 </t> 15692 </t> 15693 <t t-if="props.allowStripDomain and isAbsoluteURLInCurrentDomain()"> 15694 <CheckBox value="state.stripDomain" onChange="onClickStripDomain.bind(this)" className="'strip-domain-option'"> 15695 Autoconvert to relative link 15696 </CheckBox> 15697 </t> 15698 <div class="d-flex justify-content-between align-items-center mt-1"> 15699 <div> 15700 <button class="o_we_apply_link btn btn-sm btn-primary" t-att-disabled="!state.url" t-on-click="onClickApply">Apply</button> 15701 <button class="o_we_discard_link btn btn-sm btn-secondary ms-1" t-on-click="this.discard">Discard</button> 15702 </div> 15703 <div class="d-flex align-items-center gap-1"> 15704 <a t-if="props.canRemove and state.url" href="#" class="o_we_remove_link text-dark d-flex me-1" t-on-click.prevent="onClickRemove" title="Remove Link"> 15705 <i class="fa fa-chain-broken"/> 15706 </a> 15707 <button class="btn btn-sm btn-secondary" title="Advanced mode" t-att-disabled="!state.url" t-on-click="toggleAdvancedOptions"> 15708 <i class="fa fa-gear"/> 15709 </button> 15710 </div> 15711 </div> 15712 </div> 15713 </t> 15714 </div> 15715 </div> 15716 <div t-else="" style="width: 274px;" data-prevent-closing-overlay="true"> 15717 <div class="d-flex flex-column p-2"> 15718 <div class="d-flex"> 15719 <span class="o_we_preview_favicon" style="width: 16px; height: 18px"> 15720 <img t-if="state.previewIcon.type === 'imgSrc'" t-att-src="state.previewIcon.value" class="align-content-center"/> 15721 <span t-elif="state.previewIcon.type === 'mimetype'" class="o_image" t-att-data-mimetype="state.previewIcon.value"/> 15722 <i t-else="" t-attf-class="fa fa-fw {{state.previewIcon.value}}"/> 15723 </span> 15724 <div class="ms-1 w-100"> 15725 <div class="d-flex"> 15726 <a href="#" target="_blank" t-attf-href="{{state.url}}" class="o_we_url_link fw-bold flex-grow-1 text-truncate" style="max-width: 160px;" t-attf-title="{{state.urlTitle}}"> 15727 <t t-esc="state.urlTitle"/> 15728 </a> 15729 <div class="flex-grow-1 d-flex justify-content-end align-items-center gap-1"> 15730 <a href="#" class="justify-content-center btn-link o_we_replace_title_btn text-dark" t-if="this.state.canReplaceTitle and state.urlTitle and state.label === '' and !state.showReplaceTitleBanner" t-on-click="onClickReplaceTitle" title="Replace URL with its title"> 15731 <i class="fa fa-magic"/> 15732 </a> 15733 <t t-if="props.canEdit"> 15734 <a href="#" class="o_we_edit_link btn btn-sm btn-secondary" t-on-click="onClickEdit" title="Edit Link">Edit</a> 15735 </t> 15736 </div> 15737 </div> 15738 <div t-if="state.urlTitle and state.url and state.urlTitle !== state.url" class="text-truncate" style="max-width: 200px; font-size: 12px;">
15739 <span t-attf-class="o_we_full_url text-muted o_we_webkit_box" t-attf-title="{{state.url}}"> 15740 <t t-if="state.url" t-esc="state.url"/> 15741 <t t-else="">No URL specified</t> 15742 </span> 15743 </div> 15744 </div> 15745 </div> 15746 <div t-if="state.imgSrc" class="o_extra_info_card" style="align-self: center; max-width: 235px"> 15747 <a href="#" target="_blank" t-attf-href="{{state.url}}" title="Open in a new tab"> 15748 <img t-att-src="state.imgSrc" class="img-fluid mb-1" style="max-width: 230; max-height: 100%;"/> 15749 </a> 15750 </div> 15751 <div t-if="state.urlDescription" class="d-flex"> 15752 <i class="fa fa-align-right align-content-center"/> 15753 <span class="ms-1 o_we_description_link_preview" style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; font-size: 12px;color: gray; overflow: hidden;" t-attf-title="{{state.urlDescription}}"> 15754 <t t-esc="state.urlDescription"/> 15755 </span> 15756 </div> 15757 </div> 15758 <div t-if="this.state.canReplaceTitle and state.urlTitle and state.label === '' and state.showReplaceTitleBanner" class="d-flex align-items-baseline" style="background-color: var(--primary);"> 15759 <i class="fa fa-magic fa-fw m-1" style="color: var(--o-cc1-btn-primary-text);"/> 15760 <span class="me-2 flex-grow-1" style="color: var(--o-cc1-btn-primary-text);font-size: smaller;">Replace URL with its title?</span> 15761 <button class=" btn btn-sm btn-primary o_we_replace_title_btn" style="margin: 1px;font-size: smaller;" t-on-click="onClickReplaceTitle">Yes</button> 15762 </div> 15763 </div> 15764 </div> 15765 </t> 15766 15767`); 15768registerTemplate("html_editor.ListSelector", `/html_editor/static/src/main/list/list_selector.xml`, `<t t-name="html_editor.ListSelector" xml:space="preserve"> 15769 <Dropdown menuClass="'o-we-toolbar-dropdown'" bottomSheet="false" menuRef="menuRef"> 15770 <button class="btn btn-light fa fa-list-ul" t-att-title="props.title" name="list_selector"/> 15771 <t t-set-slot="content" t-key="props.key.value"> 15772 <div data-prevent-closing-overlay="true"> 15773 <t t-set="activeMode" t-value="getActiveMode()"/> 15774 <t t-foreach="props.getButtons()" t-as="button" t-key="button_index"> 15775 <button t-att-title="button.description" t-att-name="button.id" t-attf-class="btn btn-light fa {{button.icon}}" t-att-class="{ active: activeMode === button.mode }" t-on-click="button.run" t-on-pointerdown.prevent="() => {}"/> 15776 </t> 15777 </div> 15778 </t> 15779 </Dropdown> 15780 </t> 15781`); 15782registerTemplate("html_editor.ImageCrop", `/html_editor/static/src/main/media/image_crop.xml`, `<t t-name="html_editor.ImageCrop" xml:space="preserve"> 15783 <div class="o_we_crop_widget" tabindex="-1" contenteditable="false" t-ref="el" t-on-zoom="this.onCropZoom"> 15784 <div class="o_we_cropper_wrapper" t-ref="cropperWrapper"> 15785 <img class="o_we_cropper_img" t-ref="imageRef"/> 15786 <div class="o_we_crop_buttons text-center mt16 position-fixed o_we_no_overlay" contenteditable="false"> 15787 <div class="btn-group btn-group-toggle" title="Aspect Ratio" data-bs-toggle="buttons"> 15788 <t t-foreach="this.aspectRatios" t-as="ratio" t-key="ratio"> 15789 <t t-set="is_active" t-value="ratio === this.aspectRatio"/> 15790 <label t-attf-class="btn #{is_active and 'active' or ''}" t-on-click="() => this.setAspectRatio(ratio)"> 15791 <input type="radio"/><t t-esc="ratio_value.label"/> 15792 </label> 15793 </t> 15794 </div> 15795 <div class="btn-group" role="group"> 15796 <button type="button" title="Zoom In" t-on-click="() => this.onZoom(0.1)"><i class="fa fa-fw fa-search-plus"/></button> 15797 <button type="button" title="Zoom Out" t-on-click="() => this.onZoom(-0.1)"><i class="fa fa-fw fa-search-minus"/></button> 15798 </div> 15799 <div class="btn-group" role="group"> 15800 <button type="button" title="Rotate Left" t-on-click="() => this.onRotate(-90)"><i class="fa fa-fw fa-rotate-left"/></button> 15801 <button type="button" title="Rotate Right" t-on-click="() => this.onRotate(90)"><i class="fa fa-fw fa-rotate-right"/></button> 15802 </div> 15803 <div class="btn-group" role="group"> 15804 <button type="button" title="Flip Horizontal" t-on-click="() => this.onFlip('scaleX')"><i class="oi oi-fw oi-arrows-h"/></button> 15805 <button type="button" title="Flip Vertical" t-on-click="() => this.onFlip('scaleY')"><i class="oi oi-fw oi-arrows-v"/></button> 15806 </div> 15807 <div class="btn-group" role="group"> 15808 <button type="button" title="Reset Image" t-on-click="this.onReset"><i class="fa fa-refresh"/> Reset Image</button> 15809 </div> 15810 <div class="btn-group" role="group"> 15811 <button type="button" t-ref="applyButton" t-on-click="this.save" class="btn btn-primary"><i class="fa fa-check" role="presentation"/> Apply</button> 15812 <button type="button" t-ref="discardButton" t-on-click="this.closeCropper" class="btn btn-danger"><i class="oi oi-close" role="presentation"/> Discard</button> 15813 </div> 15814 </div> 15815 </div> 15816 </div> 15817 </t> 15818`); 15819registerTemplate("html_editor.ImageDescription", `/html_editor/static/src/main/media/image_description.xml`, `<t t-name="html_editor.ImageDescription" xml:space="preserve"> 15820 <button class="btn btn-light" t-att-title="props.title" t-on-click="this.props.openImageDescriptionPopover"> 15821 Description 15822 </button> 15823 </t> 15824 15825 `); 15826registerTemplate("html_editor.ImageDescriptionPopover", `/html_editor/static/src/main/media/image_description.xml`, `<t t-name="html_editor.ImageDescriptionPopover" xml:space="preserve"> 15827 <div class="o-we-image-description-popover p-3"> 15828 <input t-ref="description" type="text" t-model="this.state.description" placeholder="Description" title="'Alt tag' specifies an alternate text for an image, if the image cannot be displayed (slow connection, missing image, screen reader ...)." name="description" class="border-dark-subtle form-control mb-2"/> 15829 <input type="text" t-model="this.state.tooltip" placeholder="Tooltip" title="'Title tag' is shown as a tooltip when you hover the picture." name="tooltip" class="border-dark-subtle form-control mb-2"/> 15830 <div class="mt-3"> 15831 <button class="o_we_apply_link btn btn-sm btn-primary" t-on-click="this.onSave">Apply</button> 15832 <button class="o_we_discard_link btn btn-sm btn-dark ms-1" t-on-click="this.props.close">Discard</button> 15833 </div> 15834 </div> 15835 </t> 15836`); 15837registerTemplate("html_editor.ImageToolbarDropdown", `/html_editor/static/src/main/media/image_toolbar_dropdown.xml`, `<t t-name="html_editor.ImageToolbarDropdown" xml:space="preserve"> 15838 <Dropdown menuClass="\`\${props.name}_selector\`" menuRef="menuRef"> 15839 <button t-att-title="props.title" class="btn btn-light"> 15840 <t t-if="props.icon" t-call="{{props.icon}}"/> 15841 <t t-elif="state && state.displayName" t-esc="state.displayName"/> 15842 <t t-else="" t-esc="props.title"/> 15843 </button> 15844 <t t-set-slot="content"> 15845 <div data-prevent-closing-overlay="true"> 15846 <t t-foreach="items" t-as="item" t-key="item_index"> 15847 <DropdownItem class="'user-select-none'" onSelected="() => this.onSelected(item)"> 15848 <t t-esc="item.name"/> 15849 </DropdownItem> 15850 </t> 15851 </div> 15852 </t> 15853 </Dropdown> 15854 </t> 15855 15856 `); 15857registerTemplate("html_editor.ImagePaddingIcon", `/html_editor/static/src/main/media/image_toolbar_dropdown.xml`, `<t t-name="html_editor.ImagePaddingIcon" xml:space="preserve"> 15858 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" width="20" height="20" stroke-width="2"> 15859 <path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"/> 15860 <path d="M8 16v.01"/> 15861 <path d="M8 12v.01"/> 15862 <path d="M8 8v.01"/> 15863 <path d="M16 16v.01"/> 15864 <path d="M16 12v.01"/> 15865 <path d="M16 8v.01"/> 15866 <path d="M12 8v.01"/> 15867 <path d="M12 16v.01"/> 15868 </svg> 15869 </t> 15870`); 15871registerTemplate("html_editor.ImageTransformButton", `/html_editor/static/src/main/media/image_transform_button.xml`, `<t t-name="html_editor.ImageTransformButton" xml:space="preserve"> 15872 <button class="btn btn-light" t-att-class="{active: state.active, disabled: props.isDisabled}" t-att-title="state.active ? props.activeTitle : props.title" t-att-name="props.id" t-on-click="onButtonClick">
15873 <span class="fa fa-fw" t-att-class="props.icon"/> 15874 </button> 15875 </t> 15876`); 15877registerTemplate("html_editor.ImageTransformation", `/html_editor/static/src/main/media/image_transformation.xml`, `<t t-name="html_editor.ImageTransformation" xml:space="preserve"> 15878 <div class="transfo-container" t-ref="transfoContainer" t-on-mousedown.prevent="mouseDown"> 15879 <div class="transfo-controls" t-ref="transfoControls"> 15880 <div style="cursor: crosshair; position: absolute; margin: -30px; top: 0; right: 0; padding: 1px 0 0 1px;" class="transfo-rotator"> 15881 <span class="fa-stack fa-lg"> 15882 <i class="fa fa-circle fa-stack-2x"/> 15883 <i class="fa fa-repeat fa-stack-1x fa-inverse"/> 15884 </span> 15885 </div> 15886 <div style="top: 0%; left: 0%; cursor: nw-resize;" class="transfo-scaler transfo-scaler-tl"/> 15887 <div style="top: 0%; left: 100%; cursor: ne-resize;" class="transfo-scaler transfo-scaler-tr"/> 15888 <div style="top: 100%; left: 100%; cursor: se-resize;" class="transfo-scaler transfo-scaler-br"/> 15889 <div style="top: 100%; left: 0%; cursor: sw-resize;" class=" transfo-scaler transfo-scaler-bl"/> 15890 <div style="top: 0%; left: 50%; cursor: n-resize;" class="transfo-scaler transfo-scaler-tc"/> 15891 <div style="top: 100%; left: 50%; cursor: s-resize;" class="transfo-scaler transfo-scaler-bc"/> 15892 <div style="top: 50%; left: 0%; cursor: w-resize;" class="transfo-scaler transfo-scaler-ml"/> 15893 <div style="top: 50%; left: 100%; cursor: e-resize;" class="transfo-scaler transfo-scaler-mr"/> 15894 <div style="border: 0; width: 0px; height: 0px; top: 50%; left: 50%;" class="transfo-scaler transfo-scaler-mc" t-ref="transfoCenter"/> 15895 </div> 15896 </div> 15897 </t> 15898`); 15899registerTemplate("html_editor.Powerbox", `/html_editor/static/src/main/powerbox/powerbox.xml`, `<t t-name="html_editor.Powerbox" xml:space="preserve"> 15900 <div t-ref="root" class="o-we-powerbox py-2 bg-light overflow-auto my-1" style="width:300px;max-height:40vh;" t-on-mousedown.stop="" t-on-scroll="onScroll"> 15901 <t t-foreach="commands" t-as="command" t-key="command_index"> 15902 <t t-if="showCategories and command.categoryId !== lastCategory"> 15903 <div class="o-we-category mx-3 my-1 text-uppercase"><t t-esc="command.categoryName"/></div></t> 15904 <t t-set="lastCategory" t-value="command.categoryId"> 15905 </t> 15906 <div class="o-we-command d-flex align-items-center px-3 py-2 cursor-pointer" t-att-class="{active: command_index === currentIndex}" t-on-mouseenter="() => this.onMouseEnter(command_index)" t-on-mousedown="(ev) => ev.preventDefault()" t-on-click="() => this.props.applyCommand(command)"> 15907 <div class="border rounded"> 15908 <i class="o-we-command-img d-flex align-items-center justify-content-center fa" t-att-class="command.icon"/> 15909 </div> 15910 <div class="ms-3"> 15911 <div class="o-we-command-name" t-esc="command.title"/> 15912 <div class="o-we-command-description" t-esc="command.description"/> 15913 </div> 15914 </div> 15915 </t> 15916 </div> 15917 </t> 15918`); 15919registerTemplate("html_editor.Signature", `/html_editor/static/src/main/signature.xml`, `<t t-name="html_editor.Signature" xml:space="preserve"> 15920 <div t-att-class="signatureClass" t-out="signature"/> 15921 </t> 15922`); 15923registerTemplate("html_editor.TableAlignSelector", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.TableAlignSelector" xml:space="preserve"> 15924 <Dropdown menuClass="'o-we-toolbar-dropdown'" bottomSheet="false" menuRef="menuRef"> 15925 <button class="btn btn-light" t-att-title="props.title" name="vertical_align"> 15926 <t t-set="selectedItem" t-value="items.find(item => item.mode === state.displayName)"/> 15927 <t t-call="{{ selectedItem ? selectedItem.template : 'html_editor.VerticalAlignTop' }}"/> 15928 </button> 15929 <t t-set-slot="content"> 15930 <div data-prevent-closing-overlay="true"> 15931 <t t-foreach="items" t-as="item" t-key="item.mode"> 15932 <button t-attf-class="btn btn-light" t-att-class="{ active: item.mode === state.displayName }" t-on-pointerdown.prevent="() => {}" t-on-click="() => this.onSelected(item)"> 15933 <t t-call="{{item.template}}"/> 15934 </button> 15935 </t> 15936 </div> 15937 </t> 15938 </Dropdown> 15939 </t> 15940 15941 `); 15942registerTemplate("html_editor.VerticalAlignTop", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.VerticalAlignTop" xml:space="preserve"> 15943 <svg xmlns="http://www.w3.org/2000/svg" class="oe-vertical-align-icon" name="vertical_align_top" viewBox="0 0 60 60" width="16" height="16"> 15944 <g> 15945 <path d="M51.542,9.5H36.458C34.551,9.5,33,11.051,33,12.958v29.083c0,1.907,1.551,3.458,3.458,3.458h15.083 c1.907,0,3.458-1.551,3.458-3.458V12.958C55,11.051,53.449,9.5,51.542,9.5z M53,13.5v28.042 c0,0.804-0.654,1.458-1.458,1.458H36.458C35.654,43.5,35,42.846,35,42.042V12.958c0-0.804,0.654-1.458,1.458-1.458h15.083 c0.804,0,1.458,0.654,1.458,1.458V13.5z"/> 15946 <path d="M23.542,9.5H8.458C6.551,9.5,5,11.051,5,12.958v39.083C5,53.949,6.551,55.5,8.458,55.5h15.083 c1.907,0,3.458-1.551,3.458-3.458V12.958C27,11.051,25.449,9.5,23.542,9.5z"/> 15947 <path d="M59,4.5H1c-0.552,0-1,0.448-1,1s0.448,1,1,1h58c0.552,0,1-0.448,1-1S59.552,4.5,59,4.5z"/> 15948 </g> 15949 </svg> 15950 </t> 15951 15952 `); 15953registerTemplate("html_editor.VerticalAlignMiddle", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.VerticalAlignMiddle" xml:space="preserve"> 15954 <svg xmlns="http://www.w3.org/2000/svg" class="oe-vertical-align-icon" name="vertical_align_middle" viewBox="0 0 60 60" width="16" height="16"> 15955 <g> 15956 <path d="M59,29h-4V15.458C55,13.551,53.448,12,51.541,12H36.458C34.551,12,33,13.551,33,15.458V29h-6V10.458 C27,8.551,25.449,7,23.542,7H8.458C6.551,7,5,8.551,5,10.458V29H1c-0.552,0-1,0.448-1,1s0.448,1,1,1h4v18.542 C5,51.449,6.551,53,8.458,53h15.083C25.449,53,27,51.449,27,49.542V31h6v13.542C33,46.449,34.551,48,3
159566.458,48h15.083 C53.449,48,55,46.449,55,44.542V31h4c0.553,0,1-0.448,1-1S59.553,29,59,29z M53,34v10.542 C53,45.346,52.346,46,51.542,46H36.458C35.654,46,35,45.346,35,44.542V15.458C35,14.654,35.654,14,36.458,14h15.083 C52.346,14,53,14.654,53,15.458V34z"/> 15957 </g> 15958 </svg> 15959 </t> 15960 15961 `); 15962registerTemplate("html_editor.VerticalAlignBottom", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.VerticalAlignBottom" xml:space="preserve"> 15963 <svg xmlns="http://www.w3.org/2000/svg" class="oe-vertical-align-icon" name="vertical_align_bottom" viewBox="0 0 60 60" width="16" height="16"> 15964 <g> 15965 <path d="M36.458,50.5h15.083c1.669,0,3.065-1.188,3.388-2.762C54.976,47.513,55,47.28,55,47.042V17.958 c0-1.907-1.551-3.458-3.458-3.458H36.459C34.552,14.5,33,16.051,33,17.958v29.083c0,0.238,0.024,0.471,0.07,0.696 C33.393,49.312,34.789,50.5,36.458,50.5z M35,17.958c0-0.804,0.654-1.458,1.459-1.458h15.083c0.804,0,1.458,0.654,1.458,1.458 v29.584c0,0.201-0.041,0.393-0.115,0.567c-0.222,0.523-0.741,0.891-1.344,0.891H36.459c-0.604,0-1.122-0.368-1.344-0.891 C35.041,47.434,35,47.243,35,47.042V17.958z"/> 15966 <path d="M8.458,50.5h15.083c1.907,0,3.459-1.551,3.459-3.458V7.958C27,6.051,25.449,4.5,23.542,4.5H8.459 C6.552,4.5,5,6.051,5,7.958v39.083C5,48.949,6.551,50.5,8.458,50.5z"/> 15967 <path d="M59,53.5H1c-0.553,0-1,0.448-1,1s0.447,1,1,1h58c0.553,0,1-0.448,1-1S59.553,53.5,59,53.5z"/> 15968 </g> 15969 </svg> 15970 </t> 15971`); 15972registerTemplate("html_editor.TableMenu", `/html_editor/static/src/main/table/table_menu.xml`, `<t t-name="html_editor.TableMenu" xml:space="preserve"> 15973 <Dropdown menuClass="'m-0'" position="props.type === 'column' ? 'bottom' : 'right'" state="props.dropdownState" bottomSheet="false"> 15974 <button type="button" t-on-pointerdown.prevent="() => {}" t-att-data-type="props.type" class="o-we-table-menu oi" t-attf-class="oi-ellipsis-{{props.type === 'column' ? 'h w-100' : 'v h-100 px-0'}}" t-ref="dropdown"/> 15975 <t t-set-slot="content"> 15976 <div t-on-pointerdown.stop="() => {}"> 15977 <t t-foreach="items" t-as="item" t-key="item_index"> 15978 <DropdownItem onSelected="() => this.onSelected(item)"> 15979 <div class="user-select-none" t-att-name="item.name"> 15980 <span t-if="item.icon" class="me-2 fa" t-att-class="item.icon"/> 15981 <span t-esc="item.text"/> 15982 </div> 15983 </DropdownItem> 15984 </t> 15985 </div> 15986 </t> 15987 </Dropdown> 15988 </t> 15989`); 15990registerTemplate("html_editor.TablePicker", `/html_editor/static/src/main/table/table_picker.xml`, `<t t-name="html_editor.TablePicker" xml:space="preserve"> 15991 <div class="o-we-tablepicker bg-light p-1 my-1" t-on-click="insertTable" t-on-mousedown.stop=""> 15992 <t t-foreach="new Array(state.rows + 1)" t-as="row" t-key="row_index"> 15993 <div class="o-we-row d-flex"> 15994 <t t-foreach="new Array(state.cols + 1)" t-as="col" t-key="col_index"> 15995 <div class="o-we-cell" t-att-class="{'active': col_index lt state.cols and row_index lt state.rows}" t-on-mouseenter="() => this.updateSize(col_index + 1, row_index + 1)"/> 15996 </t> 15997 </div> 15998 </t> 15999 <div class="text-center"><t t-esc="state.cols"/>x<t t-esc="state.rows"/></div> 16000 </div> 16001 </t> 16002`); 16003registerTemplate("html_editor.MobileToolbar", `/html_editor/static/src/main/toolbar/mobile_toolbar.xml`, `<t t-name="html_editor.MobileToolbar" xml:space="preserve"> 16004 <div t-ref="toolbarWrapper" class="o-toolbar-above-keyboard"> 16005 <Toolbar state="props.state" getSelection="props.getSelection" focusEditable="props.focusEditable" class="props.class"/> 16006 </div> 16007 </t> 16008`); 16009registerTemplate("html_editor.Toolbar", `/html_editor/static/src/main/toolbar/toolbar.xml`, `<t t-name="html_editor.Toolbar" xml:space="preserve"> 16010 <div class="o-we-toolbar d-flex align-items-center m-0" t-att-class="props.class" style="overflow-x: auto; overflow-y:hidden" t-on-pointerdown.prevent="" t-att-data-namespace="state.namespace" data-prevent-closing-overlay="true"> 16011 <t t-foreach="state.buttonGroups" t-as="buttonGroup" t-key="buttonGroup.id">
16012 <span class="o-we-toolbar-vertical-separator"/> 16013 <div class="btn-group" t-att-name="buttonGroup.id"> 16014 <t t-foreach="buttonGroup.buttons" t-as="button" t-key="button.id"> 16015 <t t-if="button.Component"> 16016 <t t-component="button.Component" t-props="button.props" title="button.description" getSelection.bind="props.getSelection" isDisabled="'isDisabled' in button.props ? button.props.isDisabled : !!button.isDisabled"/> 16017 </t> 16018 <button t-else="" class="btn btn-light" t-att-class="{ active: button.isActive, disabled: button.isDisabled, }" t-att-disabled="button.isDisabled" t-att-title="button.description" t-att-name="button.id" t-on-click="() => this.onButtonClick(button)"> 16019 <span t-if="button.icon" t-att-class="button.icon.includes('fa-') ? 'fa fa-fw ' + button.icon : 'oi oi-fw ' + button.icon"/> 16020 <span t-if="button.text" t-esc="button.text"/> 16021 </button> 16022 </t> 16023 </div> 16024 </t> 16025 </div> 16026 </t> 16027`); 16028registerTemplate("html_editor.EmbeddedCaption", `/html_editor/static/src/others/embedded_components/backend/caption/caption.xml`, `<t t-name="html_editor.EmbeddedCaption" xml:space="preserve"> 16029 <input t-attf-class="border-0 p-0" t-ref="captionInput" type="text" maxLength="100" t-att-placeholder="'Write your caption here'" t-on-blur="onInputBlur" t-on-keydown.stop="" t-on-beforeinput="onInputBeforeInput" t-on-keyup="onInputKeyup" t-att-value="state.caption"/> 16030 </t> 16031`); 16032registerTemplate("html_editor.EmbeddedFile", `/html_editor/static/src/others/embedded_components/backend/file/file.xml`, `<t t-name="html_editor.EmbeddedFile" t-inherit="html_editor.ReadonlyEmbeddedFile" t-inherit-mode="primary" xml:space="preserve"> 16033 <xpath expr="//span[hasclass('o_file_name_container')]" position="after"> 16034 <input t-attf-class="rounded border-0 mx-2 #{ localState.editFileName ? '' : 'd-none'}" t-ref="nameInput" type="text" maxLength="100" t-att-placeholder="fileModel.filename" t-on-blur="onBlurNameInput" t-on-input.stop="" t-on-keydown.stop="onKeydownNameInput" t-att-value="fileModel.filename"/> 16035 </xpath> 16036 <xpath expr="//span[hasclass('o_file_name_container')]" position="attributes"> 16037 <attribute name="t-att-class">{ 16038 "d-none": localState.editFileName, 16039 "cursor-pointer": true, 16040 }</attribute> 16041 <attribute name="t-on-focus">onFocusFileName</attribute> 16042 <attribute name="tabindex">-1</attribute> 16043 </xpath> 16044 <xpath expr="//span[hasclass('o_file_name')]" position="after"> 16045 <i class="fa fa-pencil mx-1 invisible align-items-center d-inline-flex"/> 16046 </xpath> 16047 </t> 16048`); 16049registerTemplate("html_editor.CodeToolbar", `/html_editor/static/src/others/embedded_components/backend/syntax_highlighting/code_toolbar.xml`, `<t t-name="html_editor.CodeToolbar" xml:space="preserve"> 16050 <div t-att-class="props.isActive ? 'show' : ''" class="o_code_toolbar"> 16051 <div data-prevent-closing-overlay="true"> 16052 <Dropdown menuClass="'o_language_selector'" focusToggleOnClosed="false"> 16053 <button class="btn" t-att-title="languages[props.currentLanguage]" name="language"> 16054 <span class="px-1" t-esc="languages[props.currentLanguage]"/> 16055 <i class="fa fa-caret-down"/> 16056 </button> 16057 <t t-set-slot="content"> 16058 <t t-foreach="Object.entries(languages)" t-as="language" t-key="language[0]"> 16059 <DropdownItem attrs="{ name: language[1] }" onSelected="() => props.onLanguageChange(language[0])" t-on-pointerdown.prevent="() => {}"> 16060 <t t-esc="language[1]"/> 16061 </DropdownItem> 16062 </t> 16063 </t> 16064 </Dropdown>
16065 <CopyButton content="props.getContent" copyText.translate="Copy" successText.translate="Code copied to the clipboard." t-on-pointerdown.prevent="() => {}"/> 16066 <button class="text-nowrap btn" t-on-click="this.props.convertToParagraph"> 16067 <span class="mx-1 fa fa-paragraph" title="Convert to paragraph"/> 16068 </button> 16069 </div> 16070 </div> 16071 </t> 16072`); 16073registerTemplate("html_editor.EmbeddedSyntaxHighlighting", `/html_editor/static/src/others/embedded_components/backend/syntax_highlighting/syntax_highlighting.xml`, `<t t-name="html_editor.EmbeddedSyntaxHighlighting" xml:space="preserve"> 16074 <CodeToolbar target="state.host" currentLanguage="embeddedState.languageId" getContent="() => this.textarea.value" onLanguageChange="onLanguageChange.bind(this)" convertToParagraph="this.props.convertToParagraph"/> 16075 <pre t-ref="pre"/> 16076 <textarea t-ref="textarea" class="o_prism_source" contenteditable="true" placeholder="Code" t-on-input="onInput" t-on-scroll="onScroll" t-on-keydown="onKeydown" t-on-focus="props.onTextareaFocus"/> 16077 </t> 16078`); 16079registerTemplate("html_editor.VideoSettings", `/html_editor/static/src/others/embedded_components/backend/video/video.xml`, `<t t-name="html_editor.VideoSettings" xml:space="preserve"> 16080 <Dropdown state="this.props.dropdown"> 16081 <button t-ref="menuRef" class="btn btn-light shadow border py-1 px-1 ms-1" title="More options"> 16082 <i class="oi oi-fw oi-ellipsis-v"/> 16083 </button> 16084 <t t-set-slot="content"> 16085 <DropdownItem onSelected="props.replaceVideo"> 16086 <i class="fa-fw fa fa-exchange me-1"/>Replace 16087 </DropdownItem> 16088 <DropdownItem onSelected="props.removeVideo" class="'text-danger'"> 16089 <i class="fa fa-fw fa-trash me-1"/>Remove 16090 </DropdownItem> 16091 </t> 16092 </Dropdown> 16093 </t> 16094`); 16095registerTemplate("html_editor.EmbeddedCaptionBlueprint", `/html_editor/static/src/others/embedded_components/plugins/caption_plugin/caption_blueprint.xml`, `<t t-name="html_editor.EmbeddedCaptionBlueprint" xml:space="preserve"> 16096 <figcaption contenteditable="false" class="mt-2"> 16097 <span class="o_caption_editable" contenteditable="true" t-att-data-caption-id="captionId"/> 16098 </figcaption> 16099 </t> 16100`); 16101registerTemplate("html_editor.EmbeddedFileBlueprint", `/html_editor/static/src/others/embedded_components/plugins/embedded_file_plugin/file_blueprint.xml`, `<t t-name="html_editor.EmbeddedFileBlueprint" xml:space="preserve"> 16102 <span t-att-data-embedded-props="embeddedProps" data-embedded="file" data-oe-protected="true" contenteditable="false" class="o_file_box o-contenteditable-false"/> 16103 </t> 16104`); 16105registerTemplate("html_editor.EmbeddedSyntaxHighlightingBlueprint", `/html_editor/static/src/others/embedded_components/plugins/syntax_highlighting_plugin/syntax_highlighting_blueprint.xml`, `<t t-name="html_editor.EmbeddedSyntaxHighlightingBlueprint" xml:space="preserve"> 16106 <div t-att-data-embedded-props="embeddedProps" data-embedded="syntaxHighlighting" data-oe-protected="true" contenteditable="false" class="o_syntax_highlighting"/> 16107 </t> 16108`); 16109registerTemplate("html_editor.TableOfContentBlueprint", `/html_editor/static/src/others/embedded_components/plugins/table_of_content_plugin/table_of_content_blueprint.xml`, `<t t-name="html_editor.TableOfContentBlueprint" xml:space="preserve"> 16110 <div data-embedded="tableOfContent" data-oe-protected="true" contenteditable="false"/> 16111 </t> 16112`); 16113registerTemplate("html_editor.EmbeddedToggleBlockBlueprint", `/html_editor/static/src/others/embedded_components/plugins/toggle_block_plugin/toggle_block_blueprint.xml`, `<t t-name="html_editor.EmbeddedToggleBlockBlueprint" xml:space="preserve"> 16114 <div data-embedded="toggleBlock" data-oe-protected="true" contenteditable="false" t-att-data-embedded-props="embeddedProps"> 16115 <div data-embedded-editable="title" data-oe-protected="false" contenteditable="true"> 16116 <t t-tag="baseContainerNodeName" t-att="baseContainerAttributes"><br/></t> 16117 </div> 16118 <div data-embedded-editable="content" data-oe-protected="false" contenteditable="true"> 16119 <t t-tag="baseContainerNodeName" t-att="baseContainerAttributes"><br/></t> 16120 </div> 16121 </div> 16122 </t> 16123`); 16124registerTemplate("html_editor.EmbeddedVideoBlueprint", `/html_editor/static/src/others/embedded_components/plugins/video_plugin/video_blueprint.xml`, `<t t-name="html_editor.EmbeddedVideoBlueprint" xml:space="preserve"> 16125 <div t-att-data-embedded-props="embeddedProps" data-embedded="video" data-oe-protected="true" contenteditable="false"/> 16126 </t> 16127`); 16128registerTemplate("html_editor.QWebPicker", `/html_editor/static/src/others/qweb_picker.xml`, `<t t-name="html_editor.QWebPicker" xml:space="preserve"> 16129 <div class="o-we-qweb-picker bg-white my-1"> 16130 <t t-foreach="state.groups" t-as="group" t-key="group_index"> 16131 <select class="form-select" t-on-change="onChange"> 16132 <t t-foreach="group" t-as="element" t-key="element_index"> 16133 <option t-attf-value="{{group_index}},{{element_index}}" t-att-selected="element.isActive"> 16134 <t t-esc="element.label"/> 16135 </option> 16136 </t> 16137 </select> 16138 </t> 16139 </div> 16140 </t> 16141`); 16142registerTemplate("mail.ActionList", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.ActionList" xml:space="preserve"> 16143 <div class="o-mail-ActionList flex-shrink-0 d-flex" t-att-class="{ 'align-items-center': props.inline,'flex-column': !props.inline }"> 16144 <t t-set="groupAttClass" t-value="{ [props.groupClass]: true, 'flex-column w-100 bg-transparent': !props.inline, 'o-inline rounded-3': props.inline, 'o-rounded-bubble': props.inline and !hasBtnBg, }"/> 16145 <t t-foreach="groups" t-as="group" t-key="group_index">
16146 <span t-if="group.length" class="o-mail-ActionList-group btn-group" t-att-class="groupAttClass"> 16147 <Action t-foreach="group" t-as="action" t-key="action.id" t-props="getActionProps(action, group, { isFirstInGroup: action_first, index: action_index, isLastInGroup: action_last })"/> 16148 </span> 16149 <t t-if="!group_last" t-call="mail.ActionList.groupSeparator"/> 16150 </t> 16151 </div> 16152</t> 16153 16154`); 16155registerTemplate("mail.ActionList.groupSeparator", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.ActionList.groupSeparator" xml:space="preserve"> 16156 <span t-if="props.inline" class="text-muted align-self-stretch ms-2 me-1"/> 16157 <hr t-else="" class="mx-2 my-1 o-rounded-bubble"/> 16158</t> 16159 16160`); 16161registerTemplate("mail.Action", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action" xml:space="preserve"> 16162 <t t-if="action.dropdown"> 16163 <t t-component="Dropdown" menuClass="(action.dropdownMenuClass ?? '') + ' ' + store.discussDropdownMenuClass(this)" position="action.dropdownPosition" state="action.dropdownState"> 16164 <t t-call="mail.Action.main"/> 16165 <t t-set-slot="content"> 16166 <t t-if="action.dropdownComponent" t-component="action.dropdownComponent" t-props="action.dropdownComponentProps"/> 16167 <t t-elif="action.dropdownTemplate" t-call="{{ action.dropdownTemplate }}"> 16168 <t t-set="templateParams" t-value="action.dropdownTemplateParams"/> 16169 </t> 16170 <t t-elif="action.definition?.isMoreAction"> 16171 <t t-component="ActionList" actions="action.definition.actions" dropdown="true"/> 16172 </t> 16173 <t t-else="">No content.</t> 16174 </t> 16175 </t> 16176 </t> 16177 <t t-else="" t-call="mail.Action.main"/> 16178</t> 16179 16180`); 16181registerTemplate("mail.Action.main", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action.main" xml:space="preserve"> 16182 <t t-set="isComposerRoundedBtn" t-value="props.inline and env.inComposer"/> 16183 <t t-set="isThreadRoundedBtn" t-value="props.inline and action.tags.includes('JOIN_LEAVE_CALL') and action.icon and !action.inlineName"/> 16184 <t t-set="btnClass" t-value="attClassObjectToString({ [action.btnClass ?? '']: true, [action.tagClassNames]: true, 'position-relative': true, 'active': action.isActive, 'o-mail-ActionList-button btn btn-group-item': true, 'o-first': props.isFirstInGroup, 'o-last': props.isLastInGroup, 'o-odooControlPanelSwitchStyle': props.odooControlPanelSwitchStyle, 'o-hasBtnBg': hasBtnBg, 'rounded-circle': isComposerRoundedBtn or isThreadRoundedBtn, 'rounded-start-3': !isComposerRoundedBtn and !isThreadRoundedBtn and !action.tags.includes('JOIN_LEAVE_CALL') and props.inline and props.isFirstInGroup, 'rounded-end-3': !isComposerRoundedBtn and !isThreadRoundedBtn and !action.tags.includes('JOIN_LEAVE_CALL') and props.inline and props.isLastInGroup, 'px-2 o-py-1_5': props.inline and env.inMeetingView and !env.inComposer, 'o-px-1_5 py-1': props.inline and (hasBtnBg and !action.tags.includes('JOIN_LEAVE_CALL') and !env.inMeetingView) or (!hasBtnBg and env.inComposer), 'd-flex align-items-center': props.inline and hasBtnBg and action.tags.includes('JOIN_LEAVE_CALL') and !env.inChatWindow, 'o-p-1_5': props.inline and hasBtnBg and action.tags.includes('JOIN_LEAVE_CALL') and !env.inChatWindow and !env.inMeetingView, 'p-1 d-flex align-items-center': props.inline and hasBtnBg and action.tags.includes('JOIN_LEAVE_CALL') and env.inChatWindow, 'o-inline': props.inline, 'o-p-0_5': props.inline and !hasBtnBg and !env.inComposer, 'border-0': props.inline and !hasBtnBg and action.icon, 'border-2 o-px-0_5 o-mx-0_5': props.inline and !hasBtnBg and !action.icon, 'px-3 py-2': props.dropdown and ui.isSmall, 'py-1': props.dropdown and !ui.isSmall, 'text-start px-2': !props.inline and !ui.isSmall, 'btn-secondary': !action.tags.includes('DANGER') and !action.tags.includes('SUCCESS') and !action.tags.includes('PRIMARY'), 'btn-primary': action.tags.includes('PRIMARY'), 'btn-danger': action.tags.includes('DANGER'), 'btn-success': action.tags.includes('SUCCESS'), 'o-text-white border-0 o-simulateDarkTheme': store.shouldSimulateDarkTheme(this), 'bg-700': store.shouldSimulateDarkTheme(this) and !action.tags.includes('DANGER') and !action.tags.includes('SUCCESS') and !action.tags.includes('PRIMARY') and !action.tags.includes('
16184CALL_LAYOUT'), 'bg-transparent': store.shouldSimulateDarkTheme(this) and action.tags.includes('CALL_LAYOUT'), })"/> 16185 <t t-set="attrs" t-value="{ 'aria-label': action.name, 'disabled': action.disabledCondition, 'name': action.id, 'data-sequence': action.sequence, 'data-sequence-group': action.sequenceGroup, 'data-sequence-quick': action.sequenceQuick }"/> 16186 <t t-if="action.component and action.componentCondition" t-component="action.component" t-props="action.componentProps"/> 16187 <DropdownItem t-elif="props.dropdown" class="btnClass + ' d-flex align-items-center dropdown-item_active_noarrow ' + (ui.isSmall ? 'gap-2' : 'gap-1')" tag="'button'" onSelected="(ev) => this.onSelected(action, ev)" attrs="attrs"> 16188 <t t-call="mail.Action.content"/> 16189 </DropdownItem> 16190 <button t-else="" t-att-class="btnClass" t-att="Object.assign(attrs, { 'title': action.name })" t-on-click="(ev) => this.onSelected(action, ev)" t-att-data-hotkey="action.hotkey" t-att-style="props.style"> 16191 <t t-call="mail.Action.content"/> 16192 <t t-if="action.badge" t-call="mail.Action.badge"> 16193 <t t-set="extraBadgeClass" t-value="'position-absolute me-n1 mt-n1 end-0'"/> 16194 </t> 16195 </button> 16196</t> 16197 16198`); 16199registerTemplate("mail.Action.content", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action.content" xml:space="preserve"> 16200 <t t-if="action.icon?.template" t-call="{{ action.icon.template }}"> 16201 <t t-set="templateParams" t-value="action.icon.params"/> 16202 </t> 16203 <i t-elif="action.icon" t-attf-class="{{ action.icon }}" t-att-class="{ 'o-fs-small': props.dropdown, 'fa-fw': props.fw }"/> 16204 <i t-elif="props.dropdown" class="fa-question fa-fw opacity-0" t-att-class="props.fw ? 'fa-fw' : ''"/> 16205 <span t-if="action.name and (props.dropdown or (props.inline and (!action.icon or action.inlineName)))" class="o-mail-ActionList-actionLabel" t-attf-class="{{ action.nameClass }}" t-att-class="{ 'mx-1': props.dropdown }" t-out="(props.inline and action.inlineName) or action.name"/> 16206 <t t-if="props.dropdown and action.badge" t-call="mail.Action.badge"/> 16207</t> 16208 16209`); 16210registerTemplate("mail.Action.badge", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action.badge" xml:space="preserve"> 16211 <span class="fw-bolder badge p-0 rounded-circle d-flex justify-content-center align-items-center" t-attf-class="{{ extraBadgeClass }}" t-att-class="{ 'bg-warning': action.tags.includes('WARNING_BADGE'), 'o-discuss-badge': action.tags.includes('IMPORTANT_BADGE') }" style="aspect-ratio: 1; font-size: 0.6rem;"> 16212 <i t-if="action.badgeIcon" t-att-class="action.badgeIcon"/><span t-elif="action.badgeText" t-esc="action.badgeText"/> 16213 </span> 16214</t> 16215 16216`); 16217registerTemplate("mail.AttachmentList", `/mail/static/src/core/common/attachment_list.xml`, `<t t-name="mail.AttachmentList" xml:space="preserve"> 16218 <div class="o-mail-AttachmentList overflow-y-auto d-flex flex-column mt-1" t-att-class="{ 'o-inComposer': env.inComposer, 'o-inChatWindow': env.inChatWindow, }"> 16219 <div class="d-flex flex-wrap gap-2" t-att-class="{'justify-content-end': isInChatWindowAndIsAlignedRight and !env.inComposer}" role="menu"> 16220 <div t-foreach="props.attachments" t-as="attachment" t-key="attachment.id" t-att-aria-label="attachment.name" class="o-mail-AttachmentContainer d-flex border position-relative rounded-3" t-att-title="attachment.name ? attachment.name : undefined" t-att-class="{ 'o-inMessage': env.inMessage, 'o-inChatter': env.inChatter, 'o-isImage': attachment.isImage, 'o-isUploading opacity-25': attachment.uploading, 'o-viewable': attachment.isViewable, }" tabindex="0" t-att-data-mimetype="attachment.mimetype" t-on-click="() => this.onClickAttachment(attachment)" role="menuitem"> 16221 16222 <Gif t-if="attachment.mimetype === 'image/gif'" src="getImageUrl(attachment)" paused="attachment.gifPaused" alt="attachment.name" class="attClassObjectToString({ 'o-mail-AttachmentImage img img-fluid w-100 rounded-3': true, 'o-inMessage': env.inMessage, 'o-inChatter object-fit-scale': env.inChatter, 'object-fit-contain': !env.inChatter and env.inMessage, 'object-fit-cover': !env.inChatter and !env.inMessage, })"/> 16223 <img t-elif="attachment.isImage" class="o-mail-AttachmentImage img img-fluid w-100 rounded-3" t-att-class="{ 'o-inMessage': env.inMessage, 'o-inChatter object-fit-scale': env.inChatter, 'object-fit-contain': !env.inChatter and env.inMessage, 'object-fit-cover': !env.inChatter and !env.inMessage, }" t-att-src="getImageUrl(attachment)" t-att-alt="attachment.name" t-on-load="onImageLoaded"/> 16224 16225 <div t-else="" class="o-mail-AttachmentCard d-flex flex-column w-100 h-100"> 16226 <div class="d-flex justify-content-center align-items-center flex-grow-1 bg-white position-relative rounded-3 rounded-bottom-0" t-on-click="() => this.onClickAttachment(attachment)"> 16227 <div t-if="!attachment.has_thumbnail" class="o_image" role="menuitem" aria-label="Preview" t-att-tabindex="-1" t-att-aria-disabled="false" t-att-data-mimetype="attachment.mimetype"/> 16228 <img t-else="" t-att-src="attachment.thumbnailUrl" t-att-alt="attachment.name"/> 16229 </div> 16230 <div class="o-mail-AttachmentCard-info d-flex align-items-center px-2 py-1 bg-200 rounded-bottom-3"> 16231 <div class="o-mail-AttachmentCard-image o_image me-2 flex-shrink-0" role="menuitem" aria-label="Preview" t-att-tabindex="-1" t-att-aria-disabled="false" t-att-data-mimetype="attachment.mimetype"/> 16232 <div t-if="attachment.name" class="text-truncate align-items-center fw-bold" t-out="props.messageSearch?.highlight(attachment.name) ?? attachment.name"/> 16233 </div> 16234 </div> 16235 16236 <div t-if="!isMobileOS" class="o-mail-Attachment-hover position-absolute top-0 bottom-0 start-0 end-0 p-2 d-flex flex-column align-items-start o-opacity-hoverable opacity-100-hover opacity-0 rounded-3" t-att-class="{ 'o-image': attachment.isImage }"> 16237 <div class="d-flex flex-row align-items-start gap-2"> 16238 <img t-if="attachment.isImage" src="/mail/static/src/img/image_icon.png" class="mw-100 mh-100 rounded o-mt-0_5" draggable="false"/> 16239 <div t-else="" class="o-mail-Attachment-hover-image o_image flex-shrink-0" t-att-data-mimetype="attachment.mimetype"/> 16240 <div t-if="attachment.name" class="o-mail-Attachment-hoverImageText fw-bold overflow-hidden text-break" t-att-class="{ 'o-text-white': attachment.isImage }" t-out="props.messageSearch?.highlight(attachment.name) ?? attachment.name"/> 16241 </div> 16242 <div t-if="attachment.file_size" class="ms-4 o-mt-0_5" t-att-class="{ 'ps-1': !attachment.isImage }">
16243 <span class="opacity-75" t-att-class="{ 'o-text-white': attachment.isImage }"><t t-out="Math.round(attachment.file_size / 1024, 4)"/>KB</span> 16244 </div> 16245 16246 <div class="o-mail-AttachmentButtons d-flex justify-content-start ms-1 mb-1 mt-auto pt-2 gap-2"> 16247 <a t-if="!attachment.isImage and attachment.type === 'url'" class="w-100 h-100 btn bg-500 o-p-1_5 d-flex justify-content-center align-items-center" t-att-href="attachment.url" target="_blank" title="Open Link"> 16248 <i class="fa fa-external-link o-text-white" role="img" aria-label="Open Link"/> 16249 </a> 16250 <button t-elif="canDownload(attachment)" class="btn bg-500 w-100 h-100 o-p-1_5 d-flex justify-content-center align-items-center shadow-sm" t-on-click.stop="() => this.onClickDownload(attachment)" title="Download"> 16251 <i class="fa fa-download o-text-white" role="img" aria-label="Download"/> 16252 </button> 16253 <button t-if="showDelete" class="o-mail-Attachment-unlink btn bg-500 w-100 h-100 o-p-1_5 d-flex justify-content-center align-items-center shadow-sm" t-att-class="{ 'o-inComposer': env.inComposer }" t-on-click.stop="() => this.onClickUnlink(attachment)" title="Remove"> 16254 <i class="fa fa-trash o-text-white" role="img" aria-label="Remove"/> 16255 </button> 16256 </div> 16257 </div> 16258 16259 <Actions t-else="" actions="getActions(attachment)"/> 16260 16261 <div t-if="attachment.uploading" class="position-absolute top-0 bottom-0 start-0 end-0 d-flex align-items-center justify-content-center" title="Uploading"> 16262 <i class="fa fa-circle-o-notch fa-spin"/> 16263 </div> 16264 16265 <div t-if="showUploaded(attachment)" class="o-Attachment-uploaded position-absolute top-0 d-flex" t-att-class="!isMobileOS ? 'end-0' : 'start-0'" title="Uploaded"> 16266 <i class="fa fa-check"/> 16267 </div> 16268 </div> 16269 </div> 16270 </div> 16271 </t> 16272 16273 `); 16274registerTemplate("mail.Actions", `/mail/static/src/core/common/attachment_list.xml`, `<t t-name="mail.Actions" xml:space="preserve"> 16275 <div class="position-absolute end-0 p-1 o-text-white"> 16276 <button t-if="props.actions.length === 1" class="btn btn-sm btn-light rounded px-1 py-0" tabindex="0" t-att-aria-label="props.actions[0].label" t-att-title="props.actions[0].label" role="menuitem" t-on-click.stop="props.actions[0].onSelect"> 16277 <i t-att-class="props.actions[0].icon"/> 16278 </button> 16279 <Dropdown t-else="" menuClass="'d-flex flex-column py-0'" state="actionsMenuState" position="'right-start'"> 16280 <button class="btn btn-sm btn-light rounded px-1 py-0" tabindex="0" aria-label="Actions" title="Actions" role="menuitem"> 16281 <i class="oi oi-chevron-down"/> 16282 </button> 16283 <t t-set-slot="content"> 16284 <DropdownItem t-foreach="props.actions" t-as="action" t-key="action_index" class="'px-2 py-1 d-flex align-items-center rounded-0'" onSelected="action.onSelect"> 16285 <i class="fa-fw" t-att-class="action.icon"/> 16286 <span class="mx-2" t-out="action.label"/> 16287 </DropdownItem> 16288 </t> 16289 </Dropdown> 16290 </div> 16291 </t> 16292 16293`); 16294registerTemplate("mail.AttachmentView", `/mail/static/src/core/common/attachment_view.xml`, `<t t-name="mail.AttachmentView" xml:space="preserve"> 16295 <div t-if="state.thread.attachmentsInWebClientView.length > 0" class="o-mail-Attachment"> 16296 <div class="o_attachment_control popout d-print-none cursor-pointer" t-on-click="onClickPopout" data-tooltip="Open preview in a separate window." data-tooltip-delay="400"> 16297 <i class="fa fa-window-restore" aria-hidden="Pop out"/> 16298 </div> 16299 <t t-if="state.thread.message_main_attachment_id"> 16300 <h3 t-if="!state.thread.message_main_attachment_id.isPdf" class="mt0 mb8 ps-2 text-muted text-center"><t t-esc="displayName"/></h3> 16301 <div t-if="state.thread.message_main_attachment_id.isImage" class="o-mail-Attachment-imgContainer"> 16302 <img id="attachment_img" class="img img-fluid d-block" t-att-src="state.thread.message_main_attachment_id.defaultSource"/> 16303 </div> 16304 <iframe t-if="state.thread.message_main_attachment_id.isPdf" class="d-print-none mb48" t-att-src="state.thread.message_main_attachment_id.defaultSource" t-ref="iframeViewerPdf"/> 16305 <t t-if="state.thread.attachmentsInWebClientView.length > 1 or (state.thread.attachmentsInWebClientView.length > 0 and !(state.thread.message_main_attachment_id.isPdf or state.thread.message_main_attachment_id.isImage))"> 16306 <a class="arrow o_move_previous text-center" href="#" t-on-click.prevent="onClickPrevious">
16307 <span class="oi oi-chevron-left"/> 16308 </a> 16309 <a class="arrow o_move_next text-center" href="#" t-on-click.prevent="onClickNext"> 16310 <span class="oi oi-chevron-right"/> 16311 </a> 16312 </t> 16313 </t> 16314 </div> 16315 </t> 16316 16317 `); 16318registerTemplate("mail.PopoutAttachmentView", `/mail/static/src/core/common/attachment_view.xml`, `<t t-name="mail.PopoutAttachmentView" xml:space="preserve"> 16319 <div class="o-mail-PopoutAttachmentView"> 16320 <t t-call="mail.AttachmentView"/> 16321 </div> 16322 </t> 16323 16324`); 16325registerTemplate("mail.AutoresizeInput", `/mail/static/src/core/common/autoresize_input.xml`, `<t t-name="mail.AutoresizeInput" xml:space="preserve"> 16326 <input class="o-mail-AutoresizeInput px-1 border-1 text-truncate rounded" t-attf-class="{{ props.className }}" t-att-class="{'o-focused': state.isFocused}" t-att-placeholder="props.placeholder" t-att-disabled="!props.enabled" t-att-title="state.value" t-model="state.value" t-on-keydown="onKeydownInput" t-on-focus="() => this.state.isFocused = true" t-on-blur="onBlurInput" t-ref="input" type="text"/> 16327</t> 16328 16329`); 16330registerTemplate("mail.ChatBubble", `/mail/static/src/core/common/chat_bubble.xml`, `<t t-name="mail.ChatBubble" xml:space="preserve"> 16331 <div class="o-mail-ChatBubble position-relative" t-att-name="props.chatWindow.displayName" t-att-class="{ 'o-bouncing': state.bouncing, 'o-active': popover.isOpen, 'o-mobile': isMobileOS }" t-on-click="() => props.chatWindow.open({ focus: true })" t-on-animationend="() => state.bouncing = false" t-ref="root"> 16332 <span class="o-mail-ChatBubble-unreadIndicator position-absolute" t-att-class="{ 'opacity-0': !thread?.isUnread or thread?.importantCounter }"><i class="fa fa-circle"/></span> 16333 <div t-if="thread?.importantCounter > 0" class="o-mail-ChatBubble-counter position-absolute badge rounded-pill fw-bold o-discuss-badge shadow" t-out="thread?.importantCounter"/> 16334 <button t-if="!env.embedLivechat and !isMobileOS" class="o-mail-ChatBubble-close position-absolute shadow rounded-circle fw-bold bg-view" title="Close Chat Bubble" t-on-click.stop="() => this.props.chatWindow.close()"><i class="oi oi-close"/></button> 16335 <ImStatus t-if="showImStatus" className="'o-mail-ChatBubble-status position-absolute'" member="thread.correspondent"> 16336 <t t-set-slot="pre_icon"> 16337 <i style="font-size: 18px; right: -2px; bottom: -2px; z-index: -1;" t-att-class="{ 'bg-success rounded-pill position-absolute': thread?.correspondent?.isTyping, 'fa fa-circle position-absolute text-100': !thread?.correspondent?.isTyping, }"/> 16338 </t> 16339 </ImStatus> 16340 <CountryFlag t-if="thread?.showCorrespondentCountry" country="thread.correspondentCountry" class="'o-mail-ChatBubble-country position-absolute bottom-0 border shadow-sm'"/> 16341 <button class="o-mail-ChatHub-bubbleBtn btn shadow"> 16342 <img class="o-mail-ChatBubble-avatar bg-view rounded-circle object-fit-cover" t-att-class="{ 'o-big': env.embedLivechat }" t-att-src="thread?.avatarUrl" alt="Thread image" draggable="false"/> 16343 </button> 16344 </div> 16345 </t> 16346 16347 `); 16348registerTemplate("mail.ChatBubblePreview", `/mail/static/src/core/common/chat_bubble.xml`, `<t t-name="mail.ChatBubblePreview" xml:space="preserve"> 16349 <div class="o-mail-ChatBubble-preview o-mail-ChatBubble-menu px-0 py-1 shadow-sm border border-secondary bg-100 o-rounded-bubble"> 16350 <div class="text-truncate base-fs fw-bolder mb-0 mx-2 px-1" t-esc="props.chatWindow.displayName"/> 16351 <t t-set="message" t-value="thread?.newestPersistentOfAllMessage"/> 16352 <div t-if="previewText" class="text-truncate small mx-2 px-1 text-muted"> 16353 <t t-call="mail.message_preview_prefix"> 16354 <t t-set="message" t-value="message"/> 16355 </t> 16356 <t t-if="message.hasOnlyAttachments"> 16357 <i class="fa me-1" t-att-class="message.previewIcon"/> 16358 <t t-out="message.previewText"/> 16359 </t> 16360 <t t-else="" t-out="previewText"/> 16361 </div> 16362 </div> 16363 </t> 16364 16365 16366 `); 16367registerTemplate("mail.message_preview_prefix", `/mail/static/src/core/common/chat_bubble.xml`, `<t t-name="mail.message_preview_prefix" xml:space="preserve"> 16368 <t t-if="message.isSelfAuthored"> 16369 <i class="fa fa-mail-reply me-1 opacity-75"/>You: 16370 </t>
16371 <t t-elif="!message.author?.eq(thread.correspondent?.persona)"> 16372 <t t-esc="message.authorName"/>: 16373 </t> 16374 </t> 16375 16376`); 16377registerTemplate("mail.ChatHub", `/mail/static/src/core/common/chat_hub.xml`, `<t t-name="mail.ChatHub" xml:space="preserve"> 16378 <div class="o-mail-ChatHub d-print-none"> 16379 16380 <t t-set="visibleChatWindows" t-value="chatHub.compact ? chatHub.opened.filter(({ bypassCompact }) => bypassCompact) : chatHub.opened "/> 16381 <t t-foreach="visibleChatWindows" t-as="cw" t-key="cw.localId"> 16382 <ChatWindow chatWindow="cw" t-if="cw.canShow" right="chatHub.BUBBLE_START + chatHub.BUBBLE + (chatHub.BUBBLE_OUTER*2) + (visibleChatWindows.length - cw_index - 1) * (chatHub.WINDOW + chatHub.WINDOW_INBETWEEN * 2)"/> 16383 </t> 16384 <div class="o-mail-ChatHub-bubbles position-fixed d-flex flex-column align-content-start justify-content-end align-items-center" t-attf-style="top: {{position.top}}; left: {{position.left}}; right: {{position.right}}; --mail-ChatHub-bubbles-bottom: {{position.bottom}}" t-att-class="{ 'o-liftUp': busMonitoring.hasConnectionIssues, 'o-mobile': isMobileOS }" t-ref="bubbles"> 16385 <div class="d-flex flex-column align-content-start justify-content-end align-items-center gap-1"> 16386 <Dropdown t-if="(chatHub.showConversations and !chatHub.compact) or position.dragged" state="options" position="'top-end'" menuClass="'m-0 mb-1 ' + store.discussDropdownMenuClass(this)"> 16387 <button class="o-mail-ChatHub-bubbleBtn btn o-mail-ChatHub-optionsBtn bg-100 mt-1" t-att-class="{ 'opacity-0': !bubblesHover.isHover and !position.dragged and !options.isOpen and !isMobileOS, 'o-bubblesHover': (bubblesHover.isHover or position.dragged) and !isMobileOS, 'o-active': bubblesHover.isHover or options.isOpen }" title="Chat Options"><i class="oi oi-ellipsis-h"/></button> 16388 <t t-set-slot="content"> 16389 <ActionList actions="optionActions" dropdown="true"/> 16390 </t> 16391 </Dropdown> 16392 <t t-if="store.chatHub.compact and chatHub.showConversations" t-call="mail.ChatHub.compactButton"/> 16393 <t t-else=""> 16394 <t t-foreach="chatHub.folded.slice(0, chatHub.maxFolded)" t-as="cw" t-key="cw.localId"> 16395 <ChatBubble t-if="cw.canShow" chatWindow="cw"/> 16396 </t> 16397 <div class="o-mail-ChatHub-extraActions"/> 16398 <t t-if="chatHub.showConversations and chatHub.folded.length > chatHub.maxFolded" t-call="mail.ChatHub.hiddenButton"/> 16399 </t> 16400 </div> 16401 </div> 16402 </div> 16403</t> 16404 16405`); 16406registerTemplate("mail.ChatHub.compactButton", `/mail/static/src/core/common/chat_hub.xml`, `<t t-name="mail.ChatHub.compactButton" xml:space="preserve"> 16407 16408 <Dropdown manual="true"> 16409 <div class="o-mail-ChatHub-bubbleBtn o-mail-ChatHub-compact o-mail-ChatBubble justify-content-center"> 16410 <div t-if="compactCounter > 0" class="o-mail-ChatHub-hiddenBtnCounter position-absolute badge rounded-pill fw-bold o-discuss-badge shadow"> 16411 <t t-out="compactCounter"/> 16412 </div> 16413 <button class="o-mail-ChatHub-bubbleBtn btn fs-2 shadow" t-on-click="expand"> 16414 <i class="o-mail-ChatHub-hiddenBtnIcon d-flex justify-content-center align-items-center btn rounded-circle shadow-sm fa fa-comments"/> 16415 </button> 16416 </div> 16417 </Dropdown> 16418</t> 16419 16420`); 16421registerTemplate("mail.ChatHub.hiddenButton", `/mail/static/src/core/common/chat_hub.xml`, `<t t-name="mail.ChatHub.hiddenButton" xml:space="preserve"> 16422 <Dropdown t-if="chatHub.folded.length > chatHub.maxFolded" state="more" position="'left-middle'" menuClass="'o-mail-ChatHub-hiddenMenu mx-1 my-0 bg-100 ' + store.discussDropdownMenuClass(this)" manual="true"> 16423 <div class="o-mail-ChatBubble o-mail-ChatHub-hiddenBtn justify-content-center" t-att-class="{ 'o-active': more.isOpen }" t-on-click="() => store.chatHub.compact = true" t-ref="more-button"> 16424 <div t-if="hiddenCounter > 0" class="o-mail-ChatHub-hiddenBtnCounter position-absolute badge rounded-pill fw-bold o-discuss-badge shadow"> 16425 <t t-out="hiddenCounter"/> 16426 </div> 16427 <button class="o-mail-ChatHub-bubbleBtn btn outline-0 shadow">
16428 <span class="o-mail-ChatHub-hiddenBtnIcon d-flex justify-content-center align-items-center btn rounded-circle shadow-sm fs-2" t-att-class="{ 'o-active': more.isOpen }">+<t t-esc="chatHub.folded.slice(chatHub.maxFolded).length"/></span> 16429 </button> 16430 </div> 16431 <t t-set-slot="content"> 16432 <ul class="m-0 p-0 overflow-auto o-scrollbar-thin bg-100" role="menu" t-ref="more-menu"> 16433 <t t-foreach="chatHub.folded.slice(chatHub.maxFolded)" t-as="cw" t-key="cw.localId"> 16434 <li class="o-mail-ChatHub-hiddenItem gap-2 px-2 py-1" role="menuitem" t-att-name="cw.displayName" t-on-click="() => cw.open({ focus: true })"> 16435 <img class="o-mail-ChatHub-hiddenAvatar rounded-circle object-fit-cover" t-att-src="cw.thread?.avatarUrl" alt="Thread image" draggable="false"/> 16436 <p class="text-truncate fw-bold mb-0" t-esc="cw.displayName"/> 16437 <div t-if="cw.thread?.importantCounter > 0" class="o-mail-ChatHub-hiddenCounter badge rounded-pill fw-bold o-discuss-badge" style="padding: 3px 6px"> 16438 <t t-out="cw.thread?.importantCounter"/> 16439 </div> 16440 <button class="o-mail-ChatHub-hiddenClose o-mail-ChatBubble-close d-flex align-items-center rounded" t-on-click.stop="() => cw.close()"> 16441 <i class="oi oi-close"/> 16442 </button> 16443 </li> 16444 </t> 16445 </ul> 16446 </t> 16447 </Dropdown> 16448</t> 16449 16450`); 16451registerTemplate("mail.ChatWindow", `/mail/static/src/core/common/chat_window.xml`, `<t t-name="mail.ChatWindow" xml:space="preserve"> 16452 <t t-set="partitionedActions" t-value="threadActions.partition"/> 16453 <div class="o-mail-ChatWindow fixed-bottom overflow-hidden d-flex flex-column shadow bg-100" t-att-style="style" t-att-class="attClass" t-on-keydown="onKeydown" tabindex="1"> 16454 <div class="o-mail-ChatWindow-header d-flex align-items-center flex-shrink-0 bg-100 z-1 border-bottom border-secondary" t-on-click="onClickHeader" t-att-class="{ 'cursor-pointer': !ui.isSmall and !props.chatWindow.actionsDisabled }"> 16455 <t t-if="hasActionsMenu"> 16456 <div class="d-flex text-truncate bg-inherit"> 16457 <Dropdown position="ui.isSmall ? 'bottom-end' : 'left-start'" onStateChanged="isOpen => this.onActionsMenuStateChanged(isOpen)" menuClass="store.discussDropdownMenuClass(this)"> 16458 <button class="o-mail-ChatWindow-moreActions btn rounded-0 d-flex align-items-center o-ps-1_5 pe-0 py-1 my-0 w-100 rounded-end-0 bg-inherit" t-att-class="{ 'rounded-top-3': !ui.isSmall, 'o-active': state.actionsMenuOpened, 'o-hover': actionsMenuButtonHover.isHover and !parentChannelHover.isHover }" t-att-disabled="state.editingName or props.chatWindow.actionsDisabled" t-att-title="actionsMenuTitleText" t-ref="actionsMenuButton"> 16459 <t t-call="mail.ChatWindow.headerContent"/> 16460 <i t-if="!state.editingName" class="fa fa-fw fa-caret-down"/> 16461 </button> 16462 <t t-set-slot="content"> 16463 <t t-set="quickActionsInDropdown" t-value="partitionedActions.quick.slice(ui.isSmall ? 2 : 4)"/> 16464 <ActionList actions="[quickActionsInDropdown, partitionedActions.other, ...partitionedActions.group]" dropdown="true" thread="thread"/> 16465 </t> 16466 </Dropdown> 16467 </div> 16468 <AutoresizeInput t-if="state.editingName" className="'text-truncate fw-bold flex-shrink-1 me-1 py-0 ' + (ui.isSmall ? 'fs-4' : 'fs-5')" enabled="true" autofocus="true" onValidate.bind="renameThread" value="props.chatWindow.displayName"/> 16469 <i t-if="state.editingName" class="fa fa-fw fa-caret-down opacity-50"/> 16470 </t> 16471 <t t-else=""> 16472 <t t-call="mail.ChatWindow.headerContent"/> 16473 </t> 16474 <div t-if="thread and thread.importantCounter > 0" class="o-mail-ChatWindow-counter mx-1 badge rounded-pill fw-bold o-discuss-badge shadow-sm" t-ref="needactionCounter"> 16475 <t t-out="thread.importantCounter"/> 16476 </div> 16477 <div class="ms-1 flex-grow-1"/> 16478 <div class="d-flex flex-shrink-0 me-1"> 16479 <ActionList actions="partitionedActions.quick.slice(0, ui.isSmall ? 2 : 4).reverse()" inline="true" thread="thread"/> 16480 </div> 16481 <t t-if="this.store.inPublicPage and !this.store.self_partner"> 16482 <button class="btn ps-1" t-if="!state.editingGuestName"> 16483 <img class="o-mail-DiscussContent-selfAvatar rounded-circle object-fit-cover flex-shrink-0" alt="Avatar" t-att-src="store.self.avatarUrl" t-on-click="() => state.editingGuestName = true"/> 16484 </button> 16485 <AutoresizeInput t-if="state.editingGuestName" className="'py-1 me-2'" autofocus="true" onValidate.bind="renameGuest" value="store.self.name"/> 16486 </t> 16487 </div> 16488 <div t-if="!props.chatWindow.folded or ui.isSmall" class="d-flex flex-column h-100 overflow-auto o-scrollbar-thin position-relative bg-inherit" t-att-class="{ 'opacity-50': state.editingName }" t-ref="content"> 16489 <t name="thread content"> 16490 <div t-if="threadActions.activeAction?.actionPanelComponentCondition" class="h-100 bg-inherit" t-attf-class="{{ threadActions.activeAction.panelOuterClass }}"> 16491 <t t-component="threadActions.activeAction.actionPanelComponent" t-props="{ ...threadActions.activeAction.actionPanelComponentProps, thread }"/> 16492 </div> 16493 <t t-elif="thread"> 16494 <Thread autofocus="autofocusThread" isInChatWindow="true" thread="thread" t-key="thread.localId" jumpPresent="state.jumpThreadPresent" jumpToNewMessage="props.chatWindow.jumpToNewMessage"/> 16495 <t t-call="mail.ChatWindow.memberTyping"/> 16496 <Composer composer="thread.composer" autofocus="autofocusComposer" mode="'compact'" onPostCallback.bind="() => this.state.jumpThreadPresent++" dropzoneRef="contentRef" type="composerType"/> 16497 </t> 16498 </t> 16499 </div> 16500 </div> 16501</t> 16502 16503`); 16504registerTemplate("mail.ChatWindow.headerContent", `/mail/static/src/core/common/chat_window.xml`, `<t t-name="mail.ChatWindow.headerContent" xml:space="preserve"> 16505 <div class="o-mail-ChatWindow-threadAvatar position-relative bg-inherit my-0 me-1" t-att-class="{ 'py-1': !thread or threadActions.actions.length gt 3, 'py-2': thread and threadActions.actions.length lte 3, 'ms-1': thread, 'ms-3': !thread, 'ps-2': !hasActionsMenu, }" name="threadAvatar"> 16506 <img t-if="thread" class="rounded-3 object-fit-cover" t-att-src="thread.parent_channel_id?.avatarUrl ?? thread.avatarUrl" alt="Thread Image"/> 16507 <ImStatus t-if="showImStatus" className="'o-mail-ChatWindow-imStatus position-absolute'" member="thread.correspondent" size="'sm'"/> 16508 </div> 16509 <t t-if="thread?.parent_channel_id">
16510 <span class="fw-bold small o-mx-0_5 opacity-75 opacity-100-hover cursor-pointer o-hover-text-underline rounded fs-6" t-esc="thread.parent_channel_id.displayName" title="Open Channel" t-ref="parentChannel" t-on-click.stop="() => this.thread.parent_channel_id.open({ focus: true })"/> 16511 <i class="fa fa-chevron-right o-xsmaller ms-1 mt-1 text-muted opacity-75"/> 16512 </t> 16513 <CountryFlag t-if="thread?.showCorrespondentCountry" country="thread.correspondentCountry" class="'o-mail-ChatWindow-country border shadow-sm'"/> 16514 <div t-if="!state.editingName" class="text-truncate fw-bold border border-transparent o-mx-0_5 my-0 py-1" t-att-title="props.chatWindow.displayName" t-esc="props.chatWindow.displayName" t-att-class="{ 'fs-4': ui.isSmall, 'fs-5': !ui.isSmall }"/> 16515</t> 16516 16517`); 16518registerTemplate("mail.ChatWindow.memberTyping", `/mail/static/src/core/common/chat_window.xml`, `<t t-name="mail.ChatWindow.memberTyping" xml:space="preserve"> 16519 <div t-if="thread.hasOtherMembersTyping" class="d-flex bg-inherit position-relative"> 16520 <div class="o-mail-ChatWindow-typing d-flex px-3 position-absolute bottom-0 start-0 w-100 bg-inherit align-items-center"> 16521 <Typing channel="thread" size="'medium'"/> 16522 </div> 16523 </div> 16524</t> 16525 16526`); 16527registerTemplate("mail.Composer", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer" xml:space="preserve"> 16528 <t t-set="isChatterComposer" t-value="extended and !props.composer.message"/> 16529 <t t-set="partitionedActions" t-value="composerActions.partition"/> 16530 <t t-set="compact" t-value="props.mode === 'compact'"/> 16531 <t t-set="normal" t-value="props.mode === 'normal'"/> 16532 <t t-set="extended" t-value="props.mode === 'extended'"/> 16533 <t t-set="actionsContainerClass" t-value="'o-mail-Composer-actions d-flex o-rounded-bubble'"/> 16534 <div t-ref="root"> 16535 <div class="o-mail-Composer d-grid flex-shrink-0 pt-0 position-relative" t-att-class="{ 'pb-2': extended and !props.composer.message, 'o-extended': extended, 'o-isUiSmall': ui.isSmall, 'ps-2 pe-4 pb-2': normal and !env.inDiscussApp and !env.inMeetingView, 'ps-0 pe-3 pb-2': normal and env.inMeetingView, 'o-hasSelfAvatar': showComposerAvatar, 'o-focused': props.composer.isFocused, 'o-editing': props.composer.message, 'o-chatWindow mx-2 my-1': env.inChatWindow, 'mb-2': env.inChatWindow and !props.composer.message, 'o-discussApp pt-1 ps-2 pe-4 o-pb-2_5': env.inDiscussApp, }" t-attf-class="{{ props.className }}"> 16536 <FileUploader t-if="allowUpload" multiUpload="isMultiUpload" onUploaded.bind="(data) => { attachmentUploader.uploadData(data) }"> 16537 <t t-set-slot="toggler"> 16538 <button t-att-disabled="!state.active or areAllActionsDisabled" class="d-none" title="Attach files" aria-label="Attach files" t-ref="file-uploader"><i class="fa fa-fw fa-paperclip"/></button> 16539 </t> 16540 </FileUploader> 16541 <div t-if="showComposerAvatar" class="o-mail-Composer-sidebarMain flex-shrink-0 d-flex"> 16542 <img class="o-mail-Composer-avatar mx-auto o_avatar rounded-3" t-att-src="(thread?.effectiveSelf or message.effectiveSelf).avatarUrl" alt="Avatar of user"/> 16543 </div> 16544 <div class="o-mail-Composer-coreHeader"> 16545 <div t-if="props.composer.replyToMessage" class="text-truncate small p-2"> 16546 <span class="cursor-pointer" t-on-click="() => env.messageHighlight?.highlightMessage(props.composer.replyToMessage, props.composer.thread)"> 16547 Replying to <b t-esc="props.composer.replyToMessage.authorName"/> 16548 </span> 16549 <span t-if="props.composer.replyToMessage.thread?.notEq(props.composer.thread)"> 16550 on: <b><t t-esc="props.composer.replyToMessage.thread.displayName"/></b> 16551 </span> 16552 <i class="fa fa-lg fa-times-circle rounded-circle p-0 ms-1 cursor-pointer" title="Stop replying" t-on-click="() => (props.composer.replyToMessage = undefined)"/> 16553 </div>
16554 <span t-if="props.composer.message and ui.isSmall" class="px-1" t-on-click="onClickCancelOrSaveEditText"> 16555 <button class="btn btn-sm btn-secondary rounded-pill border border-secondary ps-1 pe-2 py-0 mb-1" t-att-data-type="EDIT_CLICK_TYPE.CANCEL"> 16556 <i class="oi oi-close pe-2" t-att-data-type="EDIT_CLICK_TYPE.CANCEL"/> 16557 Discard editing 16558 </button> 16559 </span> 16560 </div> 16561 <div class="o-mail-Composer-coreMain d-flex flex-nowrap align-items-start flex-grow-1" t-att-class="{ 'flex-column' : extended or props.composer.message }"> 16562 <div class="o-mail-Composer-inputContainer o-mail-Composer-bg d-flex flex-grow-1 border o-rounded-bubble" t-att-class="{ 'o-iosPwa': isIosPwa, 'align-self-stretch' : extended, 'w-100': props.composer.message, }" t-ref="input-container"> 16563 <div t-if="!extended" t-attf-class="{{ actionsContainerClass }}"> 16564 <Dropdown t-if="partitionedActions.other.length > 0" position="'top-start'" menuClass="store.discussDropdownMenuClass(this)"> 16565 <t t-call="mail.Composer.moreActions"/> 16566 <t t-set-slot="content"> 16567 <ActionList actions="partitionedActions.other" dropdown="true"/> 16568 </t> 16569 </Dropdown> 16570 </div> 16571 <div class="position-relative flex-grow-1"> 16572 <t t-set="inputClasses" t-value="{ 'o-mail-Composer-inputStyle form-control border-0 o-rounded-bubble': true, 'o-mobile': isMobileOS, 'ps-2': partitionedActions.other.length === 0, 'text-muted': props.composer.restoredFromFullComposer, }"/> 16573 <Wysiwyg t-if="composerService.htmlEnabled" class="'w-100 text-break overflow-auto'" config="this.wysiwygConfig" onLoad.bind="onLoadWysiwyg"/> 16574 <t t-else=""> 16575 <textarea class="o-mail-Composer-input o-mail-Composer-bg shadow-none overflow-auto o-scrollbar-thin o-discuss-text-body user-select-auto" t-att-class="inputClasses" t-ref="textarea" t-on-keydown="onKeydown" t-on-focusin="onFocusin" t-on-focusout="onFocusout" t-on-click="(ev) => markEventHandled(ev, 'composer.onClickTextarea')" t-on-paste="onPaste" t-model="props.composer.composerText" t-on-input="(ev) => this.onInput(ev)" t-att-placeholder="placeholder" t-att-readOnly="!state.active or props.composer.restoredFromFullComposer" t-att-disabled="props.composer.restoredFromFullComposer" tabindex="0"/> 16576 16577 <textarea class="o-mail-Composer-fake position-absolute overflow-hidden" t-att-class="inputClasses" t-att-value="props.composer.composerText" t-ref="fakeTextarea" disabled="1"/> 16578 </t> 16579 </div> 16580 <t t-call="mail.Composer.quickActions"/> 16581 </div> 16582 </div> 16583 <div class="o-mail-Composer-footer overflow-auto o-scrollbar-thin"> 16584 <AttachmentList t-if="props.composer.attachments.length > 0" attachments="props.composer.attachments" unlinkAttachment.bind="(...args) => attachmentUploader.unlink(...args)"/> 16585 <div t-if="!extended and !props.composer.message" class="o-mail-Composer-pickerContainer" t-att-class="{ 'o-active': composerActions.activePicker and ui.isSmall }" t-ref="picker-container"> 16586 <div t-if="partitionedActions.pickers.length > 1 and composerActions.activePicker and ui.isSmall" class="o-mail-Composer-pickerSelection btn-group w-100"> 16587 <button t-foreach="partitionedActions.pickers" t-as="pickerAction" t-key="'PICKER_' + pickerAction.id" class="btn btn-secondary" t-esc="pickerAction.pickerName" t-on-click="(ev) => pickerAction.onSelected(ev)" t-att-class="{ 'active': pickerAction.picker.isOpen }"/> 16588 </div> 16589 <div t-ref="picker-target"/> 16590 </div> 16591 <div t-else="" class="d-flex align-items-center gap-1 w-100 pe-2"> 16592 <div class="pt-1" t-att-class="{ 'mt-2': !props.composer.message }">
16593 <span t-if="props.composer.message and !ui.isSmall" class="text-muted px-1 small" t-out="CANCEL_OR_SAVE_EDIT_TEXT" t-on-click="onClickCancelOrSaveEditText"/> 16594 <t t-elif="!props.composer.message and !props.composer.restoredFromFullComposer"> 16595 <t t-call="mail.Composer.sendButton"/> 16596 <span t-if="!isSendButtonDisabled and !isMobileOS" class="text-muted small ms-1" t-out="OR_PRESS_SEND_KEYBIND"/> 16597 </t> 16598 </div> 16599 <span class="flex-grow-1"/> 16600 <t t-if="!props.composer.message" t-call="mail.Composer.extraActions"/> 16601 </div> 16602 </div> 16603 </div> 16604 </div> 16605 <NavigableList t-if="suggestion" class="'o-mail-Composer-suggestionList'" t-props="navigableListProps"/> 16606</t> 16607 16608`); 16609registerTemplate("mail.Composer.sendButton", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.sendButton" xml:space="preserve"> 16610 <button class="o-mail-Composer-send btn" t-att-class="{ 'btn-primary btn-sm': extended, 'btn-link rounded-circle p-0': !extended, 'me-2': env.inDiscussApp, 'border-start-0': env.inDiscussApp and !props.composer.message, 'border-0': props.composer.message, }" t-on-click="sendMessage" t-att-disabled="isSendButtonDisabled" t-att-aria-label="SEND_TEXT"> 16611 <t t-if="thread and thread.model !== 'discuss.channel'" t-out="SEND_TEXT"/> 16612 <t t-else=""><i class="fa fa-fw fa-lg fa-paper-plane-o"/></t> 16613 </button> 16614</t> 16615 16616`); 16617registerTemplate("mail.Composer.quickActions", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.quickActions" xml:space="preserve"> 16618 <div class="o-mail-Composer-quickActions o-mail-Composer-bg" t-attf-class="{{ actionsContainerClass }}" t-ref="quick-actions"> 16619 <div class="o-mail-Composer-mainActions d-flex flex-grow-1 align-items-baseline"> 16620 <ActionList actions="partitionedActions.quick" inline="true"/> 16621 </div> 16622 </div> 16623</t> 16624 16625`); 16626registerTemplate("mail.Composer.moreActions", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.moreActions" xml:space="preserve"> 16627 <div class="o-mail-Composer-bg" t-attf-class="{{ actionsContainerClass }}" t-ref="more-actions"> 16628 <div class="o-mail-Composer-mainActions d-flex flex-grow-1 align-items-baseline"> 16629 <t t-set="moreName">More Actions</t> 16630 <ActionList inline="true" actions="[{ 'disabledCondition': areAllActionsDisabled, 'icon': 'fa fa-plus-circle', 'id': 'more-actions', 'name': moreName, 'tags': [], }]"/> 16631 </div> 16632 </div> 16633</t> 16634 16635`); 16636registerTemplate("mail.Composer.extraActions", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.extraActions" xml:space="preserve"> 16637 <div class="me-2 o-mail-Composer-extraActions" t-attf-class="{{ actionsContainerClass }}" t-ref="extra-actions"> 16638 <div class="o-mail-Composer-mainActions d-flex flex-grow-1 align-items-baseline"> 16639 <ActionList actions="partitionedActions.other" inline="true"/> 16640 </div> 16641 </div> 16642</t> 16643 16644 `); 16645registerTemplate("mail.Composer.suggestionSpecial", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionSpecial" xml:space="preserve"> 16646 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate"> 16647 <t t-esc="option.displayName"/> 16648 </strong> 16649 <em class="text-600 text-truncate align-self-center"> 16650 <t t-esc="option.description"/> 16651 </em> 16652 </t> 16653 16654 `); 16655registerTemplate("mail.Composer.suggestionPartner", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionPartner" xml:space="preserve"> 16656 <t t-set="partner" t-value="option.partner"/> 16657 <ImStatus t-if="partner" persona="partner"/> 16658 <t t-set="title" t-value="partner.name"/> 16659 <t t-if="partner.email" t-set="title" t-value="\`\${title} (\${partner.email})\`"/> 16660 <strong class="o-mail-Composer-suggestionPartner-name px-2 py-1 align-self-center flex-shrink-0 text-truncate" t-att-class="{'o-has-email': partner.email, 'mw-100': !partner.email}" t-att-title="title"> 16661 <t t-esc="partner.name"/> 16662 <t t-if="option.thread and partner.name !== option.thread.getPersonaName(partner)"> 16663 "<t t-esc="option.thread.getPersonaName(partner)"/>" 16664 </t> 16665 </strong>
16666 <span t-if="partner.email" class="text-600 text-truncate align-self-center" t-att-title="title">(<t t-esc="partner.email"/>)</span> 16667 </t> 16668 16669 `); 16670registerTemplate("mail.Composer.suggestionRole", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionRole" xml:space="preserve"> 16671 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate" t-esc="option.label"/> 16672 <em class="text-600 text-truncate align-self-center"> 16673 <t t-if="option.thread?.channel_type === 'channel'">Notify users with this role who have permission to view this channel</t> 16674 <t t-else="">Notify users with this role</t> 16675 </em> 16676 </t> 16677 16678 `); 16679registerTemplate("mail.Composer.suggestionThread", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionThread" xml:space="preserve"> 16680 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate"> 16681 <i t-attf-class="fa #{option.thread.parent_channel_id ? 'fa-comments-o' : 'fa-hashtag'} me-2"/> 16682 <t t-if="option.thread.parent_channel_id"> 16683 <t t-esc="option.thread.parent_channel_id.displayName"/> 16684 <i class="oi oi-chevron-right o-xsmaller mx-1"/> 16685 </t> 16686 <t t-esc="option.thread.displayName"/> 16687 </strong> 16688 </t> 16689 16690 `); 16691registerTemplate("mail.Composer.suggestionChannelCommand", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionChannelCommand" xml:space="preserve"> 16692 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate"> 16693 <t t-esc="option.label"/> 16694 </strong> 16695 <span class="text-600 text-truncate align-self-center"> 16696 <t t-esc="option.help"/> 16697 </span> 16698 </t> 16699 16700 `); 16701registerTemplate("mail.Composer.suggestionCannedResponse", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionCannedResponse" xml:space="preserve"> 16702 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate mw-100"> 16703 <t t-esc="option.source"/> 16704 </strong> 16705 <span class="text-600 text-truncate align-self-center"> 16706 <t t-esc="option.label"/> 16707 </span> 16708 </t> 16709 `); 16710registerTemplate("mail.Composer.suggestionEmoji", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionEmoji" xml:space="preserve"> 16711 <strong class="px-2 align-self-center flex-shrink-1 fs-3"> 16712 <t t-esc="option.emoji.codepoints"/> 16713 </strong> 16714 <em class="text-600 text-truncate align-self-center"> 16715 <t t-esc="option.emoji.shortcodes.join(' ')"/> 16716 </em> 16717 </t> 16718 16719 16720 `); 16721registerTemplate("mail.FullComposerRecoveryPopover", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.FullComposerRecoveryPopover" xml:space="preserve"> 16722 <div class="px-2"> 16723 <div> 16724 <p class="mb-0 fs-5 fw-bold">Continue with Full Composer?</p> 16725 <p class="mb-0 small text-muted">Formatting can only be restored in Full Composer.</p> 16726 </div> 16727 <div class="d-flex align-items-center justify-content-center gap-1 mt-2"> 16728 <button class="btn btn-primary" t-on-click="onClickFullRecover"><i class="fa fa-check me-2 opacity-75"/>Yes <span class="small opacity-50">(Keep formatting)</span></button> 16729 <button class="btn btn-secondary" t-on-click="onClickTextRecover"><i class="oi oi-close me-2 opacity-75"/>No <span class="small opacity-50">(Remove formatting)</span></button> 16730 </div> 16731 </div> 16732 </t> 16733 16734`); 16735registerTemplate("mail.CountryFlag", `/mail/static/src/core/common/country_flag.xml`, `<t t-name="mail.CountryFlag" xml:space="preserve"> 16736 <img class="o-mail-CountryFlag" t-att-class="props.class" t-att-title="props.country.name" t-att-src="props.country.flagUrl"/> 16737 </t> 16738 16739`); 16740registerTemplate("mail.DateSection", `/mail/static/src/core/common/date_section.xml`, `<t t-name="mail.DateSection" xml:space="preserve"> 16741 <div class="o-mail-DateSection d-flex align-items-center w-100 fw-bold z-1" t-attf-class="{{ props.className }}"> 16742 <hr class="o-discuss-separator flex-grow-1"/>
16743 <span class="px-2 smaller text-muted opacity-50" t-att-class="{ 'user-select-none': isMobileOS }"><t t-esc="props.date"/></span> 16744 <hr class="o-discuss-separator flex-grow-1"/> 16745 </div> 16746</t> 16747`); 16748registerTemplate("mail.Gif", `/mail/static/src/core/common/gif.xml`, `<t t-name="mail.Gif" xml:space="preserve"> 16749 <img t-att-src="props.paused and state.snapshot ? state.snapshot : props.src" t-att-loading="props.loading" t-att-data-paused="props.paused" t-att-alt="props.alt" t-att-class="props.class" t-att-style="props.style" t-on-click="() => props.onClick?.()" t-on-load="onLoad"/> 16750 </t> 16751`); 16752registerTemplate("mail.ImStatus", `/mail/static/src/core/common/im_status.xml`, `<t t-name="mail.ImStatus" xml:space="preserve"> 16753 <div class="o-mail-ImStatus d-flex justify-content-center flex-shrink-0 align-items-center bg-white bg-opacity-100" t-attf-class="{{ props.className }}" t-att-style="props.style" t-att-class="{ 'o-md': props.size === 'md' or props.size === 'medium', 'o-sm': props.size === 'sm' or props.size === 'small', 'rounded-circle': !props.member?.isTyping, 'rounded-pill': props.member?.isTyping, }"> 16754 <span class="d-flex flex-column" t-att-class="{ 'smaller': props.size === 'md' or props.size === 'medium', 'o-xsmaller': props.size === 'sm' or props.size === 'small', }"> 16755 <t t-slot="pre_icon"/> 16756 <t name="icon"> 16757 <t t-if="(!props.member or !props.member.isTyping) and persona"> 16758 <i t-if="persona.im_status === 'online'" class="fa fa-circle text-success" title="Online" role="img" aria-label="User is online"/> 16759 <i t-elif="persona.im_status === 'away'" class="fa fa-circle o-yellow" title="Idle" role="img" aria-label="User is idle"/> 16760 <i t-elif="persona.im_status === 'busy'" class="fa fa-minus-circle text-danger" title="Busy" role="img" aria-label="User is busy"/> 16761 <i t-elif="persona.im_status === 'offline'" class="fa fa-circle-o text-700 opacity-75" title="Offline" role="img" aria-label="User is offline"/> 16762 <i t-elif="persona.im_status === 'bot'" class="fa fa-heart text-success" title="Bot" role="img" aria-label="User is a bot"/> 16763 <i t-else="" class="fa fa-question-circle opacity-75" title="No IM status available"/> 16764 </t> 16765 <div t-if="props.member?.isTyping" class="rounded-pill" style="padding: 1px;" t-att-class="{ 'bg-300': env.inChatBubble, 'bg-inherit': !env.inChatBubble }"> 16766 <div class="bg-success rounded-pill" style="padding: 3px;"> 16767 <Typing member="props.member" channel="props.member.threadAsTyping" size="['sm', 'smaller'].includes(props.size) ? 'sm' : 'md'" displayText="false"/> 16768 </div> 16769 </div> 16770 </t> 16771 </span> 16772 </div> 16773 </t> 16774 16775`); 16776registerTemplate("mail.ImStatusDropdown", `/mail/static/src/core/common/im_status_dropdown.xml`, `<t t-name="mail.ImStatusDropdown" xml:space="preserve"> 16777 <Dropdown menuClass="'o-mail-ImStatusDropdown'"> 16778 <a href="#" t-att-class="{ 'd-block text-body py-3 fs-4 d-flex flex-row gap-2': env.isSmall }"><ImStatus persona="store.self"/> <span t-esc="readableImStatus"/> <i t-if="env.isSmall" class="oi oi-chevron-right ms-auto mt-1"/></a> 16779 <t t-set-slot="content"> 16780 <DropdownItem class="{ 'active': this.store.self.im_status.includes('online') }" onSelected="() => this.setManualImStatus('online')"><i class="fa fa-circle text-success me-1" title="Online" role="img"/> Online</DropdownItem> 16781 <hr class="my-1"/> 16782 <DropdownItem class="{ 'active': this.store.self.im_status.includes('away') }" onSelected="() => this.setManualImStatus('away')"><i class="fa fa-circle o-yellow me-1" title="Away" role="img"/> Away</DropdownItem> 16783 <DropdownItem class="{ 'active': this.store.self.im_status.includes('busy') }" onSelected="() => this.setManualImStatus('busy')"> 16784 <i class="fa fa-minus-circle text-danger me-1" title="Busy" role="img"/> Do Not Disturb 16785 <div class="small text-muted">You will not receive any notifications</div> 16786 </DropdownItem> 16787 <DropdownItem class="{ 'active': this.store.self.im_status.includes('offline') }" onSelected="() => this.setManualImStatus('offline')"><i class="fa fa-circle-o text-700 opacity-75 me-1" title="Offline" role="img"/> Offline</DropdownItem> 16788 </t> 16789 </Dropdown> 16790 </t> 16791`); 16792registerTemplate("mail.LinkPreview", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreview" xml:space="preserve"> 16793 <t t-if="props.linkPreview.isCard"> 16794 <t t-call="mail.LinkPreviewCard"/> 16795 </t> 16796 <t t-if="props.linkPreview.isVideo"> 16797 <t t-call="mail.LinkPreviewVideo"/> 16798 </t> 16799 <t t-if="props.linkPreview.isImage"> 16800 <t t-call="mail.LinkPreviewImage"/> 16801 </t> 16802 </t> 16803 16804 `); 16805registerTemplate("mail.LinkPreviewCard", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewCard" xml:space="preserve"> 16806 <div class="o-mail-LinkPreviewCard card position-relative w-100 mb-2 rounded bg-view shadow-sm overflow-hidden" t-att-class="{ 'me-2': env.inChatter }" t-attf-class="{{ className }}"> 16807 <div class="row g-0 flex-row-reverse h-100"> 16808 <div class="col min-w-0" t-att-class="{ 'd-flex align-items-center': !props.linkPreview.og_description }"> 16809 <div class="px-3 py-2"> 16810 <h6 class="card-title mb-0 me-2" t-attf-class="{{ props.linkPreview.og_description ? 'text-truncate' : 'overflow-hidden' }}"> 16811 <a t-att-href="props.linkPreview.source_url" target="_blank" t-out="props.linkPreview.og_title"/> 16812 </h6>
16813 <span t-if="props.linkPreview.og_site_name" t-out="props.linkPreview.og_site_name"/> 16814 <p t-if="props.linkPreview.og_description" class="o-mail-LinkPreviewCard-description card-text mb-0 mt-2 text-muted small overflow-hidden" t-out="props.linkPreview.og_description"/> 16815 </div> 16816 </div> 16817 <div class="o-mail-LinkPreviewCard-imageLinkWrap col-4 d-block"> 16818 <a t-att-href="props.linkPreview.source_url" target="_blank"> 16819 <img t-if="props.linkPreview.og_image" class="w-100 h-100 object-fit-cover" t-att-src="props.linkPreview.og_image" t-att-alt="props.linkPreview.og_title" t-on-load="onImageLoaded"/> 16820 <span t-else="" class="d-flex align-items-center justify-content-center w-100 h-100 bg-100 text-300"> 16821 <i class="fa fa-camera fa-2x"/> 16822 </span> 16823 </a> 16824 </div> 16825 </div> 16826 <t t-if="props.delete" t-call="mail.LinkPreview.aside"> 16827 <t t-set="className" t-value="'fa fa-stack p-0 opacity-75 opacity-100-hover'"/> 16828 </t> 16829 </div> 16830 </t> 16831 16832 `); 16833registerTemplate("mail.LinkPreviewImage", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewImage" xml:space="preserve"> 16834 <div class="o-mail-LinkPreviewImage position-relative mb-2 rounded" t-att-class="{ 'me-2': env.inChatter }" t-attf-class="{{ className }}"> 16835 <a t-if="props.linkPreview.imageUrl" t-att-href="props.linkPreview.imageUrl" target="_blank"> 16836 <Gif t-if="props.linkPreview.isGif" paused="props.gifPaused" class="'h-auto w-auto rounded'" src="props.linkPreview.imageUrl" onLoad.bind="onImageLoaded"/> 16837 <img t-else="" class="h-auto w-auto rounded" t-att-src="props.linkPreview.imageUrl" t-on-load="onImageLoaded"/> 16838 </a> 16839 <t t-if="props.delete" t-call="mail.LinkPreview.aside"> 16840 <t t-set="className" t-value="'btn btn-sm btn-dark mt-2 me-2 rounded opacity-75 opacity-100-hover'"/> 16841 </t> 16842 </div> 16843 </t> 16844 16845 `); 16846registerTemplate("mail.LinkPreviewVideo", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewVideo" xml:space="preserve"> 16847 <div class="o-mail-LinkPreviewVideo card position-relative w-100 mb-2 rounded bg-view shadow-sm overflow-hidden" t-att-data-provider="props.linkPreview.videoProvider" t-att-class="{ 'me-2': env.inChatter, 'o-mail-LinkPreviewVideo-embed': props.linkPreview.videoURL, 'o-mail-LinkPreviewVideo-started': state.startVideo }" t-attf-class="{{ className }}"> 16848 <div class="row g-0 flex-row-reverse"> 16849 <div class="col min-w-0" t-att-class="{ 'd-flex align-items-center': !props.linkPreview.og_description }"> 16850 <div class="d-flex flex-column gap-1 px-3 py-1 bg-view"> 16851 <p t-if="props.linkPreview.og_site_name" class="mb-0 card-text text-muted smaller overflow-hidden" t-out="props.linkPreview.og_site_name"/> 16852 <h6 class="o-mail-LinkPreviewVideo-title card-title mb-0 me-2" t-attf-class="{{ props.linkPreview.og_description ? 'text-truncate' : 'o-mail-LinkPreviewVideo-hasDescription overflow-hidden' }}"> 16853 <a t-att-href="props.linkPreview.source_url" target="_blank" t-esc="props.linkPreview.og_title"/> 16854 </h6> 16855 <p t-if="props.linkPreview.og_description" class="o-mail-LinkPreviewVideo-description o-mail-LinkPreviewVideo-hasDescription card-text mb-0 text-muted small overflow-hidden" t-out="props.linkPreview.og_description"/> 16856 </div> 16857 </div> 16858 <div t-if="!props.linkPreview.videoURL" class="col-4 d-block"> 16859 <a t-att-href="props.linkPreview.source_url" target="_blank"><t t-call="mail.LinkPreviewVideo.preview"/></a> 16860 </div> 16861 </div> 16862 <div t-if="props.linkPreview.videoURL" class="o-mail-LinkPreviewVideo-container mx-3 mb-2"> 16863 <div t-if="!state.videoLoaded" class="o-mail-LinkPreviewVideo-videoWrap h-100 w-100" t-on-click="() => state.startVideo = true"><t t-call="mail.LinkPreviewVideo.preview"/></div> 16864 <iframe t-if="state.startVideo" t-att-src="props.linkPreview.videoURL" class="h-100 w-100 rounded" t-att-class="{'d-none': !state.videoLoaded}" allow="autoplay" frameborder="0" allowFullScreen="true" t-ref="video"/> 16865 </div> 16866 <t t-if="props.delete" t-call="mail.LinkPreview.aside"> 16867 <t t-set="className" t-value="'fa fa-stack p-0 opacity-75 opacity-100-hover'"/> 16868 </t> 16869 </div> 16870 </t> 16871 16872 `); 16873registerTemplate("mail.LinkPreview.aside", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreview.aside" xml:space="preserve"> 16874 <div t-if="props.message?.allowsEdition" class="position-absolute top-0 end-0 small"> 16875 <button t-attf-class="{{ className }}" class="o-mail-LinkPreview-aside btn" aria-label="Remove" t-on-click="onClick"> 16876 <i class="fa fa-times"/> 16877 </button> 16878 </div> 16879 </t> 16880 16881 `); 16882registerTemplate("mail.LinkPreviewVideo.preview", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewVideo.preview" xml:space="preserve"> 16883 <div class="o-mail-LinkPreviewVideo-overlay position-relative h-100 rounded-bottom" t-att-class="{'bg-dark': !props.linkPreview.og_image}"> 16884 <img t-if="props.linkPreview.og_image" class="img-fluid h-100 w-100 object-fit-cover rounded" t-att-src="props.linkPreview.og_image" t-att-alt="props.linkPreview.og_title" t-on-load="onImageLoaded"/> 16885 <i t-elif="props.linkPreview.videoURL" class="fa fa-television fa-8x position-absolute top-50 start-50 translate-middle"/>
16886 <span t-else="" class="d-flex align-items-center justify-content-center w-100 h-100 bg-100 text-300"> 16887 <i class="fa fa-camera fa-2x"/> 16888 </span> 16889 <div class="position-absolute top-50 start-50 translate-middle"> 16890 <div t-if="!state.startVideo" class="o-mail-LinkPreviewVideo-play btn btn-lg rounded transition-base"> 16891 <i class="fa fa-play"/> 16892 </div> 16893 <div t-elif="!props.linkPreview.og_image" class="spinner-border text-muted"/> 16894 </div> 16895 </div> 16896 </t> 16897`); 16898registerTemplate("mail.LinkPreviewConfirmDelete", `/mail/static/src/core/common/link_preview_confirm_delete.xml`, `<t t-name="mail.LinkPreviewConfirmDelete" xml:space="preserve"> 16899 <Dialog size="'md'" title.translate="Confirmation" modalRef="modalRef"> 16900 <p class="mx-3 mb-3">Do you really want to delete this preview?</p> 16901 <t t-component="props.LinkPreview" linkPreview="props.linkPreview"/> 16902 <t t-set-slot="footer"> 16903 <button class="btn btn-danger me-2" t-on-click="onClickOk">Delete</button> 16904 <button t-if="props.deleteAll" class="btn btn-outline-danger me-2" t-on-click="onClickDeleteAll">Delete all previews</button> 16905 <button class="btn btn-secondary me-2" t-on-click="onClickCancel">Cancel</button> 16906 </t> 16907 </Dialog> 16908 </t> 16909`); 16910registerTemplate("mail.MailAttachmentDropzone", `/mail/static/src/core/common/mail_attachment_dropzone.xml`, `<t t-name="mail.MailAttachmentDropzone" xml:space="preserve"> 16911 <Dropzone t-props="this.props"> 16912 <h4>Drop Files here <i class="fa fa-paperclip"/></h4> 16913 </Dropzone> 16914 </t> 16915`); 16916registerTemplate("mail.Fullscreen", `/mail/static/src/core/common/mail_fullscreen.xml`, `<t t-name="mail.Fullscreen" xml:space="preserve"> 16917 <div class="fixed-top vw-100 vh-100"> 16918 <t t-component="props.component" t-props="props.props"/> 16919 </div> 16920 </t> 16921`); 16922registerTemplate("mail.Message", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message" xml:space="preserve"> 16923 <ActionSwiper onRightSwipe="hasTouch() and props.thread?.eq(store.inbox) ? { action: () => this.message.setDone(), bgColor: 'bg-success', icon: 'fa-check-circle' } : undefined"> 16924 <t t-set="dummy" t-value="computeActions()"/> 16925 <div class="o-mail-Message position-relative rounded-0 bg-inherit" t-att-data-starred="message.starred" t-att-data-persistent="message.persistent" t-att-class="attClass" role="group" t-att-aria-label="messageTypeText" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-ref="root" t-if="message.exists()"> 16926 <div class="o-mail-Message-jumpTarget position-absolute top-0 pe-none"/> 16927 <div t-if="props.asCard and isMobileOS" class="position-absolute end-0 z-1 m-n2"><t t-call="mail.Message.actions"/></div> 16928 <div class="o-mail-Message-core position-relative d-flex flex-shrink-0 bg-inherit"> 16929 <div class="o-mail-Message-sidebar d-flex flex-shrink-0 align-items-center flex-column bg-inherit" t-att-class="{ 'align-items-start': !isAlignedRight, 'o-inChatWindow': env.inChatWindow }"> 16930 <t t-if="!props.squashed"> 16931 <div class="o-mail-Message-avatarContainer position-relative bg-inherit rounded-3" t-att-class="getAvatarContainerAttClass()"> 16932 <img class="o-mail-Message-avatar w-100 h-100 rounded-3" t-att-src="authorAvatarUrl" t-att-class="authorAvatarAttClass"/> 16933 </div> 16934 <t t-if="message.starred" t-call="mail.Message.sidebarStarred"/> 16935 </t> 16936 <t t-elif="message.isPending" t-call="mail.Message.pendingStatus"/> 16937 <t t-elif="!message.is_transient"> 16938 <small t-if="isActive and props.showDates" class="o-mail-Message-date o-xsmaller mt-2 text-center lh-1" t-att-title="message.datetimeShort"> 16939 <t t-esc="message.dateSimple"/> 16940 </small> 16941 <t t-elif="message.starred" t-call="mail.Message.sidebarStarred"/> 16942 </t> 16943 </div> 16944 <div class="w-100 o-min-width-0" t-att-class="{ 'flex-grow-1': isEditing }" t-ref="messageContent"> 16945 <div t-if="!props.squashed" class="o-mail-Message-header d-flex flex-wrap align-items-baseline lh-1" t-att-class="{ 'mb-1': !message.isNote, 'pe-2': props.asCard and isMobileOS }" name="header">
16946 <span t-if="message.authorName and shouldDisplayAuthorName" class="o-mail-Message-author smaller" t-att-class="getAuthorAttClass()"> 16947 <strong class="me-1 o-fw-600" t-esc="message.authorName"/> 16948 </span> 16949 <t t-if="!isAlignedRight" t-call="mail.Message.notification"/> 16950 <t t-if="isAlignedRight and !message.bubbleColor and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 16951 <small t-if="!message.is_transient" class="o-mail-Message-date o-xsmaller" t-att-title="message.datetimeShort"> 16952 <t t-if="message.isPending" t-call="mail.Message.pendingStatus"/> 16953 <t t-else="" t-out="message.dateSimpleWithDay"/> 16954 </small> 16955 <small t-if="isPersistentMessageFromAnotherThread" t-on-click.prevent="openRecord" class="ms-1 text-500"> 16956 <t t-if="message.thread.model !== 'discuss.channel'"> 16957 on <a t-if="message.thread.displayName" t-att-href="message.resUrl" t-esc="message.thread.displayName"/><em class="pe-1 text-decoration-line-through" t-else="">Deleted document</em> 16958 </t> 16959 <t t-else=""> 16960 (from <a t-att-href="message.resUrl"><t t-esc="message.thread.prefix"/><t t-esc="message.thread.displayName or message.default_subject"/></a>) 16961 </t> 16962 </small> 16963 <div t-if="props.message.scheduledDatetime" t-att-class="{ 'ms-2': (props.isInChatWindow and isAlignedRight) or (isPersistentMessageFromAnotherThread) }" t-att-title="props.message.scheduledDateSimple"> 16964 <span class="text-600 cursor-pointer"> 16965 <i class="fa fa-calendar-o"/> 16966 </span> 16967 </div> 16968 <t t-if="isAlignedRight" t-call="mail.Message.notification"/> 16969 <t t-if="!isAlignedRight and !message.bubbleColor and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 16970 </div> 16971 <div class="o-mail-Message-contentContainer position-relative d-flex" t-att-class="{ 'flex-row-reverse': isAlignedRight }"> 16972 <div class="o-mail-Message-content o-min-width-0" t-att-class="{ 'w-100': isEditing, 'opacity-50': message.isPending, 'pt-1': message.isNote }"> 16973 <div class="o-mail-Message-textContent position-relative d-flex" t-att-class="{ 'w-100': isEditing }"> 16974 <t t-set="showTextVisually" t-value="!message.linkPreviewSquash and (message.hasTextContent or message.subtype_id?.description or message.isEmpty)"/> 16975 <t t-if="message.message_type === 'notification' and message.richBody" t-call="mail.Message.bodyAsNotification" name="bodyAsNotification"/> 16976 <t t-if="message.isEmpty or (message.message_type !== 'notification' and !message.is_transient and (message.hasTextContent or message.subtype_id?.description or isEditing or message.parent_id))"> 16977 <MessageLinkPreviewList t-if="!isEditing and message.linkPreviewSquash and !message.parent_id" messageLinkPreviews="message.message_link_preview_ids"/> 16978 <t t-else=""> 16979 <div t-if="message.bubbleColor and !props.squashed" class="o-mail-Message-bubbleTail position-absolute d-flex" t-att-style="isAlignedRight ? 'right: -4px; transform: rotateY(180deg);' : 'left: -4px;'" t-att-class="{ 'o-blue': message.bubbleColor === 'blue', 'o-green': message.bubbleColor === 'green', 'o-orange': message.bubbleColor === 'orange', }"> 16980 <svg viewBox="0 0 6 12" height="12" width="6" x="0px" y="0px"> 16981 <path class="o-mail-Message-bubbleTailBorder" fill="currentColor" d="M 0, 0 L 5, 9 V 0 z"/> 16982 <path class="o-mail-Message-bubbleTailBg" fill="currentColor" d="M 2, 1 L 5, 7 V 1 z"/> 16983 </svg> 16984 </div> 16985 <div class="position-relative overflow-x-auto overflow-y-hidden d-inline-block o-discuss-text-body" t-att-class="{ 'w-100': isEditing, 'o-rounded-bubble': message.bubbleColor and props.squashed, 'o-rounded-bottom-bubble': message.bubbleColor and !props.squashed, 'o-rounded-start-bubble': message.bubbleColor and !props.squashed and isAlignedRight, 'o-rounded-end-bubble': message.bubbleColor and !props.squashed and !isAlignedRight, }"> 16986 <div t-if="message.bubbleColor" class="o-mail-Message-bubble position-absolute top-0 start-0 w-100 h-100 border" t-att-class="{ 'o-rounded-bubble': props.squashed, 'o-rounded-bottom-bubble': !props.squashed, 'o-rounded-start-bubble': !props.squashed and isAlignedRight, 'o-rounded-end-bubble': !props.squashed and !isAlignedRight, 'o-blue': message.bubbleColor === 'blue', 'o-green': message.bubbleColor === 'green', 'o-orange': message.bubbleColor === 'orange', }"/> 16987 <MessageInReply t-if="message.parent_id" class="'mx-2 p-1 pb-0 ' + (showTextVisually ? 'mt-1' : 'my-1')" message="message" onClick="props.onParentMessageClick"/> 16988 <div class="position-relative text-break o-mail-Message-body" t-att-class="{ 'p-1': message.isNote, 'fs-1': !isEditing and !env.inChatter and message.onlyEmojis, 'mb-0': !message.isNote, 'py-2': !message.isNote and !isEditing and showTextVisually, 'pt-2 pb-1': !message.isNote and isEditing, 'o-note': message.isNote, 'o-rounded-bubble': props.squashed, 'align-self-start o-rounded-end-bubble o-rounded-bottom-bubble': !isEditing and !message.isNote and !props.squashed, 'flex-grow-1': isEditing, }" t-ref="body"> 16989 <i t-if="message.isEmpty" class="text-muted opacity-75" t-out="message.inlineBody"/> 16990 <Composer t-elif="isEditing" autofocus="true" composer="message.composer" dropzoneRef="messageBody" onDiscardCallback.bind="exitEditMode" onPostCallback.bind="exitEditMode" mode="'compact'" sidebar="false"/> 16991 <t t-else=""> 16992 <em t-if="message.subject and !message.isSubjectSimilarToThreadName and !message.isSubjectDefault" class="d-block text-muted smaller">Subject: <t t-out="props.messageSearch?.highlight(message.subject) ?? message.subject"/></em> 16993 <div class="overflow-x-auto" t-if="message.message_type and message.message_type.includes('email')" t-ref="shadowBody"/> 16994 <t t-elif="message.showTranslation" t-out="message.richTranslationValue"/> 16995 <div class="o-mail-Message-richBody overflow-x-auto" t-elif="message.hasTextContent and message.richBody and !message.linkPreviewSquash" t-out="props.messageSearch?.highlight(message.richBody) ?? message.richBody"/> 16996 <p class="fst-italic text-muted small" t-if="message.showTranslation"> 16997 <t t-if="message.translationSource" t-esc="translatedFromText"/> 16998 </p> 16999 <p class="fst-italic text-muted small" t-if="message.translationErrors"> 17000 <i class="text-danger fa fa-warning" role="img" aria-label="Translation Failure"/> 17001 <t t-if="message.translationErrors" t-esc="translationFailureText"/> 17002 </p> 17003 <t t-if="showSubtypeDescription" t-out="props.messageSearch?.highlight(message.subtype_id?.description) ?? message.subtype_id?.description"/> 17004 </t> 17005 </div> 17006 </div> 17007 </t> 17008 </t> 17009 <t t-if="message.bubbleColor and message.hasTextContent and !env.inChatWindow and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 17010 </div> 17011 <div class="position-relative"> 17012 <AttachmentList t-if="message.extra_body_attachment_ids.length > 0" attachments="message.extra_body_attachment_ids" unlinkAttachment.bind="onClickAttachmentUnlink" messageSearch="props.messageSearch"/> 17013 </div> 17014 <MessageLinkPreviewList t-if="(message.message_link_preview_ids.length > 0 and store.hasLinkPreviewFeature and !message.linkPreviewSquash) or (!isEditing and message.linkPreviewSquash and message.parent_id)" messageLinkPreviews="message.message_link_preview_ids"/> 17015 </div> 17016 <t t-if="message.bubbleColor and (!message.hasTextContent or env.inChatWindow) and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 17017 </div> 17018 <MessageReactions message="message" openReactionMenu="openReactionMenu" t-if="message.reactions.length"/> 17019 <t name="after-reactions"/> 17020 </div> 17021 </div> 17022 </div> 17023 </ActionSwiper> 17024 </t> 17025 17026`); 17027registerTemplate("mail.Message.edited", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.edited" xml:space="preserve">
17028 <span class="o-xsmaller opacity-50"> (edited)</span> 17029</t> 17030 17031`); 17032registerTemplate("mail.Message.actions", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.actions" xml:space="preserve"> 17033 <div t-if="props.hasActions and message.hasActions and !isEditing and !env.inChatter?.disabled" class="o-mail-Message-actions d-print-none d-flex align-items-start" t-att-class="{ 'start-0': isAlignedRight, 'mt-1': message.bubbleColor and !props.asCard and !isMobileOS, 'my-n2': !message.bubbleColor and !props.asCard and !isMobileOS, 'gap-1': isMobileOS, 'mx-1': !isMobileOS, 'invisible': !isActive and !isMobileOS, 'o-expanded': optionsDropdown.isOpen }"> 17034 <t t-if="isMobileOS"> 17035 <Dropdown state="optionsDropdown" menuClass="store.discussDropdownMenuClass(this)"> 17036 <button class="d-none"/> 17037 <t t-set-slot="content"> 17038 <ActionList actions="messageActions.actions" dropdown="true"/> 17039 </t> 17040 </Dropdown> 17041 </t> 17042 <t t-set="isReverse" t-value="env.inChatWindow and isAlignedRight"/> 17043 <t t-if="isMobileOS and isReverse" t-call="mail.Message.emptyQuickAction"/> 17044 <div class="d-flex rounded-1 overflow-hidden gap-1" t-att-class="{ 'flex-row-reverse': isReverse }"> 17045 <ActionList actions="actions" inline="true" fw="false"/> 17046 <t t-foreach="Array.from({ length: quickActionCount - quickActions.length - 1 })" t-as="emptyQuickAction" t-key="emptyQuickAction_index"> 17047 <t t-call="mail.Message.emptyQuickAction"/> 17048 </t> 17049 </div> 17050 <t t-if="isMobileOS and !isReverse" t-call="mail.Message.emptyQuickAction"/> 17051 </div> 17052</t> 17053 17054`); 17055registerTemplate("mail.Message.emptyQuickAction", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.emptyQuickAction" xml:space="preserve"> 17056 <button class="btn border-0 o-p-0_5 rounded-0 opacity-0 pe-none"> 17057 <i class="fa-lg fa fa-question"/> 17058 </button> 17059</t> 17060 17061`); 17062registerTemplate("mail.Message.notification", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.notification" xml:space="preserve"> 17063 <div t-if="message.thread?.eq(props.thread) and message.notification_ids.length > 0" class="mx-1"> 17064 <span class="o-mail-Message-notification cursor-pointer opacity-100-hover" t-att-class="message.failureNotifications.length > 0 ? 'text-danger opacity-75' : 'opacity-50'" role="button" tabindex="0" t-on-click="onClickNotification"> 17065 <i t-att-class="message.notification_ids[0].icon" role="img" aria-label="Delivery failure"/> <span class="fw-bold small" t-if="message.notification_ids[0].label" t-out="message.notification_ids[0].label"/> 17066 </span> 17067 </div> 17068 <div t-elif="message.thread?.eq(props.thread) and (message.incoming_email_to?.length or message.incoming_email_cc?.length)" class="mx-1"> 17069 <span class="o-mail-Message-notification cursor-pointer" t-att-class="message.failureNotifications.length > 0 ? 'text-danger' : text-600" role="button" tabindex="0" t-on-click="onClickNotification"> 17070 <i class="fa fa-envelope-o" role="img"/> 17071 </span> 17072 </div> 17073</t> 17074 17075`); 17076registerTemplate("mail.Message.bodyAsNotification", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.bodyAsNotification" xml:space="preserve"> 17077 <div class="o-mail-Message-body text-break mb-0 w-100" t-att-class="{'o-note': message.message_type == 'notification'}"> 17078 <t t-out="props.messageSearch?.highlight(message.richBody) ?? message.richBody"/> 17079 </div> 17080</t> 17081 17082`); 17083registerTemplate("mail.Message.pendingStatus", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.pendingStatus" xml:space="preserve"> 17084 <button t-if="message.postFailRedo" class="btn p-0" title="Failed to post the message. Click to retry" t-on-click="() => message.postFailRedo?.()"><i class="fa fa-fw fa-warning text-warning"/></button> 17085 <span t-else="" class="o-mail-Message-pendingProgress"><i class="fa fa-fw fa-circle-o-notch fa-spin opacity-50"/></span> 17086</t> 17087 17088`); 17089registerTemplate("mail.Message.mentionedChannelIcon", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.mentionedChannelIcon" xml:space="preserve"> 17090 <i t-att-class="icon"/> 17091</t> 17092 17093`); 17094registerTemplate("mail.Message.sidebarStarred", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.sidebarStarred" xml:space="preserve"> 17095 <small class="text-center lh-1 o-opacity-35" t-att-class="{ 'align-self-start ms-1': isAlignedRight, 'align-self-end me-1': !isAlignedRight, 'mt-2': props.squashed, 'mt-1': !props.squashed }" title="Starred message"> 17096 <i class="fa fa-star o-mail-Message-starred"/> 17097 </small> 17098</t> 17099 17100 `); 17101registerTemplate("mail.Message.messageLink", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.messageLink" xml:space="preserve">
17102 <span> 17103 <span class="me-1" t-out="message.thread.displayName"/> 17104 <span class="fa fa-angle-right me-1" aria-hidden="true"/> 17105 <span class="fa fa-comment" aria-hidden="true"/> 17106 </span> 17107 </t> 17108 17109`); 17110registerTemplate("mail.MessageCardList", `/mail/static/src/core/common/message_card_list.xml`, `<t t-name="mail.MessageCardList" xml:space="preserve"> 17111 <div class="o-mail-MessageCardList d-flex flex-column" t-att-class="{ 'justify-content-center flex-grow-1': props.messages.length === 0 }" t-ref="message-list"> 17112 <div class="card mb-2 rounded-3 border-dark shadow-sm" t-foreach="props.messages" t-as="message" t-key="message.id"> 17113 <div class="card-body ps-0 py-2 rounded-3"> 17114 <div class="position-absolute top-0 end-0 z-1 mx-2 my-1 d-flex align-items-center"> 17115 <a role="button" class="o-mail-MessageCard-jump rounded bg-400 badge opacity-0" t-att-class="{ 'opacity-100 py-1 px-2': ui.isSmall }" t-on-click="() => this.onClickJump(message)">Jump</a> 17116 <button t-if="props.mode === 'pin' and store.self_partner" class="btn btn-link text-reset ms-2 p-0 opacity-25 opacity-100-hover" t-att-class="{ 'fs-5': ui.isSmall }" title="Unpin" t-on-click="message.unpin"> 17117 <i class="oi oi-close"/> 17118 </button> 17119 </div> 17120 <Message hasActions="false" message="message" thread="props.thread" messageSearch="props.messageSearch"/> 17121 </div> 17122 </div> 17123 <span t-if="props.loadMore" class="mb-1" t-ref="load-more"/> 17124 <p t-if="props.showEmpty !== undefined ? props.showEmpty : props.messages.length === 0" t-esc="emptyText" class="text-center fst-italic text-500 fs-6"/> 17125 </div> 17126 </t> 17127 17128`); 17129registerTemplate("mail.MessageConfirmDialog", `/mail/static/src/core/common/message_confirm_dialog.xml`, `<t t-name="mail.MessageConfirmDialog" xml:space="preserve"> 17130 <Dialog size="props.size" title="props.title" contentClass="'o-bg-body'"> 17131 <p class="mx-3 mb-3" t-esc="props.prompt"/> 17132 <blockquote class="mx-3 mb-3 fst-normal" style="pointer-events:none;"> 17133 <t t-component="messageComponent" message="props.message" isReadOnly="true" hasActions="false"/> 17134 </blockquote> 17135 <t t-set-slot="footer"> 17136 <button class="btn me-2" t-att-class="props.confirmColor" t-on-click="onClickConfirm" t-out="props.confirmText"/> 17137 <button class="btn btn-secondary me-2" t-on-click="props.close">Cancel</button> 17138 </t> 17139 </Dialog> 17140</t> 17141 17142`); 17143registerTemplate("mail.MessageInReply", `/mail/static/src/core/common/message_in_reply.xml`, `<t t-name="mail.MessageInReply" xml:space="preserve"> 17144 <div class="o-mail-MessageInReply" t-attf-class="{{ props.class }}"> 17145 <small class="o-mail-MessageInReply-core o-mail-Message-bubble o-muted border position-relative d-flex px-2 py-1 rounded-start-0 o-rounded-end-bubble d-inline-flex" t-att-class="{ 'o-blue': props.message.parent_id.bubbleColor === 'blue', 'o-green': props.message.parent_id.bubbleColor === 'green', 'o-orange': props.message.parent_id.bubbleColor === 'orange', }"> 17146 <span class="d-inline-flex align-items-center" t-att-class="{ 'cursor-pointer': props.onClick }" t-on-click="() => this.props.onClick?.()"> 17147 <t t-if="!props.message.parent_id.isEmpty"> 17148 <img class="o-mail-MessageInReply-avatar me-2 rounded object-fit-cover" t-att-src="authorAvatarUrl" t-att-title="props.message.parent_id.authorName" alt="Avatar"/> 17149 <span class="o-mail-MessageInReply-content overflow-hidden smaller"> 17150 <b class="o-mail-MessageInReply-author o-fw-600"><t t-out="props.message.parent_id.authorName"/></b>: 17151 <span class="o-mail-MessageInReply-message ms-1 text-break"> 17152 <t t-if="!props.message.parent_id.isBodyEmpty"> 17153 <t t-out="props.message.parent_id.inlineBody"/> 17154 <em t-if="props.message.parent_id.edited" class="smaller fw-bold text-500"> (edited)</em> 17155 </t> 17156 <t t-elif="props.message.parent_id.attachment_ids.length > 0">
17157 <span class="me-2 fst-italic">Click to see the attachments</span> 17158 <i class="fa fa-image"/> 17159 </t> 17160 </span> 17161 </span> 17162 </t> 17163 <i t-else="">Original message was deleted</i> 17164 </span> 17165 </small> 17166 </div> 17167 </t> 17168`); 17169registerTemplate("mail.MessageLinkPreviewList", `/mail/static/src/core/common/message_link_preview_list.xml`, `<t t-name="mail.MessageLinkPreviewList" xml:space="preserve"> 17170 <div class="o-mail-LinkPreviewList d-flex flex-column mt-2" t-att-class="{ 'me-2 pe-4': env.inChatWindow and !env.alignedRight, 'ms-2 ps-4': env.inChatWindow and env.alignedRight }"> 17171 <div class="d-flex flex-grow-1 flex-wrap"> 17172 <t t-if="props.messageLinkPreviews.length > 1"> 17173 <t t-foreach="props.messageLinkPreviews" t-as="messageLinkPreview" t-key="messageLinkPreview.id"> 17174 <LinkPreview linkPreview="messageLinkPreview.link_preview_id" delete.bind="messageLinkPreview.hide" deleteAll.bind="messageLinkPreview.message_id.hideAllLinkPreviews" gifPaused="messageLinkPreview.gifPaused" message="messageLinkPreview.message_id"/> 17175 </t> 17176 </t> 17177 <t t-else=""> 17178 <LinkPreview linkPreview="props.messageLinkPreviews[0].link_preview_id" delete.bind="props.messageLinkPreviews[0].hide" gifPaused="props.messageLinkPreviews[0].gifPaused" message="props.messageLinkPreviews[0].message_id"/> 17179 </t> 17180 </div> 17181 </div> 17182 </t> 17183`); 17184registerTemplate("mail.MessageNotificationPopover", `/mail/static/src/core/common/message_notification_popover.xml`, `<t t-name="mail.MessageNotificationPopover" xml:space="preserve"> 17185 <div class="o-mail-MessageNotificationPopover m-2"> 17186 <t t-set="otherNotifications" t-value="this.props.message.notification_ids.filter((notif) => !notif._proxy.isFollowerNotification)"/> 17187 <t t-set="followerNotifications" t-value="this.props.message.notification_ids.filter((notif) => notif._proxy.isFollowerNotification)"/> 17188 <div t-foreach="otherNotifications" t-as="notification" t-key="notification.id"> 17189 <i class="me-2 fa-fw" t-att-class="notification.statusIcon" t-att-title="notification.statusTitle" role="img"/> 17190 <span t-if="notification.res_partner_id"> 17191 <t t-esc="props.message.getPersonaName(notification.res_partner_id)"/> 17192 <t t-if="notification.res_partner_id.email and !notification.isFailure"> (<t t-out="notification.res_partner_id.email"/>)</t> 17193 </span> 17194 <span t-elif="notification.mail_email_address" t-out="notification.mail_email_address"/> 17195 <span class="ms-1 text-muted" t-if="notification.isFailure">(<t t-esc="notification.failureMessage"/>)</span> 17196 </div> 17197 <div t-if="props.message.incoming_email_cc or props.message.incoming_email_to" t-foreach="(props.message.incoming_email_cc || []).concat(props.message.incoming_email_to || [])" t-as="incomingEmail" t-key="incomingEmail_index"> 17198 <i class="me-2 fa fa-fw fa-send-o"/> 17199 <span t-if="incomingEmail[0]" t-out="incomingEmail[0]" class="pe-1"/> 17200 <span t-if="incomingEmail[1]" t-out="incomingEmail[1]" class="ps-1"/> 17201 </div> 17202 <div t-foreach="followerNotifications" t-as="notification" t-key="notification.id"> 17203 <i class="me-2 fa-fw" t-att-class="notification.statusIcon" t-att-title="notification.statusTitle" role="img"/> 17204 <span t-if="notification.res_partner_id"> 17205 <t t-esc="props.message.getPersonaName(notification.res_partner_id)"/> 17206 <t t-if="notification.res_partner_id.email and !notification.isFailure"> (<t t-out="notification.res_partner_id.email"/>)</t> 17207 </span> 17208 <span t-elif="notification.mail_email_address" t-out="notification.mail_email_address"/>
17209 <span class="ms-1 text-muted" t-if="notification.isFailure">(<t t-esc="notification.failureMessage"/>)</span> 17210 </div> 17211 </div> 17212 </t> 17213 17214`); 17215registerTemplate("mail.MessageReactionList", `/mail/static/src/core/common/message_reaction_list.xml`, `<t t-name="mail.MessageReactionList" xml:space="preserve"> 17216 <Dropdown state="preview" position="'top-middle'" menuClass="'mt-1 overflow-visible ' + store.discussDropdownMenuClass(this)" manual="true" bottomSheet="false"> 17217 <t t-call="mail.MessageReactionList.button"/> 17218 <t t-set-slot="content"> 17219 <t t-call="mail.MessageReactionList.preview"/> 17220 </t> 17221 </Dropdown> 17222 </t> 17223 17224 `); 17225registerTemplate("mail.MessageReactionList.button", `/mail/static/src/core/common/message_reaction_list.xml`, `<t t-name="mail.MessageReactionList.button" xml:space="preserve"> 17226 <button class="position-relative o-mail-MessageReaction btn d-flex p-0 bg-view border o-rounded-bubble mb-1 fs-5 px-1 gap-1 align-items-center" t-on-click="() => this.onClickReaction(props.reaction)" t-on-contextmenu="onContextMenu" t-on-mouseenter="loadEmoji" t-ref="reactionButton" t-att-class="{ 'o-selfReacted border-primary text-primary fw-bold': hasSelfReacted(props.reaction), 'border-secondary': !hasSelfReacted(props.reaction), 'ms-1': env.inChatWindow and env.alignedRight, 'me-1': !(env.inChatWindow and env.alignedRight), 'cursor-default': !props.message.canAddReaction(), }"> 17227 <span t-esc="props.reaction.content"/> 17228 <span class="small" t-esc="props.reaction.count"/> 17229 </button> 17230 </t> 17231 17232 `); 17233registerTemplate("mail.MessageReactionList.preview", `/mail/static/src/core/common/message_reaction_list.xml`, `<t t-name="mail.MessageReactionList.preview" xml:space="preserve"> 17234 <div class="o-mail-MessageReactionList-preview px-0 py-1 cursor-pointer d-flex" t-on-click="(ev) => this.onClickReactionList(props.reaction)" t-ref="reactionList"> 17235 <div class="d-flex align-items-center mx-2 gap-2"> 17236 <span class="fs-1" t-esc="props.reaction.content"/> 17237 <span class="o-mail-MessageReactionList-previewText small me-1" t-esc="previewText(props.reaction)"/> 17238 </div> 17239 </div> 17240 </t> 17241 17242`); 17243registerTemplate("mail.MessageReactionMenu", `/mail/static/src/core/common/message_reaction_menu.xml`, `<t t-name="mail.MessageReactionMenu" xml:space="preserve"> 17244 <Dialog size="'md'" header="false" footer="false" contentClass="contentClass"> 17245 <div class="d-flex h-100" t-on-keydown="onKeydown" t-att-class="{'flex-column': store.useMobileView}" t-ref="root"> 17246 <div class="d-flex overflow-auto o-scrollbar-thin bg-100 p-1 border-end" t-att-class="{'flex-column h-100 p-2': !store.useMobileView}"> 17247 <t t-foreach="props.message.reactions" t-as="reaction" t-key="reaction.content"> 17248 <button class="btn p-1 rounded-2 mx-2 py-0 d-flex align-items-center" t-att-class="{ 'bg-200 border-primary': reaction.eq(state.reaction) }" t-att-title="getEmojiShortcode(reaction)" t-on-click="() => state.reaction = reaction"> 17249 <span class="mx-1 fs-2" t-esc="reaction.content"/> 17250 <span class="mx-1 pe-2" t-att-class="{ 'text-primary': reaction.eq(state.reaction) }" t-esc="reaction.count"/> 17251 </button> 17252 </t> 17253 </div> 17254 <div class="d-flex overflow-auto o-scrollbar-thin flex-column flex-grow-1 bg-view p-2 h-100"> 17255 <div t-foreach="state.reaction.personas" t-as="persona" t-key="persona.id" class="o-mail-MessageReactionMenu-persona d-flex p-1 align-items-center" t-att-class="{ 'o-isDeviceSmall': ui.isSmall }"> 17256 <img class="rounded object-fit-cover o-mail-MessageReactionMenu-avatar" t-att-src="persona.avatarUrl"/> 17257 <span class="d-flex flex-grow-1 align-items-center">
17258 <span class="mx-2 text-truncate fs-6" t-esc="props.message.getPersonaName(persona)"/> 17259 <div class="flex-grow-1"/> 17260 <button t-if="props.message.effectiveSelf.eq(persona)" class="btn btn-light fa fa-trash rounded-pill bg-inherit border-0" title="Remove" t-on-click.stop="() => state.reaction.remove()"/> 17261 </span> 17262 </div> 17263 </div> 17264 </div> 17265 </Dialog> 17266 </t> 17267 17268`); 17269registerTemplate("mail.MessageReactions", `/mail/static/src/core/common/message_reactions.xml`, `<t t-name="mail.MessageReactions" xml:space="preserve"> 17270 <div class="o-mail-MessageReactions position-relative d-flex flex-wrap" t-att-class="{ 'flex-row-reverse me-3': env.inChatWindow and env.alignedRight, 'ms-3': !(env.inChatWindow and env.alignedRight) and (props.message.isDiscussion), 'o-emojiPickerOpen': emojiPicker.isOpen, 'mt-n1': props.message.message_type === 'comment' and !props.message.attachment_ids.length, 'o-mt-0_5': props.message.attachment_ids.length, }"> 17271 <t t-foreach="props.message.reactions" t-as="reaction" t-key="reaction.content"> 17272 <MessageReactionList message="this.props.message" openReactionMenu="this.props.openReactionMenu" reaction="reaction"/> 17273 </t> 17274 <QuickReactionMenu t-if="props.message.canAddReaction()" action="messageActions.actions.find(action => action.id === 'reaction')" classNames="{ 'p-1 mb-1 opacity-25 opacity-100-hover': true }" message="props.message"/> 17275 </div> 17276</t> 17277`); 17278registerTemplate("mail.NavigableList", `/mail/static/src/core/common/navigable_list.xml`, `<t t-name="mail.NavigableList" xml:space="preserve"> 17279 <div class="o-mail-NavigableList bg-view m-0 p-0 shadow-sm" t-ref="root" t-att-class="props.class"> 17280 <div t-if="show" class="o-open d-flex flex-column bg-inherit" t-on-mousedown.prevent=""> 17281 <div t-if="state.showLoading" t-att-class="{ 'position-absolute bg-inherit smaller o-mail-NavigableList-floatingLoading': props.options.length, 'bg-300': props.options.length and state.activeIndex === 0, 'o-mail-NavigableList-item': !props.options.length }"> 17282 <t t-call="mail.NavigableList.spinner"/> 17283 </div> 17284 <div t-foreach="sortedOptions" t-as="option" t-key="option_index" class="o-mail-NavigableList-item" t-att-class="option.classList" t-att-title="option.title" t-on-mouseenter="() => this.onOptionMouseEnter(option_index)" t-on-click="(ev) => this.selectOption(ev, option_index, { option })"> 17285 <hr class="my-2" t-if="option.group != lastGroup and option_index != 0"/> 17286 <a role="button" class="d-flex align-items-center w-100 px-3 py-1 small" t-att-class="{ 'o-mail-NavigableList-active': state.activeIndex === option_index }" t-attf-class="{{ option.buttonClass }}"> 17287 <t t-if="option.optionTemplate" t-call="{{ option.optionTemplate }}"/> 17288 <t t-elif="props.optionTemplate" t-call="{{ props.optionTemplate }}"/> 17289 <t t-else="" t-esc="option.label"/> 17290 </a> 17291 <t t-set="lastGroup" t-value="option.group"/> 17292 </div> 17293 </div> 17294 </div> 17295 </t> 17296 17297 `); 17298registerTemplate("mail.NavigableList.spinner", `/mail/static/src/core/common/navigable_list.xml`, `<t t-name="mail.NavigableList.spinner" xml:space="preserve"> 17299 <span class="d-flex align-items-center w-100 py-2 gap-1 text-muted opacity-75" t-att-class="{ 'px-1': props.options.length, 'px-4': !props.options.length }"> 17300 <i class="fa fa-spin fa-circle-o-notch"/> 17301 Loading⦠17302 </span> 17303 </t> 17304`); 17305registerTemplate("mail.NotificationMessage", `/mail/static/src/core/common/notification_message.xml`, `<t t-name="mail.NotificationMessage" xml:space="preserve"> 17306 <div class="o-mail-NotificationMessage text-break mx-auto px-3 text-center smaller position-relative" t-on-click="onClickNotificationMessage" t-ref="root"> 17307 <div class="o-mail-Message-jumpTarget position-absolute top-0 pe-none"/> 17308 <i t-if="message.notificationIcon" t-attf-class="{{ message.notificationIcon }} me-1 text-muted"/> 17309 <t t-if="message.notificationType === 'call'">
17310 <span class="text-muted" t-esc="callInformation"/> 17311 </t> 17312 <t t-elif="['channel_rename', 'thread_deletion'].includes(message.notificationType)"> 17313 <span class="text-muted" t-out="message.inlineBody"/> 17314 </t> 17315 <t t-else=""> 17316 <span class="o-mail-NotificationMessage-author d-inline text-muted" t-if="message.authorName and !message.richBody.includes(escape(message.authorName))" t-esc="message.authorName"/> <span class="text-muted" t-out="message.richBody"/> 17317 </t> 17318 <span class="o-mail-Message-date o-xsmaller ms-1" t-esc="message.dateSimpleWithDay"/> 17319 </div> 17320 </t> 17321`); 17322registerTemplate("mail.QuickReactionMenu", `/mail/static/src/core/common/quick_reaction_menu.xml`, `<t t-name="mail.QuickReactionMenu" xml:space="preserve"> 17323 <t t-if="ui.isSmall" t-call="mail.QuickReactionMenu.toggler"/> 17324 <Dropdown t-else="" state="dropdown" manual="true" menuClass="\`o-mail-QuickReactionMenu-popover shadow-none\`" position="'top-middle'" navigationOptions="navigationOptions" bottomSheet="false"> 17325 <t t-call="mail.QuickReactionMenu.toggler"/> 17326 <t t-set-slot="content"> 17327 <div class="o-mail-QuickReactionMenu d-flex align-items-center o-px-0_5 bg-100 border border-secondary o-rounded-bubble shadow-sm gap-1" t-ref="toggle"> 17328 <button t-foreach="mostFrequentEmojis" t-as="emoji" t-key="emoji" class="o-mail-QuickReactionMenu-emoji o-mail-QuickReactionMenu-popEffect o-navigable d-flex justify-content-center align-items-center o-rounded-bubble btn lh-1 p-1" t-att-class="{ 'bg-secondary': reactedBySelf(emoji) }" t-att-title="getEmojiShortcode(emoji)" t-on-click="(ev) => this.toggleReaction(emoji, !ev.shiftKey)"> 17329 <span class="fs-2" t-esc="emoji"/> 17330 </button> 17331 <button class="o-mail-QuickReactionMenu-emojiPicker o-mail-QuickReactionMenu-popEffect o-mail-QuickReactionMenu-popEffect--smaller o-navigable text-muted d-flex justify-content-center align-items-center btn btn-secondary o-rounded-bubble border border-dark-subtle" title="Toggle Emoji Picker" t-on-click="() => this.togglePicker()"> 17332 <i class="oi oi-close"/> 17333 </button> 17334 </div> 17335 </t> 17336 </Dropdown> 17337 </t> 17338 17339 `); 17340registerTemplate("mail.QuickReactionMenu.toggler", `/mail/static/src/core/common/quick_reaction_menu.xml`, `<t t-name="mail.QuickReactionMenu.toggler" xml:space="preserve"> 17341 <button class="btn border-0 o-p-0_5 o-inline o-mail-QuickReactionMenu-toggler" t-att-class="attClass" t-att-title="props.action.name" t-att-aria-label="props.action.name" t-on-click="onClick"> 17342 <i t-att-class="props.action.icon"/> 17343 </button> 17344 </t> 17345`); 17346registerTemplate("mail.SearchMessageInput", `/mail/static/src/core/common/search_message_input.xml`, `<t t-name="mail.SearchMessageInput" xml:space="preserve"> 17347 <div class="o-mail-SearchMessageInput d-flex py-2"> 17348 <div class="input-group"> 17349 <div class="o_searchview form-control d-flex align-items-center bg-view p-0" role="search" aria-autocomplete="list"> 17350 <div class="o_searchview_input_container d-flex flex-grow-1 flex-wrap gap-1 h-100"> 17351 <input type="text" class="o_searchview_input flex-grow-1 w-auto border-0 rounded-start px-2 bg-view" accesskey="Q" placeholder="Search" t-model="state.searchTerm" t-on-keydown="onKeydownSearch" t-ref="autofocus" role="searchbox"/> 17352 </div> 17353 </div> 17354 <button class="btn" t-att-class="state.searchedTerm === state.searchTerm ? 'btn-outline-secondary' : 'btn-secondary'" t-on-click="() => this.search()" aria-label="Search button"> 17355 <i t-if="!props.messageSearch.searching" class="o_searchview_icon oi oi-search" role="img" aria-label="Search Messages" title="Search Messages"/> 17356 <i t-else="" class="fa fa-circle-o-notch fa-spin" aria-label="Search in progress" title="Search in progress"/> 17357 </button> 17358 </div> 17359 <Dropdown t-if="env.inChatter"> 17360 <button class="btn btn-outline-secondary ms-3" aria-label="Filter Messages" title="Filter Messages"> 17361 <i class="fa fa-filter" role="img"/> 17362 </button> 17363 <t t-set-slot="content"> 17364 <t t-foreach="searchFilters" t-as="searchFilter" t-key="searchFilter.label"> 17365 <DropdownItem onSelected="() => this.onChangeSearchFilter(searchFilter)"> 17366 <input type="radio" class="form-check-input ms-0 me-2" t-att-checked="searchFilter.is_notification === this.props.messageSearch.is_notification" value="searchFilter.label"/> 17367 <t t-esc="searchFilter.name"/> 17368 </DropdownItem> 17369 </t> 17370 </t> 17371 </Dropdown> 17372 <button t-if="env.inChatter" class="btn btn-outline-secondary ms-3" t-on-click="() => this.clear()" aria-label="Close button"> 17373 <i class="o_searchview_icon oi oi-close cursor-pointer" role="img" aria-label="Close search" title="Close"/> 17374 </button> 17375 </div> 17376 </t> 17377`); 17378registerTemplate("mail.SearchMessageResult", `/mail/static/src/core/common/search_message_result.xml`, `<t t-name="mail.SearchMessageResult" xml:space="preserve"> 17379 <div class="o-mail-SearchMessageResult"> 17380 <p t-if="MESSAGE_FOUND" class="o-mail-SearchMessagesPanel-title py-1 mb-0 fw-bolder text-center text-uppercase text-muted smaller"> 17381 <t t-out="MESSAGE_FOUND"/> 17382 </p> 17383 <MessageCardList messages="props.messageSearch.messages" thread="props.thread" mode="'search'" messageSearch="props.messageSearch" showEmpty="props.messageSearch.messages.length === 0 and props.messageSearch.searched" onClickJump="() => this.props.onClickJump?.()" loadMore="props.messageSearch.loadMore" onLoadMoreVisible.bind="onLoadMoreVisible"/> 17384 </div> 17385 </t> 17386`); 17387registerTemplate("mail.SearchMessagesPanel", `/mail/static/src/core/common/search_messages_panel.xml`, `<t t-name="mail.SearchMessagesPanel" xml:space="preserve"> 17388 <ActionPanel title="title" minWidth="200" initialWidth="400" icon="'oi oi-search'"> 17389 <SearchMessageInput closeSearch="props.closeSearch" messageSearch="messageSearch" thread="props.thread"/> 17390 <SearchMessageResult thread="props.thread" messageSearch="messageSearch"/> 17391 </ActionPanel> 17392 </t> 17393`); 17394registerTemplate("mail.Thread", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread" xml:space="preserve"> 17395 <div class="o-mail-Thread position-relative flex-grow-1 d-flex flex-column overflow-auto o-scrollbar-thin bg-inherit" t-att-class="{ 'pb-5': env.inChatter?.aside, 'o-pb-3_5': !env.inChatter?.aside, 'ps-2 pe-3': env.inDiscussApp and !ui.isSmall, 'o-focused': props.thread.isFocused }" t-att-data-transient="props.thread.isTransient" t-ref="messages" tabindex="-1" t-on-focusin="onFocusin" t-on-focusout="onFocusout"> 17396 <t t-if="!props.thread.isEmpty or props.thread.loadOlder or props.thread.hasLoadingFailed" name="content"> 17397 <div class="d-flex flex-column position-relative flex-grow-1 bg-inherit" t-att-class="{'justify-content-end': !env.inChatter and props.thread.model !== 'mail.box'}">
17398 <span class="position-absolute w-100 invisible" t-att-class="props.order === 'asc' ? 'bottom-0' : 'top-0'" t-ref="present-treshold" t-att-style="\`height: Min(\${PRESENT_THRESHOLD}px, 100%)\`"/> 17399 <t t-set="currentDay" t-value="0"/> 17400 <t t-if="props.order === 'asc'"> 17401 <t t-if="showLoadOlder" t-call="mail.Thread.loadOlder"/> 17402 <t t-elif="props.thread.hasLoadingFailed" t-call="mail.Thread.loadingError"/> 17403 <t t-elif="showStartMessage" t-call="mail.Thread.startMessage"/> 17404 </t> 17405 <span t-else="" class="pt-1" t-ref="load-newer"/> 17406 <t t-set="messages" t-value="orderedMessages"/> 17407 <t t-foreach="messages" t-as="msg" t-key="msg.id"> 17408 <t t-set="prevMsg" t-value="messages[msg_index -1]"/> 17409 <t t-if="msg.dateDay !== currentDay and props.showDates"> 17410 <DateSection date="msg.dateDay" className="'pt-2 px-2'"/> 17411 <t t-set="currentDay" t-value="msg.dateDay"/> 17412 </t> 17413 <div t-if="msg.threadAsFirstUnread?.eq(props.thread) and (prevMsg or props.thread.markedAsUnread)" class="o-mail-Thread-newMessage d-flex align-items-center fw-bold z-1 px-2"> 17414 <div class="o-mail-Thread-newMessageLine flex-grow-1 border border-danger rounded-start-3 opacity-100 shadow-sm my-1"/><span class="o-ps-1_5 pe-1 bg-danger o-text-white rounded text-uppercase shadow-sm o-xxsmaller">New</span> 17415 </div> 17416 <NotificationMessage t-if="msg.isNotification and !msg.notificationHidden" message="msg" thread="props.thread" registerMessageRef="registerMessageRef"/> 17417 <Message t-elif="!msg.isNotification" asCard="props.thread.model === 'mail.box'" className="getMessageClassName(msg)" isInChatWindow="props.isInChatWindow" message="msg" previousMessage="prevMsg" registerMessageRef="registerMessageRef" squashed="isSquashed(msg, prevMsg)" onParentMessageClick.bind="() => this.onParentMessageClick(msg.parent_id)" thread="props.thread" isFirstMessage="msg_first" hasActions="props.messageActions and !msg.eq(props.thread.from_message_id)" showDates="props.showDates"/> 17418 </t> 17419 <span t-if="props.order === 'asc'" class="pt-1" t-ref="load-newer"/> 17420 <t t-else=""> 17421 <t t-if="showLoadOlder" t-call="mail.Thread.loadOlder"/> 17422 <t t-if="props.thread.hasLoadingFailed" t-call="mail.Thread.loadingError"/> 17423 </t> 17424 </div> 17425 </t> 17426 <t t-else=""> 17427 <div class="o-mail-Thread-empty d-flex flex-column h-100" t-att-class="{ 'p-4': props.showEmptyMessage and !showStartMessage, 'align-items-start justify-content-end': showStartMessage, 'align-items-center justify-content-center opacity-75': !showStartMessage }"> 17428 <t t-if="props.thread.isLoaded and props.showEmptyMessage"> 17429 <t name="empty-message"> 17430 <t t-if="showStartMessage" t-call="mail.Thread.startMessage"/> 17431 <div t-else="" class="d-flex flex-column align-items-center"> 17432 <span class="fs-1" style="filter: grayscale(1);">ð¶</span> 17433 <span>The conversation is empty.</span> 17434 </div> 17435 </t> 17436 </t> 17437 </div> 17438 </t> 17439 <t t-call="mail.Thread.jumpPresent"/> 17440 </div> 17441</t> 17442 17443`); 17444registerTemplate("mail.Thread.jumpPresent", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.jumpPresent" xml:space="preserve"> 17445 <button t-if="props.showJumpPresent and state.showJumpPresent" class="o-mail-Thread-jumpPresent position-fixed p-2 rounded-circle lh-1 m-n3 user-select-none btn btn-light shadow-sm border border-secondary" t-att-class="{ 'bottom-0': env.inChatter and !env.inChatter.aside }" t-ref="jump-present" t-on-click="() => this.jumpToPresent()" title="Jump to Present"><i class="oi text-muted" t-att-class="{ 'oi-chevron-down': props.order === 'asc', 'oi-chevron-up': props.order !== 'asc' }"/></button> 17446</t> 17447 17448`); 17449registerTemplate("mail.Thread.loadOlder", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.loadOlder" xml:space="preserve"> 17450 <button class="btn btn-link" t-att-class="{ 'opacity-0': !state.mountedAndLoaded }" t-on-click="onClickLoadOlder" t-ref="load-older">Load More</button> 17451</t> 17452 17453`); 17454registerTemplate("mail.Thread.loadingError", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.loadingError" xml:space="preserve"> 17455 <div class="d-flex flex-grow-1 align-items-center justify-content-center flex-column"> 17456 <div class="o-mail-Thread-error"> 17457 An error occurred while fetching messages. 17458 </div>
17459 <span t-if="props.thread.hasLoadingFailedError" class="o-xsmaller text-muted" t-esc="props.thread.hasLoadingFailedError"/> 17460 <button class="btn btn-link" t-on-click="onClickRetry"> 17461 Click here to retry 17462 </button> 17463 </div> 17464</t> 17465 17466 17467`); 17468registerTemplate("mail.discuss_badge", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.discuss_badge" xml:space="preserve"> 17469 <span class="badge rounded-pill o-discuss-badge flex-shrink-0 bg-inherit d-flex align-items-center justify-content-center" t-attf-class="{{ badgeClass }}" t-att-style="'margin: 0px; background-color: inherit !important;' + (floating ? 'padding: 1px;' : 'padding: 0px;')"> 17470 <span class="rounded-pill o-innerBadge" t-attf-class="{{ counterClass }}" t-esc="counter" style="top: 0 !important;"/> 17471 </span> 17472</t> 17473 17474`); 17475registerTemplate("mail.Thread.startMessage", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.startMessage" xml:space="preserve"> 17476 <div class="pt-4" t-att-class="{ 'px-3': env.inChatWindow, 'px-2': env.inDiscussApp or env.inMeetingChat }"> 17477 <div class="d-flex align-items-center gap-2" t-att-class="{ 'mt-2 mb-1': !props.thread.parent_channel_id, 'mt-1': props.thread.parent_channel_id, }"> 17478 <div class="o-mail-Thread-avatar d-inline" t-att-class="{'o-mail-Thread-avatarChatWindow': env.inChatWindow }"> 17479 <img t-if="!props.thread.parent_channel_id" class="rounded-3 object-fit-cover" t-att-src="props.thread?.avatarUrl" alt="Thread Image"/> 17480 <i t-else="" class="fa fa-comments-o text-muted" role="presentation"/> 17481 </div> 17482 <div role="heading" aria-level="1" class="text-break" t-att-class="{ 'fs-1': !env.inChatWindow, 'fs-3': env.inChatWindow }" t-esc="startMessageTitle"/> 17483 </div> 17484 <p class="text-muted mb-0 small text-break" t-esc="startMessageSubtitle"/> 17485 </div> 17486</t> 17487`); 17488registerTemplate("mail.ThreadIcon", `/mail/static/src/core/common/thread_icon.xml`, `<t t-name="mail.ThreadIcon" xml:space="preserve"> 17489 <div class="o-mail-ThreadIcon d-flex justify-content-center flex-shrink-0" t-att-class="props.className"> 17490 <t t-set="largeClass" t-value="props.size === 'large' ? 'fa-lg' : ''"/> 17491 <t t-if="props.thread.channel_type === 'channel'"> 17492 <div t-if="props.thread.group_public_id" class="fa fa-fw fa-hashtag" t-att-class="largeClass" t-att-title="props.thread.accessRestrictedToGroupText"/> 17493 <div t-else="" class="fa fa-fw fa-globe" t-att-class="largeClass" title="Public Channel"/> 17494 </t> 17495 <t t-elif="props.thread.channel_type?.includes('chat') and correspondent"> 17496 <t name="chat"> 17497 <t name="chat_static"> 17498 <ImStatus t-if="correspondent.im_status" member="correspondent" size="'md'"/> 17499 <div t-else="" class="d-flex rounded-circle bg-inherit"> 17500 <i class="fa-fw" t-att-class="largeClass" t-attf-class="#{ defaultChatIcon.class }" t-att-title="defaultChatIcon.title"/> 17501 </div> 17502 </t> 17503 </t> 17504 </t> 17505 <div t-elif="props.thread.channel_type === 'group'" class="o-mail-ThreadIcon oi fa-fw oi-users" t-att-class="largeClass" title="Grouped Chat"/> 17506 <t t-elif="props.thread.model === 'mail.box'"> 17507 <div t-if="props.thread.id === 'inbox'" class="fa fa-fw fa-inbox" t-att-class="largeClass"/> 17508 <div t-elif="props.thread.id === 'starred'" class="fa fa-fw fa-star-o" t-att-class="largeClass"/> 17509 <div t-elif="props.thread.id === 'history'" class="fa fa-fw fa-history" t-att-class="largeClass"/> 17510 </t> 17511 </div> 17512 </t> 17513 17514`); 17515registerTemplate("mail.ActionPanel", `/mail/static/src/discuss/core/common/action_panel.xml`, `<t t-name="mail.ActionPanel" xml:space="preserve"> 17516 <ResizablePanel t-if="props.resizable and !env.inChatWindow and !env.inChatter and !ui.isSmall" class="classNames" handleSide="'start'" initialWidth="initialWidth" minWidth="minWidth"> 17517 <t t-call="mail.ActionPanel.content"/> 17518 </ResizablePanel> 17519 <div t-else="" t-att-class="classNames"> 17520 <t t-call="mail.ActionPanel.content"/> 17521 </div> 17522 </t> 17523 17524 `); 17525registerTemplate("mail.ActionPanel.content", `/mail/static/src/discuss/core/common/action_panel.xml`, `<t t-name="mail.ActionPanel.content" xml:space="preserve"> 17526 <div class="o-mail-ActionPanel-header position-sticky top-0 pt-2 pb-1 d-flex flex-column bg-inherit smaller" t-att-class="{ 'px-1 pb-1': env.inChatWindow, 'ps-1 pe-2 pb-2': !env.inChatWindow and !env.inMeetingView, 'o-ps-2_5 pe-2': env.inMeetingChat, 'ps-1': env.inMeetingView and !env.inMeetingChat }"> 17527 <div class="d-flex align-items-center gap-1"> 17528 <button t-if="env.closeActionPanel and env.inChatWindow" class="btn p-1 opacity-75 opacity-100-hover" title="Close panel" t-on-click.stop="env.closeActionPanel"> 17529 <i class="oi oi-arrow-left fa-fw"/> 17530 </button> 17531 <i t-if="props.icon" class="text-muted fa-fw" t-att-class="props.icon"/> 17532 <p t-if="props.title" class="fw-bold text-uppercase m-0 flex-grow-1" t-esc="props.title"/> 17533 <button t-if="env.closeActionPanel and !env.inChatWindow" class="btn p-1 opacity-75 opacity-100-hover ms-auto" title="Close panel" t-on-click.stop="env.closeActionPanel"> 17534 <i class="oi oi-close fa-fw"/> 17535 </button> 17536 </div> 17537 <t t-slot="header"/> 17538 </div> 17539 <div class="o-mail-ActionPanel-content px-1 d-flex flex-column flex-grow-1 bg-inherit o-min-height-0" t-ref="contentRef"> 17540 <t t-slot="default"/> 17541 </div> 17542 </t> 17543 17544`); 17545registerTemplate("mail.AttachmentPanel", `/mail/static/src/discuss/core/common/attachment_panel.xml`, `<t t-name="mail.AttachmentPanel" xml:space="preserve"> 17546 <ActionPanel title.translate="Attachments" minWidth="200" initialWidth="400" icon="'fa fa-paperclip'"> 17547 <div class="d-flex flex-column py-2 flex-grow-1"> 17548 <div class="flex-grow-1" t-att-class="{ 'd-flex justify-content-center align-items-center': props.thread.attachments.length === 0, }"> 17549 <p t-if="props.thread.attachments.length === 0" class="text-center fst-italic text-500"> 17550 <t t-if="props.thread.channel_type === 'channel'">This channel doesn't have any attachments.</t> 17551 <t t-else="">This conversation doesn't have any attachments.</t> 17552 </p> 17553 <div t-else="" t-foreach="attachmentsByDate" t-as="dateDay" t-key="dateDay" class="d-flex flex-column">
17554 <DateSection date="dateDay" className="'my-1'"/> 17555 <AttachmentList attachments="dateDay_value" unlinkAttachment="(attachment) => this.attachmentUploadService.unlink(attachment)"/> 17556 </div> 17557 </div> 17558 <span t-ref="load-older"/> 17559 </div> 17560 </ActionPanel> 17561 </t> 17562`); 17563registerTemplate("mail.AvatarStack", `/mail/static/src/discuss/core/common/avatar_stack.xml`, `<t t-name="mail.AvatarStack" xml:space="preserve"> 17564 <div t-if="props.personas.length > 0" class="bg-inherit" t-att-class="props.containerClass" t-on-click="props.onClick"> 17565 <div class="d-flex bg-inherit position-relative z-1" t-att-class="{'flex-column': props.direction === 'v'}"> 17566 <span t-foreach="props.personas.slice(0, props.max)" t-as="persona" t-key="persona.localId" class="bg-inherit rounded-circle position-relative" t-attf-style="{{getStyle(persona_index)}}"> 17567 <img t-att-src="persona.avatarUrl" t-att-title="persona.displayName or persona.name" class="w-100 h-100 rounded-circle object-fit-cover" t-attf-class="{{props.avatarClass(persona)}}"/> 17568 <t t-slot="avatarExtraInfo" persona="persona"/> 17569 </span> 17570 <span t-if="props.personas.length > props.max" class="rounded-circle bg-secondary smaller d-flex justify-content-center align-items-center user-select-none" t-attf-style="{{getStyle(props.personas.length)}}; font-weight: 450;">+<t t-esc="props.personas.length - props.max"/></span> 17571 </div> 17572 </div> 17573 </t> 17574`); 17575registerTemplate("discuss.ChannelInvitation", `/mail/static/src/discuss/core/common/channel_invitation.xml`, `<t t-name="discuss.ChannelInvitation" xml:space="preserve"> 17576 <ActionPanel t-if="props.thread" title.translate="Invite people" resizable="!!env.inMeetingView" minWidth="env.inMeetingView ? 300 : undefined" initialWidth="env.inMeetingView ? 400 : undefined" icon="'oi oi-user-plus'"> 17577 <t t-call="discuss.ChannelInvitation.main"/> 17578 </ActionPanel> 17579 <t t-else="" t-call="discuss.ChannelInvitation.main"/> 17580 </t> 17581 17582 `); 17583registerTemplate("discuss.ChannelInvitation.main", `/mail/static/src/discuss/core/common/channel_invitation.xml`, `<t t-name="discuss.ChannelInvitation.main" xml:space="preserve"> 17584 <div class="d-flex flex-column flex-grow-1 bg-inherit o-min-height-0" t-att-class="{ 'w-100': props.hasSizeConstraints, 'px-1': !props.thread }"> 17585 <t t-if="store.self_partner"> 17586 <input class="o-discuss-ChannelInvitation-search form-control lh-1 px-2 bg-view" t-att-value="searchStr" t-ref="input" t-att-placeholder="searchPlaceholder" t-on-input="onInput"/> 17587 <ul class="d-flex flex-column mx-0 pt-1 pb-0 overflow-auto o-scrollbar-thin list-group border-0 flex-grow-1" t-att-class="{ 'align-items-center justify-content-center': selectablePartners.length === 0 and state.selectableEmails.length === 0 }"> 17588 <div t-if="selectablePartners.length === 0 and state.selectableEmails.length === 0" class="smaller text-muted mx-1 opacity-50"> 17589 <t t-if="props.thread">No user found that is not already a member of this channel.</t> 17590 <t t-else="">No user found.</t> 17591 </div> 17592 <div t-if="state.searchResultCount > selectablePartners.length" class="smaller text-muted mx-1 mb-1 fst-italic" t-esc="showingResultNarrowText"/> 17593 <t t-foreach="selectablePartners" t-as="selectablePartner" t-key="selectablePartner.id"> 17594 <t t-call="discuss.ChannelInvitation-selectableItem"> 17595 <t t-set="selectableItemIndex" t-value="selectablePartner_index"/> 17596 </t> 17597 </t> 17598 <t t-foreach="state.selectableEmails" t-as="selectableEmailAddress" t-key="selectableEmailAddress"> 17599 <t t-call="discuss.ChannelInvitation-selectableItem"> 17600 <t t-set="selectableEmailAddress" t-value="selectableEmailAddress"/> 17601 <t t-set="selectableItemIndex" t-value="selectablePartners.length + selectableEmailAddress_index"/> 17602 </t> 17603 </t> 17604 </ul> 17605 </t> 17606 <div class="o-discuss-ChannelInvitation-invitationBox pt-0 pb-1 bg-inherit"> 17607 <t t-if="store.self_partner"> 17608 <div t-if="selectedPartners.length > 0 or state.selectedEmails.length > 0" class="pt-2"> 17609 <div class="o-discuss-ChannelInvitation-selectedList d-flex flex-wrap overflow-auto o-scrollbar-thin"> 17610 <t t-foreach="selectedPartners" t-as="selectedPartner" t-key="selectedPartner.id"> 17611 <button class="btn btn-light fw-bolder smaller pe-1" title="Unselect person" t-on-click="() => this.onClickSelectedPartner(selectedPartner)"> 17612 <t t-esc="selectedPartner.name"/>Â <i class="oi oi-close border border-dark-subtle ms-1"/> 17613 </button> 17614 </t> 17615 <t t-foreach="state.selectedEmails" t-as="selectedEmail" t-key="selectedEmail"> 17616 <button class="btn btn-light fw-bolder smaller pe-1" title="Unselect person" t-on-click="() => this.onClickSelectedEmail(selectedEmail)"> 17617 <t t-esc="selectedEmail"/>Â <i class="oi oi-close border border-dark-subtle ms-1"/> 17618 </button> 17619 </t> 17620 </div> 17621 </div> 17622 <button t-if="props.thread and (selectedPartners.length > 0 or state.selectedEmails.length > 0)" class="btn btn-primary w-100 my-2" t-att-title="invitationButtonText" t-on-click="onClickInvite"> 17623 <t t-esc="invitationButtonText"/> 17624 </button> 17625 </t> 17626 <hr t-if="props.thread?.invitationLink" class="border-dark-subtle"/> 17627 <div t-if="props.thread?.invitationLink" class="input-group"> 17628 <input class="border border-secondary form-control lh-1 rounded-start border-0 smaller" type="text" t-att-value="props.thread.invitationLink" readonly="" disabled="" t-on-focus="onFocusInvitationLinkInput"/> 17629 <button class="btn btn-primary px-2 o-py-0_5" t-on-click="onClickCopy"> 17630 <i class="fa fa-copy"/> 17631 </button> 17632 </div> 17633 <div t-if="props.thread?.accessRestrictedToGroupText" class="mt-2 text-muted smaller mx-1" t-esc="props.thread.accessRestrictedToGroupText"/> 17634 </div> 17635 </div> 17636 </t> 17637 `); 17638registerTemplate("discuss.ChannelInvitation-selectableItem", `/mail/static/src/discuss/core/common/channel_invitation.xml`, `<t t-name="discuss.ChannelInvitation-selectableItem" xml:space="preserve"> 17639 <t t-set="isSelected" t-value="selectablePartner ? selectablePartner.in(selectedPartners) : state.selectedEmails.includes(selectableEmailAddress)"/> 17640 <li class="o-discuss-ChannelInvitation-selectable object-fit-cover d-flex align-items-start px-1 py-0 btn list-group-item border-0 rounded-0 w-100" t-att-class="{ 'o-odd': selectableItemIndex % 2 === 1, 'o-selected': isSelected, 'align-items-center': selectableEmailAddress }" t-on-click="() => selectablePartner ? this.onClickSelectablePartner(selectablePartner) : this.onClickSelectableEmail(selectableEmailAddress) "> 17641 <div class="d-flex align-items-center p-1 bg-inherit"> 17642 <div class="o-discuss-ChannelInvitation-avatar position-relative d-flex flex-shrink-0 bg-inherit"> 17643 <t t-if="selectablePartner"> 17644 <img class="w-100 h-100 rounded-3 object-fit-cover" t-att-src="selectablePartner.avatarUrl"/> 17645 <ImStatus persona="selectablePartner" className="'position-absolute top-100 start-100 translate-middle mt
17645-n1 ms-n1'" size="'md'"/> 17646 </t> 17647 <div t-else="" class="w-100 h-100 d-flex align-items-center justify-content-center rounded-3 bg-primary text-white"> 17648 <i class="fa fa-envelope"/> 17649 </div> 17650 </div> 17651 </div> 17652 <div class="d-flex flex-column mx-2 flex-grow-1 overflow-hidden o-mt-0_5"> 17653 <t t-if="selectablePartner"> 17654 <div class="d-flex overflow-hidden align-items-baseline" name="selectablePartnerName"> 17655 <span class="text-truncate" t-esc="selectablePartner.name"/> 17656 </div> 17657 <div class="d-flex flex-column flex-grow-1 gap-1" name="selectablePartnerDetail"> 17658 <span t-if="selectablePartner.email" t-esc="selectablePartner.email" class="text-truncate text-start smaller text-600 fw-normal lh-1"/> 17659 </div> 17660 </t> 17661 <div t-else="" class="overflow-hidden d-flex flex-column align-items-baseline"> 17662 <span class="text-truncate text-start w-100" t-esc="selectableEmailAddress"/> 17663 <span t-if="state.sentEmails.has(selectableEmailAddress)" class="text-truncate text-start smaller text-600 fw-normal lh-1 w-100">Invitation already sent to this address</span> 17664 </div> 17665 </div> 17666 <input class="form-check-input flex-shrink-0 me-1" type="checkbox" t-att-checked="isSelected ? 'checked' : undefined"/> 17667 </li> 17668 </t> 17669`); 17670registerTemplate("discuss.ChannelMemberList", `/mail/static/src/discuss/core/common/channel_member_list.xml`, `<t t-name="discuss.ChannelMemberList" xml:space="preserve"> 17671 <ActionPanel title.translate="Members" minWidth="200" initialWidth="env.inMeetingView ? 400 : 250" icon="'oi oi-users'"> 17672 <button name="inviteButton" t-on-click="() => props.openChannelInvitePanel({ keepPrevious: env.inChatWindow })" class="btn btn-sm btn-secondary mt-2 d-flex align-items-center justify-content-center gap-1 rounded-3"><i class="oi oi-user-plus"/><span>Invite a User</span></button> 17673 <t t-if="props.thread.onlineMembers.length > 0"> 17674 <t t-call="discuss.ChannelMemberList.section"> 17675 <t t-set="sectionName" t-value="onlineSectionText"/> 17676 </t> 17677 <div class="d-flex flex-column bg-inherit gap-1"> 17678 <t t-foreach="props.thread.onlineMembers" t-as="member" t-key="member.id" t-call="discuss.channel_member"/> 17679 </div> 17680 </t> 17681 <t name="offlineMembers" t-if="props.thread.offlineMembers.length > 0"> 17682 <t t-call="discuss.ChannelMemberList.section"> 17683 <t t-set="sectionName" t-value="offlineSectionText"/> 17684 </t> 17685 <div class="d-flex flex-column bg-inherit gap-1"> 17686 <t t-foreach="props.thread.offlineMembers" t-as="member" t-key="member.id" t-call="discuss.channel_member"> 17687 <t t-set="offline" t-value="1"/> 17688 </t> 17689 </div> 17690 </t> 17691 <span t-if="props.thread.unknownMembersCount === 1" class="mx-2 mt-2">And 1 other member.</span> 17692 <span t-if="props.thread.unknownMembersCount > 1" class="mx-2 mt-2">And <t t-esc="props.thread.unknownMembersCount"/> other members.</span> 17693 <div t-if="!props.thread.areAllMembersLoaded" class="mx-2 my-1"> 17694 <button class="btn btn-secondary" title="Load more" t-on-click.stop="() => props.thread.fetchChannelMembers()">Load more</button> 17695 </div> 17696 </ActionPanel> 17697 </t> 17698 17699 `); 17700registerTemplate("discuss.ChannelMemberList.section", `/mail/static/src/discuss/core/common/channel_member_list.xml`, `<t t-name="discuss.ChannelMemberList.section" xml:space="preserve"> 17701 <h6 class="text-muted pt-4 text-uppercase o-xsmaller opacity-75" t-esc="sectionName"/> 17702 </t> 17703 17704 `); 17705registerTemplate("discuss.channel_member", `/mail/static/src/discuss/core/common/channel_member_list.xml`, `<t t-name="discuss.channel_member" xml:space="preserve"> 17706 <div class="o-discuss-ChannelMember d-flex align-items-center p-1 bg-inherit rounded-3" t-att-class="{ 'cursor-pointer': canOpenChatWith(member), 'o-offline': offline }" t-on-click.stop="(ev) => this.onClickAvatar(ev, member)"> 17707 <div class="bg-inherit o-discuss-ChannelMember-avatar position-relative d-flex flex-shrink-0 rounded-3"> 17708 <img class="w-100 h-100 rounded-3 object-fit-cover" t-att-src="member.avatarUrl"/> 17709 <ImStatus member="member" className="'position-absolute top-100 start-100 translate-middle mt
17709-n1 ' + (member.isTyping ? 'ms-n2' : 'ms-n1')" size="'md'"/> 17710 </div> 17711 <div t-ref="displayName" class="d-flex overflow-hidden flex-column lh-sm"> 17712 <span class="ms-2 text-truncate text-muted fw-bold" t-esc="member.name" t-att-title="member.name"/> 17713 </div> 17714 <span class="ms-auto"> 17715 <span t-if="member.in(props.thread.invited_member_ids)" class="p-1 oi oi-user-plus opacity-75"/> 17716 <span t-if="member.rtcSession?.is_muted and !member.rtcSession?.is_deaf" class="p-1 fa fa-microphone-slash opacity-75"/> 17717 <span t-elif="member.rtcSession?.is_deaf" class="p-1 fa fa-deaf opacity-75"/> 17718 <span t-if="member.rtcSession?.raisingHand" class="p-1 fa fa-hand-paper-o"/> 17719 </span> 17720 17721 </div> 17722 </t> 17723 17724`); 17725registerTemplate("discuss.DeleteThreadDialog", `/mail/static/src/discuss/core/common/delete_thread_dialog.xml`, `<t t-name="discuss.DeleteThreadDialog" xml:space="preserve"> 17726 <ActionPanel title.translate="Delete Thread" icon="'fa fa-trash'" resizable="false"> 17727 <div class="d-flex justify-content-between align-items-center"> 17728 <p class="fs-5 mb-0">Permanently delete this thread?</p> 17729 <button class="btn btn-danger" t-on-click="onConfirmation"> 17730 Delete Thread 17731 </button> 17732 </div> 17733 </ActionPanel> 17734 </t> 17735`); 17736registerTemplate("mail.DiscussNotificationSettings", `/mail/static/src/discuss/core/common/discuss_notification_settings.xml`, `<t t-name="mail.DiscussNotificationSettings" xml:space="preserve"> 17737 <div class="o-mail-DiscussNotificationSettings d-flex flex-column"> 17738 <div class="d-flex flex-column my-1"> 17739 <h5>Channel Notifications</h5> 17740 <span class="mb-1 text-muted small">This setting will be applied to all channels using the default notification settings.</span> 17741 <t t-foreach="store.settings.NOTIFICATIONS" t-as="notif" t-key="notif.label"> 17742 <button class="btn d-flex my-1" t-att-class="{'o-selected' : notif.label === store.settings.channel_notifications}" t-on-click="()=> this.store.settings.setCustomNotifications(notif.label)"> 17743 <input class="form-check-input" type="radio" t-att-checked="notif.label === store.settings.channel_notifications"/> 17744 <div class="d-flex flex-column text-start flex-grow-1 mx-3"> 17745 <span t-esc="notif.name"/> 17746 </div> 17747 </button> 17748 </t> 17749 </div> 17750 <hr class="o-discuss-separator my-1"/> 17751 <label class="cursor-pointer d-flex align-items-center my-1"> 17752 <h5>Message sound</h5> 17753 <div class="flex-grow-1"/> 17754 <div class="form-check form-switch"> 17755 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.settings.messageSound" t-on-change="(ev) => ev.target.checked ? this.enableMessageSound() : this.disableMessageSound()"/> 17756 </div> 17757 </label> 17758 </div> 17759 </t> 17760`); 17761registerTemplateExtension("mail.Message", `/mail/static/src/discuss/core/common/message_patch.xml`, `<t t-inherit="mail.Message" t-inherit-mode="extension" xml:space="preserve"> 17762 <xpath expr="//div[hasclass('o-mail-Message-body')]" position="after"> 17763 <div class="o-mail-Message-seenContainer position-absolute"> 17764 <MessageSeenIndicator t-if="showSeenIndicator" message="props.message" thread="props.thread"/> 17765 </div> 17766 </xpath> 17767 <xpath expr="//AttachmentList" position="after"> 17768 <div t-if="props.message.isBodyEmpty and message.attachment_ids.length > 0" class="o-mail-Message-seenContainer position-absolute ratio-1x1 rounded-circle p-1"> 17769 <MessageSeenIndicator t-if="showSeenIndicator" message="props.message" thread="props.thread"/> 17770 </div> 17771 </xpath> 17772 </t> 17773`); 17774registerTemplate("mail.MessageSeenIndicator", `/mail/static/src/discuss/core/common/message_seen_indicator.xml`, `<t t-name="mail.MessageSeenIndicator" xml:space="preserve">
17775 <span class="o-mail-MessageSeenIndicator position-relative" t-att-class="{ 'opacity-25': !props.message.hasEveryoneSeen, 'o-hasEveryoneSeen opacity-75': props.message.hasEveryoneSeen, 'cursor-pointer': props.message.channelMemberHaveSeen.length }" t-att-title="summary" t-attf-class="{{ props.className }}" t-on-click="openDialog"> 17776 <t t-if="!props.message.isMessagePreviousToLastSelfMessageSeenByEveryone"> 17777 <i t-if="props.message.hasSomeoneFetched or props.message.hasSomeoneSeen" class="fa fa-check ps-1"/> 17778 <i t-if="props.message.hasSomeoneSeen" class="o-second start-0 fa fa-check position-absolute"/> 17779 </t> 17780 </span> 17781 </t> 17782 17783 `); 17784registerTemplate("mail.MessageSeenIndicatorPopover.card", `/mail/static/src/discuss/core/common/message_seen_indicator.xml`, `<t t-name="mail.MessageSeenIndicatorPopover.card" xml:space="preserve"> 17785 <div class="o-mail-MessageSeenIndicatorPopover-card d-flex align-items-center gap-2"> 17786 <span class="o_avatar position-relative o_card_avatar" style="width: 30px;height:30px;"> 17787 <img t-att-src="member.avatarUrl" class="w-100 h-100 rounded object-fit-cover"/> 17788 </span> 17789 <span class="fw-bold" t-esc="member.name"/> 17790 </div> 17791 </t> 17792 17793 `); 17794registerTemplate("mail.MessageSeenIndicatorDialog", `/mail/static/src/discuss/core/common/message_seen_indicator.xml`, `<t t-name="mail.MessageSeenIndicatorDialog" xml:space="preserve"> 17795 <Dialog size="'sm'" title.translate="Seen by:" footer="false" withBodyPadding="false" contentClass="'o-mail-MessageSeenIndicatorDialog'"> 17796 <ul class="list-group list-group-flush list-unstyled py-1" t-ref="content" tabindex="0"> 17797 <li class="list-group-item py-2" t-foreach="props.message.channelMemberHaveSeen" t-as="member" t-key="member.id"> 17798 <t t-call="mail.MessageSeenIndicatorPopover.card"/> 17799 </li> 17800 </ul> 17801 </Dialog> 17802 </t> 17803 17804`); 17805registerTemplate("discuss.NotificationSettings", `/mail/static/src/discuss/core/common/notification_settings.xml`, `<t t-name="discuss.NotificationSettings" xml:space="preserve"> 17806 <ActionPanel title.translate="Notification Settings" resizable="!!env.inMeetingView" initialWidth="400" icon="'fa fa-bell'"> 17807 <div class="o-discuss-NotificationSettings"> 17808 <t t-if="props.thread.self_member_id?.mute_until_dt"> 17809 <button class="btn w-100 d-flex p-1 opacity-75 border-0" t-on-click="()=>this.setMute(false)"> 17810 <div class="d-flex flex-column flex-grow-1 px-2 py-1 w-100 rounded"> 17811 <span class="fs-6 fw-bold text-wrap text-start text-break">Unmute Conversation</span> 17812 <span class="fw-normal smaller text-start" t-out="store.settings.getMuteUntilText(props.thread.self_member_id?.mute_until_dt)"/> 17813 </div> 17814 </button> 17815 </t> 17816 <div class="d-flex"> 17817 <Dropdown position="ui.isSmall ? 'bottom-end' : 'right-start'" menuClass="'o-mail-NotificationSettings-submenu my-0 ' + store.discussDropdownMenuClass(this)"> 17818 <button class="btn w-100 d-flex p-1 opacity-75 border-0"> 17819 <div class="d-flex flex-grow-1 align-items-center px-0 py-1 w-100 rounded"> 17820 <span class="text-wrap text-start text-break">Mute Conversation</span> 17821 <div class="o-discuss-NotificationSettings-separator flex-grow-1"/> 17822 <i class="oi oi-arrow-right ms-2 me-1"/> 17823 </div> 17824 </button> 17825 <t t-set-slot="content"> 17826 <t t-foreach="store.settings.MUTES" t-as="mute" t-key="mute.label"> 17827 <DropdownItem class="'o-mail-NotificationSettings-muteDuration btn rounded-0 d-flex align-items-center px-2 py-2 m-0'" onSelected="()=>this.setMute(mute.value)"><button class="btn p-0 mx-2 text-wrap text-start text-break" t-out="mute.name"/></DropdownItem> 17828 </t> 17829 </t> 17830 </Dropdown> 17831 </div> 17832 <t t-if="props.thread.channel_type === 'channel'"> 17833 <hr class="solid mx-1 my-2"/> 17834 <button class="btn d-flex w-100 p-0 border-0" t-on-click="() => store.settings.setCustomNotifications(false, props.thread)"> 17835 <div class="d-flex flex-grow-1 align-items-center px-2 rounded"> 17836 <div class="d-flex flex-column align-items-start">
17837 <span class="fs-6 text-wrap text-start text-break">Use Default</span> 17838 <span class="fw-bolder o-xsmaller ps-2 o-discuss-NotificationSettings-defaultValue"><t t-out="store.settings.NOTIFICATIONS.find((n) => n.label === store.settings.channel_notifications).name"/></span> 17839 </div> 17840 <div class="o-discuss-NotificationSettings-separator flex-grow-1"/> 17841 <input class="form-check-input shadow-sm" type="radio" t-att-checked="!props.thread.self_member_id?.custom_notifications"/> 17842 </div> 17843 </button> 17844 <t t-foreach="store.settings.NOTIFICATIONS" t-as="notif" t-key="notif.label"> 17845 <button class="btn w-100 d-flex p-0 border-0" t-on-click="() => store.settings.setCustomNotifications(notif.label, props.thread)"> 17846 <div class="d-flex flex-grow-1 align-items-center px-2 py-1 rounded"> 17847 <span class="fs-6 fw-normal text-wrap text-start text-break" t-esc="notif.name"/> 17848 <div class="o-discuss-NotificationSettings-separator flex-grow-1"/> 17849 <input class="form-check-input ms-2 shadow-sm" type="radio" t-att-checked="props.thread.self_member_id?.custom_notifications === notif.label"/> 17850 </div> 17851 </button> 17852 </t> 17853 </t> 17854 </div> 17855 </ActionPanel> 17856 </t> 17857 17858`); 17859registerTemplateExtension("mail.Thread", `/mail/static/src/discuss/core/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 17860 <xpath expr="//div[hasclass('o-mail-Thread')]" position="before"> 17861 <span t-if="!env.inChatter and props.thread.showUnreadBanner" class="o-mail-Thread-banner d-flex cursor-pointer shadow-sm smaller fw-bolder border border-warning"> 17862 <t t-set="alertClass" t-value="'alert alert-warning m-0 border-start-0 o-mail-Thread-bannerHover py-1 rounded-0'"/> 17863 <span t-attf-class="{{ alertClass }} flex-grow-1" t-on-click="onClickUnreadMessagesBanner" t-esc="newMessageBannerText"/> 17864 <span t-attf-class="{{ alertClass }}" t-on-click="() => props.thread.markAsRead()">Mark as Read<i class="ms-2 fa fa-check-square"/></span> 17865 </span> 17866 </xpath> 17867 </t> 17868`); 17869registerTemplate("discuss.BlurPerformanceWarning", `/mail/static/src/discuss/call/common/blur_performance_warning.xml`, `<t t-name="discuss.BlurPerformanceWarning" xml:space="preserve"> 17870 <CallDropdown class="'z-2'" menuClass="'o-discuss-BlurPerformanceWarning shadow bg-warning-subtle border-warning-subtle'" openByDefault="true"> 17871 <div class="o-discuss-BlurPerformanceWarning-button btn bg-warning-subtle p-1 rounded-circle position-absolute top-0 start-0" title="Background Blur Performance Warning"> 17872 <i class="fa fa-exclamation-triangle fa-fw"/> 17873 </div> 17874 <t t-set-slot="content"> 17875 <div class="position-relative p-3 rounded text-dark" style="min-width:275px;"> 17876 <div class="position-absolute top-0 end-0 m-2 cursor-pointer" t-on-click="onClickClose" title="Dismiss warning"> 17877 <i class="oi oi-close"/> 17878 </div> 17879 <div> 17880 <strong>Performance Warning:</strong><br/> 17881 Hardware acceleration is disabled. Blur effect impacts performance significantly. 17882 </div> 17883 </div> 17884 </t> 17885 </CallDropdown> 17886 </t> 17887`); 17888registerTemplate("discuss.Call", `/mail/static/src/discuss/call/common/call.xml`, `<t t-name="discuss.Call" xml:space="preserve"> 17889 <div class="o-discuss-Call user-select-none d-flex position-relative shadow-sm" t-att-class="{ 'o-fullSize': isFullSize, 'o-compact': props.compact and !isMobileOs, 'o-minimized': minimized, 'position-relative o-mx-0_5 o-mt-0_5 p-1': !rtc.state.isFullscreen and !props.isPip, 'rounded-2': !rtc.state.isFullscreen and !props.isPip and isActiveCall, 'o-hasVideo': channel.videoCount > 0, 'o-selfInCall': isActiveCall, 'border-bottom': !isActiveCall, }" t-ref="root"> 17890 <div class="o-discuss-Call-main d-flex flex-grow-1 flex-column align-items-center justify-content-center position-relative overflow-auto o-scrollbar-thin" t-on-mouseleave="onMouseleaveMain"> 17891 <PttAdBanner t-if="!props.compact"/> 17892 <BlurPerformanceWarning t-if="store.settings.blurPerformanceWarning"/> 17893 <div class="o-discuss-Call-mainCards d-flex align-items-center overflow-hidden h-100 w-100 flex-wrap justify-content-center" t-att-class="{'mt-1': minimized}" t-attf-style="--height:{{state.tileHeight}}px; --width:{{state.tileWidth}}px;" t-on-click="() => this.showOverlay()" t-on-mousemove="onMousemoveMain" t-ref="grid"> 17894 <CallParticipantCard t-foreach="visibleMainCards.slice(0,6)" t-as="cardData" t-key="cardData.key" cardData="cardData" className="'o-discuss-Call-mainCardStyle'" minimized="minimized" compact="props.compact" thread="channel"/>
17895 <span t-if="env.inChatWindow and visibleMainCards.length > 6" class="oi oi-ellipsis-h ps-1 pe-1"/> 17896 <CallParticipantCard t-if="!env.inChatWindow" t-foreach="visibleMainCards.slice(6)" t-as="cardData" t-key="cardData.key" cardData="cardData" className="'o-discuss-Call-mainCardStyle p-1'" minimized="minimized" compact="props.compact" thread="channel"/> 17897 </div> 17898 17899 17900 <t t-if="hasSidebarButton"> 17901 <i t-if="state.sidebar" class="o-discuss-Call-sidebarToggler p-2 fs-5 cursor-pointer position-absolute oi oi-arrow-right" title="Hide sidebar" t-on-click="() => this.state.sidebar = false"/> 17902 <i t-else="" class="o-discuss-Call-sidebarToggler p-2 fs-5 cursor-pointer position-absolute oi oi-arrow-left" title="Show sidebar" t-on-click="() => this.state.sidebar = true"/> 17903 </t> 17904 <div t-if="props.hasOverlay and (state.overlay or !isControllerFloating)" class="o-discuss-Call-overlay d-flex justify-content-center w-100 pb-1" t-att-class="{ 'o-isFloating position-absolute z-2 bottom-0 pb-2': isControllerFloating }"> 17905 <div t-on-mousemove="onMousemoveOverlay"> 17906 <CallActionList thread="channel" compact="props.compact or props.isPip"/> 17907 </div> 17908 </div> 17909 <div t-if="hasCallNotifications" class="position-absolute d-flex flex-column-reverse start-0 bottom-0" t-att-class="{ 'ps-5 pb-5': rtc.state.isFullscreen, 'ps-2 pb-2': !rtc.state.isFullscreen }"> 17910 <span class="o-discuss-Call-notification text-bg-800 shadow-lg rounded-1 m-1" t-att-class="{ 'p-4 fs-4': rtc.state.isFullscreen, 'p-2': !rtc.state.isFullscreen }" t-foreach="rtc.notifications.values()" t-as="notification" t-key="notification.id" t-esc="notification.text"/> 17911 </div> 17912 <div class="o-discuss-Call-layoutActions position-absolute z-2 bottom-0 end-0"> 17913 <ActionList actions="layoutActions" inline="true"/> 17914 </div> 17915 </div> 17916 <div t-if="state.sidebar and channel.activeRtcSession" class="o-discuss-Call-sidebar d-flex align-items-center h-100 flex-column"> 17917 <CallParticipantCard t-foreach="channel.visibleCards" t-as="cardData" t-key="cardData.key" cardData="cardData" className="'o-discuss-Call-sidebarCard w-100 p-1'" thread="channel" isSidebarItem="true"/> 17918 </div> 17919 <CallParticipantCard t-if="channel.videoCount > 0 and state.insetCard" cardData="state.insetCard" className="'o-discuss-Call-mainCardStyle o-bg-black'" thread="channel" inset.bind="setInset"/> 17920 </div> 17921 </t> 17922 17923`); 17924registerTemplate("discuss.CallActionList", `/mail/static/src/discuss/call/common/call_action_list.xml`, `<t t-name="discuss.CallActionList" xml:space="preserve"> 17925 <div class="o-discuss-CallActionList d-flex flex-column justify-content-center" t-attf-class="{{ className }}" t-ref="root"> 17926 <div class="o-discuss-CallActionList-bar d-flex align-items-center justify-content-between" t-att-class="{ 'w-100 ps-2 pe-2': isSmall }"> 17927 <ActionList actions="actions" inline="true" hasBtnBg="true"/> 17928 </div> 17929 <div t-if="isMobileOS and store.settings.use_push_to_talk and isOfActiveCall" class="d-flex align-items-center flex-wrap justify-content-between p-2"> 17930 <button class="o-discuss-CallActionList-pushToTalk btn btn-primary d-flex w-100 border-0 shadow-none" aria-label="Push to talk" t-on-touchstart.stop="rtc.onPushToTalk" t-on-touchend.stop="rtc.setPttReleaseTimeout"> 17931 <span class="w-100 fs-4 text-center">Push to talk</span> 17932 </button> 17933 </div> 17934 </div> 17935 </t> 17936 17937`); 17938registerTemplate("discuss.CallContextMenu", `/mail/static/src/discuss/call/common/call_context_menu.xml`, `<t t-name="discuss.CallContextMenu" xml:space="preserve"> 17939 <div class="o-discuss-CallContextMenu d-flex flex-column p-3 rounded"> 17940 <div class="text-center pb-2 fw-bolder" t-out="props.rtcSession.name"/> 17941 <div t-if="!isSelf" class="d-flex flex-row gap-2 align-items-center"> 17942 <i class="fa fa-fw fa-lg opacity-75" t-attf-class="{{state.rangeV
17942olume > 0 ? 'fa-volume-up' : 'fa-volume-off'}}"/> 17943 <div class="position-relative"> 17944 <input type="range" min="0.0" max="1" step="0.01" class="form-range h-auto" t-att-value="volume" t-model="state.rangeVolume" t-on-change="onChangeVolume"/> 17945 <output t-esc="\`\${Math.round(state.rangeVolume * 200)}%\`" class="o-mail-CallContextMenu-volumeTooltip fw-bold rounded" t-attf-style="--progress:{{state.rangeVolume * 100}}%;"/> 17946 </div> 17947 </div> 17948 <t t-if="env.debug and !isSelf and rtc.state.connectionType === rtcConnectionTypes.P2P"> 17949 <hr class="w-100 border-top"/> 17950 <div><span class="fw-bolder">RTC Session ID: </span><t t-out="props.rtcSession.id"/></div> 17951 <div><span class="fw-bolder">Connection type: </span><t t-out="rtc.state.connectionType"/></div> 17952 <div><span class="fw-bolder">To peer: </span><t t-out="outboundConnectionTypeText"/></div> 17953 <div><span class="fw-bolder">From peer: </span><t t-out="inboundConnectionTypeText"/></div> 17954 <div><span class="fw-bolder">Connection: </span><t t-out="state.peerStats.connectionState"/></div> 17955 <div><span class="fw-bolder">ICE connection: </span><t t-out="state.peerStats.iceConnectionState"/></div> 17956 <div><span class="fw-bolder">ICE: </span><t t-out="state.peerStats.iceState"/></div> 17957 <div><span class="fw-bolder">DTLS: </span><t t-out="state.peerStats.dtlsState"/></div> 17958 <div><span class="fw-bolder">Data channel: </span><t t-out="state.peerStats.dataChannelState"/></div> 17959 <div t-if="props.rtcSession.audioError"><span class="fw-bolder">Audio player: </span><t t-out="props.rtcSession.audioError"/></div> 17960 <div t-if="props.rtcSession.videoError"><span class="fw-bolder">Video player: </span><t t-out="props.rtcSession.videoError"/></div> 17961 <hr class="w-100 border-top"/> 17962 <div><span class="fw-bolder">ICE gathering: </span><t t-out="state.peerStats.iceGatheringState"/></div> 17963 <div><span class="fw-bolder">Packets sent: </span><t t-out="state.peerStats.packetsSent"/></div> 17964 <div><span class="fw-bolder">Packets received: </span><t t-out="state.peerStats.packetsReceived"/></div> 17965 <div><span class="fw-bolder">Log step: </span><t t-out="props.rtcSession.logStep"/></div> 17966 </t> 17967 <t t-elif="env.debug and isSelf and rtc.state.connectionType === rtcConnectionTypes.SERVER"> 17968 <div><span class="fw-bolder">Connection type: </span><t t-out="rtc.state.connectionType"/></div> 17969 <div><span class="fw-bolder">RTC Session ID: </span><t t-out="props.rtcSession.id"/></div> 17970 <hr class="w-100 border-top"/> 17971 <div><span class="fw-bolder">Upload: </span><t t-out="outboundConnectionTypeText"/></div> 17972 <div><span class="fw-bolder">up ICE: </span><t t-out="state.uploadStats.iceState"/></div> 17973 <div><span class="fw-bolder">up DTLS: </span><t t-out="state.uploadStats.dtlsState"/></div> 17974 <div><span class="fw-bolder">Packets sent: </span><t t-out="state.uploadStats.packetsSent"/></div> 17975 <div><span class="fw-bolder">available bitrate: </span><t t-out="state.uploadStats.availableOutgoingBitrate"/></div> 17976 <hr class="w-100 border-top"/> 17977 <div><span class="fw-bolder">Download: </span><t t-out="inboundConnectionTypeText"/></div> 17978 <div><span class="fw-bolder">down ICE: </span><t t-out="state.downloadStats.iceState"/></div> 17979 <div><span class="fw-bolder">down DTLS: </span><t t-out="state.downloadStats.dtlsState"/></div> 17980 <div><span class="fw-bolder">Packets received: </span><t t-out="state.downloadStats.packetsReceived"/></div> 17981 <t t-if="state.producerStats.audio"> 17982 <hr class="w-100 border-top"/> 17983 <div><span class="fw-bolder">microphone</span></div> 17984 <div><span class="fw-bolder">codec: </span><t t-out="state.producerStats.audio.codec"/></div> 17985 <div><span class="fw-bolder">clock rate: </span><t t-out="state.producerStats.audio.clockRate"/></div> 17986 </t> 17987 <t t-if="state.producerStats.camera and props.rtcSession.is_camera_on"> 17988 <hr class="w-100 border-top"/> 17989 <div><span class="fw-bolder">camera</span></div> 17990 <div><span class="fw-bolder">codec: </span><t t-out="state.producerStats.camera.codec"/></div> 17991 <div><span class="fw-bolder">clock rate: </span><t t-out="state.producerStats.camera.clockRate"/></div> 17992 </t> 17993 <t t-if="state.producerStats.screen and props.rtcSession.is_screen_sharing_on"> 17994 <hr class="w-100 border-top"/> 17995 <div><span class="fw-bolder">screen</span></div> 17996 <div><span class="fw-bolder">codec: </span><t t-out="state.producerStats.screen.codec"/></div> 17997 <div><span class="fw-bolder">clock rate: </span><t t-out="state.producerStats.screen.clockRate"/></div> 17998 </t> 17999 </t> 18000 </div> 18001 </t> 18002`); 18003registerTemplate("discuss.CallDropdown", `/mail/static/src/discuss/call/common/call_dropdown.xml`, `<t t-name="discuss.CallDropdown" xml:space="preserve"> 18004 <t t-slot="default"/> 18005 <div t-if="isOpen" class="o-discuss-CallDropdown" t-att-class="props.class"> 18006 <div t-ref="menu" t-on-click="onClickMenu" class="o-discuss-CallDropdown-content o-dropdown--menu dropdown-menu d-block" t-att-class="props.menuClass"> 18007 <t t-slot="content"/> 18008 </div> 18009 </div> 18010 </t> 18011 18012`); 18013registerTemplate("discuss.CallInfiniteMirroringWarning", `/mail/static/src/discuss/call/common/call_infinite_mirroring_warning.xml`, `<t t-name="discuss.CallInfiniteMirroringWarning" xml:space="preserve"> 18014 <div class="d-flex justify-content-start align-items-start position-fixed top-0 end-0 w-100 pe-none"> 18015 <div class="d-flex o-discuss-CallInfiniteMirroringWarning rounded justify-content-between fs-3 w-100 m-5 px-3 py-2 pe-auto"> 18016 <div class="d-flex align-items-center fs-4"> 18017 To avoid the infinite mirror effect, please share a specific window or tab or another monitor. 18018 </div> 18019 <div class="d-flex gap-2 flex-shrink-0"> 18020 <button class="btn btn-link text-info fs-4" t-on-click="() => this.props.onClose({ stopScreensharing: true })"> 18021 Stop sharing 18022 </button> 18023 <button class="o-discuss-CallInfiniteMirroringWarning-dismiss border-0 bg-transparent opacity-50 opacity-100-hover pe-auto" t-on-click="() => this.props.onClose()"> 18024 <i class="fa fa-lg fa-times-circle"/> 18025 </button> 18026 </div> 18027 </div> 18028 </div> 18029 </t> 18030`); 18031registerTemplate("discuss.CallInvitation", `/mail/static/src/discuss/call/common/call_invitation.xml`, `<t t-name="discuss.CallInvitation" xml:space="preserve"> 18032 <div class="o-discuss-CallInvitation align-self-center o-rounded-bubble overflow-hidden shadow-sm" t-att-class="{'o-preview-open': state.showCameraPreview, 'o-chat': props.thread.channel_type === 'chat', 'border border-light': !store.isOdooWhiteTheme}"> 18033 <div class="d-flex flex-colum d-flex flex-column"> 18034 <div class="o-discuss-CallInvitation-main" t-ref="root"> 18035 <div class="ms-1 position-relative d-flex justify-content-between p-2"> 18036 <div class="d-flex align-items-center" style="min-width: 0;"> 18037 <div class="o-mail-CallInvitation-avatar flex-shrink-0 cursor-pointer d-flex align-items-center justify-content-center rounded-circle overflow-hidden" t-att-class="{'bg-primary': !inviter}" t-on-click="() => props.thread.open({ focus: true })" t-att-title="avatarTitle"> 18038 <img t-if="inviter" class="object-fit-cover h-100 w-100" t-att-src="inviter.avatarUrl" alt="Avatar"/> 18039 <i t-else="" class="fa fa-phone"/> 18040 </div> 18041 <div class="ms-2 me-3 flex-grow-1 overflow-hidden"> 18042 <p class="o-discuss-CallInvitation-channelName m-0 fw-bold small text-truncate" t-esc="props.thread.displayName"/> 18043 <p class="o-discuss-CallInvitation-description m-0 fst-italic
18043smaller text-truncate pe-1" t-esc="incomingCallText"/> 18044 </div> 18045 </div> 18046 <div class="d-flex align-items-center flex-shrink-0"> 18047 <ActionList actions="acceptOrRejectActions" inline="true" hasBtnBg="true"/> 18048 <ActionList actions="otherActions" inline="true"/> 18049 </div> 18050 </div> 18051 <div class="o-discuss-CallInvitation-cameraPreview" t-att-class="{'o-opened': state.showCameraPreview}"> 18052 <CallPreview activateCamera="state.activateCamera" activateMicrophone="state.activateMicrophone" onSettingsChanged="(settings) => this.onCallSettingsChanged(settings)"/> 18053 </div> 18054 </div> 18055 </div> 18056 </div> 18057 </t> 18058`); 18059registerTemplate("discuss.CallInvitations", `/mail/static/src/discuss/call/common/call_invitations.xml`, `<t t-name="discuss.CallInvitations" xml:space="preserve"> 18060 <div t-if="store.ringingThreads.length > 0" class="o-discuss-CallInvitations position-fixed top-0 end-0 d-flex flex-column p-2"> 18061 <t t-foreach="store.ringingThreads" t-as="thread" t-key="thread.localId"> 18062 <CallInvitation thread="thread"/> 18063 </t> 18064 </div> 18065 </t> 18066 18067`); 18068registerTemplate("discuss.CallMenu", `/mail/static/src/discuss/call/common/call_menu.xml`, `<t t-name="discuss.CallMenu" xml:space="preserve"> 18069 <div class="dropdown" t-attf-class="{{ className }}" t-ref="root"> 18070 <button t-if="rtc.channel" class="user-select-none dropdown-toggle o-no-caret o-dropdown--narrow" t-att-title="buttonTitle" role="button" t-on-click="rtc.channel.open"> 18071 <div class="o-discuss-CallMenu-buttonContent d-flex btn-group rounded-2 opacity-75 opacity-100-hover" t-att-class="{ 'o-is-talking': rtc.selfSession?.isActuallyTalking, 'o-isOdooCommunity': !isEnterprise }"> 18072 <div class="o-discuss-CallMenu-channelInfo text-truncate btn btn-group-item border-0 m-0 p-0 d-flex align-items-center o-gap-0_5 ps-1" role="button"> 18073 <span class="position-relative small bg-transparent"> 18074 <i class="me-2 fa fa-fw" t-att-class="icon"/> 18075 <small class="d-flex position-absolute top-0 end-0 smaller bg-inherit"> 18076 <i class="o-discuss-CallMenu-animation fa fa-volume-up o-discuss-inCallIconColor bg-inherit" t-att-class="{ 'o-isOdooCommunity': !isEnterprise }"/> 18077 </small> 18078 </span> 18079 <span class="text-truncate fw-bold pe-1" t-esc="rtc.channel.displayName"/> 18080 </div> 18081 <Dropdown> 18082 <button class="o-discuss-CallMenu-dropdownMore btn btn-group-item m-0 pe-1 o-ps-0_5"> 18083 <i class="oi oi-chevron-down o-xsmaller"/> 18084 </button> 18085 <t t-set-slot="content"> 18086 <ActionList actions="callActions.actions" dropdown="true"/> 18087 </t> 18088 </Dropdown> 18089 </div> 18090 </button> 18091 </div> 18092 </t> 18093 18094`); 18095registerTemplate("discuss.CallParticipantCard", `/mail/static/src/discuss/call/common/call_participant_card.xml`, `<t t-name="discuss.CallParticipantCard" xml:space="preserve"> 18096 <div class="o-discuss-CallParticipantCard position-relative cursor-pointer d-flex flex-column align-items-center justify-content-center mh-100 mw-100" t-att-class="{ 'o-isTalking': !props.minimized and isTalking, 'o-isInvitation opacity-50': !rtcSession, 'o-inset': props.inset, 'pe-none': rtc.state.screenTrack and !rtc.state.screenTrack.enabled, 'o-small': props.inset and (ui.isSmall or props.minimized), 'o-active': isActiveRtcSession and !props.inset and props.compact, 'p-1 rounded-1': !isActiveRtcSession, }" t-att-title="name" t-att-aria-label="name" t-att-data-is-context-menu-available="isContextMenuAvailable" t-attf-class="{{ props.className }}" t-on-click="onClick" t-on-mousedown="onMouseDown" t-on-touchmove="onTouchMove" t-ref="root"> 18097 18098 <t t-if="!props.isSidebarItem and props.cardData.type === 'screen' and rtc.state.screenTrack and !rtc.state.screenTrack.enabled"> 18099 <div class="o-text-white display-5 gap-3"> 18100 <button class="pe-auto bg-transparent o-text-white border-0 opacity-25 opacity-75-hover" t-ref="resumeStream" t-on-click.stop="() => (this.rtc.state.screenTrack.enabled = true)"> 18101 <i class="fa fa-fw" t-att-class="{ 'fa-play-circle-o': resumeStreamHover.isHover, 'fa-pause-circle-o': !resumeStreamHover.isHover }"/> <span><t t-if="resumeStreamHover.isHover">Resume stream</t><t t-else="">Stream paused</t></span> 18102 </button> 18103 </div> 18104 </t> 18105 <CallParticipantVideo t-elif="hasVideo" session="rtcSession" type="props.cardData.type" inset="props.inset"/> 18106 <div t-else="" class="o-discuss-CallParticipantCard-avatar d-flex align-items-center justify-content-center h-100 w-100 rounded-1" t-att-class="{ 'o-minimized': props.minimized, 'o-isRemoteVideo': isRemoteVideo }" draggable="false"> 18107 <img t-if="!showRemoteWarning" alt="Avatar" class="h-100 rounded-circle border-5 object-fit-cover" t-att-src="channelMember?.avatarUrl" draggable="false" t-att-class="{ 'o-isTalking': isTalking and props.minimized, 'o-isInv
18107itation': !rtcSession, }"/> 18108 </div> 18109 <t t-if="rtcSession"> 18110 18111 <span class="o-discuss-CallParticipantCard-overlay o-discuss-CallParticipantCard-overlayBottom z-1 position-absolute bottom-0 start-0 d-flex overflow-hidden rounded-1" t-att-class="{ 'o-proportional-container w-50': isSmall }" t-att-data-connection-state="rtcSession.connectionState"> 18112 <span t-if="!props.minimized and !props.inset" class="rounded-1 text-truncate opacity-75 w-100 o-proportional-text o-discuss-CallParticipantCard-overlayBottomName" t-att-class="{'o-minimized px-1': isSmall, 'p-0': !isSmall }" t-esc="name"/> 18113 <small t-if="rtcSession.is_screen_sharing_on and props.minimized and !isOfActiveCall" class="user-select-none o-proportional-text o-minimized rounded text-bg-danger d-flex align-items-center fw-bolder p-1" title="live" aria-label="live"> 18114 LIVE 18115 </small> 18116 </span> 18117 <span t-if="showRemoteWarning" class="o-discuss-CallParticipantCard-overlay o-proportional-container z-1 w-50 position-absolute d-flex align-items-center justify-content-center overflow-hidden"> 18118 <span class="fw-bolder p-1 rounded-1 o-video-text o-proportional-text">Video visible in the call tab</span> 18119 </span> 18120 <CallDropdown t-if="isContextMenuAvailable and ((!isMobileOS and rootHover.isHover) or (isMobileOS and !props.minimized))" menuClass="'d-flex o-discuss-CallParticipantCard-contextMenu'"> 18121 <button class="o-discuss-CallParticipantCard-contextButton btn btn-secondary btn-sm rounded-circle border-0 smaller p-1 position-absolute top-0 end-0" title="Participant options"> 18122 <i class="fa fa-chevron-down fa-fw"/> 18123 </button> 18124 <t t-set-slot="content"> 18125 <CallContextMenu rtcSession="rtcSession"/> 18126 </t> 18127 </CallDropdown> 18128 <div class="o-discuss-CallParticipantCard-overlay position-absolute bottom-0 end-0 d-flex w-50 flex-row-reverse w-50" t-att-class="{ 'o-proportional-container': isSmall, 'mw-25': props.isSidebarItem or props.inset }"> 18129 <span t-if="hasRaisingHand" class="o-proportional-text d-flex flex-column justify-content-center me-1 rounded-circle bg-500" t-att-class="{'o-minimized p-1': isSmall, 'p-2': !isSmall }" title="raising hand" aria-label="raising hand"> 18130 <i class="fa fa-hand-paper-o"/> 18131 </span> 18132 <span t-if="rtcSession.is_muted and !rtcSession.is_deaf" class="o-proportional-text d-flex flex-column justify-content-center me-1 rounded-circle o-discuss-CallParticipantCard-iconBlackBg" t-att-class="{'o-minimized p-1': isSmall, 'p-2': !isSmall }" title="muted" aria-label="muted"> 18133 <i class="fa fa-microphone-slash"/> 18134 </span> 18135 <span t-if="rtcSession.is_deaf" class="o-proportional-text d-flex flex-column justify-content-center me-1 rounded-circle o-discuss-CallParticipantCard-iconBlackBg" t-att-class="{'o-minimized p-1': isSmall, 'p-2': !isSmall }" title="deaf" aria-label="deaf"> 18136 <i class="fa fa-deaf"/> 18137 </span> 18138 <span t-if="hasMediaError" class="o-discuss-CallParticipantCard-overlay-replayButton o-proportional-text d-flex flex-column justify-content-center me-1 rounded-circle" t-att-class="{'o-minimized p-1': isSmall, 'p-2': !isSmall }" title="media player Error" t-on-click.stop="onClickReplay"> 18139 <i t-if="rootHover.isHover" class="fa fa-repeat text-danger"/> 18140 <i t-else="" class="fa fa-exclamation-triangle text-danger"/> 18141 </span> 18142 <span t-if="showConnectionState" class="o-proportional-text d-flex flex-column justify-content-center me-1 rounded-circle o-discuss-CallParticipantCard-iconBlackBg" t-att-class="{'o-minimized p-1': isSmall, 'p-2': !isSmall }" t-att-title="rtcSession.connectionState"> 18143 <i class="fa fa-exclamation-triangle text-warning"/> 18144 </span>
18145 <span t-if="showLiveLabel" class="user-select-none rounded o-proportional-text text-bg-danger d-flex align-items-center py-1 px-2 fw-bolder" title="live" aria-label="live"> 18146 LIVE 18147 </span> 18148 </div> 18149 </t> 18150 </div> 18151 </t> 18152 18153`); 18154registerTemplate("discuss.CallParticipantVideo", `/mail/static/src/discuss/call/common/call_participant_video.xml`, `<t t-name="discuss.CallParticipantVideo" xml:space="preserve"> 18155 <video class="w-100 h-100 cursor-pointer" t-att-class="{ 'o-inset rounded-1': props.inset }" t-att-type="props.type" t-att-data-facing-mode="store.settings.cameraFacingMode" playsinline="true" autoplay="true" muted="true" t-on-loadedmetadata="onVideoLoadedMetaData" t-ref="root"/> 18156 </t> 18157`); 18158registerTemplate("discuss.CallPermissionDialog", `/mail/static/src/discuss/call/common/call_permission_dialog.xml`, `<t t-name="discuss.CallPermissionDialog" xml:space="preserve"> 18159 <Dialog title="''" size="'md'"> 18160 <h5 class="fw-medium fs-2 mb-2" t-out="permissionPrompt"/> 18161 <small class="text-muted" t-out="permissionNote"/> 18162 <t t-set-slot="footer"> 18163 <button class="btn btn-primary px-4" t-on-click="props.media === 'microphone' ? onClickUseMicrophone : onClickUseCamera" t-out="primaryActionText"/> 18164 <button class="btn btn-outline-primary px-4" t-if="rtc.cameraPermission !== 'granted' and rtc.microphonePermission !== 'granted'" t-on-click="onClickUseMicAndCamera">Use microphone and camera</button> 18165 </t> 18166 </Dialog> 18167 </t> 18168 18169`); 18170registerTemplate("mail.CallPreview", `/mail/static/src/discuss/call/common/call_preview.xml`, `<t t-name="mail.CallPreview" xml:space="preserve"> 18171 <div class="o-mail-CallPreview ratio ratio-16x9"> 18172 <div class="bg-dark"> 18173 <video class="object-fit-cover h-100 w-100" autoplay="" style="background-color: rgba(0, 0, 0, 0.5);" t-ref="video"/> 18174 <div class="position-absolute bottom-0 mb-3 w-100 d-flex justify-content-center"> 18175 <ActionList actions="actions" inline="true" hasBtnBg="true"/> 18176 </div> 18177 </div> 18178 <audio autoplay="" t-ref="audio"/> 18179 </div> 18180 </t> 18181`); 18182registerTemplate("discuss.CallSettings", `/mail/static/src/discuss/call/common/call_settings.xml`, `<t t-name="discuss.CallSettings" xml:space="preserve"> 18183 <ActionPanel t-if="props.withActionPanel" title.translate="Voice settings" icon="'fa fa-gear'"> 18184 <t t-call="discuss.CallSettings.content"/> 18185 </ActionPanel> 18186 <t t-else="" t-call="discuss.CallSettings.content"/> 18187 </t> 18188 18189 `); 18190registerTemplate("discuss.CallSettings.content", `/mail/static/src/discuss/call/common/call_settings.xml`, `<t t-name="discuss.CallSettings.content" xml:space="preserve"> 18191 <div class="o-discuss-CallSettings d-flex flex-column"> 18192 <h4>Voice</h4> 18193 <label class="d-flex align-items-baseline mb-2" title="Microphone" aria-label="Microphone"> 18194 <span class="flex-shrink-0 pe-2"> 18195 Microphone 18196 </span> 18197 <div class="flex-grow-1"/> 18198 <DeviceSelect kind="'audioinput'"/> 18199 </label> 18200 <label class="d-flex align-items-baseline mb-2" title="Audio Output" aria-label="Audio Output"> 18201 <span class="flex-shrink-0 pe-2"> 18202 Audio Output 18203 </span> 18204 <div class="flex-grow-1"/> 18205 <DeviceSelect kind="'audiooutput'"/> 18206 </label> 18207 <div class="d-flex flex-column"> 18208 <button class="btn d-flex my-1" t-att-class="{'bg-300' : !store.settings.use_push_to_talk }" t-on-click="()=>this.store.settings.setPushToTalk(false)"> 18209 <input class="form-check-input" type="radio" t-att-checked="store.settings.use_push_to_talk ? '' : 'checked'"/> 18210 <span class="text-start flex-grow-1 mx-3">Voice Detection</span> 18211 </button> 18212 <button class="btn d-flex my-1" t-att-class="{'bg-300' : store.settings.use_push_to_talk }" t-on-click="()=>this.store.settings.setPushToTalk(true)"> 18213 <input class="form-check-input" type="radio" t-att-checked="store.settings.use_push_to_talk ? 'checked' : ''"/>
18214 <span class="text-start flex-grow-1 mx-3">Push to Talk</span> 18215 </button> 18216 <span t-if="store.settings.use_push_to_talk and !isMobileOS and !pttExtService.isEnabled" class="small text-muted fst-italic mb-3" t-out="pttExtService.downloadText"/> 18217 </div> 18218 <div class="d-flex flex-column"> 18219 <t t-if="!store.settings.use_push_to_talk"> 18220 <span class="me-2 my-1">Voice detection sensitivity</span> 18221 <div class="d-flex align-items-center w-100 h-100"> 18222 <button class="btn btn-primary" t-on-click="microphoneVolume.toggle" t-att-disabled="!microphoneVolume.isReady"> 18223 <div class="position-relative"> 18224 <span class="d-flex invisible text-nowrap"> 18225 <t t-out="testText.length > stopText.length ? testText : stopText"/> 18226 </span> 18227 <span class="position-absolute start-0 top-0"> 18228 <t t-if="microphoneVolume.isActive" t-out="stopText"/> 18229 <t t-else="" t-out="testText"/> 18230 </span> 18231 </div> 18232 </button> 18233 <label class="w-100 d-flex ms-2" title="Voice detection sensitivity" aria-label="Voice detection sensitivity"> 18234 <input class="o-Discuss-CallSettings-thresholdInput form-range rounded" t-attf-style="--volume: {{microphoneVolume.value * 100}}%;" type="range" min="0.001" max="1" step="0.001" t-model="store.settings.voiceActivationThreshold" t-on-input="store.settings.saveVoiceThresholdDebounce"/> 18235 </label> 18236 </div> 18237 </t> 18238 <div t-if="store.settings.use_push_to_talk" class="d-flex" t-att-class="{'flex-column': props.isCompact}"> 18239 <div t-if="!isMobileOS" class="d-flex flex-column align-items-center" t-att-class="{'me-1 w-50': !props.isCompact}"> 18240 <label class="d-flex flex-column align-items-start flex-wrap w-100" title="Push-to-talk key" aria-label="Push-to-talk key"> 18241 <span class="me-2 my-1 text-truncate text-wrap">Push-to-talk key</span> 18242 <span class="d-flex border border-2 rounded w-100" t-attf-class="{{ store.settings.isRegisteringKey ? 'border-danger' : 'border-primary' }}"> 18243 <span t-if="store.settings.push_to_talk_key" class="ms-1 px-3 fs-3 flex-grow-1" t-esc="pushToTalkKeyText"/> 18244 <button class="btn btn-link px-2 py-0 text-black" t-on-click="onClickRegisterKeyButton"> 18245 <i t-if="store.settings.isRegisteringKey" title="Cancel" aria-label="Cancel" class="fa fa-2x fa-times-circle"/> 18246 <i t-else="" title="Register new key" aria-label="Register new key" class="fa fa-2x fa-keyboard-o"/> 18247 </button> 18248 </span> 18249 </label> 18250 </div> 18251 <div class="d-flex align-items-center" t-att-class="{'ms-1 w-50': !props.isCompact}"> 18252 <label class="d-flex flex-column align-items-start flex-wrap h-100 w-100" title="Delay after releasing push-to-talk" aria-label="Delay after releasing push-to-talk"> 18253 <span class="me-2 my-1 text-truncate text-wrap">Delay after releasing push-to-talk</span> 18254 <div class="d-flex w-100 align-items-center"> 18255 <input class="flex-grow-1 form-range" type="range" min="0" max="2000" step="1" t-att-value="store.settings.voice_active_duration" t-on-input="onChangeDelay"/> 18256 <span class="p-1 text-end"><t t-out="store.settings.voice_active_duration"/>ms</span> 18257 </div> 18258 </label> 18259 </div> 18260 </div>
18261 <span t-if="store.settings.isRegisteringKey">Press a key to register it as the push-to-talk shortcut.</span> 18262 </div> 18263 <hr class="o-discuss-separator my-2"/> 18264 <h4>Video</h4> 18265 <label class="d-flex align-items-baseline mb-2" title="Camera" aria-label="Camera"> 18266 <span class="flex-shrink-0 pe-2"> 18267 Camera 18268 </span> 18269 <div class="flex-grow-1"/> 18270 <DeviceSelect kind="'videoinput'"/> 18271 </label> 18272 <div class="d-flex flex-column my-1"> 18273 <t t-call="discuss.CallSettings.textToggler"> 18274 <t t-set="text">Show video participants only</t> 18275 <t t-set="value" t-value="store.settings.showOnlyVideo"/> 18276 <t t-set="onchange" t-value="onChangeShowOnlyVideo"/> 18277 </t> 18278 </div> 18279 <div t-if="store.settings.hasCanvasFilterSupport" class="d-flex flex-column my-1"> 18280 <t t-call="discuss.CallSettings.textToggler"> 18281 <t t-set="text">Blur video background</t> 18282 <t t-set="value" t-value="store.settings.useBlur"/> 18283 <t t-set="onchange" t-value="onChangeBlur"/> 18284 </t> 18285 </div> 18286 <t t-if="store.settings.useBlur"> 18287 <div class="d-flex mt-1" t-att-class="{'flex-column': props.isCompact}"> 18288 <div class="d-flex flex-column align-items-center" t-att-class="{'me-1 w-50': !props.isCompact}"> 18289 <label class="d-flex flex-column align-items-start flex-wrap w-100" title="Background blur intensity" aria-label="Background blur intensity"> 18290 <span class="me-2 text-truncate text-wrap">Background blur intensity</span> 18291 <div class="d-flex w-100 flex-grow-1 align-items-center"> 18292 <input class="flex-grow-2 form-range" type="range" min="0" max="20" step="1" t-att-value="store.settings.backgroundBlurAmount" t-on-change="onChangeBackgroundBlurAmount"/> 18293 <span class="p-1 text-end o-discuss-DiscussCallSettings-width-text-percentage"><t t-out="Math.floor(store.settings.backgroundBlurAmount * 5)"/>%</span> 18294 </div> 18295 </label> 18296 </div> 18297 <div class="d-flex align-items-center" t-att-class="{'ms-1 w-50': !props.isCompact}"> 18298 <label class="d-flex flex-column align-items-start flex-wrap h-100 w-100" title="Edge blur intensity" aria-label="Edge blur intensity"> 18299 <span class="me-2 text-truncate text-wrap">Edge blur intensity</span> 18300 <div class="d-flex w-100 flex-grow-1 align-items-center"> 18301 <input class="flex-grow-2 form-range" type="range" min="0" max="20" step="1" t-att-value="store.settings.edgeBlurAmount" t-on-change="onChangeEdgeBlurAmount"/> 18302 <span class="p-1 text-end o-discuss-DiscussCallSettings-width-text-percentage"><t t-out="Math.floor(store.settings.edgeBlurAmount * 5)"/>%</span> 18303 </div> 18304 </label> 18305 </div> 18306 </div> 18307 </t> 18308 <hr class="o-discuss-separator my-2"/> 18309 <h4>Technical Settings</h4> 18310 <t t-if="env.debug"> 18311 <div class="d-flex flex-column my-1"> 18312 <t t-call="discuss.CallSettings.textToggler"> 18313 <t t-set="text">Log RTC events</t> 18314 <t t-set="value" t-value="store.settings.logRtc"/> 18315 <t t-set="onchange" t-value="onChangeLogRtc"/> 18316 </t> 18317 </div> 18318 </t> 18319 <button class="btn btn-secondary mt-1 mb-2 w-100" t-on-click="onClickDownloadLogs">Download logs</button> 18320 </div> 18321 </t> 18322 `); 18323registerTemplate("discuss.CallSettings.textToggler", `/mail/static/src/discuss/call/common/call_settings.xml`, `<t t-name="discuss.CallSettings.textToggler" xml:space="preserve"> 18324 <div class="d-flex flex-wrap align-items-center"> 18325 <label class="d-flex align-items-center flex-wrap mw-100" t-att-title="text" t-att-aria-label="text">
18326 <span class="text-truncate text-wrap" t-out="text"/> 18327 </label> 18328 <div class="flex-grow-1"/> 18329 <div class="form-check form-switch"> 18330 <input class="form-check-input" type="checkbox" role="switch" t-on-change="onchange" t-att-checked="value ? 'checked' : ''" t-att-title="text" t-att-aria-label="text"/> 18331 </div> 18332 </div> 18333 </t> 18334 18335`); 18336registerTemplateExtension("mail.ChatWindow", `/mail/static/src/discuss/call/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18337 <xpath expr="//Thread" position="before"> 18338 <PipBanner t-if="rtc.state.isPipMode and thread.eq(rtc.channel)" compact="true"/> 18339 <Call t-elif="thread.showCallView" thread="thread" compact="true"/> 18340 </xpath> 18341 </t> 18342`); 18343registerTemplate("discuss.CallDeviceSelect", `/mail/static/src/discuss/call/common/device_select.xml`, `<t t-name="discuss.CallDeviceSelect" xml:space="preserve"> 18344 <select t-if="!isPermissionGranted(props.kind)" name="inputDevice" class="form-select d-flex shadow-sm" t-on-pointerdown.prevent="() => this.showPermissionDialog(props.kind)" t-on-keydown.prevent="() => this.showPermissionDialog(props.kind)"> 18345 <option value="">Permission Needed</option> 18346 </select> 18347 <select t-else="" name="inputDevice" class="form-select d-flex shadow-sm" t-on-change="onChangeSelectAudioInput"> 18348 <option t-if="!isBrowserChrome" value="">Browser Default</option> 18349 <t t-foreach="state.userDevices" t-as="device" t-key="device_index"> 18350 <option t-if="device.kind === props.kind" t-att-selected="isSelected(device.deviceId)" t-att-value="device.deviceId"> 18351 <t t-esc="device.label || 'device ' + device_index"/> 18352 </option> 18353 </t> 18354 </select> 18355 </t> 18356 18357`); 18358registerTemplate("mail.DiscussCallSettingsClientAction", `/mail/static/src/discuss/call/common/discuss_call_settings_client_action.xml`, `<t t-name="mail.DiscussCallSettingsClientAction" xml:space="preserve"> 18359 <div class="o-mail-DiscussCallSettingsClientAction mx-3 my-2"> 18360 <CallSettings withActionPanel="false"/> 18361 </div> 18362 </t> 18363`); 18364registerTemplate("mail.Meeting", `/mail/static/src/discuss/call/common/meeting.xml`, `<t t-name="mail.Meeting" xml:space="preserve"> 18365 <div t-if="store.rtc.channel" class="o-mail-Meeting h-100 w-100 d-flex flex-column" t-att-class="{'o-fullscreen': store.rtc.state.isFullscreen, 'p-1': !ui.isSmall, 'pb-3': !ui.isSmall and !props.isPip}"> 18366 <div class="d-flex flex-grow-1 h-100 o-min-height-0 gap-1 position-relative"> 18367 <div class="o-mail-Meeting-callContainer h-100 flex-grow-1 o-min-width-0" t-att-class="{'d-none': ui.isSmall and threadActions.activeAction?.actionPanelComponentCondition, 'pb-0': ui.isSmall}"> 18368 <Call hasOverlay="false" isPip="props.isPip"/> 18369 </div> 18370 <div t-if="threadActions.activeAction?.actionPanelComponentCondition" t-attf-class="{{ threadActions.activeAction.panelOuterClass }}" class="o-mail-DiscussContent-panelContainer o-mail-discussSidebarBgColor h-100 border-start border-secondary flex-shrink-0 rounded-2" t-att-class="{ 'w-100': ui.isSmall }"> 18371 <t t-component="threadActions.activeAction.actionPanelComponent" t-props="threadActions.activeAction.actionPanelComponentProps" thread="thread"/> 18372 </div> 18373 </div> 18374 <div class="pt-2 d-flex justify-content-between overflow-x-auto flex-shrink-0" t-att-class="{'p-2 pb-3': ui.isSmall}"> 18375 <div/> 18376 <CallActionList thread="store.rtc.channel"/> 18377 <MeetingSideActions threadActions="threadActions"/> 18378 </div> 18379 </div> 18380 </t> 18381`); 18382registerTemplate("mail.MeetingChat", `/mail/static/src/discuss/call/common/meeting_chat.xml`, `<t t-name="mail.MeetingChat" xml:space="preserve"> 18383 <ActionPanel t-if="thread" title.translate="Chat" resizable="true" minWidth="300" initialWidth="400" icon="'fa fa-comments'" contentRef="panelContentRef"> 18384 <Thread thread="thread" jumpPresent="state.jumpPresent"/> 18385 <t t-call="mail.ChatWindow.memberTyping"/> 18386 <Composer composer="thread.composer" autofocus="!isMobileOS" onDiscardCallback="() =>
18386 (thread.composer.replyToMessage = undefined)" onPostCallback.bind="() => this.state.jumpPresent++" dropzoneRef="panelContentRef"/> 18387 </ActionPanel> 18388 </t> 18389`); 18390registerTemplate("mail.MeetingSideActions", `/mail/static/src/discuss/call/common/meeting_side_actions.xml`, `<t t-name="mail.MeetingSideActions" xml:space="preserve"> 18391 <t t-set="dummy" t-value="computeActions()"/> 18392 <div class="o-mail-MeetingSideActions d-flex"> 18393 <ActionList actions="actions" inline="true" hasBtnBg="true" thread="store.rtc.channel" odooControlPanelSwitchStyle="true"/> 18394 </div> 18395 </t> 18396`); 18397registerTemplate("discuss.pipBanner", `/mail/static/src/discuss/call/common/pip_banner.xml`, `<t t-name="discuss.pipBanner" xml:space="preserve"> 18398 <span class="o-discuss-PipBanner px-2 py-1 mx-1 mt-1 rounded-1"> 18399 <div class="d-flex justify-content-between align-items-center p-2"> 18400 <span class="small fw-bold">Your call is in another window. <t t-if="!props.compact">Using picture-in-picture lets you stay in the call while you do other things.</t></span> 18401 <button class="btn o-discuss-PipBannerButton d-flex rounded-1" title="Bring call back" t-on-click="onClickClose"> 18402 <t t-if="props.compact"> 18403 Bring back 18404 </t> 18405 <t t-else=""> 18406 Bring the call back here 18407 </t> 18408 </button> 18409 </div> 18410 <div class="d-flex justify-content-center"> 18411 <CallActionList thread="rtc.channel" compact="true"/> 18412 </div> 18413 </span> 18414</t> 18415 18416`); 18417registerTemplate("discuss.pttAdBanner", `/mail/static/src/discuss/call/common/ptt_ad_banner.xml`, `<t t-name="discuss.pttAdBanner" xml:space="preserve"> 18418 <span t-if="isVisible" class="o-discuss-PttAdBanner alert alert-info px-2 py-1 m-0 rounded-0"> 18419 <div class="d-flex justify-content-between align-items-center"> 18420 <span class="small" t-out="pttExtService.downloadText"/> 18421 <button class="btn d-flex opacity-75 opacity-100-hover" title="Close banner" t-on-click="onClickClose"> 18422 <i class="fa fa-fw fa-close"/> 18423 </button> 18424 </div> 18425 </span> 18426</t> 18427 18428`); 18429registerTemplate("discuss.QuickVideoSettings", `/mail/static/src/discuss/call/common/quick_video_settings.xml`, `<t t-name="discuss.QuickVideoSettings" xml:space="preserve"> 18430 <div class="o-discuss-QuickVideoSettings d-flex flex-column gap-1"> 18431 <label class="btn border-transparent d-flex flex-column align-items-baseline"> 18432 <span class="flex-shrink-0 pe-2"> 18433 Camera 18434 </span> 18435 <div class="flex-grow-1"/> 18436 <DeviceSelect kind="'videoinput'"/> 18437 </label> 18438 <div t-if="!isBrowserSafari()" class="btn border-transparent d-flex gap-2" t-on-click="() => store.settings.setUseBlur(!store.settings.useBlur)"> 18439 <label class="d-flex align-items-center flex-wrap mw-100 cursor-pointer gap-2"> 18440 <i class="fa fa-fw fa-photo"/><span class="text-truncate text-wrap">Blur background</span> 18441 </label> 18442 <div class="flex-grow-1"/> 18443 <div class="form-check form-switch"> 18444 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.settings?.useBlur ? 'checked' : ''"/> 18445 </div> 18446 </div> 18447 <button class="btn border-transparent d-flex align-items-center gap-2" t-on-click="onClickVideoSettings"> 18448 <i class="fa fa-fw fa-gear"/><span>Video Settings</span> 18449 </button> 18450 </div> 18451 </t> 18452 18453`); 18454registerTemplate("discuss.QuickVoiceSettings", `/mail/static/src/discuss/call/common/quick_voice_settings.xml`, `<t t-name="discuss.QuickVoiceSettings" xml:space="preserve"> 18455 <div class="o-discuss-QuickVoiceSettings d-flex flex-column gap-1"> 18456 <label class="btn border-transparent d-flex flex-column align-items-baseline"> 18457 <span class="flex-shrink-0 pe-2"> 18458 Microphone 18459 </span> 18460 <div class="flex-grow-1"/> 18461 <DeviceSelect kind="'audioinput'"/> 18462 </label> 18463 <label class="btn border-transparent d-flex flex-column align-items-baseline">
18464 <span class="flex-shrink-0 pe-2"> 18465 Audio Output 18466 </span> 18467 <div class="flex-grow-1"/> 18468 <DeviceSelect kind="'audiooutput'"/> 18469 </label> 18470 <button t-if="store.rtc.selfSession" class="btn border-transparent d-flex" t-on-click="() => this.store.rtc.toggleDeafen()"> 18471 <label class="d-flex align-items-center flex-wrap mw-100 cursor-pointer"> 18472 <span class="text-truncate text-wrap">Deafen</span> 18473 </label> 18474 <div class="flex-grow-1"/> 18475 <div class="form-check form-switch"> 18476 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.rtc.selfSession?.is_deaf ? 'checked' : ''"/> 18477 </div> 18478 </button> 18479 <button class="btn border-transparent d-flex" t-on-click="() => this.store.settings.use_push_to_talk = !this.store.settings.use_push_to_talk"> 18480 <label class="d-flex align-items-center flex-wrap mw-100 cursor-pointer"> 18481 <span class="text-truncate text-wrap">Push-to-Talk</span> 18482 </label> 18483 <div class="flex-grow-1"/> 18484 <div class="form-check form-switch"> 18485 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.settings.use_push_to_talk ? 'checked' : ''"/> 18486 </div> 18487 </button> 18488 <button class="btn border-transparent d-flex align-items-center gap-2" t-on-click="onClickVoiceSettings"> 18489 <i class="fa fa-fw fa-gear"/><span>Voice Settings</span> 18490 </button> 18491 </div> 18492 </t> 18493 18494`); 18495registerTemplateExtension("mail.Composer", `/mail/static/src/discuss/typing/common/composer_patch.xml`, `<t t-inherit="mail.Composer" t-inherit-mode="extension" xml:space="preserve"> 18496 <xpath expr="//*[hasclass('o-mail-Composer-coreHeader')]" position="before"> 18497 <div t-if="thread?.model === 'discuss.channel' and !compact and !env.inMeetingView" class="o-discuss-Typing d-flex position-absolute top-0 w-100 bg-100 pe-none o-pt-0_5 pe-2 z-1"> 18498 <Typing t-if="thread.hasOtherMembersTyping" channel="thread" size="'medium'"/> 18499 </div> 18500 </xpath> 18501 </t> 18502`); 18503registerTemplateExtension("mail.ThreadIcon", `/mail/static/src/discuss/typing/common/thread_icon_patch.xml`, `<t t-inherit="mail.ThreadIcon" t-inherit-mode="extension" xml:space="preserve"> 18504 <xpath expr="//t[@name='chat']" position="replace"> 18505 <div t-if="props.thread.hasOtherMembersTyping" class="bg-inherit rounded-pill" style="padding: 1px;"> 18506 <div class="bg-success rounded-pill" style="padding: 3px;"> 18507 <Typing member="props.member" channel="props.thread" size="props.size" displayText="false"/> 18508 </div> 18509 </div> 18510 <t t-else="">$0</t> 18511 </xpath> 18512 </t> 18513`); 18514registerTemplate("discuss.Typing", `/mail/static/src/discuss/typing/common/typing.xml`, `<t t-name="discuss.Typing" xml:space="preserve"> 18515 <t t-if="props.member ? props.member.isTyping : props.channel.hasOtherMembersTyping"> 18516 <div class="o-discuss-Typing-icon d-flex align-items-center bg-inherit" t-attf-class="{{ className }}" t-att-title="text"> 18517 <span class="o-discuss-Typing-dot d-flex flex-shrink-0 rounded-pill" t-att-class="{ 'o-sizeMedium': ['medium', 'md'].includes(props.size), 'o-sizeSmall': ['small', 'sm'].includes(props.size), }"/> 18518 <span class="flex-grow-1 flex-shrink-0"/> 18519 <span class="o-discuss-Typing-dot o-discuss-Typing-dot2 d-flex flex-shrink-0 rounded-pill" t-att-class="{ 'o-sizeMedium': ['medium', 'md'].includes(props.size), 'o-sizeSmall': ['small', 'sm'].includes(props.size), }"/> 18520 <span class="flex-grow-1 flex-shrink-0"/> 18521 <span class="o-discuss-Typing-dot o-discuss-Typing-dot3 d-flex flex-shrink-0 rounded-pill" t-att-class="{ 'o-sizeMedium': ['medium', 'md'].includes(props.size), 'o-sizeSmall': ['small', 'sm'].includes(props.size), }"/> 18522 </div> 18523 <t t-if="props.displayText">
18524 <span class="ms-1"/> 18525 <span class="text-truncate smaller text-muted" t-out="text"/> 18526 </t> 18527 </t> 18528 </t> 18529 18530`); 18531registerTemplateExtension("discuss.ChannelMemberList", `/im_livechat/static/src/core/common/channel_member_list_patch.xml`, `<t t-name="im_livechat.ChannelMemberList" t-inherit="discuss.ChannelMemberList" t-inherit-mode="extension" xml:space="preserve"> 18532 <xpath expr="//button[@name='inviteButton']" position="attributes"> 18533 <attribute name="t-if">!props.thread.livechat_end_dt</attribute> 18534 </xpath> 18535 </t> 18536`); 18537registerTemplateExtension("mail.ChatWindow", `/im_livechat/static/src/core/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18538 <xpath expr="//*[@name='thread content']" position="replace"> 18539 <t>$0</t> 18540 <t t-if="props.chatWindow.livechatStep === CW_LIVECHAT_STEP.CONFIRM_CLOSE"> 18541 <CloseConfirmation onCloseConfirmationDialog.bind="onCloseConfirmationDialog" onClickLeaveConversation.bind="close"/> 18542 </t> 18543 </xpath> 18544 <xpath expr="//Composer" position="replace"> 18545 <div t-if="thread?.composerDisabled" class="bg-200 py-1 text-center d-flex fst-italic fw-bold text-muted" t-ref="composerDisabledContainer"> 18546 <span t-if="!showGiveFeedbackBtn" class="flex-grow-1"/> 18547 <span t-esc="thread.composerDisabledText"/> 18548 <span class="flex-grow-1"/> 18549 </div> 18550 <t t-else="">$0</t> 18551 </xpath> 18552 </t> 18553`); 18554registerTemplate("im_livechat.CloseConfirmation", `/im_livechat/static/src/core/common/close_confirmation.xml`, `<t t-name="im_livechat.CloseConfirmation" xml:space="preserve"> 18555 <div class="o-livechat-CloseConfirmation position-absolute w-100 h-100 d-flex justify-content-center align-items-center" t-on-click.stop="() => this.props.onCloseConfirmationDialog()"> 18556 <div class="o-livechat-CloseConfirmation-dialog rounded bg-view bg-opacity-100 p-3 m-3 d-flex flex-column position-relative" t-ref="dialog"> 18557 <div class="position-absolute top-0 end-0 p-1 o-xsmaller"> 18558 <button class="o-livechat-CloseConfirmation-close btn-close" t-on-click.stop="() => this.props.onCloseConfirmationDialog()"/> 18559 </div> 18560 <span class="pt-2 pb-3">Leaving will end the live chat. Do you want to proceed?</span> 18561 <button class="o-livechat-CloseConfirmation-leave btn btn-danger p-2 gap-1" t-on-keydown.stop.prevent="onKeydown" t-on-click.stop="() => this.props.onClickLeaveConversation()" t-ref="confirm"><i class="fa fa-fw fa-sign-out"/>Yes, leave conversation</button> 18562 </div> 18563 </div> 18564 </t> 18565`); 18566registerTemplate("im_livechat.LivechatCommandDialog", `/im_livechat/static/src/core/common/livechat_command_dialog.xml`, `<t t-name="im_livechat.LivechatCommandDialog" xml:space="preserve"> 18567 <ActionPanel title="props.title" icon="props.icon" resizable="false"> 18568 <div class="input-group my-2 shadow-sm"> 18569 <div class="o-livechat-LivechatCommandDialog-form form-control bg-view p-0" aria-autocomplete="list"> 18570 <input type="text" class="border-0 h-100 rounded px-2" accesskey="Q" t-att-placeholder="props.placeholderText" t-on-keydown="onKeydown" t-ref="autofocus" t-model="state.inputText"/> 18571 </div> 18572 <button class="btn btn-primary" t-on-click="executeCommand" t-att-disabled="!state.inputText" t-out="props.title"/> 18573 </div> 18574 </ActionPanel> 18575 </t> 18576`); 18577registerTemplateExtension("mail.Thread", `/im_livechat/static/src/core/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 18578 <xpath expr="//div[hasclass('o-mail-Thread')]" position="before"> 18579 <div t-if="showVisitorDisconnected" class="o-livechat-VisitorDisconnected bg-secondary py-1 px-3 fw-bold smaller shadow-sm border border-secondary" t-out="disconnectedText"/> 18580 </xpath> 18581 </t> 18582`); 18583registerTemplate("im_livechat.TranscriptSender", `/im_livechat/static/src/core/common/transcript_sender.xml`, `<t t-name="im_livechat.TranscriptSender" xml:space="preserve"> 18584 <div class="o-livechat-TranscriptSender"> 18585 <div class="input-group"> 18586 <input t-ref="input" t-on-keydown="onKeydown" t-model="state.email" t-att-disabled="isInputDisabled" type="text" class="form-control" t-att-class="{'bg-view': !isInputDisabled}" placeholder="[email protected]"/> 18587 <button class="btn btn-primary" type="button" data-action="sendTranscript" t-att-disabled="isButtonDisabled" t-on-click="onClickSend"> 18588 <i class="fa" t-att-class="{ 'fa-circle-o-notch fa-spin': state.status === STATUS.SENDING, 'fa-check': state.status === STATUS.SENT, 'fa-paper-plane': state.status === STATUS.IDLE, 'fa-repeat': state.status === STATUS.FAILED, }"/> 18589 </button> 18590 </div> 18591 <div class="form-text ms-1"> 18592 <t t-if="state.status === STATUS.SENT">The conversation was sent.</t> 18593 <t t-elif="state.status === STATUS.FAILED">An error occurred. Please try again.</t> 18594 </div> 18595 </div> 18596 </t> 18597`); 18598registerTemplateExtension("mail.ChatHub", `/im_livechat/static/src/embed/common/chat_hub_patch.xml`, `<t t-inherit="mail.ChatHub" t-inherit-mode="extension" xml:space="preserve"> 18599 <xpath expr="//*[hasclass('o-mail-ChatHub')]" position="attributes"> 18600 <attribute name="part">ChatHub</attribute> 18601 </xpath> 18602 <xpath expr="//*[hasclass('o-mail-ChatHub-extraActions')]" position="inside"> 18603 <LivechatButton/> 18604 </xpath> 18605 </t> 18606`); 18607registerTemplateExtension("mail.ChatWindow", `/im_livechat/static/src/embed/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18608 <xpath expr="//*[@name='thread content']" position="replace"> 18609 <FeedbackPanel t-if="props.chatWindow.livechatStep === CW_LIVECHAT_STEP.FEEDBACK" onClickClose
18609="() => this.close()" onClickNewSession="() => this.onClickNewSession()" thread="thread"/> 18610 <t t-else=""> 18611 <t>$0</t> 18612 </t> 18613 </xpath> 18614 <xpath expr="//*[@t-ref='needactionCounter']" position="replace"> 18615 <t t-if="!thread?.chatbot">$0</t> 18616 </xpath> 18617 <xpath expr="//*[hasclass('o-mail-ChatWindow-header')]" position="attributes"> 18618 <attribute name="t-attf-style" add="color: {{ livechatService.options.title_color }}; --o-mail-livechat-btn-color: {{ livechatService.options.title_color }}; background-color: {{ livechatService.options.header_background_color }} !important;" separator=" "/> 18619 </xpath> 18620 <xpath expr="//*[@t-ref='composerDisabledContainer']" position="inside"> 18621 <button t-if="showGiveFeedbackBtn" class="btn btn-link p-0" title="Give your feedback" t-on-click="() => this.onClickFeedback()">Continue</button> 18622 </xpath> 18623 <xpath expr="//*[@t-ref='composerDisabledContainer']" position="attributes"> 18624 <attribute name="t-attf-class" add="{{ showGiveFeedbackBtn ? 'px-2' : '' }}" separator=" "/> 18625 </xpath> 18626 </t> 18627`); 18628registerTemplate("im_livechat.FeedbackPanel", `/im_livechat/static/src/embed/common/feedback_panel/feedback_panel.xml`, `<t t-name="im_livechat.FeedbackPanel" xml:space="preserve"> 18629<div class="d-flex flex-column bg-view flex-grow-1 p-3"> 18630 <div class="p-2"> 18631 <div class="mb-5"> 18632 <t t-if="state.step === STEP.RATING"> 18633 <p class="text-center fs-6 mb-4">Did we correctly answer your question?</p> 18634 <div class="d-flex justify-content-center"> 18635 <img role="button" class="mx-3 opacity-50 opacity-100-hover" t-att-class="{ 'opacity-100': state.rating === RATING.GOOD }" t-att-src="url(\`/rating/static/src/img/rating_\${RATING.GOOD}.png\`)" t-att-alt="RATING.GOOD" t-on-click="() => this.select(RATING.GOOD)"/> 18636 <img role="button" class="mx-3 opacity-50 opacity-100-hover" t-att-class="{ 'opacity-100': state.rating === RATING.OK }" t-att-src="url(\`/rating/static/src/img/rating_\${RATING.OK}.png\`)" t-att-alt="RATING.OK" t-on-click="() => this.select(RATING.OK)"/> 18637 <img role="button" class="mx-3 opacity-50 opacity-100-hover" t-att-class="{ 'opacity-100': state.rating === RATING.BAD }" t-att-src="url(\`/rating/static/src/img/rating_\${RATING.BAD}.png\`)" t-att-alt="RATING.BAD" t-on-click="() => this.select(RATING.BAD)"/> 18638 </div> 18639 </t> 18640 <t t-else=""> 18641 <p class="text-center fs-5 fw-bold mb-4">Thank you for your feedback</p> 18642 </t> 18643 </div> 18644 <div t-if="state.rating and state.step === STEP.RATING" class="d-flex flex-column mb-5"> 18645 <textarea t-model="state.feedback" class="form-control my-2" placeholder="Explain your note"/> 18646 <button class="btn btn-primary align-self-end" t-on-click="onClickSendFeedback">Send</button> 18647 </div> 18648 <label class="mb-5 w-100" t-if="store.self_partner?.main_user_id?.share === false"> 18649 Receive a copy of this conversation 18650 <TranscriptSender thread="props.thread" disableOnSend="true"/> 18651 </label> 18652 <div class="d-flex gap-2 justify-content-center"> 18653 <button class="btn btn-outline-secondary" t-on-click="props.onClickClose">Close</button> 18654 <button t-if="allowNewSession" class="btn btn-outline-secondary" t-on-click="props.onClickNewSession">New Session</button> 18655 <a t-if="store.can_download_transcript" class="btn btn-outline-secondary" title="Download a copy of this conversation" target="_blank" t-att-href="props.thread.transcriptUrl"><i class="fa fa-download"/></a> 18656 </div> 18657 </div> 18658</div> 18659</t> 18660`); 18661registerTemplate("im_livechat.LivechatButton", `/im_livechat/static/src/embed/common/livechat_button.xml`, `<t t-name="im_livechat.LivechatButton" xml:space="preserve"> 18662 <button part="openChatButton" t-if="isShown" class="btn o-livechat-LivechatButton p-3 d-flex justify-content-center align-items-center shadow rounded-circle " t-attf-style="color: {{livechatService.options.button_text_color}}; background-color: {{livechatService.options.button_background_color}};" t-ref="button" t-on-click="onClick" title="Drag to Move"> 18663 <i class="fa fa-commenting" style="font-size: 22px;"/> 18664 <div t-if="store.livechat_rule?.action === 'display_button_and_text'" class="o-livechat-LivechatButton-notification text-nowrap position-absolute bg-100 py-2 px-3 rounded" style="max-width: 75vw;" t-att-class="{'o-livechat-LivechatButton-animate': state.animateNotification}"> 18665 <p class="m-0 text-dark text-truncate" t-esc="livechatService.options.button_text"/> 18666 </div> 18667 </button> 18668</t> 18669 18670`); 18671registerTemplateExtension("mail.Message", `/im_livechat/static/src/embed/common/message_patch.xml`, `<t t-inherit="mail.Message" t-inherit-mode="extension" xml:space="preserve"> 18672 <xpath expr="//*[@t-ref='messageContent']" position="replace"> 18673 <div t-if="props.isTypingMessage"> 18674 <img height="30" t-att-src="url('/im_livechat/static/src/img/chatbot_is_typing.gif')"/> 18675 </div> 18676 <t t-else="">$0</t> 18677 </xpath> 18678 <xpath expr="//*[hasclass('o-mail-Message-textContent')]" position="after"> 18679 <ul class="p-0 m-0" t-if="props.message.chatbotStep?.answer_ids.length and !props.message.chatbotStep.selectedAnswer"> 18680 <li class="list-unstyled" t-foreach="props.message.chatbotStep?.answer_ids" t-as="answer" t-key="answer.id"> 18681 <button t-esc="answer.name" t-att-disabled="props.message.disableChatbotAnswers" t-on-click="() => this.answerChatbot(answer)" class="btn btn-outline-primary w-100 mt-2 py-2"/> 18682 </li> 18683 </ul> 18684 </xpath> 18685 </t> 18686`); 18687registerTemplateExtension("mail.NotificationMessage", `/im_livechat/static/src/embed/common/notification_message_patch.xml`, `<t t-inherit="mail.NotificationMessage" t-inherit-mode="extension" xml:space="preserve"> 18688 <xpath expr="//*[hasclass('o-mail-NotificationMessage')]" position="attributes"> 18689 <attribute name="t-attf-class" add="{{ props.thread.channel_type === 'livechat' ? 'o-livechat-NoPinMenu' : '' }}" separator=" "/> 18690 </xpath> 18691</t>`); 18692registerTemplateExtension("mail.Thread", `/im_livechat/static/src/embed/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 18693 <xpath expr="//*[@name='content']" position="before"> 18694 <div t-if="props.thread?.livechatWelcomeMessage" class="bg-100 py-3" data-name="LivechatWelcomeMessage"> 18695 <Message message="props.thread.livechatWelcomeMessage" hasActions="false" thread="props.thread"/> 18696 </div> 18697 </xpath> 18698 <xpath expr="(//div[hasclass('o-mail-Thread')])" position="inside"> 18699 <Message t-if="props.thread.chatbot?.typingMessage" message="props.thread.chatbot.typingMessage" hasActions="false" isInChatWindow="env.inChatWindow" isTypingMessage="true" thread="props.thread"/> 18700 </xpath> 18701 <xpath expr="//*[hasclass('o-mail-Thread-empty')]" position="replace"> 18702 <t t-if="props.thread.channel_type !== 'livechat'">$0</t> 18703 </xpath> 18704 <xpath expr="//*[hasclass('o-mail-Thread-newMessage')]" position="replace"> 18705 <t t-if="!props.thread.chatbot">$0</t> 18706 </xpath> 18707 </t> 18708`); 18709registerTemplateExtension("mail.Thread", `/ai_website_livechat/static/src/discuss/core/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 18710 <xpath expr="//div[@data-name='LivechatWelcomeMessage']" position="replace"> 18711 <t t-if="props.thread?.livechatWelcomeMessage and !props.thread?.messages.length"> 18712 <t>$0</t> 18713 </t> 18714 </xpath> 18715 </t> 18716`); 18717registerTemplateExtension("mail.ChatWindow", `/ai_livechat/static/src/discuss/core/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18718 <xpath expr="//Composer" position="before">
18719 <div t-if="showForwardOperatorButton" class="m-3"> 18720 <button class="btn btn-primary" t-on-click="forwardOperator">Ask a Human</button> 18721 </div> 18722 </xpath> 18723 </t> 18724`); 18725 });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.