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/* /saas_trial/static/src/owl3_compatibility_layer.js */ 1451(function(){const owl=globalThis.owl;const owl_version_major=parseInt(owl.__info__.version.split(".")[0]);if(owl_version_major<=2){const customDirectives={ref:(node,value)=>{node.setAttribute("t-ref",value);},model:(node,value,modifiers)=>{let attribute="t-model";for(const modifier of modifiers){attribute+=`.${modifier}`;} 1452node.setAttribute(attribute,value);},slot:(node,value)=>{node.setAttribute("t-slot",value);}};class App extends owl.App{constructor(Root,config={}){super(Root,{...config,customDirectives:{...customDirectives,...config.customDirectives,},});}} 1453owl.App=App;} 1454else if(owl_version_major>=3){const customDirectives={model:(node,value)=>{node.setAttribute("t-model.proxy",value);},slot:(node,value)=>{node.setAttribute("t-call-slot",value);},};if(owl.useRef===undefined){customDirectives['ref']=(node,value)=>{node.removeAttribute('t-custom-ref');};} 1455class App extends owl.App{constructor(config){super({...config,customDirectives:{...customDirectives,...config.customDirectives,},});}} 1456owl.App=App;owl.useState=function useState(data){return owl.proxy(data);};}})();; 1457 1458/* /web/static/lib/owl/odoo_module.js */ 1459odoo.define("@odoo/owl",[],function(){"use strict";return owl;});; 1460 1461/* /web/static/src/env.js */ 1462odoo.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!");},};} 1463const 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;
1463__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;} 1464if(toStart.size){const namedService=Object.assign(Object.create(service),{name});toStart.set(name,namedService);}else{await _startServices(env,toStart);}});await _startServices(env,toStart);} 1465async function _startServices(env,toStart){if(startServicesPromise){return startServicesPromise.then(()=>_startServices(env,toStart));} 1466const 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);}} 1467async function start(){let service=null;const proms=[];while((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;} 1468const value=service.start(env,dependencies);if("async"in service){SERVICES_METADATA[name]=service.async;} 1469proms.push(Promise.resolve(value).then((val)=>{services[name]=val||null;}));} 1470await Promise.all(proms);if(proms.length){return start();}} 1471startServicesPromise=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);}}} 1472const depNames=[...missingDeps].join(", ");throw new Error(`Some services could not be started: ${[ 1473 ...toStart.keys(), 1474 ]}. Missing dependencies: ${depNames}`);} 1475function findNext(){for(const s of toStart.values()){if(s.dependencies){if(s.dependencies.every((d)=>d in services)){return s;}}else{return s;}} 1476return null;}} 1477const customDirectives=__exports.customDirectives={click:(node,value,modifiers)=>{let mods="";if(modifiers.includes("synthetic")){mods+=".synthetic";} 1478if(modifiers.includes("capture")){mods+=".capture";} 1479const handlerFunction=`(ev) => __globals__.click(ev, (${value}).bind(this), '${JSON.stringify( 1480 modifiers 1481 )}')`;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();} 1482if(modifier==="prevent"){ev.preventDefault();}} 1483const 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);} 1484const 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};} 1485return app;} 1486return __exports;});; 1487 1488/* /web/static/src/session.js */ 1489odoo.define('@web/session',[],function(require){'use strict';let __exports={};const session=__exports.session=odoo.__session_info__||{};delete odoo.__session_info__;return __exports;});; 1490 1491/* /web/static/src/core/action_swiper/action_swiper.js */ 1492odoo.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)=>
1492e.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(()=>{if(this.targetContainer.el){this.state.width=this.targetContainer.el.getBoundingClientRect().width;} 1493if(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);});} 1494get localizedProps(){return{onLeftSwipe:localization.direction==="rtl"?this.props.onRightSwipe:this.props.onLeftSwipe,onRightSwipe:localization.direction==="rtl"?this.props.onLeftSwipe:this.props.onRightSwipe,};} 1495_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="";}}} 1496_onTouchMoveSwipe(ev){if(this.state.isSwiping){if(this.props.swipeInvalid&&this.props.swipeInvalid()){this.state.isSwiping=false;return;} 1497const{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();} 1498if(!this.isScrollValidated&&this.scrollables&&!isScrollSwipable(this.scrollables)[this.swipedDistance>0?"left":"right"]){return this._reset();} 1499this.isScrollValidated=true;if(this.props.animationOnMove){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;}}} 1500_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;} 1501this.state.isSwiping=true;this.isScrollValidated=false;this.startX=ev.touches[0].clientX;} 1502_reset(){Object.assign(this.state,{...this.defaultState});this.scrollables=undefined;this.startX=undefined;this.swipedDistance=0;this.isScrollValidated=false;} 1503handleSwipe(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());}}} 1504return __exports;});; 1505 1506/* /web/static/src/core/anchor_scroll_prevention.js */ 1507odoo.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;});; 1508 1509/* /web/static/src/core/assets.js */ 1510odoo.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;} 1511function getAssetCache(targetDoc){if(!assetCacheByDocument.has(targetDoc)){assetCacheByDocument.set(targetDoc,new Map());} 1512return assetCacheByDocument.get(targetDoc);} 1513__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());} 1514for(const link of targetDoc.head.querySelectorAll("link[rel=stylesheet][href]")){cacheMap.set(link.getAttribute("href"),Promise.resolve());}} 1515whenReady(()=>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();});};
1515__exports.getBundle=getBundle;function getBundle(){return assets.getBundle(...arguments);} 1516__exports.loadBundle=loadBundle;function loadBundle(){return assets.loadBundle(...arguments);} 1517__exports.loadJS=loadJS;function loadJS(){return assets.loadJS(...arguments);} 1518__exports.loadCSS=loadCSS;function loadCSS(){return assets.loadCSS(...arguments);} 1519const AssetsLoadingError=__exports.AssetsLoadingError=class AssetsLoadingError extends Error{} 1520const 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);});} 1521get componentProps(){return typeof this.props.props==="function"?this.props.props():this.props.props;}} 1522const assets=__exports.assets={retries:{count:3,delay:5000,extraDelay:2500,},getBundle(bundleName){const cacheMap=getGlobalBundleCache();if(cacheMap.has(bundleName)){return cacheMap.get(bundleName);} 1523const url=new URL(`/web/bundle/${bundleName}`,location.origin);for(const[key,value]of Object.entries(session.bundle_params||{})){url.searchParams.set(key,value);} 1524const 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);}}} 1525return{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( 1526 bundleName 1527 )} as ${typeof bundleName}`);} 1528return getBundle(bundleName).then(({cssLibs,jsLibs})=>{const promises=[];if(css&&cssLibs){promises.push(...cssLibs.map((url)=>assets.loadCSS(url,{targetDoc})));} 1529if(js&&jsLibs){promises.push(...jsLibs.map((url)=>assets.loadJS(url,{targetDoc})));} 1530return Promise.all(promises);});},loadCSS(url,{retryCount=0,targetDoc=document}={}){const cacheMap=getAssetCache(targetDoc);if(cacheMap.has(url)){return cacheMap.get(url);} 1531const 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);} 1532const scriptEl=targetDoc.createElement("script");scriptEl.setAttribute("src",url);scriptEl.type=url.includes("web/static/lib/pdfjs/")?"module":"text/javascript";
1532const 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;});; 1533 1534/* /web/static/src/core/autocomplete/autocomplete.js */ 1535odoo.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;} 1536setup(){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"});} 1537this.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);}} 1538get targetDropdown(){return this.inputRef.el;} 1539get activeSourceOptionId(){if(!this.isOpened||!this.state.activeSourceOption){return undefined;} 1540const[sourceIndex,optionIndex]=this.state.activeSourceOption;const source=this.sources[sourceIndex];return`${this.props.id || "autocomplete"}_${sourceIndex}_${ 1541 source.isLoading ? "loading" : optionIndex 1542 }`;} 1543get dropdownOptions(){return{position:"bottom-start",...this.props.menuPositionOptions,};} 1544get isOpened(){return this.state.open;} 1545get hasOptions(){for(const source of this.sources){if(source.isLoading||source.options.length){return true;}} 1546return false;} 1547get activeOption(){if(!this.state.activeSourceOption){return null;} 1548const[sourceIndex,optionIndex]=this.state.activeSourceOption;return this.sources[sourceIndex].options[optionIndex];} 1549open(useInput=false){this.state.open=true;return this.loadSources(useInput);} 1550close(){this.state.open=false;this.state.activeSourceOption=null;this.mouseSelectionActive=false;} 1551discardPendingInput(){this.debouncedProcessInput.cancel();this.pendingPromise?.resolve();if(this.loadingPromise===this.pendingPromise){this.loadingPromise=null;} 1552this.pendingPromise=null;} 1553cancel(){if(this.inputRef.el.value.length){if(this.props.autoSelect){this.inputRef.el.value=this.props.value;this.props.onCancel();}} 1554this.close();} 1555async 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));}} 1556await Promise.all(proms);this.navigate(0);this.scroll();} 1557get displayOptions(){return!this.props.dropdown||(this.isOpened&&this.hasOptions);} 1558loadOptions(options,request){if(typeof options==="function"){return options(request);}else{return options;}} 1559makeOption(option){return{cssClass:"",data:{},...option,id:++this.nextOptionId,unselectable:!option.onSelect,};} 1560makeSource(source){return{id:++this.nextSourceId,options:[],isLoading:false,placeholder:source.placeholder,optionSlot:source.optionSlot,};} 1561isActiveSourceOption([sourceIndex,optionIndex]){return(this.state.activeSourceOption&&this.state.activeSourceOption[0]===sourceIndex&&this.state.activeSourceOption[1]===optionIndex);} 1562selectOption(option){this.inEdition=false;this.discardPendingInput();if(option.unselectable){return;} 1563if(this.props.resetOnSelect){this.inputRef.el.value="";} 1564this.isOptionSelected=true;this.forceValFromProp=true;option.onSelect();this.close();} 1565navigate(direction){let step=Math.sign(direction);if(!step){this.state.activeSourceOption=null;step=1;}else{this.state.navigationRev++;}
1566do{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];} 1567if(source){optionIndex=step<0?source.options.length-1:0;}} 1568this.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];} 1569if(source){const optionIndex=step<0?source.options.length-1:0;if(optionIndex<source.options.length){this.state.activeSourceOption=[sourceIndex,optionIndex];}}}}while(this.activeOption?.unselectable);} 1570onInputBlur(){if(this.ignoreBlur){this.ignoreBlur=false;return;} 1571if(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);}} 1572this.props.onBlur({inputValue:this.inputRef.el.value,});this.inEdition=false;this.isOptionSelected=false;} 1573onInputClick(){if(!this.isOpened&&this.props.searchOnInputClick){this.open(this.inputRef.el.value.trim()!==this.props.value.trim());}else{this.close();}} 1574onInputChange(ev){if(this.ignoreBlur){ev.stopImmediatePropagation();} 1575this.props.onChange({inputValue:this.inputRef.el.value,isOptionSelected:this.ignoreBlur,});} 1576async onInput(){this.inEdition=true;this.pendingPromise=this.pendingPromise||new Deferred();this.loadingPromise=this.pendingPromise;this.debouncedProcessInput();} 1577onInputFocus(ev){this.inputRef.el.setSelectionRange(0,this.inputRef.el.value.length);this.props.onFocus(ev);} 1578get autoCompleteRootClass(){let classList="";if(this.props.class){classList+=this.props.class;} 1579if(this.props.dropdown){classList+=" dropdown";} 1580return classList;} 1581get ulDropdownClass(){return mergeClasses(this.props.menuCssClass,{"dropdown-menu ui-autocomplete":this.props.dropdown,"list-group":!this.props.dropdown,});} 1582async onInputKeydown(ev){const hotkey=getActiveHotkey(ev);const isSelectKey=hotkey==="enter"||hotkey==="tab";if(this.loadingPromise&&isSelectKey){if(hotkey==="enter"){ev.stopPropagation();ev.preventDefault();} 1583await this.loadingPromise;} 1584switch(hotkey){case"enter":if(!this.isOpened||!this.state.activeSourceOption){return;} 1585this.selectOption(this.activeOption);break;case"escape":if(!this.isOpened){return;} 1586this.cancel();break;case"tab":case"shift+tab":if(!this.isOpened){return;} 1587if(this.props.autoSelect&&this.state.activeSourceOption&&(this.state.navigationRev>0||this.inputRef.el.value.length>0)){this.selectOption(this.activeOption);} 1588this.close();return;case"arrowup":this.navigate(-1);if(!this.isOpened){this.open(true);} 1589this.scroll();break;case"arrowdown":this.navigate(+1);if(!this.isOpened){this.open(true);} 1590this.scroll();break;default:return;} 1591ev.stopPropagation();ev.preventDefault();} 1592onOptionMouseEnter(indices){if(!this.mouseSelectionActive){return;} 1593const[sourceIndex,optionIndex]=indices;if(this.sources[sourceIndex].options[optionIndex]?.unselectable){this.state.activeSourceOption=null;}else{this.state.activeSourceOption=indices;}} 1594onOptionMouseLeave(){this.state.activeSourceOption=null;} 1595onOptionClick(option){this.selectOption(option);this.inputRef.el.focus();} 1596onOptionPointerDown(option,ev){this.ignoreBlur=true;if(option.unselectable){ev.preventDefault();}} 1597externalClose(ev){if(this.isOpened&&!this.root.el.contains(ev.target)){this.cancel();}} 1598scroll(){if(!this.activeSourceOptionId){return;} 1599if(isScrollableY(this.listRef.el)){const element=this.listRef.el.querySelector(`#${this.activeSourceOptionId}`);if(element){scrollTo(element);}}}} 1600return __exports;});; 1601 1602/* /web/static/src/core/barcode/ZXingBarcodeDetector.js */ 1603odoo.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);} 1604async detect(video){if(!(video instanceof HTMLVideoElement)){throw new DOMException("imageDataFrom() requires an HTMLVideoElement","InvalidArgumentError");} 1605if(!isVideoElementReady(video)){throw new DOMException("HTMLVideoElement is not ready","InvalidStateError");} 1606const 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,};} 1607canvas.width=barcodeArea.width;
1607canvas.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[];} 1608throw err;}} 1609setCropArea(cropArea){this.cropArea=cropArea;}} 1610ZXingBarcodeDetector.getSupportedFormats=async()=>allSupportedFormats;return ZXingBarcodeDetector;} 1611const HAVE_NOTHING=0;const HAVE_METADATA=1;__exports.isVideoElementReady=isVideoElementReady;function isVideoElementReady(video){return![HAVE_NOTHING,HAVE_METADATA].includes(video.readyState);} 1612return __exports;});; 1613 1614/* /web/static/src/core/barcode/barcode_dialog.js */ 1615odoo.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"),});} 1616onResult(result){this.props.close();this.props.onResult(result);} 1617onError(error){this.state.barcodeScannerSupported=false;this.state.errorMessage=error.message;}} 1618__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;} 1619return __exports;});; 1620 1621/* /web/static/src/core/barcode/barcode_video_scanner.js */ 1622odoo.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);} 1623const 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;} 1624if(!this.videoPreviewRef.el){this.cleanStreamAndTimeout();const errorMessage=_t("Barcode Video Scanner could not be mounted properly.");this.props.onError(new Error(errorMessage));return;} 1625this.videoPreviewRef.el.srcObject=this.stream;const ready=await this.isVideoReady();if(!ready){return;} 1626if(this.videoPreviewRef.el.paused){await this.videoPreviewRef.el.play();} 1627const{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);} 1628this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);});onWillUnmount(()=>this.cleanStreamAndTimeout());} 1629cleanStreamAndTimeout(){clearTimeout(this.detectorTimeout);this.detectorTimeout=null;
1629if(this.stream){this.stream.getTracks().forEach((track)=>track.stop());this.stream=null;}} 1630isZXingBarcodeDetector(){return this.detector&&this.detector.__proto__.constructor.name==="ZXingBarcodeDetector";} 1631async isVideoReady(){while(!isVideoElementReady(this.videoPreviewRef.el)){await delay(10);if(status(this)==="destroyed"){return false;}} 1632this.state.isReady=true;if(this.props.onReady){this.props.onReady();} 1633return true;} 1634onResize(overlayInfo){this.overlayInfo=overlayInfo;if(this.isZXingBarcodeDetector()){this.detector.setCropArea(this.adaptValuesWithRatio(this.overlayInfo,true));}} 1635async detectCode(){let barcodeDetected=false;let codes=[];try{codes=await this.detector.detect(this.videoPreviewRef.el);}catch(err){this.props.onError(err);} 1636for(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;}} 1637barcodeDetected=true;this.barcodeDetected(code.rawValue);break;} 1638if(this.stream&&(!barcodeDetected||!this.props.delayBetweenScan)){this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);}} 1639barcodeDetected(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);} 1640this.props.onResult(barcode);} 1641adaptValuesWithRatio(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;}} 1642return newObject;} 1643addZoomSlider(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);}}} 1644__exports.isBarcodeScannerSupported=isBarcodeScannerSupported;function isBarcodeScannerSupported(){return Boolean(browser.navigator.mediaDevices&&browser.navigator.mediaDevices.getUserMedia);} 1645return __exports;});; 1646 1647/* /web/static/src/core/barcode/crop_overlay.js */ 1648odoo.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();} 1649setupCropRect(){if(!this.props.isReady){return;} 1650this.computeDefaultPoint();this.computeOverlayPosition();this.calculateAndSetTransparentRect();this.executeOnResizeCallback();} 1651boundPoint(pointValue,boundaryRect){return{x:clamp(pointValue.x,boundaryRect.left,boundaryRect.left+boundaryRect.width),y:clamp(pointValue.y,boundaryRect.top,boundaryRect.top+boundaryRect.height),};} 1652calculateAndSetTransparentRect(){const cropTransparentRect=this.getTransparentRec(this.relativePosition,this.boundaryOverlay);this.setCropValue(cropTransparentRect,this.relativePosition);} 1653computeOverlayPosition(){const cropOverlayElement=this.cropContainerRef.el.querySelector(".o_crop_overlay");this.boundaryOverlay=cropOverlayElement.getBoundingClientRect();} 1654executeOnResizeCallback(){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
1654parentRec.y,});} 1655computeDefaultPoint(){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,};}} 1656getTransparentRec(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,};} 1657setCropValue(point,iconPoint){if(!iconPoint){iconPoint=point;} 1658this.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`);} 1659pointerDown(event){if(event.target.matches("input")){return;} 1660event.preventDefault();if(event.target.matches(".o_crop_icon")){this.computeOverlayPosition();this.isMoving=true;}} 1661pointerMove(event){if(!this.isMoving){return;} 1662let eventPosition;if(event.touches&&event.touches.length){eventPosition=event.touches[0];}else{eventPosition=event;} 1663const{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);} 1664pointerUp(event){this.isMoving=false;this.executeOnResizeCallback();}} 1665return __exports;});; 1666 1667/* /web/static/src/core/bottom_sheet/bottom_sheet.js */ 1668odoo.define('@web/core/bottom_sheet/bottom_sheet',['@odoo/owl','@web/core/h
1668otkeys/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");});} 1669initializeSheet(){if(!this.containerRef.el||!this.scrollRailRef.el||!this.sheetRef.el){return;} 1670this.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,});}} 1671updateDimensions(){this.state.isSnappingEnabled=false;this.measureDimensions();this.applyDimensions();const scrollTop=this.scrollRailRef.el.scrollTop;this.updateProgressValue(scrollTop);} 1672measureDimensions(){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),};} 1673applyDimensions(){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`);} 1674positionSheet(){const scrollRail=this.scrollRailRef.el;const bodyContent=this.sheetBodyRef.el;const scrollValue=this.measurements.maxHeight;if(bodyContent){bodyContent.style.overflowY="auto";} 1675scrollRail.scrollTop=scrollValue||0;scrollRail.style.containerType="scroll-state size";} 1676setupEventHandlers(){const scrollRail=this.scrollRailRef.el;scrollRail.addEventListener("scroll",this.throttledOnScroll);} 1677onScroll(){if(!this.scrollRailRef.el){return;} 1678const scrollTop=this.scrollRailRef.el.scrollTop;this.updateProgressValue(scrollTop);if(scrollTop<this.measurements.dismissThreshold){this.slideOut();}} 1679updateProgressValue(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;}}
1680slideOut(){if(this.state.isDismissing){return;} 1681if(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,});} 1682this.state.isDismissing=true;this.state.isSnappingEnabled=false;} 1683close(){this.slideOut();} 1684back(){if(this.props.onBack){this.props.onBack();}else{this.slideOut();}}} 1685return __exports;});; 1686 1687/* /web/static/src/core/bottom_sheet/bottom_sheet_service.js */ 1688odoo.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");}} 1689const _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");} 1690return removeAndUpdateCount;};return{add};},};registry.category("services").add("bottom_sheet",popoverService);return __exports;});; 1691 1692/* /web/static/src/core/browser/browser.js */ 1693odoo.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();} 1694const 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"";},};} 1695return __exports;});; 1696 1697/* /web/static/src/core/browser/cookie.js */ 1698odoo.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}`);} 1699fullCookie=fullCookie.concat(["path=/",`max-age=${Math.floor(ttl)}`]);this._cookieMonster=fullCookie.join("; ");},delete(key){this.set(key,"kill",0);},};return __exports;});; 1700 1701/* /web/static/src/core/browser/feature_detection.js */ 1702odoo.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);} 1703__exports.isBrowserFirefox=isBrowserFirefox;function isBrowserFirefox(){return/Firefox/i.test(browser.navigator.userAgent);} 1704__exports.isBrowserMicrosoftEdge=isBrowserMicrosoftEdge;function isBrowserMicrosoftEdge(){return/Edg/i.test(browser.navigator.userAgent);} 1705__exports.isBrowserSafari=isBrowserSafari;function isBrowserSafari(){return!isBrowserChrome()&&browser.navigator.userAgent?.includes("Safari");} 1706__exports.isAndroid=isAndroid;function isAndroid(){return/Android/i.test(browser.navigator.userAgent);} 1707__exports.isIOS=isIOS;function isIOS(){let isIOSPlatform=false;if("platform"in browser.navigator){isIOSPlatform=browser.navigator.platform==="MacIntel";} 1708return(/(iPad|iPhone|iPod)/i.test(browser.navigator.userAgent)||(isIOSPlatform&&maxTouchPoints()>1));} 1709__exports.isOtherMobileOS=isOtherMobileOS;
1709function isOtherMobileOS(){return/(webOS|BlackBerry|Windows Phone)/i.test(browser.navigator.userAgent);} 1710__exports.isMacOS=isMacOS;function isMacOS(){return/Mac/i.test(browser.navigator.userAgent);} 1711__exports.isMobileOS=isMobileOS;function isMobileOS(){return isAndroid()||isIOS()||isOtherMobileOS();} 1712__exports.isIosApp=isIosApp;function isIosApp(){return/OdooMobile \(iOS\)/i.test(browser.navigator.userAgent);} 1713__exports.isAndroidApp=isAndroidApp;function isAndroidApp(){return/OdooMobile.+Android/i.test(browser.navigator.userAgent);} 1714__exports.isDisplayStandalone=isDisplayStandalone;function isDisplayStandalone(){return browser.matchMedia("(display-mode: standalone)").matches;} 1715__exports.hasTouch=hasTouch;function hasTouch(){return browser.ontouchstart!==undefined||browser.matchMedia("(pointer:coarse)").matches;} 1716__exports.maxTouchPoints=maxTouchPoints;function maxTouchPoints(){return browser.navigator.maxTouchPoints||1;} 1717__exports.isVirtualKeyboardSupported=isVirtualKeyboardSupported;function isVirtualKeyboardSupported(){return"virtualKeyboard"in browser.navigator;} 1718return __exports;});; 1719 1720/* /web/static/src/core/browser/router.js */ 1721odoo.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();} 1722function cast(value){return!value||isNaN(value)?value:Number(value);} 1723function 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);} 1724return result;} 1725function 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));} 1726return sanitizeSearch(nextState);} 1727function sanitize(obj,valueToRemove){return Object.fromEntries(Object.entries(obj).filter(([,v])=>v!==valueToRemove).map(([k,v])=>[k,cast(v)]));} 1728function sanitizeSearch(search){return sanitize(search);} 1729function sanitizeHash(hash){return sanitize(hash,"");} 1730__exports.parseHash=parseHash;function parseHash(hash){return hash&&hash!=="#"?parseString(hash.slice(1)):{};} 1731__exports.parseSearchQuery=parseSearchQuery;function parseSearchQuery(search){return search?parseString(search.slice(1)):{};} 1732function pathFromActionState(state){const path=[];const{action,model,active_id,resId}=state;if(active_id&&typeof active_id==="number"){path.push(active_id);} 1733if(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}`);}} 1734if(resId&&(typeof resId==="number"||resId==="new")){path.push(resId);} 1735return path.join("/");} 1736__exports.startUrl=startUrl;function startUrl(){return isScopedApp()?"scoped_app":"odoo";} 1737function 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;} 1738if(prevAction===currentAction&&!prevResId&¤tActiveId===prevActiveId){delete currentAct.action;delete currentAct.active_id;}}
1739const pathSegments=actionStack.map(pathFromActionState).filter(Boolean);if(pathSegments.length){path=`/${pathSegments.join("/")}`;}} 1740if(state.active_id&&typeof state.active_id!=="number"){pathKeysToOmit.splice(pathKeysToOmit.indexOf("active_id"),1);} 1741if(state.resId&&typeof state.resId!=="number"&&state.resId!=="new"){pathKeysToOmit.splice(pathKeysToOmit.indexOf("resId"),1);} 1742const search=objectToUrlEncodedString(omit(state,...pathKeysToOmit));const start_url=startUrl();return`/${start_url}${path}${search ? `?${search}` : ""}`;} 1743function 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;} 1744Object.assign(state,sanitizedHash);const url=browser.location.origin+router.stateToUrl(state);urlObj.href=url;} 1745const[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);} 1746if(right==="new"){action.resId="new";}else if(isNumeric(right)){action.resId=parseInt(right);} 1747if(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;} 1748if(action.resId&&action.action){actions.push(omit(action,"resId"));} 1749if(action.action||action.resId||i===splitPath.length-1){actions.push(action);}} 1750const activeAction=actions.at(-1);if(activeAction){Object.assign(state,activeAction);state.actionStack=actions;} 1751if(prefix==="scoped_app"&&!isDisplayStandalone()){const url=browser.location.origin+router.stateToUrl(state);urlObj.href=url;}} 1752return state;} 1753let 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);} 1754pushTimeout=null;pushArgs={replace:false,reload:false,state:{},};_lockedKeys=new Set(["debug","lang"]);_hiddenKeysFromUrl=new Set([...PATH_KEYS,"actionStack"]);} 1755browser.addEventListener("popstate",(ev)=>{browser.clearTimeout(pushTimeout);if(!ev.state){browser.history.replaceState({nextState:state},"",browser.location.href);return;} 1756state=ev.state?.nextState||router.urlToState(new URL(browser.location));if(!ev.state?.skipRouteChange&&!router.skipLoad){routerBus.trigger("ROUTE_CHANGE");} 1757router.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;} 1758const a=ev.target.closest("a");const href=a?.getAttribute("href");if(href&&!href.startsWith("#")){let url;try{url=new URL(a.href);}catch{return;} 1759if(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);} 1760new 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);} 1761state=nextState;if(pushArgs.reload){browser.location.reload();}} 1762return 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();});}};} 1763const 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={};
1763Object.entries(obj).forEach(([k,v])=>{query[k]=v?String(v):v;});return query;} 1764return __exports;});; 1765 1766/* /web/static/src/core/checkbox/checkbox.js */ 1767odoo.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});} 1768onClick(ev){if(ev.composedPath().find((el)=>["INPUT","LABEL"].includes(el.tagName))){ev.stopPropagation();return;} 1769const input=this.rootRef.el.querySelector("input");input.focus();if(!this.props.disabled){ev.stopPropagation();input.checked=!input.checked;this.props.onChange(input.checked);}} 1770onChange(ev){if(!this.props.disabled){this.props.onChange(ev.target.checked);}}} 1771return __exports;});; 1772 1773/* /web/static/src/core/code_editor/code_editor.js */ 1774odoo.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;} 1775const 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;} 1776session.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;} 1777session.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);}});});}}} 1778return __exports;});; 1779 1780/* /web/static/src/core/color_picker/color_picker.js */ 1781odoo.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]);} 1782getDefaultTab(){if(this.props.enabledTabs.includes(this.props.state.defaultTab)){return this.props.state.defaultTab;} 1783return this.props.enabledTabs[0];} 1784get selectedColor(){return this.props.state.selectedColor;}
1785get isDarkTheme(){return cookie.get("color_scheme")==="dark";} 1786setTab(tab){this.state.activeTab=tab;this.setOperationCallbacks({onPreviewRevertCallback:()=>{}});this.applyColorResetPreview();} 1787processColorFromEvent(ev){const target=this.getTarget(ev);let color=target.dataset.color||"";if(color&&isColorCombination(color)){return color;} 1788if(color&&!isCSSColor(color)&&!isColorGradient(color)){color=this.props.colorPrefix+color;} 1789return color;} 1790setOperationCallbacks(cbs){if(this.props.setOperationCallbacks){this.props.setOperationCallbacks(cbs);} 1791if(cbs.onApplyCallback){this.onApplyCallback=cbs.onApplyCallback;} 1792if(cbs.onPreviewRevertCallback){this.onPreviewRevertCallback=cbs.onPreviewRevertCallback;} 1793if(cbs.getPreviewColor){this.getPreviewColor=cbs.getPreviewColor;}} 1794applyColor(color){this.state.currentCustomColor=color;this.props.applyColor(color);this.defaultColorSet=this.getDefaultColorSet();this.onApplyCallback();} 1795onColorApply(ev){if(!this.isColorButton(this.getTarget(ev))){return;} 1796const color=this.processColorFromEvent(ev);this.applyColor(color);this.props.close();} 1797applyColorResetPreview(){this.props.applyColorResetPreview();this.state.currentColorPreview=undefined;this.onPreviewRevertCallback();} 1798onColorPreview(ev){const color=ev.hex||ev.gradient||this.processColorFromEvent(ev);this.props.applyColorPreview(color);this.state.currentColorPreview=this.getPreviewColor();} 1799onColorHover(ev){if(!this.isColorButton(this.getTarget(ev))){return;} 1800this.onColorPreview(ev);} 1801onColorHoverOut(ev){if(!this.isColorButton(this.getTarget(ev))){return;} 1802this.applyColorResetPreview();} 1803getTarget(ev){const target=ev.target.closest(`[data-color]`);return this.root.el.contains(target)?target:ev.target;} 1804onColorFocusin(ev){if(this.focusedBtn===ev.target){this.focusedBtn=null;return;} 1805this.focusedBtn=ev.target;this.onColorHover(ev);if(document.activeElement!==ev.target){ev.target.focus();}} 1806onColorFocusout(ev){if(!ev.relatedTarget||!this.isColorButton(ev.relatedTarget)){return;} 1807const activeEl=document.activeElement;this.applyColorResetPreview();if(document.activeElement!==activeEl){ev.relatedTarget.focus();}} 1808getDefaultColorSet(){if(!this.props.state.selectedColor){return;} 1809let defaultColors=this.props.enabledTabs.includes("solid")?this.DEFAULT_THEME_COLOR_VARS:[];for(const grayscale of Object.values(this.grayscales)){defaultColors=defaultColors.concat(grayscale);} 1810const 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;}} 1811return false;} 1812colorPickerNavigation(ev){const{target,key}=ev;if(!target.classList.contains("o_color_button")){return;} 1813if(!["ArrowRight","ArrowLeft","ArrowUp","ArrowDown"].includes(key)){return;} 1814let 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];}}} 1815if(targetBtn&&targetBtn.classList.contains("o_color_button")){targetBtn.focus();}} 1816isColorButton(targetEl){return targetEl.tagName==="BUTTON"&&!targetEl.matches(".o_colorpicker_ignore");}} 1817__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();};} 1818const colorPicker=usePopover(ColorPicker,options);const root=useRef(refName);function onClick(){if(colorPicker.isOpen){colorPicker.close();}else{colorPicker.open(root.el,props);options.onOpen?.();}} 1819useEffect((el)=>{if(!el){return;} 1820el.addEventListener("click",onClick);return()=>{el.removeEventListener("click",onClick);};},()=>[root.el]);return colorPicker;} 1821function isColorCombination(color){return color.startsWith("o_cc");} 1822return __exports;});; 1823 1824/* /web/static/src/core/color_picker/custom_color_picker/custom_color_picker.js */ 1825odoo.define('@web/core/color_picker/custom_color_picker/custom_color_picker',['@web/core/h
1825otkeys/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;} 1826if(this.props.defaultColor.length<=7){const opacityHex=Math.round((this.props.defaultOpacity/100)*255).toString(16).padStart(2,"0");this.props.defaultColor+=opacityHex;} 1827this.colorComponents={};this.uniqueId=uniqueId("colorpicker");this.selectedHexValue="";this.shouldSetSelectedColor=false;this.lastFocusedSliderEl=undefined;if(!this.props.selectedColor){this.props.selectedColor=this.props.defaultColor;} 1828this.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});} 1829this.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);} 1830this.previewActive=true;this._updateUI();});onWillUpdateProps((newProps)=>{const newSelectedColor=newProps.selectedColor?newProps.selectedColor:newProps.defaultColor;if(normalizeCSSColor(newSelectedColor)!==this.colorComponents.cssColor){this.setSelectedColor(newSelectedColor);}});} 1831setSelectedColor(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();}} 1832getAllowedHotkeys(allowedKeys){return allowedKeys.flatMap((key)=>[key,`control+${key}`]);} 1833setLastFocusedSliderEl(el){this.lastFocusedSliderEl=el;document.activeElement.blur();} 1834get el(){return this.elRef.el;} 1835handleRangeKeydownValue(hotkey,value,{min=0,max=100,defaultStep=10,modifierStep=1,leap=20}={}){let step=defaultStep;if(hotkey.startsWith("control+")){step=modifierStep;} 1836const mainKey=hotkey.replace("control+","");if(mainKey==="pageup"||mainKey==="pagedown"){step=leap;} 1837if(["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;} 1838return clamp(value,min,max);} 1839selectColorOnEnter(hotkey){if(hotkey==="enter"&&this.shouldSetSelectedColor){this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;this._colorSelected();}} 1840_updateUI(){for(const[color,value]of Object.entries(this.colorComponents)){const input=this.el.querySelector(`.o_${color}_input`);if(input){input.value=value;}} 1841const 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%)`;}} 1842_updateHex(hex){const rgb=convertCSSColorToRgba(hex);if(!rgb){return;} 1843Object.assign(this.colorComponents,{hex:hex},rgb,convertRgbToHsl(rgb.red,rgb.green,rgb.blue));this._updateCssColor();} 1844_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;} 1845const hex=convertRgbaToCSSColor(r,g,b,a);if(!hex){return;} 1846Object.assign(this.colorComponents,{red:r,green:g,blue:b},a===undefined?{}:{opacity:a},{hex:hex},convertRgbToHsl(r,g,b));this._updateCssColor();} 1847_updateHsl(h,s,l){if(0.1<Math.abs(h-this.colorComponents.hue)){if(l<0.1||99.9<l){l=50;} 1848if(s<0.1){s=100;}} 1849let a=this.colorComponents.opacity;if(a<0.1&&l>0.1){a=this.props.defaultOpacity;} 1850const rgb=convertHslToRgb(h,s,l);if(!rgb){return;} 1851const 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();} 1852_updateOpacity(a){if(a<0||a>100){return;} 1853Object.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();} 1854_colorSelected(){this.props.onColorSelect(this.colorComponents);} 1855_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);}} 1856onKeydown(ev){if(ev.key==="Enter"){if(ev.target.tagName==="INPUT"){this.onChangeInputs(ev);} 1857ev.preventDefault();this.props.onInputEnter(ev);}} 1858onClick(ev){if(this.props.stopClickPropagation){ev.stopPropagation();} 1859ev.__isColorpickerClick=true;if(ev.target.dataset.colorMethod==="hex"&&!this.selectedHexValue){ev.target.select();this.selectedHexValue=ev.target.value;return;} 1860this.selectedHexValue="";} 1861onPointerUp(){if(this.pickerFlag||this.sliderFlag||this.opacitySliderFlag){this.shouldSetSelectedColor=true;this._updateCssColor();} 1862this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;if(this.lastFocusedSliderEl){this.lastFocusedSliderEl.focus();this.lastFocusedSliderEl=undefined;}}
1863onEscapeKeydown(ev){const hotkey=getActiveHotkey(ev);if(hotkey==="escape"){this.props.setOnCloseCallback?.(()=>{});}} 1864onPointerDownPicker(ev){this.pickerFlag=true;ev.preventDefault();this.onPointerMovePicker(ev);this.setLastFocusedSliderEl(this.colorPickerPointerRef.el);} 1865onPointerMovePicker(ev){if(!this.pickerFlag){return;} 1866const 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();} 1867onPickerKeydown(ev){const hotkey=getActiveHotkey(ev);this.selectColorOnEnter(hotkey);if(!this.getAllowedHotkeys(ARROW_KEYS).includes(hotkey)){return;} 1868let saturation=this.colorComponents.saturation;let lightness=this.colorComponents.lightness;let step=10;if(hotkey.startsWith("control+")){step=1;} 1869const 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;} 1870lightness=clamp(lightness,0,100);saturation=clamp(saturation,0,100);this._updateHsl(this.colorComponents.hue,saturation,lightness);this._updateUI();this.shouldSetSelectedColor=true;} 1871onPointerDownSlider(ev){this.sliderFlag=true;ev.preventDefault();this.onPointerMoveSlider(ev);this.setLastFocusedSliderEl(this.colorSliderPointerRef.el);} 1872onPointerMoveSlider(ev){if(!this.sliderFlag){return;} 1873const 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();} 1874onSliderKeydown(ev){const hotkey=getActiveHotkey(ev);this.selectColorOnEnter(hotkey);if(!this.getAllowedHotkeys(SLIDER_KEYS).includes(hotkey)){return;} 1875const 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;} 1876onPointerDownOpacitySlider(ev){this.opacitySliderFlag=true;ev.preventDefault();this.onPointerMoveOpacitySlider(ev);this.setLastFocusedSliderEl(this.opacitySliderPointerRef.el);} 1877onPointerMoveOpacitySlider(ev){if(!this.opacitySliderFlag||this.props.noTransparency){return;} 1878const 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();} 1879onOpacitySliderKeydown(ev){const hotkey=getActiveHotkey(ev);this.selectColorOnEnter(hotkey);if(!this.getAllowedHotkeys(SLIDER_KEYS).includes(hotkey)){return;} 1880const opacity=this.handleRangeKeydownValue(hotkey,this.colorComponents.opacity);this._updateOpacity(opacity);this._updateUI();this.shouldSetSelectedColor=true;} 1881onChangeInputs(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;} 1882this._updateUI();this._colorSelected();} 1883onHexColorInput(ev){const hexColorValue=ev.target.value.replaceAll("#","");if(hexColorValue.length===6||hexColorValue.length===8){this._updateHex(`#${hexColorValue}`);this._updateUI();this._colorSelected();}}} 1884return __exports;});; 1885 1886/* /web/static/src/core/color_picker/tabs/color_picker_custom_tab.js */ 1887odoo.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}
1887,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();} 1888isValidCustomColor(color){return color&&color.slice(7,9)!=="00"&&!isColorGradient(color);}} 1889registry.category("color_picker_tabs").add("web.custom",{id:"custom",name:_t("Custom"),component:ColorPickerCustomTab,});return __exports;});; 1890 1891/* /web/static/src/core/color_picker/tabs/color_picker_solid_tab.js */ 1892odoo.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},};} 1893registry.category("color_picker_tabs").add("web.solid",{id:"solid",name:_t("Solid"),component:ColorPickerSolidTab,});return __exports;});; 1894 1895/* /web/static/src/core/colorlist/colorlist.js */ 1896odoo.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);} 1897get colors(){return this.constructor.COLORS;} 1898onColorSelected(id){this.props.onColorSelected(id);if(!this.props.forceExpanded){this.state.isExpanded=false;}} 1899onOutsideClick(ev){if(this.colorlistRef.el.contains(ev.target)||this.props.forceExpanded){return;} 1900this.state.isExpanded=false;} 1901onToggle(ev){if(this.props.canToggle){ev.preventDefault();ev.stopPropagation();this.state.isExpanded=!this.state.isExpanded;this.colorlistRef.el.firstElementChild.focus();}}} 1902return __exports;});; 1903 1904/* /web/static/src/core/colors/colors.js */ 1905odoo.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;}} 1906__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";} 1907const colors=getColors(colorScheme,paletteName);return colors[index%colors.length];} 1908const 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)";} 1909const 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})`;} 1910__exports.getCustomColor=getCustomColor;function getCustomColor(colorScheme,brightModeColor,darkModeColor){if(darkModeColor===undefined){return brightModeColor;}else{return colorScheme==="dark"?darkModeColor:brightModeColor;}} 1911__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}`;} 1912__exports.darkenColor=darkenColor;
1912function 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}`;} 1913return __exports;});; 1914 1915/* /web/static/src/core/commands/command_category.js */ 1916odoo.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;});; 1917 1918/* /web/static/src/core/commands/command_hook.js */ 1919odoo.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),()=>[]);} 1920return __exports;});; 1921 1922/* /web/static/src/core/commands/command_palette.js */ 1923odoo.define('@web/core/commands/command_palette',['@web/core/dialog/dialog','@web/core/h
1923otkeys/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;};} 1924const 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},};} 1925const 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));} 1926this.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));} 1927get 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,});}} 1928return categories;} 1929async 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];}} 1930const{namespace,searchValue}=this.processSearchValue(config.searchValue||"");this.switchNamespace(namespace);this.state.searchValue=searchValue;await this.race.add(this.search(searchValue));} 1931async 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");} 1932for(const category of this.categoryKeys){commandsSorted=commandsSorted.concat(commands.filter(commandsWithinCategory(category,this.categoryKeys)));} 1933commands=commandsSorted;}} 1934this.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();}
1935selectCommand(index){if(index===-1||index>=this.state.commands.length){this.state.selectedCommand=null;return;} 1936this.state.selectedCommand=markRaw(this.state.commands[index]);} 1937selectCommandAndScrollTo(type){this.mouseSelectionActive=false;const index=this.state.commands.indexOf(this.state.selectedCommand);if(index===-1){return;} 1938let 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;} 1939this.selectCommand(nextIndex);const command=this.listboxRef.el.querySelector(`#o_command_${nextIndex}`);scrollTo(command,{scrollable:this.listboxRef.el});} 1940onCommandClicked(event,index){event.preventDefault();this.selectCommand(index);const ctrlKey=isMacOS()?event.metaKey:event.ctrlKey;this.executeSelectedCommand(ctrlKey);} 1941async executeCommand(command){const config=await command.action();if(config){this.setCommandPaletteConfig(config);}else{this.props.close();}} 1942async 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");}}} 1943onCommandMouseEnter(index){if(this.mouseSelectionActive){this.selectCommand(index);}else{this.mouseSelectionActive=true;}} 1944async 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;} 1945if(this.inputRef.el){this.inputRef.el.focus();}} 1946debounceSearch(value){const{namespace,searchValue}=this.processSearchValue(value);if(namespace!=="default"&&this.state.namespace!==namespace){this.switchNamespace(namespace);} 1947this.state.searchValue=searchValue;this.searchValuePromise=this.lastDebounceSearch(searchValue).catch(()=>{this.searchValuePromise=null;});} 1948onSearchInput(ev){this.debounceSearch(ev.target.value);} 1949onKeyDown(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;});}} 1950onWindowMouseDown(ev){if(!this.root.el.contains(ev.target)){this.props.close();}} 1951switchNamespace(namespace){if(this.lastDebounceSearch){this.lastDebounceSearch.cancel();} 1952const 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();} 1953processSearchValue(searchValue){let namespace="default";if(searchValue.length&&this.providersByNamespace[searchValue[0]]){namespace=searchValue[0];searchValue=searchValue.slice(1);} 1954return{namespace,searchValue};} 1955get isMacOS(){return isMacOS();} 1956get isMobileOS(){return isMobileOS();}} 1957return __exports;});; 1958 1959/* /web/static/src/core/commands/command_service.js */ 1960odoo.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");
1960const 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);} 1961onClick(namespace){this.props.switchNamespace(namespace);}} 1962const 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:{},};}} 1963for(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;}} 1964for(const[namespace,{emptyMessage,debounceDelay,placeholder},]of commandSetupRegistry.getEntries()){if(namespace in configByNamespace){if(emptyMessage){configByNamespace[namespace].emptyMessage=emptyMessage;} 1965if(debounceDelay!==undefined){configByNamespace[namespace].debounceDelay=debounceDelay;} 1966if(placeholder){configByNamespace[namespace].placeholder=placeholder;}}} 1967config=Object.assign({configByNamespace,FooterComponent:DefaultFooter,providers:commandProviderRegistry.getAll(),},config);return openPalette(config,onClose);} 1968function openPalette(config,onClose){if(isPaletteOpened){bus.trigger("SET-CONFIG",config);return;} 1969isPaletteOpened=true;dialog.add(CommandPalette,{config,bus,},{onClose:()=>{isPaletteOpened=false;if(onClose){onClose();}},});} 1970function 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.");} 1971const 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})`;}}} 1972if(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);} 1973if(available&&options.hotkeyOptions?.isAvailable){available=options.hotkeyOptions?.isAvailable(...args);} 1974return available;},});} 1975const token=nextToken++;registeredCommands.set(token,registration);if(!options.activeElement){Promise.resolve().then(()=>{registration.activeElement=ui.activeElement;});} 1976return token;} 1977function unregisterCommand(token){const cmd=registeredCommands.get(token);if(cmd&&cmd.removeHotkey){cmd.removeHotkey();} 1978registeredCommands.delete(token);} 1979return{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;});; 1980 1981/* /web/static/src/core/commands/default_providers.js */ 1982odoo.define('@web/core/commands/default_providers',['@web/core/browser/feature_detection','@web/core/h
1982otkeys/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);} 1983getKeysToPress(command){const{hotkey}=command;let result=hotkey.split("+");if(isMacOS()){result=result.map((x)=>x.replace("control","command")).map((x)=>x.replace("alt","control"));} 1984return result.map((key)=>key.toUpperCase());}} 1985const commandCategoryRegistry=registry.category("command_categories");
1985const 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;} 1986const 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}`,},});} 1987return commands;},});return __exports;});; 1988 1989/* /web/static/src/core/confirmation_dialog/confirmation_dialog.js */ 1990odoo.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? 1991It will be gone forever! 1992 1993Think 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;} 1994async _cancel(){return this.execButton(this.props.cancel);} 1995async _confirm(){return this.execButton(this.props.confirm);} 1996async _dismiss(){return this.execButton(this.props.dismiss||this.props.cancel);} 1997setButtonsDisabled(disabled){this.isProcess=disabled;if(!this.modalRef.el){return;} 1998for(const button of[...this.modalRef.el.querySelectorAll(".modal-footer button")]){button.disabled=disabled;}} 1999async execButton(callback){if(this.isProcess){return;} 2000this.setButtonsDisabled(true);if(callback){let shouldClose;try{shouldClose=await callback();}catch(e){this.props.close();throw e;} 2001if(shouldClose===false){this.setButtonsDisabled(false);return;}} 2002this.props.close();}} 2003const 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"),};} 2004return __exports;});; 2005 2006/* /web/static/src/core/context.js */ 2007odoo.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);}} 2008return context;} 2009function getPartialNames(ast){if(ast.type===5){return[ast.value];} 2010if(ast.type===6){return getPartialNames(ast.right);} 2011if(ast.type===14||ast.type===7){return getPartialNames(ast.left).concat(getPartialNames(ast.right));} 2012if(ast.type===15){return getPartialNames(ast.obj);} 2013return[];} 2014__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;} 2015try{context[key]=evaluate(value,evaluationContext);}catch{}} 2016return context;} 2017return __exports;});; 2018 2019/* /web/static/src/core/copy_button/copy_button.js */ 2020odoo.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);} 2021showTooltip(){this.popover.open(this.button.el,{tooltip:this.props.successText});browser.setTimeout(this.popover.close,800);} 2022async onClick(){let write,content;if(typeof this.props.content==="function"){content=this.props.content();}else{content=this.props.content;} 2023if(typeof content==="string"||content instanceof String){write=(value)=>browser.navigator.clipboard.writeText(value);}else{write=(value)=>browser.navigator.clipboard.write(value);} 2024try{await write(content);}catch(error){return browser.console.warn(error);} 2025this.showTooltip();}} 2026return __exports;});; 2027 2028/* /web/static/src/core/currency.js */ 2029odoo.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];} 2030__exports.getCurrencyRates=getCurrencyRates;async function getCurrencyRates(){const rates=reactive({});function recordsToRates(records){return Object.fromEntries(records.map((r)=>[r.id,r.inverse_rate]));} 2031const 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)=>
2031{if(hasChanged){Object.assign(rates,recordsToRates(records));}},},});Object.assign(rates,recordsToRates(records));return rates;} 2032__exports.formatCurrency=formatCurrency;function formatCurrency(amount,currencyId,options={}){const currency=getCurrency(currencyId);const digits=(options.digits!==undefined)?options.digits:(currency&¤cy.digits) 2033let 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});} 2034if(!currency||options.noSymbol){return formattedAmount;} 2035const formatted=[currency.symbol,formattedAmount];if(currency.position==="after"){formatted.reverse();} 2036return formatted.join(nbsp);} 2037return __exports;});; 2038 2039/* /web/static/src/core/datetime/datetime_input.js */ 2040odoo.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),});}} 2041return __exports;});; 2042 2043/* /web/static/src/core/datetime/datetime_picker.js */ 2044odoo.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;
2044w++){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});} 2045if(w===WEEKS_PER_MONTH-1){shouldAddLastWeek=true;}} 2046const weekItem=toWeekItem(weekDayItems);if(w===WEEKS_PER_MONTH-1){lastWeeks.push(weekItem);}else{weeks.push(weekItem);}} 2047const 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"),""]);} 2048return{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]);}} 2049return 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);} 2050get isLastPrecisionLevel(){return(this.allowedPrecisionLevels.indexOf(this.state.precision)===this.allowedPrecisionLevels.length-1);} 2051get titles(){return ensureArray(this.title);} 2052setup(){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());}
2053onPropsUpdated(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");} 2054if(this.maxDate<this.minDate){throw new Error(`DateTimePicker error: given "maxDate" comes before "minDate".`);} 2055this.state.timeValues=this.getTimeValues(props);this.shouldAdjustFocusDate=!props.range;this.adjustFocus(this.values,props.focusedDateIndex);} 2056onWillRender(){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;}} 2057adjustFocus(values,focusedDateIndex){if(!this.shouldAdjustFocusDate&&this.state.focusDate){return;} 2058const dateToFocus=values[focusedDateIndex]||values[focusedDateIndex===1?0:1]||today();this.shouldAdjustFocusDate=false;this.state.focusDate=this.clamp(dateToFocus.startOf("month"));} 2059clamp(value){return clampDate(value,this.minDate,this.maxDate);} 2060filterPrecisionLevels(minPrecision,maxPrecision){const levels=[...PRECISION_LEVELS.keys()];return levels.slice(levels.indexOf(minPrecision),levels.indexOf(maxPrecision)+1);} 2061getActiveRangeInfo({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;} 2062return result;} 2063getTimeValues(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;}} 2064isSelectedDate({range}){return this.values.some((value)=>isInRange(value,range));} 2065next(ev){ev.preventDefault();const{step}=this.activePrecisionLevel;this.state.focusDate=this.clamp(this.state.focusDate.plus(step));} 2066previous(ev){ev.preventDefault();const{step}=this.activePrecisionLevel;this.state.focusDate=this.clamp(this.state.focusDate.minus(step));} 2067onTimeChange(valueIndex,newTime){this.state.timeValues[valueIndex]=newTime;const value=this.values[valueIndex]||today();this.validateAndSelect(value,valueIndex,"time");} 2068validateAndSelect(value,valueIndex,unit){if(!this.props.onSelect){return false;} 2069const 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});} 2070if(!isInRange(result[valueIndex],[this.minDate,this.maxDate])){return false;} 2071this.props.onSelect(result.length===2?result:result[0],unit);return true;} 2072zoomIn(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;} 2073return false;} 2074zoomOut(){const index=this.allowedPrecisionLevels.indexOf(this.state.precision)+1;if(index in this.allowedPrecisionLevels){this.state.precision=this.allowedPrecisionLevels[index];return true;} 2075return false;} 2076zoomOrSelect(dateItem){if(!dateItem.isValid){return;} 2077if(this.zoomIn(dateItem.range[0])){return;} 2078const[value]=dateItem.range;const valueIndex=this.props.focusedDateIndex;const isValid=this.validateAndSelect(value,valueIndex,"date");this.shouldAdjustFocusDate=isValid&&!this.props.range;}} 2079return __exports;});; 2080 2081/* /web/static/src/core/datetime/datetime_picker_hook.js */ 2082odoo.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);} 2083const 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;} 2084return __exports;});; 2085 2086/* /web/static/src/core/datetime/datetime_picker_popover.js */ 2087odoo.define('@web/core/datetime/datetime_picker_popover',['@odoo/owl','@web/core/h
2087otkeys/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());}} 2088return __exports;});; 2089 2090/* /web/static/src/core/datetime/datetimepicker_service.js */ 2091odoo.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;}} 2092return copy;} 2093function stringifyProps(props){const copy={};for(const[key,value]of Object.entries(props)){copy[key]=JSON.stringify(value);} 2094return copy;} 2095const 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;} 2096lastAppliedStringValue=stringValue;inputsChanged=ensureArray(value).map(()=>false);await params.onApply?.(value);stringProps.value=stringValue;} 2097function 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);}} 2098const calendarIconGroupEl=getInput(0)?.parentElement.querySelector(".o_input_group_date_icon");if(calendarIconGroupEl){calendarIconGroupEl.classList.add("cursor-pointer");calendarIconGroupEl.addEventListener("click",()=>open(0));} 2099return()=>{};} 2100function focusActiveInput(){const inputEl=getInput(pickerProps.focusedDateIndex);if(!inputEl){shouldFocus=true;return;} 2101const{activeElement}=inputEl.ownerDocument;if(activeElement!==inputEl){inputEl.focus();} 2102setInputFocus(inputEl);} 2103function getInput(valueIndex){const el=getInputs()[valueIndex];if(el?.isConnected){return el;} 2104return null;} 2105function getPopoverTarget(){const target=getTarget();if(target){return target;} 2106if(pickerProps.range){let parentElement=getInput(0).parentElement;const inputEls=getInputs();while(parentElement&&!inputEls.every((inputEl)=>parentElement.contains(inputEl))){parentElement=parentElement.parentElement;} 2107return parentElement||getInput(0);}else{return getInput(0);}} 2108function getTarget(){return targetRef?targetRef.el:params.target;} 2109function isOpen(){return popover.isOpen;} 2110function onInputChange(ev){updateValueFromInputs();inputsChanged[ev.target===getInput(1)?1:0]=true;if(!isOpen()||inputsChanged.every(Boolean)){saveAndClose();}} 2111function onInputClick({target}){open(target===getInput(1)?1:0);} 2112function onInputFocus({target}){pickerProps.focusedDateIndex=target===getInput(1)?1:0;setInputFocus(target);} 2113function onInputKeydown(ev){if(ev.key=="Enter"&&ev.ctrlKey){ev.preventDefault();updateValueFromInputs();return open(ev.target===getInput(1)?1:0);} 2114switch(ev.key){case"Enter":case"Escape":{return saveAndClose();}
2115case"Tab":{if(!getInput(0)||!getInput(1)||ev.target!==getInput(ev.shiftKey?1:0)){return saveAndClose();}}}} 2116function 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;};} 2117for(const picker of dateTimePickerList){picker.close();} 2118popover.open(popoverTarget,{pickerProps});} 2119focusActiveInput();} 2120function 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;} 2121try{return[convertFn(value,options),null];}catch(error){if(error?.name==="ConversionError"){return[null,error];}else{throw error;}}} 2122function saveAndClose(){if(isOpen()){popover.close();}else{apply();}} 2123function setFocusClass(input){for(const el of getInputs()){if(el){el.classList.toggle(FOCUS_CLASSNAME,isOpen()&&el===input);}}} 2124function setInputFocus(inputEl){inputEl.selectionStart=0;inputEl.selectionEnd=inputEl.value.length;setFocusClass(inputEl);shouldFocus=false;} 2125function updateInput(el,value){if(!el){return;} 2126const[formattedValue]=safeConvert("format",value);el.value=formattedValue||"";} 2127function updateValue(value,unit,source){if(source==="input"&&areDatesEqual(pickerProps.value,value)){return;} 2128pickerProps.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});} 2129pickerProps.focusedDateIndex=1;}else{pickerProps.focusedDateIndex=pickerProps.focusedDateIndex===1?0:1;}} 2130params.onChange?.(value);} 2131function updateValueFromInputs(){const values=zipWith(getInputs(),ensureArray(pickerProps.value),(el,currentValue)=>{if(!el||el.tagName?.toLowerCase()!=="input"){return currentValue;} 2132const[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");} 2133const 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();}}} 2134shouldFocus=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);} 2135onWillRender(function computeBasePickerProps(){const nextProps=markValuesRaw(params.pickerProps);const oldStringProps=stringProps;stringProps=stringifyProps(nextProps);lastAppliedStringValue=stringProps.value;if(shallowEqual(oldStringProps,stringProps)){return;} 2136inputsChanged=ensureArray(nextProps.value).map(()=>false);for(const[key,value]of Object.entries(nextProps)){if(!areDatesEqual(pickerProps[key],value)){pickerProps[key]=value;}}});
2136useEffect(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`);} 2137const 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;});; 2138 2139/* /web/static/src/core/debug/debug_context.js */ 2140odoo.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,[{}]]));} 2141activateCategory(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);}};} 2142async 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;});}} 2143const debugContextSymbol=Symbol("debugContext");__exports.createDebugContext=createDebugContext;function createDebugContext({categories=[]}={}){return{[debugContextSymbol]:new DebugContext(categories)};} 2144__exports.useOwnDebugContext=useOwnDebugContext;function useOwnDebugContext({categories=[]}={}){useSubEnv(createDebugContext({categories}));} 2145__exports.useEnvDebugContext=useEnvDebugContext;function useEnvDebugContext(){const debugContext=useEnv()[debugContextSymbol];if(!debugContext){throw new Error("There is no debug context available in the current environment.");} 2146return debugContext;} 2147__exports.useDebugCategory=useDebugCategory;function useDebugCategory(category,context={}){const env=useEnv();if(env.debug){const debugContext=useEnvDebugContext();useEffect(()=>debugContext.activateCategory(category,context),()=>[]);}} 2148return __exports;});; 2149 2150/* /web/static/src/core/debug/debug_menu.js */ 2151odoo.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=[];
2151items.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",});}} 2152return __exports;});; 2153 2154/* /web/static/src/core/debug/debug_menu_basic.js */ 2155odoo.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();} 2156async 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);} 2157getSectionLabel(section){return debugSectionRegistry.get(section,{label:section}).label;}} 2158return __exports;});; 2159 2160/* /web/static/src/core/debug/debug_menu_items.js */ 2161odoo.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;} 2162return{type:"item",description:_t("Activate Test Mode"),callback:()=>{router.pushState({debug:"assets,tests"},{reload:true});},sequence:580,section:"tools",};} 2163__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",};} 2164__exports.becomeSuperuser=becomeSuperuser;function becomeSuperuser({env}){const becomeSuperuserURL=browser.location.origin+"/web/become";if(!user.isAdmin){return false;} 2165return{type:"item",description:_t("Become Superuser"),href:becomeSuperuserURL,callback:()=>{browser.open(becomeSuperuserURL,"_self");},sequence:560,section:"tools",};} 2166function leaveDebugMode(){return{type:"item",description:_t("Leave Debug Mode"),callback:()=>{router.pushState({debug:0},{reload:true});},sequence:650,};} 2167registry.category("debug").category("default").add("regenerateAssets",regenerateAssets).add("becomeSuperuser",becomeSuperuser).add("activateTestsAssetsDebugging",activateTestsAssetsDebugging).add("leaveDebugMode",leaveDebugMode);return __exports;});; 2168 2169/* /web/static/src/core/debug/debug_providers.js */ 2170odoo.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");
2170const 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)"),});} 2171result.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})`,});}} 2172return result;},});return __exports;});; 2173 2174/* /web/static/src/core/debug/debug_utils.js */ 2175odoo.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",});} 2176return __exports;});; 2177 2178/* /web/static/src/core/dialog/dialog.js */
2179odoo.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);} 2180onWillDestroy(()=>{if(this.env.isSmall){this.data.scrollToOrigin();}});this.bodyTabIndex=hasTouch()?"0":undefined;} 2181get isFullscreen(){return this.props.fullscreen||this.env.isSmall;} 2182get contentStyle(){if(this.isMovable){return`top: ${this.position.top}px; left: ${this.position.left}px;`;} 2183return"";} 2184onResize(){this.position.left=0;this.position.top=0;} 2185onEscape(){return this.dismiss();} 2186async dismiss(){if(this.data.dismiss){await this.data.dismiss();} 2187return this.data.close({dismiss:true});}} 2188return __exports;});; 2189 2190/* /web/static/src/core/dialog/dialog_service.js */ 2191odoo.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});}} 2192const 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=()=>
2192{if(!stack.length){window.scrollTo(scrollOrigin);}};const remove=overlay.add(DialogWrapper,{subComponent:dialogClass,subProps:markRaw({...props,close}),subEnv,},{onRemove:async(closeParams)=>{if(isBeingClosed){return;} 2193isBeingClosed=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);}} 2194return{add,closeAll};},};registry.category("services").add("dialog",dialogService);return __exports;});; 2195 2196/* /web/static/src/core/domain.js */ 2197odoo.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{} 2198const Domain=__exports.Domain=class Domain{static combine(domains,operator){if(domains.length===0){return new Domain([]);} 2199const domain1=domains[0]instanceof Domain?domains[0]:new Domain(domains[0]);if(domains.length===1){return domain1;} 2200const 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;} 2201static and(domains){return Domain.combine(domains,"AND");} 2202static or(domains){return Domain.combine(domains,"OR");} 2203static not(domain){const result=new Domain(domain);result.ast.value.unshift({type:1,value:"!"});return result;} 2204static 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);} 2205return 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;} 2206newDomain.ast.value.push(leaf);if(leaf.value==="!"){return 1+processLeaf(elements,idx+1,"&",newDomain);} 2207const firstLeafSkip=processLeaf(elements,idx+1,leaf.value,newDomain);const secondLeafSkip=processLeaf(elements,idx+1+firstLeafSkip,leaf.value,newDomain);return 1+firstLeafSkip+secondLeafSkip;} 2208return 0;} 2209domain=new Domain(domain);if(domain.ast.value.length===0){return domain;} 2210const newDomain=new Domain([]);processLeaf(domain.ast.value,0,"&",newDomain);return newDomain;} 2211constructor(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,});} 2212this.ast=normalizeDomainAST(rawAST);}} 2213contains(record){const expr=evaluate(this.ast,record);return matchDomain(record,expr);} 2214toString(){return formatAST(this.ast);} 2215toList(context){return evaluate(this.ast,context);} 2216toJson(){try{const evaluatedAsList=this.toList({});const evaluatedDomain=new Domain(evaluatedAsList);if(evaluatedDomain.toString()===this.toString()){return evaluatedAsList;} 2217return this.toString();}catch{return this.toString();}}} 2218const 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};}
2219function 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");}} 2220if(domain.value.length===0){return domain;} 2221let 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");} 2222break;case 4:case 10:if(child.value.length===3){expected--;break;} 2223throw new InvalidDomainError("Invalid domain AST");default:throw new InvalidDomainError("Invalid domain AST");}} 2224const values=domain.value.slice();while(expected<0){expected++;values.unshift({type:1,value:op});} 2225if(expected>0){throw new InvalidDomainError(`invalid domain ${formatAST(domain)} (missing ${expected} segment(s))`);} 2226return{type:4,value:values};} 2227function matchCondition(record,condition){if(typeof condition==="boolean"){return condition;} 2228const[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]);}} 2229let 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");} 2230const fieldValue=typeof field==="number"?field:record[field];const isNot=operator.startsWith("not ");switch(operator){case"=?":if([false,null].includes(value)){return true;} 2231case"=":case"==":if(Array.isArray(fieldValue)&&Array.isArray(value)){return shallowEqual(fieldValue,value);} 2232return 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;} 2233case"like":case"not like":if(fieldValue===false){return isNot;} 2234return Boolean(fieldValue.match(likeRegexp))!=isNot;case"=like":case"not =like":if(fieldValue===false){return isNot;} 2235return(Boolean(new RegExp(escapeRegExp(value).replace(/%/g,".*")).test(fieldValue))!=isNot);case"ilike":case"not ilike":if(fieldValue===false){return isNot;} 2236return Boolean(fieldValue.match(ilikeRegexp))!=isNot;case"=ilike":case"not =ilike":if(fieldValue===false){return isNot;} 2237return(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;} 2238throw new InvalidDomainError("could not match domain");} 2239function makeOperators(record){const match=matchCondition.bind(null,record);return{"!":(x)=>!match(x),"&":(a,b)=>match(a)&&match(b),"|":(a,b)=>match(a)||match(b),};} 2240function matchDomain(record,domain){if(domain.length===0){return true;} 2241const 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);}} 2242return matchCondition(record,condStack.pop());} 2243return __exports;});; 2244 2245/* /web/static/src/core/domain_selector/domain_selector.js */ 2246odoo.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));} 2247async onPropsUpdated(p){let domain;let isSupported=true;try{domain=new Domain(p.domain);}catch{isSupported=false;} 2248if(!isSupported){this.tree=null;this.showArchivedCheckbox=false;this.includeArchived=false;return;} 2249const[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)=>
2249{if(areEqualTrees(child,ARCHIVED_CONDITION)){this.includeArchived=true;return false;} 2250return 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("&");}}} 2251getShowArchivedCheckBox(hasActiveField,props){return hasActiveField;} 2252getDefaultCondition(fieldDefs){return getDefaultCondition(fieldDefs);} 2253getDefaultOperator(fieldDef){return getDomainDisplayedOperators(fieldDef)[0];} 2254getOperatorEditorInfo(fieldDef){const operators=getDomainDisplayedOperators(fieldDef);return getOperatorEditorInfo(operators,fieldDef);} 2255getPathEditorInfo(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"),};} 2256toggleIncludeArchived(){this.includeArchived=!this.includeArchived;this.update(this.tree);} 2257resetDomain(){this.props.update("[]");} 2258onDomainInput(domain){if(this.props.debugUpdate){this.props.debugUpdate(domain);}} 2259onDomainChange(domain){this.props.update(domain,true);} 2260update(tree){const archiveDomain=this.includeArchived?ARCHIVED_DOMAIN:`[]`;const domain=tree?Domain.and([domainFromTree(tree),archiveDomain]).toString():archiveDomain;this.props.update(domain);}} 2261return __exports;});; 2262 2263/* /web/static/src/core/domain_selector/domain_selector_operator_editor.js */ 2264odoo.define('@web/core/domain_selector/domain_selector_operator_editor',[],function(require){'use strict';let __exports={};__exports.getDomainDisplayedOperators=getDomainDisplayedOperators;function getDomainDisplayedOperators(fieldDef){if(!fieldDef){fieldDef={};} 2265const{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"];}} 2266switch(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",];}} 2267return __exports;});; 2268 2269/* /web/static/src/core/domain_selector/utils.js */ 2270odoo.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);} 2271__exports.getDefaultDomain=getDefaultDomain;function getDefaultDomain(fieldDefs){return domainFromTree(getDefaultCondition(fieldDefs));} 2272__exports.useGetDefaultLeafDomain=useGetDefaultLeafDomain;function useGetDefaultLeafDomain(){const fieldService=useService("field");return async(resModel)=>{const fieldDefs=await fieldService.loadFields(resModel);return getDefaultDomain(fieldDefs);};} 2273return __exports;});; 2274 2275/* /web/static/src/core/domain_selector_dialog/domain_selector_dialog.js */ 2276odoo.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");} 2277get confirmButtonText(){return this.props.confirmButtonText||_t("Confirm");} 2278get dialogTitle(){return this.props.title||_t("Domain");} 2279get disabled(){if(this.props.disableConfirmButton){return this.props.disableConfirmButton(this.state.domain);} 2280return false;} 2281get discardButtonText(){return this.props.discardButtonText||_t("Discard");} 2282get 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;},};} 2283async 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;}
2284if(isValid===undefined){isValid=await rpc("/web/domain/validate",{model:this.props.resModel,domain,});} 2285if(!isValid){if(this.confirmButtonRef.el){this.confirmButtonRef.el.disabled=false;} 2286this.notification.add(_t("Domain is invalid. Please correct it"),{type:"danger",});return;} 2287this.props.onConfirm(this.state.domain);this.props.close();} 2288onDiscard(){this.props.close();}} 2289return __exports;});; 2290 2291/* /web/static/src/core/dropdown/_behaviours/dropdown_group_hook.js */ 2292odoo.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);});} 2293return group;} 2294return __exports;});; 2295 2296/* /web/static/src/core/dropdown/_behaviours/dropdown_nesting.js */ 2297odoo.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);} 2298set isOpen(value){this._isOpen=value;if(this._isOpen){BUS.trigger("dropdown-opened",this);}} 2299get isOpen(){return this._isOpen;} 2300remove(){this.parent?.children.delete(this);} 2301closeAllParents(){this.close();if(this.parent){this.parent.closeAllParents();}} 2302closeChildren(){this.children.forEach((child)=>child.close());} 2303shouldIgnoreChanges(other){return(other===this||other.activeEl!==this.activeEl||[...this.children].some((child)=>child.shouldIgnoreChanges(other)));} 2304handleChange(other){if(this.shouldIgnoreChanges(other)){return;} 2305if(other.isOpen&&this.isOpen){this.close();}}} 2306__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();}},},},},};} 2307return __exports;});; 2308 2309/* /web/static/src/core/dropdown/_behaviours/dropdown_popover.js */ 2310odoo.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");
2310const DropdownPopover=__exports.DropdownPopover=class DropdownPopover extends Component{static components={DropdownItem};static template=xml` 2311 <t t-if="this.props.items"> 2312 <t t-foreach="this.props.items" t-as="item" t-key="this.getKey(item, item_index)"> 2313 <DropdownItem class="item.class" onSelected="() => item.onSelected()" t-out="item.label"/> 2314 </t> 2315 </t> 2316 <t t-slot="content" /> 2317 `;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?.();});} 2318getKey(item,index){return"id"in item?item.id:index;}} 2319return __exports;});; 2320 2321/* /web/static/src/core/dropdown/accordion_item.js */ 2322odoo.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?.();});}} 2323return __exports;});; 2324 2325/* /web/static/src/core/dropdown/checkbox_item.js */ 2326odoo.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,},};} 2327return __exports;});; 2328 2329/* /web/static/src/core/dropdown/dropdown.js */ 2330odoo.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;} 2331if(node.el){return node.el.nodeType===Node.ELEMENT_NODE?node.el:null;} 2332if(node.bdom||node.child){return getFirstElementOfNode(node.bdom||node.child);} 2333if(node.children){for(const child of node.children){const el=getFirstElementOfNode(child);if(el){return el;}}} 2334return null;} 2335const 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:()=>
2335{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),});} 2336this.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();}});} 2337get isBottomSheet(){return utils.isSmall()&&hasTouch()&&this.props.bottomSheet;} 2338get position(){return this.props.position||(this.hasParent?"right-start":"bottom-start");} 2339get hasParent(){return this.nesting.hasParent;} 2340get 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.");} 2341return target;} 2342handleClick(event){if(this.props.disabled){return;} 2343event.stopPropagation();if(this.state.isOpen&&!this.hasParent){this.state.close();}else{this.state.open();}} 2344handleMouseEnter(){if(this.props.disabled){return;} 2345if(this.hasParent||this.group.isOpen){this.target.focus();this.state.open();}} 2346onStateChanged(state){if(state.isOpen){this.openPopover();}else{this.closePopover();}} 2347popoverCloseOnClickAway(target){const rootNode=target.getRootNode();if(rootNode instanceof ShadowRoot){target=rootNode.host;} 2348return this.uiService.getActiveElementOf(target)===this.activeEl;} 2349setTargetElement(target){if(!target){return;} 2350target.ariaExpanded=false;const optionalClasses=[];const requiredClasses=[];optionalClasses.push("o-dropdown");if(this.hasParent){requiredClasses.push("o-dropdown--has-parent");} 2351const 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");}}} 2352target.classList.add(...requiredClasses);if(!this.props.noClasses){target.classList.add(...optionalClasses);} 2353this.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));};}} 2354setTargetDirectionClass(direction){if(!this.target||this.props.noClasses){return;} 2355const directionClasses={bottom:"dropdown",top:"dropup",left:"dropstart",right:"dropend",};this.target.classList.remove(...Object.values(directionClasses));this.target.classList.add(directionClasses[direction]);} 2356openPopover(){if(this.popover.isOpen||status(this)!=="mounted"){return;} 2357if(!this.target||!this.target.isConnected){this.state.close();return;} 2358this.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);} 2359closePopover(){this.popover.close();if(this.props.focusToggleOnClosed&&!this.group.isInGroup){this._focusedElBeforeOpen?.focus();this._focusedElBeforeOpen=undefined;}} 2360onOpened(){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");} 2361const menuEl=this.menuRef.el;if(menuEl){this.observer=new MutationObserver(()=>this.navigation.update());this.observer.observe(menuEl,{childList:true,subtree:true,});}} 2362onClosed(){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);} 2363if(this.observer){this.observer.disconnect();this.observer=null;}}} 2364return __exports;});; 2365 2366/* /web/static/src/core/dropdown/dropdown_group.js */ 2367odoo.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
2367ount:0,});} 2368GROUPS.get(id).count++;return GROUPS.get(id).group;} 2369function removeGroup(id){const groupData=GROUPS.get(id);groupData.count--;if(groupData.count<=0){GROUPS.delete(id);}} 2370const 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()});}}} 2371return __exports;});; 2372 2373/* /web/static/src/core/dropdown/dropdown_hooks.js */ 2374odoo.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;} 2375open(){this.isOpen=true;this._onOpen?.();} 2376close(){this.isOpen=false;this._onClose?.();}} 2377__exports.useDropdownState=useDropdownState;function useDropdownState({onOpen,onClose}={}){return useState(new DropdownState({onOpen,onClose}));} 2378__exports.useDropdownCloser=useDropdownCloser;function useDropdownCloser(){const env=useEnv();const dropdown=env[DROPDOWN_NESTING];return{close:()=>dropdown?.close(),closeChildren:()=>dropdown?.closeChildren(),closeAll:()=>dropdown?.closeAllParents(),};} 2379return __exports;});; 2380 2381/* /web/static/src/core/dropdown/dropdown_item.js */ 2382odoo.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();} 2383onClick(ev){if(this.props.attrs&&this.props.attrs.href){ev.preventDefault();} 2384this.props.onSelected?.(ev);switch(this.props.closingMode){case ClosingMode.ClosestParent:this.dropdownControl.close();break;case ClosingMode.AllParents:this.dropdownControl.closeAll();break;}}} 2385return __exports;});; 2386 2387/* /web/static/src/core/dropzone/dropzone.js */ 2388odoo.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;`;});}} 2389return __exports;});; 2390 2391/* /web/static/src/core/dropzone/dropzone_hook.js */ 2392odoo.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();} 2393dragCount=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});} 2394if(!shouldDisplayDropzone&&hasDropzone){removeDropzone();removeDropzone=false;}} 2395function onDragEnter(ev){if(dragCount||(ev.dataTransfer&&ev.dataTransfer.types.includes("Files"))){dragCount++;updateDropzone();}}
2395 2396function onDragLeave(){if(dragCount){dragCount--;updateDropzone();}} 2397useEffect((el)=>{hasTarget=!!el;updateDropzone();},()=>[targetRef.el]);} 2398__exports.useDropzone=useDropzone;function useDropzone(targetRef,onDrop,extraClass,isDropzoneEnabled=()=>true){const dropzoneComponent=Dropzone;const dropzoneComponentProps={extraClass,onDrop};useCustomDropzone(targetRef,dropzoneComponent,dropzoneComponentProps,isDropzoneEnabled);} 2399return __exports;});; 2400 2401/* /web/static/src/core/effects/effect_service.js */ 2402odoo.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!");} 2403if(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};} 2404env.services.notification.add(message);} 2405effectRegistry.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;});; 2406 2407/* /web/static/src/core/effects/rainbow_man.js */ 2408odoo.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);},()=>[]);}} 2409onAnimationEnd(ev){if(this.delay&&ev.animationName==="reward-fading-reverse"){ev.stopPropagation();this.closeRainbowMan();}} 2410closeRainbowMan(){this.props.close();}} 2411return __exports;});; 2412 2413/* /web/static/src/core/emoji_picker/emoji_picker.js */ 2414odoo.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);} 2415const loader=__exports.loader=reactive({loadEmoji:()=>
2415loadBundle("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;} 2416loader.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"),};}}} 2417const 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;} 2418this.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();} 2419this.state.hoveredEmoji=this.activeEmoji;});onPatched(()=>{if(this.emojis.length===0){return;} 2420if(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;} 2421if(activeEl&&this.keyboardNavigated&&!isElementVisible(activeEl,gridEl)){activeEl.scrollIntoView({block:"center",behavior:"instant"});this.keyboardNavigated=false;} 2422this.state.hoveredEmoji=this.activeEmoji;},()=>[this.state.activeEmojiIndex,this.gridRef.el]);useEffect(()=>{if(!this.gridRef.el){return;} 2423if(this.searchTerm){this.gridRef.el.scrollTop=0;this.state.categoryId=null;}else{if(this.lastSearchTerm){this.gridRef.el.scrollTop=0;} 2424this.highlightActiveCategory();} 2425this.lastSearchTerm=this.searchTerm;},()=>[this.searchTerm]);onWillUnmount(()=>{this.navbarResizeObserver?.disconnect();if(!this.gridRef.el){return;} 2426if(this.props.storeScroll){this.props.storeScroll.set(this.gridRef.el.scrollTop);}});} 2427adaptNavbar(){if(!this.navbarRef.el){return;} 2428const computedStyle=getComputedStyle(this.navbarRef.el);const availableWidth=this.navbarRef.el.getBoundingClientRect().width- 2429parseInt(computedStyle.paddingLeft)- 2430parseInt(computedStyle.marginLeft)- 2431parseInt(computedStyle.paddingLeft)- 2432parseInt(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");} 2433panel.push(category.sortId);} 2434if(panel.length>0){if(repr.length>0){panel.push(...[...Array(maxAvailableNavbarItemAmountAtOnce-panel.length)].map((_,idx)=>"empty_"+idx));} 2435repr.push(panel);} 2436this.state.emojiNavbarRepr=repr;} 2437get currentNavbarPanel(){if(!this.state.emojiNavbarRepr){return this.getAllCategories().map((c)=>c.sortId);} 2438if(this.state.categoryId===null||Number.isNaN(this.state.categoryId)){return this.state.emojiNavbarRepr[0];} 2439return this.state.emojiNavbarRepr.find((panel)=>panel.includes(this.state.categoryId));} 2440get searchTerm(){return this.props.state?this.props.state.searchTerm:this.state.searchTerm;} 2441set searchTerm(value){if(this.props.state){this.props.state.searchTerm=value;}else{this.state.searchTerm=value;}} 2442get itemsNumber(){return this.recentEmojis.length+this.getEmojis().length;} 2443get 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,]);} 2444return recent.slice(0,42);} 2445get placeholder(){return this.state.hoveredEmoji?.shortcodes.join(" ")??_t("Search emoji");} 2446onMouseenterEmoji(ev,emoji){this.state.hoveredEmoji=emoji;} 2447onMouseleaveEmoji(ev,emoji){this.state.hoveredEmoji=this.activeEmoji;} 2448onClick(ev){markEventHandled(ev,"emoji.selectEmoji");} 2449onClickToNextCategories(){const panelIndex=this.state.emojiNavbarRepr.findIndex((p)=>p.includes(this.state.categoryId));this.selectCategory(this.state.emojiNavbarRepr[panelIndex+1][1]);} 2450onClickToPreviousCategories(){const panelIndex=this.state.emojiNavbarRepr.findIndex((p)=>p.includes(this.state.categoryId));this.selectCategory(this.state.emojiNavbarRepr[panelIndex-1].at(-2));} 2451updateEmojiPickerRepr(){if(this.emojis.length===0){return;}
2452const 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([]);} 2453this.emojiMatrix.at(-1).push(parseInt(emojiIndex));}} 2454handleNavigation(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);} 2455let 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)];} 2456break;} 2457case"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)];} 2458break;} 2459case"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];} 2460break;} 2461case"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];} 2462break;}} 2463this.state.activeEmojiIndex=newIdx??this.state.activeEmojiIndex;} 2464get 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
2464ndefined;} 2465onKeydown(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();}} 2466getAllCategories(){const res=[...this.categories];if(this.recentEmojis.length>0){res.unshift(this.recentCategory);} 2467return res;} 2468getEmojis(){let emojisToDisplay=[...this.emojis];const recentEmojis=this.recentEmojis;if(recentEmojis.length>0&&this.searchTerm){emojisToDisplay=emojisToDisplay.filter((emoji)=>!recentEmojis.includes(emoji));} 2469if(this.searchTerm.length>0){return fuzzyLookup(this.searchTerm,emojisToDisplay,(emoji)=>[emoji.name,...emoji.keywords,...emoji.emoticons,...emoji.shortcodes,]);} 2470return emojisToDisplay;} 2471getEmojisFromSearch(){return[...this.recentEmojis,...this.getEmojis()];} 2472selectCategory(categoryId){this.searchTerm="";this.state.categoryId=categoryId;this.shouldScrollElem=true;} 2473selectEmoji(ev){const codepoints=ev.currentTarget.dataset.codepoints;let resetOnSelect=!ev.shiftKey;const res=this.props.onSelect(codepoints,resetOnSelect);if(res===false){resetOnSelect=false;} 2474this.frequentEmojiService.incrementEmojiUsage(codepoints);if(resetOnSelect){this.gridRef.el.scrollTop=0;this.props.close?.();this.props.onClose?.();}} 2475highlightActiveCategory(){if(!this.gridRef||!this.gridRef.el){return;} 2476const coords=this.gridRef.el.getBoundingClientRect();const res=document.elementFromPoint(coords.x+10,coords.y+10);if(!res){return;} 2477this.state.categoryId=parseInt(res.dataset.category);}} 2478__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;} 2479ref.el.addEventListener("click",toggler);ref.el.addEventListener("mouseenter",loadEmoji);if(show){ref.el.click();}} 2480function 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);},});} 2481return def;} 2482return popover.open(ref.el,{...props,...openProps});} 2483function close(){remove?.();popover.close?.();} 2484function toggle(ref,onSelect=props.onSelect){if(state.isOpen){close();}else{open(ref,{...props,onSelect});}} 2485if(ref){add(ref);} 2486onMounted(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;} 2487ref.el.addEventListener("click",toggle);ref.el.addEventListener("mouseenter",loadEmoji);}});onWillPatch(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;} 2488ref.el.removeEventListener("click",toggle);ref.el.removeEventListener("mouseenter",loadEmoji);}});onPatched(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;} 2489ref.el.addEventListener("click",toggle);ref.el.addEventListener("mouseenter",loadEmoji);}});Object.assign(state,{open,close,toggle});return state;} 2490class PickerMobile extends Component{static props=[...PICKER_PROPS,"onClose?"];static template=xml` 2491 <t t-component="props.PickerComponent" t-props="pickerProps"/> 2492 `;get pickerProps(){return{...this.props,onSelect:(...args)=>this.props.onSelect(...args),mobile:true,};}} 2493class PickerMobileInDialog extends PickerMobile{static components={Dialog};static props=[...PICKER_PROPS,"onClose?"];static template=xml` 2494 <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'"> 2495 <div class="h-100" t-ref="root"> 2496 <t t-component="props.PickerComponent" t-props="pickerProps"/> 2497 </div> 2498 </Dialog> 2499 `;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});}} 2500function 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;} 2501return __exports;});; 2502 2503/* /web/static/src/core/emoji_picker/frequent_emoji_service.js */ 2504odoo.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;});; 2505 2506/* /web/static/src/core/ensure_jquery.js */ 2507odoo.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");}} 2508return __exports;});; 2509 2510/* /web/static/src/core/errors/error_dialogs.js */ 2511odoo.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
2511ssDenied":_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} `;} 2512if(this.props.model){this.contextDetails+=`on model ${this.props.model} `;} 2513this.contextDetails+=`on ${DateTime.now() 2514 .setZone("UTC") 2515 .toFormat("yyyy-MM-dd HH:mm:ss")} GMT`;} 2516showTooltip(){this.popover.open(this.copyButtonRef.el,{tooltip:_t("Copied")});browser.setTimeout(this.popover.close,800);} 2517onClickClipboard(){browser.navigator.clipboard.writeText(`${this.props.name}\n\n${this.props.message}\n\n${this.contextDetails}\n\n${this.props.traceback}`);this.showTooltip();}} 2518const ClientErrorDialog=__exports.ClientErrorDialog=class ClientErrorDialog extends ErrorDialog{} 2519ClientErrorDialog.title=_t("Odoo Client Error");const NetworkErrorDialog=__exports.NetworkErrorDialog=class NetworkErrorDialog extends ErrorDialog{} 2520NetworkErrorDialog.title=_t("Odoo Network Error");const RequestEntityTooLargeErrorDialog=__exports.RequestEntityTooLargeErrorDialog=class RequestEntityTooLargeErrorDialog extends ErrorDialog{} 2521RequestEntityTooLargeErrorDialog.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}`;}} 2522inferTitle(){if(this.props.exceptionName&&odooExceptionTitleMap.has(this.props.exceptionName)){this.title=odooExceptionTitleMap.get(this.props.exceptionName).toString();return;} 2523if(!this.props.type){return;} 2524switch(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;}} 2525onClickClipboard(){browser.navigator.clipboard.writeText(`${this.props.name}\n\n${this.props.message}\n\n${this.contextDetails}\n\n${this.traceback}`);this.showTooltip();}} 2526const 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;}} 2527inferTitle(){if(this.props.exceptionName&&odooExceptionTitleMap.has(this.props.exceptionName)){return odooExceptionTitleMap.get(this.props.exceptionName).toString();} 2528return this.props.title||_t("Odoo Warning");}} 2529const 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;} 2530async onClick(){const options={forceLeave:true};if(this.additionalContext){options.additionalContext=this.additionalContext;} 2531if(this.actionId.help){this.actionId.help=markup(this.actionId.help);} 2532await this.actionService.doAction(this.actionId,options);this.props.close();}} 2533const Error504Dialog=__exports.Error504Dialog=class Error504Dialog extends Component{static template="web.Error504Dialog";static components={Dialog};static props={...standardErrorDialogProps};} 2534const SessionExpiredDialog=__exports.SessionExpiredDialog=class SessionExpiredDialog extends Component{static template="web.SessionExpiredDialog";static components={Dialog};static props={...standardErrorDialogProps};onClick(){browser.location.reload();}}
2535registry.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;});; 2536 2537/* /web/static/src/core/errors/error_handlers.js */ 2538odoo.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;} 2539if(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;} 2540if(errorDialogRegistry.contains(exceptionName)){ErrorComponent=errorDialogRegistry.get(exceptionName);}} 2541if(!ErrorComponent&&originalError.data.context){const exceptionClass=originalError.data.context.exception_class;if(errorDialogRegistry.contains(exceptionClass)){ErrorComponent=errorDialogRegistry.get(exceptionClass);}} 2542env.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;}} 2543errorHandlerRegistry.add("rpcErrorHandler",rpcErrorHandler,{sequence:97});let connectionLostNotifRemove=null;__exports.lostConnectionHandler=lostConnectionHandler;function lostConnectionHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;} 2544if(originalError instanceof ConnectionLostError){if(connectionLostNotifRemove){return true;} 2545connectionLostNotifRemove=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;} 2546env.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;}} 2547errorHandlerRegistry.add("lostConnectionHandler",lostConnectionHandler,{sequence:98});__exports.requestEntityTooLargeHandler=requestEntityTooLargeHandler;function requestEntityTooLargeHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;} 2548if(originalError instanceof RequestEntityTooLargeError){env.services.dialog.add(RequestEntityTooLargeErrorDialog);return true;}} 2549errorHandlerRegistry.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;} 2550errorHandlerRegistry.add("defaultHandler",defaultHandler,{sequence:100});__exports.swallowAllVisitorErrors=swallowAllVisitorErrors;function swallowAllVisitorErrors(env,error,originalError){if(!user.isInternalUser&&!odoo.debug&&!session.test_mode){return true;}} 2551if(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});} 2552return __exports;});; 2553 2554/* /web/static/src/core/errors/error_service.js */ 2555odoo.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
2555Error{static message="Error loading an HTML Element";constructor(message=HTMLElementLoadingError.message,event){super(message);this.event=event;}} 2556const UncaughtError=__exports.UncaughtError=class UncaughtError extends Error{constructor(message){super(message);this.name=getErrorTechnicalName(this);this.traceback=null;}} 2557const UncaughtClientError=__exports.UncaughtClientError=class UncaughtClientError extends UncaughtError{constructor(message="Uncaught Javascript Error"){super(message);}} 2558const UncaughtPromiseError=__exports.UncaughtPromiseError=class UncaughtPromiseError extends UncaughtError{constructor(message="Uncaught Promise"){super(message);this.unhandledRejectionEvent=null;}} 2559const ThirdPartyScriptError=__exports.ThirdPartyScriptError=class ThirdPartyScriptError extends UncaughtError{constructor(message="Third-Party Script Error"){super(message);}} 2560const errorService=__exports.errorService={start(env){function handleError(uncaughtError,retry=true){function shouldLogError(){return(uncaughtError.event&&!uncaughtError.event.defaultPrevented&&uncaughtError.traceback);} 2561let originalError=uncaughtError;while(originalError instanceof Error&&"cause"in originalError){originalError=originalError.cause;} 2562for(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 "${ 2563 e.cause || e 2564 }" while trying to handle:\n`+uncaughtError.traceback);} 2565return;}} 2566if(shouldLogError()){uncaughtError.event.preventDefault();console.error(uncaughtError.traceback);}} 2567browser.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;} 2568const isRedactedError=!filename&&!lineno&&!colno;const isThirdPartyScriptError=isRedactedError||(isBrowserFirefox()&&new URL(filename).origin!==window.location.origin);if(isThirdPartyScriptError&&!odoo.debug){return;} 2569let 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);}} 2570uncaughtError.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;} 2571let message;if(error.target){message=`${HTMLElementLoadingError.message}: ${error.target.nodeName}`;} 2572error=new HTMLElementLoadingError(message,error);} 2573let traceback;if(isBrowserChrome()&&ev instanceof CustomEvent&&error===undefined){if(!odoo.debug){return;} 2574traceback=`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.)`;} 2575const 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);} 2576uncaughtError.cause=error;handleError(uncaughtError);});},};registry.category("services").add("error",errorService,{sequence:1});return __exports;});; 2577 2578/* /web/static/src/core/errors/error_utils.js */ 2579odoo.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}`;}} 2580__exports.fullTraceback=fullTraceback;function fullTraceback(error){let traceback=formatTraceback(error);let current=error.cause;while(current){traceback+=`\n\nCaused by: ${ 2581 current instanceof Error ? formatTraceback(current) : current 2582 }`;current=current.cause;} 2583return traceback;} 2584__exports.fullAnnotatedTraceback=fullAnnotatedTraceback;async function fullAnnotatedTraceback(error){if(error.annotatedTraceback){return error.annotatedTraceback;} 2585if(error.errorEvent){error.errorEvent.preventDefault();} 2586let traceback;try{traceback=await annotateTraceback(error);let current=error.cause;while(current){traceback+=`\n\nCaused by: ${ 2587 current instanceof Error ? await annotateTraceback(current) : current 2588 }`;current=current.cause;}}catch(e){console.warn("Failed to annotate traceback for error:",error,"failure reason:",e);traceback=fullTraceback(error);} 2589error.annotatedTraceback=traceback;if(error.errorEvent){throw error;} 2590return traceback;} 2591__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);} 2592if(originalError.message){uncaughtError.message=`${uncaughtError.message} > ${originalError.message}`;} 2593uncaughtError.cause=originalError;} 2594__exports.getErrorTechnicalName=getErrorTechnicalName;function getErrorTechnicalName(error){return error.name!==Error.name?error.
2594name:error.constructor.name;} 2595__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 ");} 2596return traceback;} 2597__exports.annotateTraceback=annotateTraceback;async function annotateTraceback(error){const traceback=formatTraceback(error);try{await loadJS("/web/static/lib/stacktracejs/stacktrace.js");}catch{return traceback;} 2598if(error.stack){const regex=/ line (\d*) > (Function):(\d*)/gm;const subst=`:$1`;error.stack=error.stack.replace(regex,subst);} 2599let frames;try{frames=await StackTrace.fromError(error);}catch(e){console.warn("The following error could not be annotated:",error,e);return traceback;} 2600const lines=traceback.split("\n");if(lines[lines.length-1].trim()===""){lines.splice(-1);} 2601let lineIndex=0;let frameIndex=0;while(frameIndex<frames.length){const line=lines[lineIndex];if(!line.match(/:\d+:\d+\)?$/)){lineIndex++;continue;} 2602const frame=frames[frameIndex];const info=` (${frame.fileName}:${frame.lineNumber})`;lines[lineIndex]=line+info;lineIndex++;frameIndex++;} 2603return lines.join("\n");} 2604return __exports;});; 2605 2606/* /web/static/src/core/errors/scss_error_dialog.js */ 2607odoo.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;} 2608const 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;} 2609const 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;});; 2610 2611/* /web/static/src/core/expression_editor/expression_editor.js */ 2612odoo.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,};
2612setup(){onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));} 2613async 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;}} 2614getFieldDef(name,props=this.props){if(typeof name==="string"){return props.fields[name]||null;} 2615return null;} 2616getDefaultCondition(){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);} 2617getDefaultOperator(fieldDef){return getExpressionDisplayedOperators(fieldDef)[0];} 2618getOperatorEditorInfo(fieldDef){const operators=getExpressionDisplayedOperators(fieldDef);return getOperatorEditorInfo(operators,fieldDef);} 2619getPathEditorInfo(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`);} 2620return{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"),};} 2621get isDebugMode(){return!!this.env.debug;} 2622onExpressionChange(expression){this.props.update(expression);} 2623resetExpression(){this.props.update("True");} 2624update(tree){const expression=expressionFromTree(tree,{getFieldDef:(name)=>this.getFieldDef(name),generateSmartDates:false,});this.props.update(expression);}} 2625return __exports;});; 2626 2627/* /web/static/src/core/expression_editor/expression_editor_operator_editor.js */ 2628odoo.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));} 2629return __exports;});; 2630 2631/* /web/static/src/core/expression_editor_dialog/expression_editor_dialog.js */ 2632odoo.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");} 2633get expressionEditorProps(){return{resModel:this.props.resModel,fields:this.props.fields,expression:this.state.expression,update:(expression)=>{this.state.expression=expression;},};} 2634makeDefaultRecord(){const record={};for(const[name,{type}
2634]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;}} 2635return record;} 2636async 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;} 2637this.notification.add(_t("Expression is invalid. Please correct it"),{type:"danger",});return;} 2638this.props.onConfirm(this.state.expression);this.props.close();} 2639onDiscard(){this.props.close();}} 2640return __exports;});; 2641 2642/* /web/static/src/core/field_service.js */ 2643odoo.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;} 2644if(fieldDef.comodel&&followRelationalProperties){return fieldDef.comodel;} 2645return null;} 2646const 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}`);} 2647return orm.cache({type:"disk"}).call(resModel,"fields_get",[options.fieldNames,options.attributes]);} 2648async 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]:{},},});} 2649const 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,};}} 2650return definitions;} 2651async function loadPropertyDefinitions(resModel,fieldName,domain){const fieldDefs=await loadFields(resModel);return _loadPropertyDefinitions(resModel,fieldDefs,fieldName,domain);} 2652async function _loadPath(resModel,fieldDefs,names,followRelationalProperties=false){if(!fieldDefs){return{isInvalid:"path",names,modelsInfo:[]};} 2653const[name,...remainingNames]=names;const modelsInfo=[{resModel,fieldDefs}];if(resModel==="*"&&remainingNames.length){return{isInvalid:"path",names,modelsInfo};} 2654const fieldDef=fieldDefs[name];if((name!=="*"&&!fieldDef)||(name==="*"&&remainingNames.length)){return{isInvalid:"path",names,modelsInfo};} 2655if(!remainingNames.length){return{names,modelsInfo};} 2656let 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);} 2657if(subResult){const result={names,modelsInfo:[...modelsInfo,...subResult.modelsInfo],};if(subResult.isInvalid){result.isInvalid="path";} 2658return result;} 2659return{isInvalid:"path",names,modelsInfo};} 2660async function loadPath(resModel,path="*",followRelationalProperties=false){const fieldDefs=await loadFields(resModel);if(typeof path!=="string"||!path){throw new Error(`Invalid path: ${path}`);} 2661return _loadPath(resModel,fieldDefs,path.split("."),followRelationalProperties);} 2662async function loadFieldInfo(resModel,path){if(typeof path!=="str
2662ing"||!path||path==="*"){return{resModel,fieldDef:null};} 2663const{isInvalid,names,modelsInfo}=await loadPath(resModel,path);if(isInvalid){return{resModel,fieldDef:null};} 2664const name=names.at(-1);const modelInfo=modelsInfo.at(-1);return{resModel:modelInfo.resModel,fieldDef:modelInfo.fieldDefs[name]};} 2665function makeString(value){return String(value??"-");} 2666async function loadPathDescription(resModel,path,allowEmpty){if([0,1].includes(path)){return{isInvalid:false,displayNames:[makeString(path)]};} 2667if(allowEmpty&&!path){return{isInvalid:false,displayNames:[]};} 2668if(typeof path!=="string"||!path||path==="*"){return{isInvalid:true,displayNames:[makeString()]};} 2669const{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;}} 2670for(let index=0;index<names.length;index++){const name=names[index];const fieldDef=modelsInfo[index]?.fieldDefs[name];result.displayNames.push(fieldDef?.string||makeString(name));} 2671return result;} 2672return{loadFieldInfo,loadFields,loadPath,loadPathDescription,loadPropertyDefinitions,};},};registry.category("services").add("field",fieldService);return __exports;});; 2673 2674/* /web/static/src/core/file_input/file_input.js */ 2675odoo.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();}});} 2676get httpParams(){const{resId,resModel}=this.props;const params={csrf_token:odoo.csrf_token,ufile:[...this.fileInputRef.el.files],};if(resModel){params.model=resModel;} 2677if(resId!==undefined){params.id=resId;} 2678return params;} 2679async 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;}} 2680const parsedFileData=await this.uploadFiles(this.props.route,httpParams);if(status(this)==="destroyed"){return;} 2681if(parsedFileData){this.props.onUpload(parsedFileData,this.fileInputRef.el?this.fileInputRef.el.files:[]);this.fileInputRef.el.value=null;} 2682this.state.isDisable=false;} 2683async onTriggerClicked(){if(await this.props.beforeOpen()){this.fileInputRef.el.click();}}} 2684return __exports;});; 2685 2686/* /web/static/src/core/file_upload/file_upload_progress_bar.js */ 2687odoo.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");} 2688onCancel(){if(!this.props.fileUpload.xhr){return;} 2689this.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();},});}} 2690return __exports;});; 2691 2692/* /web/static/src/core/file_upload/file_upload_progress_container.js */ 2693odoo.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},};} 2694return __exports;});; 2695 2696/* /web/static/src/core/file_upload/file_upload_progress_record.js */ 2697odoo.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);
2697return{left:_t("Uploading... (%s%)",percent),right:_t("(%(mbLoaded)s/%(mbTotal)sMB)",{mbLoaded,mbTotal}),};}}} 2698const FileUploadProgressKanbanRecord=__exports.FileUploadProgressKanbanRecord=class FileUploadProgressKanbanRecord extends FileUploadProgressRecord{static template="web.FileUploadProgressKanbanRecord";} 2699const FileUploadProgressDataRow=__exports.FileUploadProgressDataRow=class FileUploadProgressDataRow extends FileUploadProgressRecord{static template="web.FileUploadProgressDataRow";} 2700return __exports;});; 2701 2702/* /web/static/src/core/file_upload/file_upload_service.js */ 2703odoo.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);} 2704if(params.buildFormData){params.buildFormData(formData);} 2705const 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;} 2706delete 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;} 2707if(resp){let content=resp;if(typeof content==="string"){try{content=JSON.parse(content);}catch{try{content=new DOMParser().parseFromString(content,"text/html");}catch{}}} 2708if(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;}}}} 2709if(error){throw new Error(errorMessage);} 2710return true;} 2711function 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,});} 2712bus.trigger("FILE_UPLOAD_ERROR",{upload});} 2713xhr.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;});; 2714 2715/* /web/static/src/core/file_viewer/file_model.js */ 2716odoo.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`;} 2717if(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);}} 2718return`https://www.youtube.com/embed/${token}`;} 2719return route;}
2720get downloadUrl(){return url(this.urlRoute,{...this.urlQueryParams,download:true});} 2721get 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);} 2722get isPdf(){return this.mimetype&&this.mimetype.startsWith("application/pdf");} 2723get isText(){const textMimeType=["application/javascript","application/json","text/css","text/html","text/plain",];return textMimeType.includes(this.mimetype);} 2724get isUrl(){return this.type==="url"&&this.url;} 2725get isUrlYoutube(){return!!this.url&&this.url.includes("youtu");} 2726get isVideo(){const videoMimeTypes=["audio/mpeg","video/x-matroska","video/mp4","video/webm"];return videoMimeTypes.includes(this.mimetype);} 2727get isViewable(){return((this.isText||this.isImage||this.isVideo||this.isPdf||this.isUrlYoutube)&&!this.uploading);} 2728get urlQueryParams(){if(this.uploading&&this.tmpUrl){return{};} 2729const 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];}} 2730return params;} 2731get urlRoute(){if(this.uploading&&this.tmpUrl){return this.tmpUrl;} 2732return this.isImage?`/web/image/${this.id}`:`/web/content/${this.id}`;}};const FileModel=__exports.FileModel=class FileModel extends FileModelMixin(Object){} 2733return __exports;});; 2734 2735/* /web/static/src/core/file_viewer/file_viewer.js */ 2736odoo.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]);} 2737onImageLoaded(){this.state.imageLoaded=true;} 2738onIframeLoaded(ev){requestAnimationFrame(()=>{this.state.isIframeLoaded=true;});} 2739close(){this.props.close&&this.props.close();} 2740next(){const last=this.props.files.length-1;this.activateFile(this.state.index===last?0:this.state.index+1);} 2741previous(){const last=this.props.files.length-1;this.activateFile(this.state.index===0?last:this.state.index-1);} 2742activateFile(index){this.state.index=index;this.state.file=this.props.files[index];} 2743onKeydown(ev){switch(ev.key){case"ArrowRight":this.next();break;case"ArrowLeft":this.previous();break;case"Escape":this.close();break;case"q":this.close();break;} 2744if(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;}}} 2745onWheelImage(ev){if(ev.deltaY>0){this.zoomOut({scroll:true});}else{this.zoomIn({scroll:true});}} 2746onMousedownImage(ev){if(this.isDragging){return;} 2747if(ev.button!==0){return;} 2748this.isDragging=true;this.dragStartX=ev.clientX;this.dragStartY=ev.clientY;} 2749onMouseupImage(){if(!this.isDragging){return;} 2750this.isDragging=false;this.translate.x+=this.translate.dx;this.translate.y+=this.translate.dy;this.translate.dx=0;this.translate.dy=0;this.updateZoomerStyle();} 2751onMousemoveView(ev){if(!this.isDragging){return;} 2752this.translate.dx=ev.clientX-this.dragStartX;this.translate.dy=ev.clientY-this.dragStartY;this.updateZoomerStyle();} 2753resetZoom(){this.state.scale=1;this.updateZoomerStyle();} 2754rotate(){this.state.angle+=90;} 2755zoomIn({scroll=false}={}){this.state.scale=this.state.scale+(scroll?this.scrollZoomStep:this.zoomStep);this.updateZoomerStyle();} 2756zoomOut({scroll=false}={}){if(this.state.scale===this.minScale){return;} 2757const unflooredAdaptedScale=this.state.scale-(scroll?this.scrollZoomStep:this.zoomStep);this.state.scale=Math.max(this.minScale,unflooredAdaptedScale);this.updateZoomerStyle();} 2758updateZoomerStyle(){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;} 2759if(ty===0){this.translate.y=0;} 2760this.zoomerRef.el.style="transform: "+`translate(${tx}px, ${ty}px)`;} 2761get 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%;";} 2762style+=`background: repeating-conic-gradient(#ccc 0deg 90deg, #fff 90deg 180deg) 50% / 20p
2762x 20px;`;return style;} 2763onClickPrint(){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);} 2764onClickDownload(){downloadFile(this.state.file.downloadUrl);}} 2765return __exports;});; 2766 2767/* /web/static/src/core/file_viewer/file_viewer_hook.js */ 2768odoo.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;} 2769if(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},});}} 2770function close(){registry.category("main_components").remove(fileViewerId);} 2771return{open,close};} 2772__exports.useFileViewer=useFileViewer;function useFileViewer(){const{open,close}=createFileViewer();onWillDestroy(close);return{open,close};} 2773return __exports;});; 2774 2775/* /web/static/src/core/hotkeys/hotkey_hook.js */ 2776odoo.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),()=>[]);} 2777return __exports;});; 2778 2779/* /web/static/src/core/hotkeys/hotkey_service.js */ 2780odoo.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"";} 2781if(ev.isComposing){return"";} 2782const hotkey=[];if(isMacOS()?ev.ctrlKey:ev.altKey){hotkey.push("alt");} 2783if(isMacOS()?ev.metaKey:ev.ctrlKey){hotkey.push("control");} 2784if(ev.shiftKey){hotkey.push("shift");} 2785let key=ev.key.toLowerCase();if(key===" "){key="space";} 2786if(ev.code&&ev.code.indexOf("Digit")===0){key=ev.code.slice(-1);} 2787if(!AUTHORIZED_KEYS.includes(key)&&ev.code&&ev.code.indexOf("Key")===0){key=ev.code.slice(-1).toLowerCase();} 2788if(!MODIFIERS.includes(key)){hotkey.push(key);} 2789return hotkey.join("+");} 2790const 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);} 2791function onKeydown(event){if(event.code&&event.code.indexOf("Numpad")===0&&/^\d$/.test(event.key)){return;} 2792const hotkey=getActiveHotkey(event);if(!hotkey){return;} 2793const{activeElement,isBlocked}=ui;if(isBlocked){return;} 2794const elementsWithAccessKey=document.querySelectorAll("[accesskey]");for(const el of elementsWithAccessKey){if(el instanceof HTMLElement){el.dataset.hotkey=el.accessKey;el.removeAttribute("accesskey");}} 2795if(!overlaysVisible&&hotkey===hotkeyService.overlayModifier){if(addHotkeyOverlays(activeElement)){event.preventDefault();} 2796return;} 2797const singleKey=hotkey.split("+").pop();if(!AUTHORIZED_KEYS.includes(singleKey)){return;} 2798const 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);
2798if(dispatched){event.preventDefault();event.stopImmediatePropagation();} 2799if(overlaysVisible){removeHotkeyOverlays();event.preventDefault();}} 2800function 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;}}} 2801if(winner){winner.callback({area:winner.area&&winner.area(),target,});return true;} 2802return false;} 2803function getDomRegistrations(hotkey,activeElement){const overlayModParts=hotkeyService.overlayModifier.split("+");if(!overlayModParts.every((el)=>hotkey.includes(el))){return[];} 2804const 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();} 2805el.focus();setTimeout(()=>el.click());},}));} 2806function 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,});}} 2807const hotkeysFromDomToHighlight=getVisibleElements(activeElement,"[data-hotkey]:not(:disabled)").map((el)=>({hotkey:el.dataset.hotkey,el}));const items=[...hotkeysFromDomToHighlight,...hotkeysFromHookToHighlight];if(!items.length){return false;} 2808for(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;} 2809if(overlayParent.style.position!=="absolute"){overlayParent.style.position="relative";} 2810overlayParent.appendChild(overlay);} 2811overlaysVisible=true;return true;} 2812function removeHotkeyOverlays(){for(const overlay of document.querySelectorAll(".o_web_hotkey_overlay")){overlay.remove();} 2813overlaysVisible=false;} 2814function registerHotkey(hotkey,callback,options={}){if(!hotkey||hotkey.length===0){throw new Error("You must specify an hotkey when registering a registration.");} 2815if(!callback||typeof callback!=="function"){throw new Error("You must specify a callback function when registering a registration.");} 2816const 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}') 2817 that contains parts not whitelisted: ${keys.join(", ")}`);}else if(keys.length>1){throw new Error(`You are trying to subscribe for an hotkey ('${hotkey}') 2818 that contains more than one single key part: ${keys.join("+")}`);} 2819const 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;} 2820function unregisterHotkey(token){registrations.delete(token);} 2821return{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;});; 2822 2823/* /web/static/src/core/install_scoped_app/install_scoped_app.js */ 2824odoo.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;});} 2825onChangeName(ev){const value=ev.target.value;if(value!==this.state.manifest.name){const url=new URL(document.location.href);
2825url.searchParams.set("app_name",encodeURIComponent(value));browser.location.replace(url);}} 2826onInstall(){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;}},});}} 2827registry.category("public_components").add("web.install_scoped_app",InstallScopedApp);return __exports;});; 2828 2829/* /web/static/src/core/ir_ui_view_code_editor/code_editor.js */ 2830odoo.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]);} 2831async 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} 2832const{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"));}}}}} 2833clearMarkers(){this.markers.forEach((marker)=>this.aceEditor.session.removeMarker(marker));this.markers=[];}} 2834return __exports;});; 2835 2836/* /web/static/src/core/l10n/dates.js */ 2837odoo.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";} 2838__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]));} 2839if(d1 instanceof DateTime&&d2 instanceof DateTime&&d1!==d2){return d1.equals(d2);}else{return d1===d2;}} 2840__exports.clampDate=clampDate;
2840function clampDate(desired,minDate,maxDate){if(maxDate<desired){return maxDate;} 2841if(minDate>desired){return minDate;} 2842return desired;} 2843__exports.getLocalYearAndWeek=getLocalYearAndWeek;function getLocalYearAndWeek(date){if(!date.isLuxonDateTime){date=DateTime.fromJSDate(date);} 2844const{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 2845year=date.year-1}else{diffDays=date.diff(jan4,"day").days;year=date.year} 2846return{year:year,week:Math.trunc(diffDays/7)+1,startDate,};} 2847__exports.getStartOfLocalWeek=getStartOfLocalWeek;function getStartOfLocalWeek(date){const{weekStart}=localization;const weekday=date.weekday<weekStart?weekStart-7:weekStart;return date.set({weekday}).startOf("day");} 2848__exports.getEndOfLocalWeek=getEndOfLocalWeek;function getEndOfLocalWeek(date){return getStartOfLocalWeek(date).plus({days:6}).endOf("day");} 2849__exports.isInRange=isInRange;function isInRange(value,range){if(!value||!range){return false;} 2850if(Array.isArray(value)){const actualValues=value.filter(Boolean).sort();if(actualValues.length<2){return isInRange(actualValues[0],range);} 2851return((actualValues[0]<=range[0]&&range[0]<=actualValues[1])||(range[0]<=actualValues[0]&&actualValues[0]<=range[1]));}else{return range[0]<=value&&value<=range[1];}} 2852function isValidDate(date){return date&&date.isValid&&isInRange(date,[MIN_VALID_DATE,MAX_VALID_DATE]);} 2853function parseSmartDateInput(value){const terms=value.split(/\s+/);if(!terms.length){return false;} 2854var 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";} 2855for(let i=0;i<terms.length;i++){const term=terms[i];const operator=term[0];if(term.length<3||!["+","-","="].includes(operator)){return false;} 2856const 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");} 2857now=now.plus({days:weekdayOffset});continue;} 2858try{const field_name=smartDateUnits[term[term.length-1]];const number=parseInt(term.slice(1,-1),10);if(!field_name||isNaN(number)){return false;} 2859if(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");} 2860now=now.set({[field_name]:number});}}catch{return false;}} 2861return now;} 2862const 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;} 2863if(/[a-z]/gi.test(character)){if(inToken&&normalizeFormatTable[character]!==undefined){character=normalizeFormatTable[character];}else{character=`'${character}'`;}} 2864output.push(character);inToken=false;} 2865return output.join("");});__exports.today=today;function today(){return DateTime.local().startOf("day");} 2866__exports.formatDate=formatDate;function formatDate(value,options={}){if(!value){return"";} 2867const format=options.format||localization.dateFormat;return value.toFormat(format);} 2868__exports.formatDateTime=formatDateTime;function formatDateTime(value,options={}){if(!value){return"";} 2869const format=options.format||localization.dateTimeFormat;return value.setZone(options.tz||"default").toFormat(format);} 2870__exports.toLocaleDateString=toLocaleDateString;function toLocaleDateString(value){if(!value){return"";} 2871const format={...DateTime.DATE_MED};if(today().year===value.year){delete format.year;}
2872return value.toLocaleString(format);} 2873__exports.toLocaleDateTimeString=toLocaleDateTimeString;function toLocaleDateTimeString(value,options={showDate:true,showTime:true,showSeconds:false}){if(!value){return"";} 2874const format={...DateTime.DATETIME_MED_WITH_SECONDS};if(!options.showSeconds){delete format.second;} 2875if(options.showDate===false){delete format.day;delete format.month;delete format.year;} 2876if(options.showTime===false){delete format.hour;delete format.minute;} 2877if(today().year===value.year){delete format.year;} 2878return value.setZone(options.tz||"default").toLocaleString(format);} 2879__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;} 2880seconds-=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");} 2881return durationSplit.slice(0,numberOfValuesToDisplay).join(",");} 2882__exports.serializeDate=serializeDate;function serializeDate(value){if(!dateCache.has(value)){dateCache.set(value,value.toFormat(SERVER_DATE_FORMAT,{numberingSystem:"latn"}));} 2883return dateCache.get(value);} 2884__exports.serializeDateTime=serializeDateTime;function serializeDateTime(value){if(!dateTimeCache.has(value)){dateTimeCache.set(value,value.setZone("utc").toFormat(SERVER_DATETIME_FORMAT,{numberingSystem:"latn"}));} 2885return dateTimeCache.get(value);} 2886__exports.parseDate=parseDate;function parseDate(value,options={}){const parsed=parseDateTime(value,{...options,format:options.format||localization.dateFormat,});return parsed&&parsed.startOf("day");} 2887__exports.parseDateTime=parseDateTime;function parseDateTime(value,options={}){if(!value){return false;} 2888const 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";} 2889let result=DateTime.fromFormat(value,fmt,parseOpts);if(!isValidDate(result)){result=parseSmartDateInput(value);} 2890if(!isValidDate(result)){const fmtWoZero=stripAlphaDupes(fmt);result=DateTime.fromFormat(value,fmtWoZero,parseOpts);} 2891if(!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);} 2892if(!isValidDate(result)){const valueDigits=value.replace(nonDigitRegex,"");if(valueDigits.length>4){result=DateTime.fromISO(value,parseOpts);if(!isValidDate(result)){result=DateTime.fromSQL(value,parseOpts);}}} 2893if(!isValidDate(result)){throw new ConversionError(_t("'%s' is not a correct date or datetime",value));} 2894if(switchToLatin){result=result.reconfigure({numberingSystem:Settings.defaultNumberingSystem,});} 2895return result.setZone(options.tz||"default");} 2896__exports.deserializeDate=deserializeDate;function deserializeDate(value,options={}){options={numberingSystem:"latn",zone:"default",...options};return DateTime.fromSQL(value,options).reconfigure({numberingSystem:Settings.defaultNumberingSystem,});} 2897__exports.deserializeDateTime=deserializeDateTime;function deserializeDateTime(value,options={}){return DateTime.fromSQL(value,{numberingSystem:"latn",zone:"utc"}).setZone(options?.tz||"default").reconfigure({numberingSystem:Settings.defaultNumberingSystem,});} 2898return __exports;});; 2899 2900/* /web/static/src/core/l10n/localization.js */ 2901odoo.define('@web/core/l10n/localization',[],function(require){'use strict';let __exports={};const localization=__exports.localization=new Proxy({},{get:(target,p)=>
2901{if(p in target||p==="then"){return Reflect.get(target,p);} 2902throw new Error(`could not access localization parameter "${p}": parameters are not ready yet. Maybe add 'localization' to your dependencies?`);},});return __exports;});; 2903 2904/* /web/static/src/core/l10n/localization_service.js */ 2905odoo.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");} 2906const 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;}} 2907Object.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;} 2908translatedTerms[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;}} 2909localization.code=jsToPyLocale(locale);return localization;},};registry.category("services").add("localization",localizationService);return __exports;});; 2910 2911/* /web/static/src/core/l10n/time.js */ 2912odoo.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;}} 2913constructor({hour=0,minute=0,second=0}={}){this.hour=hour;this.minute=minute;this.second=second;this._is24HourFormat=is24HourFormat();this._isMeridiemFormat=isMeridiemFormat();} 2914roundMinutes(rounding){this.minute=Math.round(this.minute/rounding)*rounding;} 2915copy(){return new Time(this);} 2916equals(other,checkSeconds=false){return(other&&this.hour===other.hour&&this.minute===other.minute&&(!checkSeconds||this.second===other.second));} 2917toString(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();} 2918toDateTime(){return DateTime.fromObject(this.toObject());} 2919toObject(){return{hour:this.hour,minute:this.minute,second:this.second,};}} 2920__exports.is24HourFormat=is24HourFormat;function is24HourFormat(format){return/H/.test(format||localization.timeFormat);} 2921__exports.isMeridiemFormat=isMeridiemFormat;function isMeridiemFormat(format){return/a/.test(format||localization.timeFormat);} 2922__exports.parseTime=parseTime;function parseTime(value,parseSeconds){const{isPm,isAm}=meridiemCheck(value);value=normalizeTimeStr(value);if(!value){return null;} 2923let 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;} 2924hour=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];
2924const 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"));} 2925break;}}};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;} 2926hour=parse(raw.slice(0,2));minute=parse(raw.slice(2,4));second=parse(raw.slice(4).padEnd(2,"0"));}else{return null;}} 2927if(isPm&&hour<12){hour+=12;}else if(isAm&&hour===12){hour=0;} 2928if(hour>=0&&hour<=24&&minute>=0&&minute<60&&second>=0&&second<60){if(hour===24){hour=0;} 2929return new Time({hour,minute,second});}else{return null;}} 2930function normalizeTimeStr(timeStr){if(typeof timeStr!=="string"){return false;} 2931timeStr=timeStr.trim().toLowerCase();for(const map of NUMERAL_MAPS){for(let i=0;i<map.length;i++){timeStr=timeStr.replaceAll(map[i],i);}} 2932return timeStr.replace(/^\D+|\D+$/g,"").replace(/\D+/g,":");} 2933function 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",};} 2934return __exports;});; 2935 2936/* /web/static/src/core/l10n/translation.js */ 2937odoo.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);} 2938function translationSprintf(str,substitutions){let hasMarkup=false;function formatSubstitution(value){hasMarkup||=isMarkup(value);if(isIterable(value)&&!(value instanceof String)){return formatList(value);}else{return value;}} 2939const formattedSubstitutions=mapSubstitutions(substitutions,formatSubstitution);if(hasMarkup){return htmlSprintf(str,...formattedSubstitutions);}else{return sprintf(str,...formattedSubstitutions);}} 2940const DEFAULT_MODULE="base";const R_BLANK=/^[\s\u200B]*$/;__exports._t=_t;function _t(source,...substitutions){return appTranslateFn(source,odoo.translationContext,...substitutions);} 2941__exports.appTranslateFn=appTranslateFn;function appTranslateFn(source,moduleName,...substitutions){const string=new TranslatedString(source,substitutions,moduleName);return string.lazy?string:string.valueOf();} 2942__exports.loadLanguages=loadLanguages;async function loadLanguages(orm){if(!loadLanguages.installedLanguages){loadLanguages.installedLanguages=await orm.call("res.lang","get_installed");} 2943return loadLanguages.installedLanguages;} 2944const TranslatedString=__exports.TranslatedString=class TranslatedString extends String{context;lazy=false;substitutions;constructor(value,substitutions,context){super(value);if(!isNotBlank(value)){return new String(value);} 2945this.lazy=!translatedTerms[translationLoaded];this.substitutions=substitutions;this.context=context||DEFAULT_MODULE;} 2946toString(){return this.valueOf();} 2947valueOf(){const source=super.valueOf();if(this.lazy&&!translatedTerms[translationLoaded]){throw new Error(`Cannot translate string: translations have not been loaded`);} 2948const translation=translatedTerms[this.context]?.[source]??translatedTermsGlobal[source]??source;if(this.substitutions.length){return translationSprintf(translation,this.substitutions);}else{return translation;}}} 2949const 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;});; 2950 2951/* /web/static/src/core/l10n/utils.js */ 2952odoo.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;});; 2953 2954/* /web/static/src/core/l10n/utils/format_list.js */ 2955odoo.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));} 2956return __exports;});; 2957 2958/* /web/static/src/core/l10n/utils/locales.js */ 2959odoo.define('@web/core/l10n/utils/locales',[],function(require){'use strict';let __exports={};__exports.jsToPyLocale=jsToPyLocale;function jsToPyLocale(locale){if(!locale){return"";}
2960try{var{language,script,region}=new Intl.Locale(locale);if(language==="fil"){language="tl";}}catch{return locale;} 2961let xpgLocale=language;if(region){xpgLocale+=`_${region}`;} 2962switch(script){case"Cyrl":xpgLocale+="@Cyrl";break;case"Latn":xpgLocale+="@latin";break;} 2963return xpgLocale;} 2964__exports.pyToJsLocale=pyToJsLocale;function pyToJsLocale(locale){if(!locale){return"";} 2965const regex=/^([a-z]+)(_[A-Z\d]+)?(@.+)?$/;const match=locale.match(regex);if(!match){return locale;} 2966const[,language,territory,modifier]=match;const subtags=[language];switch(modifier){case"@Cyrl":subtags.push("Cyrl");break;case"@latin":subtags.push("Latn");break;} 2967if(territory){subtags.push(territory.slice(1));} 2968return subtags.join("-");} 2969return __exports;});; 2970 2971/* /web/static/src/core/l10n/utils/normalize.js */ 2972odoo.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"))));} 2973__exports.normalizedMatch=normalizedMatch;function normalizedMatch(src,substr){if(!substr){return{start:0,end:0,match:""};} 2974const 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;} 2975if(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};}}} 2976return{start:-1,end:-1,match:""};} 2977__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;}} 2978return matches;} 2979const 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("");} 2980const 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("");} 2981function casefold(str){return str.toLowerCase().toUpperCase().toLowerCase();} 2982return __exports;});; 2983 2984/* /web/static/src/core/macro.js */ 2985odoo.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;}} 2986async function performAction(trigger,action){if(!action){return;} 2987try{return await action(trigger);}catch(error){throw new MacroError("Action",error.stack||`ERROR during perform action: ${error.message}`,{cause:error});}} 2988async function waitForTrigger(trigger){if(!trigger){return;} 2989try{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,});}} 2990__exports.waitUntil=waitUntil;async function waitUntil(predicate){const result=predicate();if(result){return Promise.resolve(result);} 2991let handle;return new Promise((resolve)=>{const runCheck=()=>{const result=predicate();if(result){resolve(result);} 2992handle=requestAnimationFrame(runCheck);};handle=requestAnimationFrame(runCheck);}).finally(()=>{cancelAnimationFrame(handle);});} 2993const 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}`);} 2994Object.assign(this,descr);this.onComplete=this.onComplete||(()=>{});this.onStep=this.onStep||(()=>{});this.onError=this.onError||((error,step,index)=>{console.error(error.message,step,index);});} 2995async start(){await this.advance();} 2996async advance(){if(this.isComplete||this.currentIndex>=this.steps.length){this.stop();return;} 2997try{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;} 2998this.currentIndex++;await this.advance();} 2999stop(error){if(this.isComplete){return;} 3000this.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();}}} 3001const 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)=>
3001Array.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"));} 3002iframes.forEach((iframeEl)=>this.observeIframe(iframeEl,observer,()=>callback()));this.findAllShadowRoots(node).forEach((shadowRoot)=>observer.observe(shadowRoot,this.observerOptions));}));});} 3003disconnect(){this.observer.disconnect();} 3004findAllShadowRoots(node,shadowRoots=[]){if(node.shadowRoot){shadowRoots.push(node.shadowRoot);this.findAllShadowRoots(node.shadowRoot,shadowRoots);} 3005node.childNodes.forEach((child)=>{this.findAllShadowRoots(child,shadowRoots);});return shadowRoots;} 3006observe(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);});} 3007observeIframe(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);}} 3008return __exports;});; 3009 3010/* /web/static/src/core/main_components_container.js */ 3011odoo.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` 3012 <div class="o-main-components-container" t-att-class="{'o_rtl': this.isRTL}"> 3013 <t t-foreach="Components.entries" t-as="C" t-key="C[0]"> 3014 <ErrorHandler onError="error => this.handleComponentError(error, C)"> 3015 <t t-component="C[1].Component" t-props="C[1].props"/> 3016 </ErrorHandler> 3017 </t> 3018 </div> 3019 `;setup(){this.Components=useRegistry(mainComponents);this.isRTL=localization.direction==="rtl";} 3020handleComponentError(error,C){this.Components.entries.splice(this.Components.entries.indexOf(C),1);this.render();Promise.resolve().then(()=>{throw error;});}} 3021return __exports;});; 3022 3023/* /web/static/src/core/model_field_selector/model_field_selector.js */ 3024odoo.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()=>
3024{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);}});} 3025openPopover(currentTarget){if(this.props.readonly){return;} 3026this.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,});} 3027async updateState(params,isConcurrent){const{resModel,path,allowEmpty}=params;let prom=this.fieldService.loadPathDescription(resModel,path,allowEmpty);if(isConcurrent){prom=this.keepLast.add(prom);} 3028const state=await prom;Object.assign(this.state,state);} 3029clear(){if(this.popover.isOpen){this.newPath="";this.popover.close();return;} 3030this.props.update("",{resModel:this.props.resModel,fieldDef:null});}} 3031return __exports;});; 3032 3033/* /web/static/src/core/model_field_selector/model_field_selector_popover.js */ 3034odoo.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();} 3035get 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}'])`;} 3036return`${previousPath}.get('${name}')`;} 3037if(name){if(previousPath){return`${previousPath}.${name}`;} 3038return name;} 3039return previousPath;} 3040get selectedField(){return this.fieldDefs[this.selectedName];} 3041get title(){const prefix=this.previousPage?.previousPage?"... > ":"";const title=this.previousPage?.selectedField?.string||"";if(prefix.length||title.length){return`${prefix}${title}`;} 3042return _t("Select a field");} 3043focus(direction){if(!this.fieldNames.length){return;} 3044const 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];}}} 3045resetFocusedFieldName(){if(this.selectedName&&this.fieldNames.includes(this.selectedName)){this.focusedFieldName=this.selectedName;}else{this.focusedFieldName=this.fieldNames.length?this.fieldNames[0]:null;}} 3046searchFields(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);} 3047return vals;});} 3048this.resetFocusedFieldName();}} 3049const 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,};
3049static 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]);} 3050get fieldNames(){return this.state.page.fieldNames;} 3051get showDebugInput(){return this.props.showDebugInput??this.props.isDebugMode;} 3052canFollowRelationFor(fieldDef){if(fieldDef.type==="properties"){return true;} 3053if(!this.props.followRelations){return false;} 3054return fieldDef.relation;} 3055filter(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]]));} 3056async 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,}));} 3057goToPreviousPage(){this.keepLast.add(Promise.resolve());this.openPage(this.state.page.previousPage);} 3058async loadNewPath(path){const newPage=await this.keepLast.add(this.loadPages(this.props.resModel,path));this.openPage(newPage);} 3059async 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,});} 3060const{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,});} 3061default:{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,});} 3062return page;}}} 3063openPage(page){this.state.page=page;this.state.page.searchFields();this.props.update(page.path);} 3064searchFields(query){this.state.page.searchFields(query);} 3065selectField(field){if(field.type==="properties"){return this.followRelation(field);} 3066this.keepLast.add(Promise.resolve());this.state.page.selectedName=field.name;this.props.update(this.state.page.path,field);this.props.close(true);} 3067onDebugInputKeydown(ev){switch(ev.key){case"Enter":{ev.preventDefault();ev.stopPropagation();this.loadNewPath(ev.currentTarget.value);break;}}} 3068async onInputKeydown(ev){const{page}=this.state;switch(ev.key){case"ArrowUp":{if(ev.target.selectionStart===0){page.focus("previous");} 3069break;} 3070case"ArrowDown":{if(ev.target.selectionStart===page.query.length){page.focus("next");} 3071break;} 3072case"ArrowLeft":{if(ev.target.selectionStart===0&&page.previousPage){this.goToPreviousPage();} 3073break;} 3074case"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);}}} 3075break;} 3076case"Enter":{const focusedFieldName=this.state.page.focusedFieldName;if(focusedFieldName){const fieldDef=this.state.page.fieldDefs[focusedFieldName];this.selectField(fieldDef);}else{ev.preventDefault();ev.stopPropagation();} 3077break;} 3078case"Escape":{ev.preventDefault();ev.stopPropagation();this.props.close();break;}}}} 3079return __exports;});; 3080 3081/* /web/static/src/core/model_selector/model_selector.js */ 3082odoo.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()=>
3082{if(!this.props.models){this.models=await this._fetchAvailableModels();}else{this.models=await this.orm.call("ir.model","display_name_for",[this.props.models,]);} 3083this.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,}),}));});} 3084get sources(){return[this.optionsSource];} 3085get placeholder(){return this.props.placeholder||_t("Type a model here...");} 3086get optionsSource(){return{placeholder:_t("Loading..."),options:this.loadOptionsSource.bind(this),};} 3087get nbVisibleModels(){return this.props.nbVisibleModels||8;} 3088filterModels(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",});} 3089return visibleModels;} 3090return fuzzyLookup(name,this.models,(model)=>model.data.technical+model.label);} 3091loadOptionsSource(request){const options=this.filterModels(request);if(!options.length){options.push({label:_t("No records"),cssClass:"o_m2o_no_result",});} 3092return options;} 3093async _fetchAvailableModels(){const result=await this.orm.call("ir.model","get_available_models");return result||[];}} 3094return __exports;});; 3095 3096/* /web/static/src/core/name_service.js */ 3097odoo.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;} 3098const nameService=__exports.nameService={dependencies:["orm"],async:["loadDisplayNames"],start(env,{orm}){let cache={};const batches={};function clearCache(){cache={};} 3099env.bus.addEventListener("ACTION_MANAGER:UPDATE",clearCache);function getMapping(resModel){if(!cache[resModel]){cache[resModel]={};} 3100return cache[resModel];} 3101function addDisplayNames(resModel,displayNames){const mapping=getMapping(resModel);for(const resId in displayNames){mapping[resId]=new Deferred();mapping[resId].resolve(displayNames[resId]);}} 3102async 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}`);} 3103if(!(resId in mapping)){mapping[resId]=new Deferred();resIdsToFetch.push(resId);} 3104proms.push(mapping[resId]);} 3105if(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);}});}} 3106const names=await Promise.all(proms);return Object.fromEntries(zip(resIds,names));} 3107return{addDisplayNames,clearCache,loadDisplayNames};},};registry.category("services").add("name",nameService);return __exports;});; 3108 3109/* /web/static/src/core/navigation/navigation.js */ 3110odoo.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;} 3111if(this.el.ariaSelected!==true){this.el.ariaSelected=false;} 3112const onFocus=()=>this.setActive(false);const onMouseMove=()=>this._onMouseMove();
3112this.target.addEventListener("focus",onFocus);this.target.addEventListener("mousemove",onMouseMove);this._removeListeners=()=>{this.target.removeEventListener("focus",onFocus);this.target.removeEventListener("mousemove",onMouseMove);};} 3113select(){this.setActive();this.target.click();} 3114setActive(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);}} 3115setInactive(blur=true){this.target.classList.remove(ACTIVE_ELEMENT_CLASS);this.target.ariaSelected=false;if(blur&&!this._options.virtualFocus){this.target.blur();}} 3116_onMouseMove(){if(this._navigator.activeItem!==this&&this._navigator._isNavigationAvailable(this.target)){this.setActive(false);this._options.onMouseEnter?.(this);}}} 3117const 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:()=>
3117this.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();}} 3118get hasActiveItem(){return Boolean(this.activeItem?.el.isConnected);} 3119get isFocused(){return this.items.some((item)=>item.target.contains(document.activeElement));} 3120next(){if(!this.hasActiveItem){this.items[0]?.setActive();}else{this.items[(this.activeItemIndex+1)%this.items.length]?.setActive();}} 3121previous(){const index=this.activeItemIndex-1;if(!this.hasActiveItem||index<0){this.items.at(-1)?.setActive();}else{this.items[index%this.items.length]?.setActive();}} 3122update(){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;} 3123oldItems.delete(element);}else{didUpdate=true;item=new NavigationItem({index,el:element,options:this._options,navigator:this,});} 3124this.items.push(item);} 3125for(const item of oldItems.values()){item._removeListeners();} 3126if(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);} 3127this._options.onUpdated?.(this);if(this._options.shouldFocusFirstItem){this.items[0]?.setActive();}}} 3128contains(target){return this.items.some((item)=>item.target.contains(target));} 3129registerHotkeys(){if(this._hotkeyRemoves.length>0){return;} 3130for(const[hotkey,hotkeyInfo]of Object.entries(this._options.hotkeys)){if
3130(!hotkeyInfo){continue;} 3131const callback=typeof hotkeyInfo=="function"?hotkeyInfo:hotkeyInfo.callback;if(!callback){continue;} 3132const 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,}));}} 3133unregisterHotkeys(){for(const removeHotkey of this._hotkeyRemoves){removeHotkey();} 3134this._hotkeyRemoves=[];} 3135_destroy(){for(const item of this.items){item._removeListeners();} 3136this.items=[];this.unregisterHotkeys();} 3137_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;}} 3138_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;}} 3139_isNavigationAvailable(target){return this._options.isNavigationAvailable({navigator:this,target});} 3140_checkFocus(target){if(!(target instanceof HTMLElement)||!this._isNavigationAvailable(target)){this._setActiveItem(-1);}}} 3141__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")??[];} 3142const 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,});} 3143return()=>observer.disconnect();},()=>[containerRef.el]);useExternalListener(browser,"focus",({target})=>navigator._checkFocus(target),true);onWillDestroy(()=>navigator._destroy());return navigator;} 3144return __exports;});; 3145 3146/* /web/static/src/core/network/download.js */ 3147odoo.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");} 3148const 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");}} 3149__exports.parse=parse;function parse(string){if(!string||typeof string!=="string"){throw new TypeError("argument string is required");} 3150let match=DISPOSITION_TYPE_REGEXP.exec(string);if(!match){throw new TypeError("invalid type format");} 3151let 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");} 3152index+=match[0].length;key=match[1].toLowerCase();value=match[2];
3152if(names.indexOf(key)!==-1){throw new TypeError("invalid duplicate parameter");} 3153names.push(key);if(key.indexOf("*")+1===key.length){key=key.slice(0,-1);value=decodefield(value);params[key]=value;continue;} 3154if(typeof params[key]==="string"){continue;} 3155if(value[0]==='"'){value=value.substr(1,value.length-2).replace(QESC_REGEXP,"$1");} 3156params[key]=value;} 3157if(index!==-1&&index!==string.length){throw new TypeError("invalid parameter format");} 3158return new ContentDisposition(type,params);} 3159function pdecode(str,hex){return String.fromCharCode(parseInt(hex,16));} 3160function ContentDisposition(type,parameters){this.type=type;this.parameters=parameters;} 3161function _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];} 3162if(url&&url.length<2048){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;} 3163return new Promise((resolve,reject)=>{let xhr=new browser.XMLHttpRequest();xhr.open("GET",url,true);configureBlobDownloadXHR(xhr,{onSuccess:resolve,onFailure:reject,url});xhr.send();});} 3164if(/^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);}} 3165blob=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);} 3166return new myBlob([uiArr],{type});} 3167function 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;} 3168if(/(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;}} 3169return true;} 3170let f=document.createElement("iframe");document.body.appendChild(f);if(!winMode){url=`data:${url.replace(/^data:([\w\/\-+]+)/, defaultMime)}`;} 3171f.src=url;setTimeout(()=>{document.body.removeChild(f);},333);} 3172if(navigator.msSaveBlob){return navigator.msSaveBlob(blob,fileName);} 3173if(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)}`);}} 3174reader=new FileReader();reader.onload=function(){saver(this.result);};reader.readAsDataURL(blob);} 3175return true;} 3176__exports.downloadFile=downloadFile;function downloadFile(data,filename,mimetype){return downloadFile._download(data,filename,mimetype);} 3177downloadFile._download=_download;__exports.download=download;function download(options){return download._download(options);} 3178download._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();
3178Object.entries(options.data).forEach((entry)=>{const[key,value]=entry;data.append(key,value);});} 3179data.append("token","dummy-because-api-expects-one");if(odoo.csrf_token){data.append("csrf_token",odoo.csrf_token);} 3180configureBlobDownloadXHR(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 : ""} 3181 ${nodes.length > 1 ? nodes[1].textContent : ""}`,},};} 3182error=makeErrorFromResponse(error);onFailure(error);};decoder.readAsText(xhr.response);}};xhr.onerror=()=>{onFailure(new ConnectionLostError(url));};} 3183return __exports;});; 3184 3185/* /web/static/src/core/network/http_service.js */ 3186odoo.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");} 3187if(response.status===413){throw new Error("Content too large");}} 3188__exports.get=get;async function get(route,readMethod="json"){const response=await browser.fetch(route,{method:"GET"});checkResponseStatus(response);return response[readMethod]();} 3189__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);}}} 3190const response=await browser.fetch(route,{body:formData,method:"POST",});checkResponseStatus(response);return response[readMethod]();} 3191const httpService=__exports.httpService={start(){return{get,post};},};registry.category("services").add("http",httpService);return __exports;});; 3192 3193/* /web/static/src/core/network/rpc.js */ 3194odoo.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(" ")}`);} 3195if("cache"in settings&&"xhr"in settings){throw new Error("Can't use 'cache' and 'xhr' at the same time");}} 3196const 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;}} 3197const 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;}} 3198const ConnectionAbortedError=__exports.ConnectionAbortedError=class ConnectionAbortedError extends
3198Error{} 3199const RequestEntityTooLargeError=__exports.RequestEntityTooLargeError=class RequestEntityTooLargeError extends Error{constructor(){super("The request you sent exceeded the maximum size limit configured on the server");}} 3200__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;} 3201let 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);} 3202rpc._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);} 3203const 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;} 3204if(specialError){rpcBus.trigger("RPC:RESPONSE",{data,settings,error:specialError});reject(specialError);return;} 3205let params;try{params=JSON.parse(request.response);}catch{const error=new ConnectionLostError(url);rpcBus.trigger("RPC:RESPONSE",{data,settings,error});return reject(error);} 3206const{error:responseError,result:responseResult}=params;if(!params.error){rpcBus.trigger("RPC:RESPONSE",{data,settings,result:params.result});return resolve(responseResult);} 3207const 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);} 3208request.send(JSON.stringify(data));});promise.abort=function(rejectError=true){if(request.abort){request.abort();} 3209const error=new ConnectionAbortedError("XmlHttpRequestError abort");rpcBus.trigger("RPC:RESPONSE",{data,settings,error});if(rejectError){rejectFn(error);}};return promise;};return __exports;});; 3210 3211/* /web/static/src/core/network/rpc_cache.js */ 3212odoo.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);} 3213function validateSettings({type,update}){if(!["ram","disk"].includes(type)){throw new Error(`Invalid "type" settings provided to RPCCache: ${type}`);} 3214if(!["always","once"].includes(update)){throw new Error(`Invalid "update" settings provided to RPCCache: ${update}`);}} 3215const 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;});} 3216async 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};} 3217async decrypt({ciphertext,iv}){await this._ready;
3217const decrypted=await window.crypto.subtle.decrypt({name:CRYPTO_ALGO,iv,length:64,},this._cryptoKey,ciphertext);return JSON.parse(new TextDecoder().decode(decrypted));}} 3218class RamCache{constructor(){this.ram={};} 3219write(table,key,value){if(!(table in this.ram)){this.ram[table]={};} 3220this.ram[table][key]=value;} 3221read(table,key){return this.ram[table]?.[key];} 3222delete(table,key){delete this.ram[table]?.[key];} 3223invalidate(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={};}}} 3224const 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();} 3225async 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();}} 3226read(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));} 3227if(!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;} 3228delete 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;}});});} 3229return result;};const onRejected=async(error)=>{await fromCache;if(!request.invalidated){delete this.pendingRequests[requestKey];if(!fromCacheValue){this.ramCache.delete(table,key);}} 3230if(fromCacheValue){throw error;} 3231reject(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;} 3232resolve(decrypted);fromCacheValue=decrypted;}}).finally(()=>fromCache.resolve());}else{fromCache.resolve();}});this.ramCache.write(table,key,prom);ramValue=prom;} 3233return ramValue.then((result)=>deepCopy(result));} 3234invalidate(tables){this.indexedDB.invalidate(tables);this.ramCache.invalidate(tables);for(const key in this.pendingRequests){this.pendingRequests[key].invalidated=true;} 3235this.pendingRequests={};}} 3236return __exports;});; 3237 3238/* /web/static/src/core/notebook/notebook.js */ 3239odoo.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);});} 3240get navItems(){return this.pages.filter((e)=>
3240e[1].isVisible);} 3241get page(){const page=this.pages.find((e)=>e[0]===this.state.currentPage)[1];return page.Component&&page;} 3242async 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;}}} 3243computePages(props){if(!props.slots&&!props.pages){return[];} 3244if(props.pages){for(const page of props.pages){page.isVisible=true;}} 3245this.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]);} 3246if(v.isDisabled){this.disabledPages.push(k);}} 3247for(const page of pagesWithIndex){pages.splice(page[1].index,0,page);} 3248return pages;} 3249computeActivePage(defaultPage,activateDefault){if(!this.pages.length){return null;} 3250const 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;}}} 3251const current=this.state.currentPage;if(!current||(current&&!pages.includes(current))){return pages[0];} 3252return current;} 3253computeInvalidPages(){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]);}}}} 3254return __exports;});; 3255 3256/* /web/static/src/core/notifications/notification.js */ 3257odoo.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());} 3258freeze(){this.startedTimestamp=false;this.autocloseProgress.el.style.width=0;} 3259refresh(){this.startNotificationTimer();} 3260close(){this.props.close();} 3261startNotificationTimer(){if(this.props.sticky){return;} 3262this.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;} 3263if(this.autocloseProgress.el){this.autocloseProgress.el.style.width=`${(1 - currentProgress) * 100}%`;} 3264requestAnimationFrame(cb);}};cb();}} 3265return __exports;});; 3266 3267/* /web/static/src/core/notifications/notification_container.js */ 3268odoo.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` 3269 <div class="o_notification_manager"> 3270 <t t-foreach="notifications" t-as="notification" t-key="notification"> 3271 <Transition leaveDuration="0" immediate="true" name="'o_notification_fade'" t-slot-scope="transition"> 3272 <Notification t-props="notification_value.props" className="(notification_value.props.className || '') + ' ' + transition.className"/> 3273 </Transition> 3274 </t> 3275 </div>`;static components={Notification,Transition};setup(){this.notifications=useState(this.props.notifications);}} 3276return __exports;});; 3277 3278/* /web/static/src/core/notifications/notification_service.js */ 3279odoo.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;}
3280function close(id){if(notifications[id]){const notification=notifications[id];if(notification.onClose){notification.onClose();} 3281delete notifications[id];}} 3282return{add};},};registry.category("services").add("notification",notificationService);return __exports;});; 3283 3284/* /web/static/src/core/orm_service.js */ 3285odoo.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}`);}} 3286function validatePrimitiveList(name,type,value){if(!Array.isArray(value)||value.some((val)=>typeof val!==type)){throw new Error(`Invalid ${name} list: ${value}`);}} 3287function validateObject(name,obj){if(typeof obj!=="object"||obj===null||Array.isArray(obj)){throw new Error(`${name} should be an object`);}} 3288function validateArray(name,array){if(!Array.isArray(array)){throw new Error(`${name} should be an array`);}} 3289const 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;} 3290get silent(){return Object.assign(Object.create(this),{_silent:true});} 3291cache(options={}){return Object.assign(Object.create(this),{_cache:options});} 3292call(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,});} 3293create(model,records,kwargs={}){validateArray("records",records);for(const record of records){validateObject("record",record);} 3294return this.call(model,"create",[records],kwargs);} 3295read(model,ids,fields,kwargs={}){validatePrimitiveList("ids","number",ids);if(fields){validatePrimitiveList("fields","string",fields);} 3296if(!ids.length){return Promise.resolve([]);} 3297return this.call(model,"read",[ids,fields],kwargs);} 3298formattedReadGroup(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();} 3299return res;});} 3300formattedReadGroupingSets(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();}} 3301return res;});} 3302search(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"search",[domain],kwargs);} 3303searchRead(model,domain,fields,kwargs={}){validateArray("domain",domain);if(fields){validatePrimitiveList("fields","string",fields);} 3304return this.call(model,"search_read",[],{...kwargs,domain,fields});} 3305searchCount(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"search_count",[domain],kwargs);} 3306unlink(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);if(!ids.length){return Promise.resolve(true);} 3307return this.call(model,"unlink",[ids],kwargs);} 3308webReadGroup(model,domain,groupby,aggregates,kwargs={}){validateArray("domain",domain);validatePrimitiveList("aggregates","string",aggregates);return this.call(model,"web_read_group",[],{domain,groupby,aggregates,...kwargs,});} 3309webRead(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);return this.call(model,"web_read",[ids],kwargs);} 3310webResequence(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);
3310return this.call(model,"web_resequence",[ids],{...kwargs,specification:kwargs.specification||{},});} 3311webSearchRead(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"web_search_read",[],{...kwargs,domain});} 3312write(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateObject("data",data);return this.call(model,"write",[ids,data],kwargs);} 3313webSave(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateObject("data",data);return this.call(model,"web_save",[ids,data],kwargs);} 3314async 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);}} 3315const 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;});; 3316 3317/* /web/static/src/core/overlay/overlay_container.js */ 3318odoo.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;} 3319useChildSubEnv({[OVERLAY_SYMBOL]:{contains:(target)=>this.contains(target),},});} 3320get subOverlays(){return OVERLAY_ITEMS.slice(OVERLAY_ITEMS.indexOf(this));} 3321contains(target){return(this.rootRef.el?.contains(target)||this.subOverlays.some((oi)=>oi.rootRef.el?.contains(target)));}} 3322const 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});} 3323get sortedOverlays(){return sortBy(Object.values(this.props.overlays),(overlay)=>overlay.sequence);} 3324isVisible(overlay){return overlay.rootId===this.env?.rootId;} 3325handleError(overlay,error){overlay.remove();Promise.resolve().then(()=>{throw error;});}} 3326return __exports;});; 3327 3328/* /web/static/src/core/overlay/overlay_service.js */ 3329odoo.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;});; 3330 3331/* /web/static/src/core/pager/pager.js */ 3332odoo.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,});} 3333firstMount=false;},()=>[this.props.offset,this.props.limit,this.props.total]);} 3334get minimum(){return this.props.offset+1;} 3335get maximum(){return Math.min(this.props.offset+this.props.limit,this.props.total);} 3336get value(){const parts=[this.minimum];if(this.props.limit>1){parts.push(this.maximum);} 3337return parts.join("-");} 3338get isSinglePage(){return!this.props.updateTotal&&this.minimum===1&&this.maximum===this.props.total;} 3339async 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();} 3340if(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);} 3341this.update(minimum,this.props.limit,true);} 3342async 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};} 3343return{minimum:clamp(minimum,1,this.props.total)-1,maximum:clamp(maximum,1,this.props.total),};} 3344async setValue(value){const{minimum,maximum}=await this.parse(value);if(!isNaN(minimum)&&!isNaN(maximum)&&minimum<maximum){this.update(minimum,maximum-minimum);}} 3345async 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;}} 3346async updateTotal(){if(!this.state.isDisabled){this.state.isDisabled=true;await this.props.updateTotal();this.state.isDisabled=false;}} 3347onClickAway(ev){if(ev.target!==this.inputRef.el){this.state.isEditing=false;}} 3348onInputBlur(){this.state.isEditing=false;} 3349onInputChange(ev){this.setValue(ev.target.value);if(!this.state.isDisabled){ev.preventDefault();}} 3350onInputKeydown(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;}} 3351onValueClick(){if(this.props.isEditable&&!this.state.isEditing&&!this.state.isDisabled){if(this.inputRef.el){this.inputRef.el.focus();} 3352this.state.isEditing=true;}}} 3353return __exports;});; 3354 3355/* /web/static/src/core/pager/pager_indicator.js */ 3356odoo.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);} 3357pagerUpdate({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);}} 3358registry.category("main_components").add("PagerIndicator",{Component:PagerIndicator,});return __exports;});; 3359 3360/* /web/static/src/core/popover/popover.js */ 3361odoo.define('@web/core/popover/popover',['@odoo/owl','@web/core/h
3361otkeys/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));} 3362function useClickAway(popover,callback){function blurHandler(ev){const target=ev.relatedTarget||document.activeElement;if(target?.tagName==="IFRAME"){callback(target);}} 3363function navigationHandler(){callback(document.documentElement);} 3364function pointerDownHandler(ev){callback(ev.composedPath()[0]);} 3365useEarlyExternalListener(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;} 3366checkEl=checkEl.parentElement;} 3367callback(iframeEl);},{capture:true,once:true});}catch(e){if(e.name!=="SecurityError")throw e;}}} 3368const POPOVERS=new WeakMap();__exports.getPopoverForTarget=getPopoverForTarget;function getPopoverForTarget(target){return POPOVERS.get(target);} 3369const 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");} 3370useForwardRefToParent("ref");this.popoverRef=useRef("ref");this.position=usePosition("ref",()=>this.props.target,this.positioningOptions);if(!this.props.animation){this.animationDone=true;} 3371const 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());} 3372const targetObserver=new MutationObserver(this.onTargetMutate.bind(this));targetObserver.observe(this.props.target.parentElement,{childList:true});onWillDestroy(()=>targetObserver.disconnect());}else{this.props.close();}} 3373get defaultClassObj(){return mergeClasses("o_popover popover mw-100 bs-popover-auto",this.props.class);} 3374get 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,};} 3375animate(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);} 3376isInside(target){return(this.props.target?.contains(target)||this.popoverRef?.el?.contains(target)||this.env[OVERLAY_SYMBOL]?.contains(target));} 3377onClickAway(target){if(this.props.closeOnClickAway(target)&&!this.isInside(target)){this.props.close();}} 3378onPositioned({direction,variant,variantOffset}){if(this.props.arrow){this.updateArrow(direction,variant,variantOffset);} 3379if(this.props.animation&&!this.animationDone){this.position.lock();this.animate(direction).finished.then(()=>{this.animationDone=true;if(!this.props.fixedPosition){this.position.unlock();}});} 3380if(this.props.fixedPosition){this.position.lock();}} 3381onTargetMutate(){if(!this.props.target.isConnected){this.props.close();}} 3382updateArrow(direction,variant,variantOffset){const{el}=this.popoverRef;[direction,variant]=reverseForRTL(direction,variant);el.dataset.popperPlacement=direction;const vertical=["top","bottom"].includes(direction);
3382const 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( 3383 var(--position-min), 3384 calc(var(${placement}) - ${variantOffset}px), 3385 var(--position-max) 3386 )`,});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);}} 3387return __exports;});; 3388 3389/* /web/static/src/core/popover/popover_hook.js */ 3390odoo.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?.();} 3391return{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);},};} 3392__exports.usePopover=usePopover;function usePopover(component,options={}){let service;if(options.useBottomSheet){service=useService("bottom_sheet");}else{service=useService("popover");} 3393const 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;} 3394return __exports;});; 3395 3396/* /web/static/src/core/popover/popover_service.js */ 3397odoo.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;});; 3398 3399/* /web/static/src/core/position/position_hook.js */ 3400odoo.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;} 3401const 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()=>
3401{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});} 3402const throttledUpdate=useThrottleForAnimation(()=>bus.trigger("update"));useEffect(()=>{bus.trigger("update");if(isTopmost){const scrollListener=(e)=>{if(ref.el?.contains(e.target)){return;} 3403throttledUpdate();};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{}}} 3404for(const document of documents){document.addEventListener("scroll",scrollListener,{capture:true});document.addEventListener("load",throttledUpdate,{capture:true});} 3405window.addEventListener("resize",throttledUpdate);return()=>{for(const document of documents){document.removeEventListener("scroll",scrollListener,{capture:true});document.removeEventListener("load",throttledUpdate,{capture:true});} 3406window.removeEventListener("resize",throttledUpdate);};}});return{lock:()=>{lock=true;},unlock:()=>{lock=false;bus.trigger("update");},};} 3407return __exports;});; 3408 3409/* /web/static/src/core/position/utils.js */ 3410odoo.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));} 3411__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";}} 3412return[direction,variant];} 3413function 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];} 3414const variants=VARIANT_FLIP_ORDER[variant];if(!container){container=popper.ownerDocument.documentElement;}else if(typeof container==="function"){container=container();} 3415if(variant==="fit"){const styleProperty=["top","bottom"].includes(direction)?"width":"height";popper.style[styleProperty]=getComputedStyle(target)[styleProperty];} 3416const 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-
3416popBox.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;}} 3417let 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);} 3418let 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);} 3419let 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];} 3420result.maxHeight=Math.floor(height);} 3421return{result,malus};} 3422const matches=[];for(const d of directions){for(const v of variants){const match=getPositioningData(d,v);if(!match.malus){return match.result;} 3423matches.push(match);} 3424if(!flip){break;}} 3425return matches.sort((a,b)=>a.malus-b.malus)[0].result;} 3426__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";} 3427return solution;} 3428return __exports;});; 3429 3430/* /web/static/src/core/pwa/install_prompt.js */ 3431odoo.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();} 3432onClose(){this.props.close();this.props.onClose();}} 3433return __exports;});; 3434 3435/* /web/static/src/core/pwa/pwa_service.js */ 3436odoo.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]:"";} 3437function _setInstallationState(value){const ls=JSON.parse(browser.localStorage.getItem("pwaService.installationState")||"{}");ls[state.startUrl]=value;browser.localStorage.setItem("pwaService.installationState",JSON.stringify(ls));} 3438function _removeInstallationState(){const ls=JSON.parse(browser.localStorage.getItem("pwaService.installationState"));delete ls[state.startUrl];browser.localStorage.setItem("pwaService.installationState",JSON.stringify(ls));} 3439if(state.isScopedApp){if(browser.location.pathname==="/scoped_app"){state.startUrl="/"+new URL(browser.location.href).searchParams.get("path");}else{state.startUrl=browser.location.pathname;}} 3440state.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
3440FOREINSTALLPROMPT_EVENT,installationState);BEFOREINSTALLPROMPT_EVENT=null;} 3441REGISTER_BEFOREINSTALLPROMPT_EVENT=(ev)=>{_handleBeforeInstallPrompt(ev,installationState);};if(isBrowserSafari()){state.canPromptToInstall=installationState!=="dismissed";state.isAvailable=true;}} 3442function _handleBeforeInstallPrompt(ev,installationState){nativePrompt=ev;if(installationState==="accepted"){if(!isDisplayStandalone()){_removeInstallationState();}} 3443state.canPromptToInstall=installationState!=="dismissed";state.isAvailable=true;} 3444async function getManifest(){if(!_manifest){const manifest=await get(document.querySelector("link[rel=manifest]")?.getAttribute("href"),"text");_manifest=JSON.parse(manifest);} 3445return _manifest;} 3446function hasScopeBeenInstalled(scope){return _getInstallationState(scope)==="accepted";} 3447async function show({onDone}={}){if(!state.isAvailable){return;} 3448if(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({});} 3449this.decline();},});}} 3450function decline(){_setInstallationState("dismissed");state.canPromptToInstall=false;} 3451return state;},};serviceRegistry.add("pwa",pwaService);return __exports;});; 3452 3453/* /web/static/src/core/py_js/py.js */ 3454odoo.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);} 3455__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}`);} 3456try{return evaluate(ast,context);}catch(error){throw new EvalError(`Can not evaluate python expression: (${expr})\nError: ${error.message}`);}} 3457__exports.evaluateBooleanExpr=evaluateBooleanExpr;function evaluateBooleanExpr(expr,context={}){if(!expr||expr==='False'||expr==='0'){return false;} 3458if(expr==='True'||expr==='1'){return true;} 3459return evaluateExpr(`bool(${expr})`,context);} 3460return __exports;});; 3461 3462/* /web/static/src/core/py_js/py_builtin.js */ 3463odoo.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{} 3464__exports.execOnIterable=execOnIterable;function execOnIterable(iterable,func){if(iterable===null){throw new EvaluationError(`value not iterable`);} 3465if(typeof iterable==="object"&&!Array.isArray(iterable)&&!(iterable instanceof Set)){iterable=Object.keys(iterable);} 3466if(typeof iterable?.[Symbol.iterator]!=="function"){throw new EvaluationError(`value not iterable`);} 3467return func(iterable);} 3468const 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;} 3469if(value.isTrue){return value.isTrue();} 3470if(value instanceof Array){return!!value.length;} 3471if(value instanceof Set){return!!value.size;} 3472return Object.keys(value).length!==0;} 3473return true;},set(iterable){if(arguments.length>2){throw new EvaluationError(`set expected at most 1 argument, got (${arguments.length - 1}`);} 3474return 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,}
3474,relativedelta:PyRelativeDelta,true:true,false:false,};return __exports;});; 3475 3476/* /web/static/src/core/py_js/py_date.js */ 3477odoo.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{} 3478const ValueError=__exports.ValueError=class ValueError extends Error{} 3479const NotSupportedError=__exports.NotSupportedError=class NotSupportedError extends Error{} 3480function fmt2(n){return String(n).padStart(2,"0");} 3481function fmt4(n){return String(n).padStart(4,"0");} 3482function divmod(a,b,fn){let mod=a%b;if((mod>0&&b<0)||(mod<0&&b>0)){mod+=b;} 3483return fn(Math.floor(a/b),mod);} 3484function assert(bool,message="AssertionError"){if(!bool){throw new AssertionError(message);}} 3485const 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];} 3486function daysInMonth(year,month){if(month===2&&isLeap(year)){return 29;} 3487return DAYS_IN_MONTH[month];} 3488function isLeap(year){return year%4===0&&(year%100!==0||year%400===0);} 3489function daysBeforeYear(year){const y=year-1;return y*365+Math.floor(y/4)-Math.floor(y/100)+Math.floor(y/400);} 3490function daysBeforeMonth(year,month){const postLeapFeb=month>2&&isLeap(year);return DAYS_BEFORE_MONTH[month]+(postLeapFeb?1:0);} 3491function ymd2ord(year,month,day){const dim=daysInMonth(year,month);if(!(1<=day&&day<=dim)){throw new ValueError(`day must be in 1..${dim}`);} 3492return daysBeforeYear(year)+daysBeforeMonth(year,month)+day;} 3493const 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,};} 3494const 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);} 3495n-=preceding;return{year:year,month:month,day:n+1,};} 3496function 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;});} 3497if(second<0||second>59){divmod(second,60,function(carry,s){second=s;minute+=carry;});} 3498if(minute<0||minute>59){divmod(minute,60,function(carry,m){minute=m;hour+=carry;});} 3499if(hour<0||hour>23){divmod(hour,24,function(carry,h){hour=h;day+=carry;});} 3500if(month<1||month>12){divmod(month-1,12,function(carry,m){month=m+1;year+=carry;});} 3501const 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;}} 3502return{year:year,month:month,day:day,hour:hour,minute:minute,second:second,microsecond:microsecond,};} 3503const PyDate=__exports.PyDate=class PyDate{static today(){return this.convertDate(new Date());} 3504static convertDate(date){const year=date.getFullYear();const month=date.getMonth()+1;const day=date.getDate();return new PyDate(year,month,day);} 3505constructor(year,month,day){this.year=year;this.month=month;this.day=day;} 3506static create(...args){const{year,month,day}=parseArgs(args,["year","month","day"]);return new PyDate(year,month,day);} 3507add(timedelta){const s=tmxxx(this.year,this.month,this.day+timedelta.days);return new PyDate(s.year,s.month,s.day);} 3508isEqual(other){if(!(other instanceof PyDate)){return false;} 3509return this.year===other.year&&this.month===other.month&&this.day===other.day;} 3510strftime(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);} 3511throw new ValueError(`No known conversion for ${m}`);});} 3512substract(other){if(other instanceof PyTimeDelta){return this.add(other.negate());}
3513if(other instanceof PyDate){return PyTimeDelta.create(this.toordinal()-other.toordinal());} 3514throw new NotSupportedError();} 3515toJSON(){return this.strftime("%Y-%m-%d");} 3516toordinal(){return ymd2ord(this.year,this.month,this.day);}} 3517const PyDateTime=__exports.PyDateTime=class PyDateTime{static now(){return this.convertDate(new Date());} 3518static 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);} 3519static 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);} 3520static combine(...args){const{date,time}=parseArgs(args,["date","time"]);return PyDateTime.create(date.year,date.month,date.day,time.hour,time.minute,time.second);} 3521constructor(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;} 3522add(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);} 3523isEqual(other){if(!(other instanceof PyDateTime)){return false;} 3524return(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);} 3525strftime(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);} 3526throw new ValueError(`No known conversion for ${m}`);});} 3527substract(timedelta){return this.add(timedelta.negate());} 3528toJSON(){return this.strftime("%Y-%m-%d %H:%M:%S");} 3529to_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);}} 3530const 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);} 3531constructor(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;} 3532strftime(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);} 3533throw new ValueError(`No known conversion for ${m}`);});} 3534toJSON(){return this.strftime("%H:%M:%S");}} 3535const 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");} 3536for(const period of PERIODS){if(period in params){const val=params[period];assert(val>=0,`${period} ${val} is out of range`);}} 3537for(const key of RELATIVE_KEYS){params[key]=params[key]||0;} 3538for(const key of ABSOLUTE_KEYS){params[key]=key in params?params[key]:null;} 3539params.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;}} 3540if(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];} 3541break;}}} 3542return new PyRelativeDelta(params);} 3543static add(date,delta){if(!(date instanceof PyDate||date instanceof PyDateTime)){throw new NotSupportedError();} 3544const 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;}
3545const 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));} 3546return returnDate;} 3547static substract(date,delta){return PyRelativeDelta.add(date,delta.negate());} 3548constructor(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;} 3549negate(){return new PyRelativeDelta(this,-1);} 3550isEqual(other){throw new NotSupportedError();}} 3551const 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)];} 3552const 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;} 3553let 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;} 3554const[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);} 3555constructor(days,seconds,microseconds){this.days=days;this.seconds=seconds;this.microseconds=microseconds;}
3556add(other){return PyTimeDelta.create({days:this.days+other.days,seconds:this.seconds+other.seconds,microseconds:this.microseconds+other.microseconds,});} 3557divide(n){const us=(this.days*24*3600+this.seconds)*1e6+this.microseconds;return PyTimeDelta.create({microseconds:Math.floor(us/n)});} 3558isEqual(other){if(!(other instanceof PyTimeDelta)){return false;} 3559return(this.days===other.days&&this.seconds===other.seconds&&this.microseconds===other.microseconds);} 3560isTrue(){return this.days!==0||this.seconds!==0||this.microseconds!==0;} 3561multiply(n){return PyTimeDelta.create({days:n*this.days,seconds:n*this.seconds,microseconds:n*this.microseconds,});} 3562negate(){return PyTimeDelta.create({days:-this.days,seconds:-this.seconds,microseconds:-this.microseconds,});} 3563substract(other){return PyTimeDelta.create({days:this.days-other.days,seconds:this.seconds-other.seconds,microseconds:this.microseconds-other.microseconds,});} 3564total_seconds(){return this.days*86400+this.seconds+this.microseconds/1000000;}} 3565return __exports;});; 3566 3567/* /web/static/src/core/py_js/py_interpreter.js */ 3568odoo.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();} 3569return-value;case"+":return value;case"not":return!isTrue(value);} 3570throw new EvaluationError(`Unknown unary operator: ${ast.op}`);} 3571function pytypeIndex(val){switch(typeof val){case"object":return val===null?1:Array.isArray(val)?5:3;case"number":return 2;case"string":return 4;} 3572throw new EvaluationError(`Unknown type: ${typeof val}`);} 3573function isConstructor(obj){return!!obj.prototype&&!!obj.prototype.constructor.name;} 3574function isLess(left,right){if(typeof left==="number"&&typeof right==="number"){return left<right;} 3575if(typeof left==="boolean"){left=left?1:0;} 3576if(typeof right==="boolean"){right=right?1:0;} 3577const leftIndex=pytypeIndex(left);const rightIndex=pytypeIndex(right);if(leftIndex===rightIndex){return left<right;} 3578return leftIndex<rightIndex;} 3579function isEqual(left,right){if(typeof left!==typeof right){if(typeof left==="boolean"&&typeof right==="number"){return right===(left?1:0);} 3580if(typeof left==="number"&&typeof right==="boolean"){return left===(right?1:0);} 3581return false;} 3582if(left instanceof Object&&left.isEqual){return left.isEqual(right);} 3583return left===right;} 3584function isIn(left,right){if(Array.isArray(right)){return right.includes(left);} 3585if(typeof right==="string"&&typeof left==="string"){return right.includes(left);} 3586if(typeof right==="object"){return left in right;} 3587return false;} 3588function 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);} 3589const timeDeltaOnLeft=left instanceof PyTimeDelta;const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnLeft&&timeDeltaOnRight){return left.add(right);} 3590if(timeDeltaOnLeft){if(right instanceof PyDate||right instanceof PyDateTime){return right.add(left);}else{throw new NotSupportedError();}} 3591if(timeDeltaOnRight){if(left instanceof PyDate||left instanceof PyDateTime){return left.add(right);}else{throw new NotSupportedError();}} 3592if(left instanceof Array&&right instanceof Array){return[...left,...right];} 3593return left+right;} 3594case"-":{const isRightDelta=right instanceof PyRelativeDelta;if(isRightDelta){return PyRelativeDelta.substract(left,right);} 3595const 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();}} 3596if(left instanceof PyDate){return left.substract(right);} 3597return left-right;} 3598case"*":{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);} 3599return left*right;} 3600case"/":return left/right;case"%":return left%right;
3600case"//":if(left instanceof PyTimeDelta){return left.divide(right);} 3601return 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);} 3602throw new EvaluationError(`Unknown binary operator: ${ast.op}`);} 3603const DICT={get(...args){const{key,defValue}=parseArgs(args,["key","defValue"]);if(key in this){return this[key];}else if(defValue){return defValue;} 3604return 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);} 3605if(args.length>2){throw new EvaluationError(`${key}: py_js supports at most 1 argument, got (${args.length - 1})`);} 3606return execOnIterable(args[0],func);} 3607const SET={intersection(...args){return applyFunc("intersection",(iterable)=>{const intersection=new Set();for(const i of iterable){if(this.has(i)){intersection.add(i);}} 3608return 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);}} 3609return 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]);} 3610const 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
3610(!pyContext){pyContext=toPyDict(context);} 3611return pyContext;},});} 3612function _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`);} 3613case 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);}} 3614case 4:case 10:return ast.value.map(_evaluate);case 11:{const dict={};for(const key in ast.value){dict[key]=_evaluate(ast.value[key]);} 3615dicts.add(dict);return dict;} 3616case 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]);} 3617if(fnValue===PyDate||fnValue===PyDateTime||fnValue===PyTime||fnValue===PyRelativeDelta||fnValue===PyTimeDelta){return fnValue.create(...args,kwargs);} 3618return fnValue(...args,kwargs);} 3619case 12:{const dict=_evaluate(ast.target);const key=_evaluate(ast.key);return dict[key];} 3620case 13:{if(isTrue(_evaluate(ast.condition))){return _evaluate(ast.ifTrue);}else{return _evaluate(ast.ifFalse);}} 3621case 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];} 3622if(typeof result==="function"){if(!isConstructor(result)){const bound=result.bind(left);bound[unboundFn]=result;return bound;}} 3623return result;}} 3624throw new EvaluationError(`AST of type ${ast.type} cannot be evaluated`);} 3625function _evaluate(ast){const val=_innerEvaluate(ast);if(typeof val==="function"&&!allowedFns.has(val)&&!allowedFns.has(val[unboundFn])){throw new Error("Invalid Function Call");} 3626return val;} 3627return _evaluate(ast);} 3628return __exports;});; 3629 3630/* /web/static/src/core/py_js/py_parser.js */ 3631odoo.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{} 3632const 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;} 3633return 0;} 3634function bindingPower(token){return token.type===2?bp(token.value):0;} 3635function isSymbol(token,value){return token.type===2&&token.value===value;} 3636function 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"};} 3637case 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");}} 3638if(!tokens[0]||!isSymbol(tokens[0],")")){throw new ParserError("parsing error");} 3639tokens.shift();isTuple=isTuple||content.length===0;return isTuple?{type:10,value:content}:content[0];} 3640case"[":{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");}}} 3641if(!tokens[0]||!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");} 3642tokens.shift();return{type:4,value};} 3643case"{":{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");} 3644tokens.shift();const value=_parse(tokens,0);dict[key.value]=value;if(isSymbol(tokens[0],",")){tokens.shift();}} 3645if(!tokens.shift()){throw new ParserError("parsing error");} 3646return{type:11,value:dict};}}} 3647throw new ParserError("Token cannot be parsed");} 3648function 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");}} 3649let op={type:7,op:current.value,left,right,};
3649while(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;} 3650return op;} 3651switch(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);} 3652if(tokens[0]&&isSymbol(tokens[0],",")){tokens.shift();}} 3653if(!tokens[0]||!isSymbol(tokens[0],")")){throw new ParserError("parsing error");} 3654tokens.shift();return{type:8,fn:left,args,kwargs};} 3655case"=":if(left.type===5){return{type:9,name:left,value:_parse(tokens,10),};} 3656break;case"[":{const key=_parse(tokens);if(!tokens[0]||!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");} 3657tokens.shift();return{type:12,target:left,key:key,};} 3658case"if":{const condition=_parse(tokens);if(!tokens[0]||!isSymbol(tokens[0],"else")){throw new ParserError("parsing error");} 3659tokens.shift();const ifFalse=_parse(tokens);return{type:13,condition,ifTrue:left,ifFalse,};}}} 3660throw new ParserError("Token cannot be parsed");} 3661function _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);} 3662return expr;} 3663__exports.parse=parse;function parse(tokens){if(tokens.length){const ast=_parse(tokens,0);if(tokens.length){throw new ParserError("Token(s) unused");} 3664return ast;} 3665throw new ParserError("Missing token");} 3666__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;} 3667return kwargs;} 3668return __exports;});; 3669 3670/* /web/static/src/core/py_js/py_tokenizer.js */ 3671odoo.define('@web/core/py_js/py_tokenizer',[],function(require){'use strict';let __exports={};const TokenizerError=__exports.TokenizerError=class TokenizerError extends Error{} 3672const 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;} 3673var escape=str[i+1];if(escape in directMap){out.push(directMap[escape]);++i;continue;} 3674switch(escape){case"\n":++i;continue;case"N":if(!unicode){break;} 3675throw new TokenizerError("SyntaxError: \\N{} escape not implemented");case"u":if(!unicode){break;} 3676var 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(""));} 3677code=parseInt(uni,16);out.push(String.fromCharCode(code));i+=5;continue;case"U":if(!unicode){break;} 3678throw 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");} 3679throw new TokenizerError(["SyntaxError: (unicode error) 'unicodeescape'"," codec can't decode bytes in position ",i,"-",i+2,": truncated \\xXX escape",].join(""));} 3680code=parseInt(hex,16);out.push(String.fromCharCode(code));i+=3;continue;default:if(!/[0-8]/.test(escape)){break;} 3681var 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;} 3682out.push("\\");} 3683return out.join("");} 3684const 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("|")+")";} 3685const 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);
3685if(!pseudomatch){if(/^\s+$/.test(str.slice(end))){break;} 3686throw new TokenizerError("Failed to tokenize <<"+ 3687str+">> at index "+ 3688(end||0)+"; parsed so far: "+ 3689tokens);} 3690if(pseudomatch.index>end){if(str.slice(end,pseudomatch.index).trim()){throw new TokenizerError("Invalid expression");}} 3691start=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();} 3692tokens.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");}} 3693return tokens;} 3694return __exports;});; 3695 3696/* /web/static/src/core/py_js/py_utils.js */ 3697odoo.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]);} 3698return{type:11,value:content};} 3699default:throw new Error("Invalid type");}} 3700__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);} 3701return 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;} 3702case 11:{const pairs=[];for(const k in ast.value){pairs.push(`"${k}": ${formatAST(ast.value[k])}`);} 3703return`{`+pairs.join(", ")+`}`;} 3704case 10:return`(${ast.value.map(formatAST).join(", ")})`;case 5:return ast.value;case 12:{return`${formatAST(ast.target)}[${formatAST(ast.key)}]`;} 3705case 13:{const{ifTrue,condition,ifFalse}=ast;return`${formatAST(ifTrue)} if ${formatAST(condition)} else ${formatAST(ifFalse)}`;} 3706case 14:{const abp=bp(ast.op);const str=`${formatAST(ast.left, abp)} ${ast.op} ${formatAST(ast.right, abp)}`;return abp<lbp?`(${str})`:str;} 3707case 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])}`);} 3708const argStr=args.concat(kwargs).join(", ");return`${formatAST(ast.fn)}(${argStr})`;}} 3709throw new Error("invalid expression: "+ast);} 3710const PY_DICT=__exports.PY_DICT=Object.create(null);__exports.toPyDict=toPyDict;function toPyDict(obj){return new Proxy(obj,{getPrototypeOf(){return PY_DICT;},});} 3711return __exports;});; 3712 3713/* /web/static/src/core/record_selectors/multi_record_selector.js */ 3714odoo.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));} 3715get isAvatarModel(){return["res.partner","res.users","hr.employee","hr.employee.public"].includes(this.props.resModel);} 3716async computeDerivedParams(props=this.props){const displayNames=await this.getDisplayNames(props);this.tags=this.getTags(props,displayNames);} 3717async getDisplayNames(props){const ids=this.getIds(props);return this.nameService.loadDisplayNames(props.resModel,ids);} 3718get placeholder(){return this.getTags(this.props,{}).length?"":this.props.placeholder;} 3719getIds(props=this.props){return props.resIds;} 3720getTags(props,displayNames){return props.resIds.map((id,index)=>
3720{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"),};});} 3721deleteTag(index){this.props.update([...this.props.resIds.slice(0,index),...this.props.resIds.slice(index+1),]);} 3722update(resIds){this.props.update([...this.props.resIds,...resIds]);}} 3723return __exports;});; 3724 3725/* /web/static/src/core/record_selectors/record_autocomplete.js */ 3726odoo.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,},];} 3727addNames(options){const displayNames=Object.fromEntries(options);this.nameService.addDisplayNames(this.props.resModel,displayNames);} 3728getIds(){return this.props.getIds();} 3729async loadOptionsSource(name){if(this.lastProm){this.lastProm.abort(false);} 3730this.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),});} 3731if(options.length===0){options.push({label:_t("(no result)")});} 3732return options;} 3733async 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());} 3734const 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);} 3735this.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]);},});} 3736getDomain(){const domainIds=Domain.not([["id","in",this.getIds()]]);if(this.props.domain){return Domain.and([this.props.domain,domainIds]).toList();} 3737return domainIds.toList();} 3738search(name,limit){const domain=this.getDomain();return this.orm.call(this.props.resModel,"name_search",[],{name,domain:domain,limit,context:this.props.context||{},});} 3739onChange({inputValue}){if(!inputValue.length){this.props.update([]);}}} 3740return __exports;});; 3741 3742/* /web/static/src/core/record_selectors/record_selector.js */ 3743odoo.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));} 3744get isAvatarModel(){return["res.partner","res.users","hr.employee","hr.employee.public"].includes(this.props.resModel);} 3745get hasAvatarImg(){return this.isAvatarModel&&isId(this.props.resId);} 3746async computeDerivedParams(props=this.props){const displayNames=await this.getDisplayNames(props);this.displayName=this.getDisplayName(props,displayNames);} 3747async getDisplayNames(props){const ids=this.getIds(props);return this.nameService.loadDisplayNames(props.resModel,ids);} 3748getDisplayName(props=this.props,displayNames){const{resId}=props;if(resId===false){return"";}
3749return typeof displayNames[resId]==="string"?displayNames[resId]:_t("Inaccessible/missing record ID: %s",resId);} 3750getIds(props=this.props){if(props.resId){return[props.resId];} 3751return[];} 3752update(resIds){this.props.update(resIds[0]||false);this.render(true);}} 3753return __exports;});; 3754 3755/* /web/static/src/core/record_selectors/tag_navigation_hook.js */ 3756odoo.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);} 3757navigator.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;}} 3758return 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(),},},});} 3759return __exports;});; 3760 3761/* /web/static/src/core/registry.js */ 3762odoo.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{} 3763const DuplicatedKeyError=__exports.DuplicatedKeyError=class DuplicatedKeyError extends Error{} 3764const validateSchema=(name,key,value,schema)=>
3764{if(!odoo.debug){return;} 3765try{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;});} 3766add(key,value,{force,sequence}={}){if(this.validationSchema){validateSchema(this.name,key,value,this.validationSchema);} 3767if(!force&&key in this.content){throw new DuplicatedKeyError(`Cannot add key "${key}" in the "${this.name}" registry: it already exists`);} 3768let previousSequence;if(force){const elem=this.content[key];previousSequence=elem&&elem[0];} 3769sequence=sequence===undefined?previousSequence||50:sequence;this.content[key]=[sequence,value];const payload={operation:"add",key,value};this.trigger("UPDATE",payload);return this;} 3770get(key,defaultValue){if(arguments.length<2&&!(key in this.content)){throw new KeyNotFoundError(`Cannot find key "${key}" in the "${this.name}" registry`);} 3771const info=this.content[key];return info?info[1]:defaultValue;} 3772contains(key){return key in this.content;} 3773getAll(){if(!this.elements){const content=Object.values(this.content).sort((el1,el2)=>el1[0]-el2[0]);this.elements=content.map((elem)=>elem[1]);} 3774return this.elements.slice();} 3775getEntries(){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]]);} 3776return this.entries.slice();} 3777remove(key){const value=this.content[key];delete this.content[key];const payload={operation:"delete",key,value};this.trigger("UPDATE",payload);} 3778category(subcategory){if(!(subcategory in this.subRegistries)){this.subRegistries[subcategory]=new Registry(subcategory);} 3779return this.subRegistries[subcategory];} 3780addValidation(schema){if(this.validationSchema){throw new Error("Validation schema already set on this registry");} 3781this.validationSchema=schema;for(const[key,value]of this.getEntries()){validateSchema(this.name,key,value,schema);}}} 3782const registry=__exports.registry=new Registry();return __exports;});; 3783 3784/* /web/static/src/core/registry_hook.js */ 3785odoo.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;} 3786return __exports;});; 3787 3788/* /web/static/src/core/resizable_panel/resizable_panel.js */ 3789odoo.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(()=>
3789{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");} 3790function onMouseUp(){isChangingSize=false;document.body.classList.remove("pe-none","user-select-none");} 3791function onMouseMove(ev){if(!isChangingSize||!containerRef.el){return;} 3792const 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));} 3793function 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);} 3794function 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;} 3795return containerRect;} 3796function getLimitWidth(){const offsetParent=containerRef.el.offsetParent;return offsetParent?offsetParent.offsetWidth:window.innerWidth;} 3797function resize(width){containerRef.el.style.setProperty("width",`${width}px`);onResize(width);}} 3798const 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,});} 3799get class(){const classes=this.props.class.split(" ");if(!classes.some((cls)=>cls.startsWith("position-"))){classes.push("position-relative");} 3800return classes.join(" ");}} 3801return __exports;});; 3802 3803/* /web/static/src/core/select_menu/select_menu.js */ 3804odoo.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)=>
3804{if(!this.dropdownState.isOpen){this.dropdownState.open();} 3805this.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;} 3806if(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();} 3807if(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();}},};} 3808get displayValue(){return this.state.searchValue===null?this.selectedChoice?.label||"":this.state.searchValue;} 3809get displayInputInToggler(){return!this.props.slots||!this.props.slots.default;} 3810get displayInputInDropdown(){return(this.isBottomSheet||!this.displayInputInToggler)&&this.props.searchable;} 3811get isBottomSheet(){return this.env.isSmall&&hasTouch();} 3812get canDeselect(){return!this.props.required&&this.selectedChoice!==undefined;} 3813get 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);},}));} 3814get menuClass(){return mergeClasses({"my-0":this.displayInputInToggler,o_select_menu_menu:true,o_select_menu_multi_select:this.props.multiSelect,},this.props.menuClass);} 3815get placeholderValue(){if(this.state.isFocused&&this.props.searchPlaceholder){return this.props.searchPlaceholder;} 3816return this.props.placeholder;} 3817async onBeforeOpen(){this.onInput("");} 3818onInputFocus(ev){if(!this.props.searchable){return ev.target.blur();} 3819if(ev.target.classList.contains("o_select_menu_input")){this.state.isFocused=true;ev.target.select();}} 3820onInputBlur(ev){this.state.isFocused=false;if(ev.target.value===""&&!this.props.multiSelect){if(this.canDeselect){this.onInputClear();}else{this.state.searchValue=null;}}} 3821onInputClick(ev){if(!ev.target.classList.contains("o_select_menu_toggler")){ev.stopPropagation();}} 3822onSearchInput(ev){this.state.searchValue=ev.target.value;this.debouncedOnInput(this.state.searchValue);} 3823onInputClear(){this.props.onSelect(null);this.dropdownState.close();} 3824onStateChanged(open){if(open){if(this.isBottomSheet){document.activeElement.blur();} 3825if(this.displayInputInDropdown&&!this.isBottomSheet){this.inputRef.el.focus();} 3826this.menuRef.el?.addEventListener("scroll",(ev)=>this.onScroll(ev));const selectedElement=this.menuRef.el?.querySelectorAll(".selected")[0];if(selectedElement){scrollTo(selectedElement);} 3827this.props.onOpened();}else{this.state.searchValue=null;this.props.onClosed();}} 3828isOptionSelected(choice){if(this.props.multiSelect){return this.props.value.includes(choice.value);} 3829return this.props.value===choice.value;} 3830getItemClass(choice){if(this.isOptionSelected(choice)){return"o_select_menu_item fw-bolder selected";}else{return"o_select_menu_item";}} 3831async onInput(searchString){this.filterOptions(searchString);if(this.props.onInput){await this.props.onInput(searchString);}} 3832getSelectedChoice(props){const choices=[...props.choices,...props.groups.flatMap((g)=>g.choices||[])];if(!this.props.multiSelect){return choices.find((c)=>c.value===props.value);} 3833const 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);} 3834onItemSelected(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;}} 3835this.state.searchValue=null;} 3836filterOptions(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));}} 3837if(filteredOptions.length===0){continue;} 3838if(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});}} 3839if(group.label){_choices.push({...group,isGroup:true});} 3840_choices.push(...filteredOptions);} 3841this.state.choices=_choices;this.sliceDisplayedOptions();} 3842onScroll(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+ 3843this.constructor.SCROLL_SETTINGS.increaseAmount;this.state.displayedOptions=this.state.choices.slice(0,displayCount);}} 3844sliceDisplayedOptions(){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);}} 3845getSelectedOptionIndex(){let selectedIndex=-1;for(let i=0;i<this.state.choices.length;i++){if(this.isOptionSelected(this.state.choices[i])){selectedIndex=i;}} 3846return selectedIndex;}} 3847return __exports;});; 3848 3849/* /web/static/src/core/signature/name_and_signature.js */ 3850odoo.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
3850FontList: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();} 3851if(this.props.signature.signatureImage){this.clear();this.fromDataURL(this.props.signature.signatureImage);}}},()=>[this.signatureRef.el]);} 3852async drawCurrentName(){const font=this.fonts[this.currentFont];const text=this.getCleanedName();if(text.trim()===""){this.clear();return;} 3853const canvas=this.signatureRef.el;const img=this.getSVGText(font,text,canvas.width,canvas.height);await this.printImage(img);} 3854focusName(){if(!isMobileOS()&&this.signNameInputRef.el){this.signNameInputRef.el.focus();}} 3855clear(){this.signaturePad.clear();this.props.signature.isSignatureEmpty=this.isSignatureEmpty;} 3856async fromDataURL(){await this.signaturePad.fromDataURL(...arguments);this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);} 3857getCleanedName(){const text=this.props.signature.name.replace(/Â /g," ");if(this.props.signatureType==="initial"&&text){return(text.split(" ").map(function(w){return w[0];}).join(".")+".");} 3858return text;} 3859getSVGText(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);} 3860getSVGTextFont(font){const height=100;const width=parseInt(height*this.props.displaySignatureRatio);return this.getSVGText(font,this.getCleanedName(),width,height);} 3861uploadFile(){this.signInputLoad.el?.click();} 3862async onChangeSignLoadInput(ev){var file=ev.target.files[0];if(file===undefined){return false;} 3863if(file.type.substr(0,5)!=="image"){this.clear();this.state.loadIsInvalid=true;return false;} 3864this.state.loadIsInvalid=false;const result=await getDataURLFromFile(file);await this.printImage(result);} 3865onClickSignAutoSelectStyle(){this.state.showFontList=true;} 3866onClickSignDrawClear(){this.clear();this.props.onSignatureChange(this.state.signMode);} 3867onClickSignLoad(){this.setMode("load");} 3868onClickSignAuto(){this.setMode("auto");} 3869onInputSignName(ev){this.props.signature.name=ev.target.value;if(!this.state.showSignatureArea&&this.getCleanedName()){this.state.showSignatureArea=true;return;} 3870if(this.state.signMode==="auto"){this.drawCurrentName();}} 3871onSelectFont(index){this.currentFont=index;this.drawCurrentName();} 3872async 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;} 3873resetSignature(){this.resizeSignature();this.clear();this.setMode(this.state.signMode,true);this.focusName();} 3874resizeSignature(){const width=this.signatureRef.el.clientWidth;const height=parseInt(width/this.props.displaySignatureRatio);Object.assign(this.signatureRef.el,{width,height});} 3875setMode(mode,reset){if(reset!==true&&mode===this.signMode){return;} 3876this.state.signMode=mode;this.signaturePad[this.state.signMode==="draw"?"on":"off"]();this.clear();if(this.state.signMode==="auto"){this.drawCurrentName();} 3877this.props.onSignatureChange(this.state.signMode);} 3878get isSignatureEmpty(){return this.signaturePad.isEmpty();} 3879get loadIsInvalid(){return this.state.signMode==="load"&&this.state.loadIsInvalid;}} 3880return __exports;});; 3881 3882/* /web/static/src/core/signature/signature_dialog.js */ 3883odoo.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,};
3883static defaultProps={defaultName:"",};setup(){this.signature=useState({name:this.props.defaultName,isSignatureEmpty:true,});} 3884onClickConfirm(){this.props.uploadSignature({name:this.signature.name,signatureImage:this.signature.getSignatureImage(),});this.props.close();} 3885get nameAndSignatureProps(){return{...this.props.nameAndSignatureProps,signature:this.signature,};}} 3886return __exports;});; 3887 3888/* /web/static/src/core/tags_list/tags_list.js */ 3889odoo.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;} 3890get visibleTags(){if(this.props.visibleItemsLimit&&this.props.tags.length>this.props.visibleItemsLimit){return this.props.tags.slice(0,this.visibleTagsCount);} 3891return this.props.tags;} 3892get otherTags(){if(this.props.visibleItemsLimit&&this.props.tags.length>this.props.visibleItemsLimit){return this.props.tags.slice(this.visibleTagsCount);} 3893return[];} 3894get tooltipInfo(){return JSON.stringify({tags:this.otherTags.map((tag)=>({text:tag.text,id:tag.id,})),});}} 3895return __exports;});; 3896 3897/* /web/static/src/core/template_inheritance.js */ 3898odoo.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);} 3899return getTranslationContext(node.parentElement);} 3900const contextByTextNode=new Map();function setTranslationContext(node){switch(node.nodeType){case Node.TEXT_NODE:if(node.nodeValue.trim()!=""){contextByTextNode.set(node,translationContext);} 3901break;case Node.ELEMENT_NODE:node.setAttribute(TCTX,translationContext);break;}} 3902__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);} 3903contextByTextNode.clear();} 3904__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));}} 3905if(node.childNodes?.length){for(const childNode of[...node.childNodes]){clone.append(deepClone(childNode));}} 3906return clone;} 3907function addBefore(target,operation){const nodes=getNodes(target,operation);if(nodes.length===0){return;} 3908const{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();}}}} 3909function getRoot(element){while(element.parentElement){element=element.parentElement;} 3910return element;} 3911const 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");}} 3912return xpath.replaceAll(HASCLASS_REGEXP,(_,capturedGroup)=>capturedGroup.split(",").map((c)=>`contains(concat(' ', @class, ' '), ' ${c.trim().slice(1, -1)} ')`).join(" and "));} 3913function 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;} 3914const attributes=[...operation.attributes].filter((attr)=>!attr.name.startsWith(TCTX));
3914for(const elem of root.querySelectorAll(operation.tagName)){if(attributes.every(({name,value})=>name==="position"||elem.getAttribute(name)===value)){return elem;}} 3915return null;} 3916function getElement(element,operation){const node=getNode(element,operation);if(!node){throw new Error(`Element '${operation.outerHTML}' cannot be located in element tree`);} 3917if(!(node instanceof Element)){throw new Error(`Found node ${node} instead of an element`);} 3918return node;} 3919function 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);}} 3920return nodes;} 3921function splitAndTrim(str,separator){return str.split(separator).map((s)=>s.trim());} 3922function modifyAttributes(target,operation){for(const child of operation.children){if(child.tagName!=="attribute"){continue;} 3923const 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}`);} 3924const 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);} 3925if(value){target.setAttribute(attributeName,value);if(!(add||remove)){target.setAttribute(`t-translation-context-${attributeName}`,translationContext);}}else{target.removeAttribute(attributeName);}}} 3926function 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();}} 3927function 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));} 3928if(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;} 3929if(child.nodeType===Node.COMMENT_NODE){comment=child;}} 3930root=deepClone(operationContent);if(target.hasAttribute("t-name")){root.setAttribute("t-name",target.getAttribute("t-name"));} 3931if(comment){root.prepend(comment);}} 3932break;} 3933case"inner":while(target.firstChild){target.removeChild(target.lastChild);} 3934for(const node of[...operation.childNodes]){setTranslationContext(node);target.append(node);} 3935break;default:throw new Error(`Invalid mode attribute: '${mode}'`);} 3936return root;} 3937__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);}} 3938switch(position){case"replace":{root=replace(root,target,operation);break;} 3939case"attributes":{modifyAttributes(target,operation);break;} 3940case"inside":{const sentinel=document.createElement("sentinel");target.append(sentinel);addBefore(sentinel,operation);removeNode(sentinel);break;} 3941case"after":{const sentinel=document.createElement("sentinel");target.after(sentinel);addBefore(sentinel,operation);removeNode(sentinel);break;} 3942case"before":{addBefore(target,operation);break;} 3943default:throw new Error(`Invalid position attribute: '${position}'`);}} 3944translationContext=null;return root;} 3945return __exports;});; 3946 3947/* /web/static/src/core/templates.js */ 3948odoo.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;} 3949function getKey(args){return JSON.stringify([...args]);} 3950function getParsedTemplate(templateString){const doc=parser.parseFromString(templateString,"text/xml");for(const processor of templateProcessors){processor(doc);} 3951return doc.firstChild;} 3952function _getTemplate(name,blockId=null){if(!(name in parsedTemplates)){if(!(name in templates)){return null;} 3953const templateString=templates[name];parsedTemplates[name]=getParsedTemplate(templateString);const inheritFrom=parsedTemplates[name].getAttribute("t-inherit");if(!inheritFrom){const addon=info[name].url.split("/")[1];
3953parsedTemplates[name].setAttribute("t-translation-context",addon);}} 3954let 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`);} 3955const 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);} 3956for(const{name,value}of element.attributes){if(!["t-inherit","t-inherit-mode"].includes(name)){processedTemplate.setAttribute(name,value);}}} 3957let cloned=false;for(const otherBlockId in templateExtensions[name]||{}){if(blockId&&otherBlockId>blockId){break;} 3958if(!(name in parsedTemplateExtensions)){parsedTemplateExtensions[name]={};} 3959if(!(otherBlockId in parsedTemplateExtensions[name])){parsedTemplateExtensions[name][otherBlockId]=[];for(const{templateString,url}of templateExtensions[name][otherBlockId]){parsedTemplateExtensions[name][otherBlockId].push({template:getParsedTemplate(templateString),url,});}} 3960for(const{template,url}of parsedTemplateExtensions[name][otherBlockId]){if(!urlFilters.every((filter)=>filter(url))){continue;} 3961if(!inheritFrom&&!cloned){cloned=true;processedTemplate=getClone(processedTemplate);} 3962processedTemplate=applyInheritance(processedTemplate,getClone(template),url);}} 3963return processedTemplate;} 3964const 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(", ")}`);}} 3965__exports.clearProcessedTemplates=clearProcessedTemplates;function clearProcessedTemplates(){processedTemplates.clear();} 3966__exports.getTemplate=getTemplate;function getTemplate(name){if(!processedTemplates.has(name)){processedTemplates.set(name,_getTemplate(name));applyContextToTextNode();} 3967return processedTemplates.get(name);} 3968__exports.registerTemplate=registerTemplate;function registerTemplate(name,url,templateString){const key=getKey(arguments);if(registered.has(key)){return;} 3969registered.add(key);if(blockType!=="templates"){blockType="templates";blockId++;} 3970if(name in templates&&(info[name].url!==url||templates[name]!==templateString)){throw new Error(`Template ${name} already exists`);} 3971templates[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);};} 3972__exports.registerTemplateExtension=registerTemplateExtension;function registerTemplateExtension(inheritFrom,url,templateString){const key=getKey(arguments);if(registered.has(key)){return;} 3973registered.add(key);if(blockType!=="extensions"){blockType="extensions";blockId++;} 3974if(!templateExtensions[inheritFrom]){templateExtensions[inheritFrom]=[];} 3975if(!templateExtensions[inheritFrom][blockId]){templateExtensions[inheritFrom][blockId]=[];} 3976templateExtensions[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);} 3977registered.delete(key);};} 3978__exports.registerTemplateProcessor=registerTemplateProcessor;function registerTemplateProcessor(processor){templateProcessors.push(processor);} 3979__exports.setUrlFilters=setUrlFilters;function setUrlFilters(filters){const prev=urlFilters;urlFilters=filters;return function restoreUrlFilters(){urlFilters=prev;};} 3980return __exports;});; 3981 3982/* /web/static/src/core/time_picker/time_picker.js */ 3983odoo.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
3983otkeys/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));} 3984get cssClass(){return mergeClasses(this.props.cssClass,{o_time_picker_seconds:this.props.showSeconds,});} 3985get inputCssClass(){return mergeClasses(this.props.inputCssClass,{o_invalid:!this.state.isValid,});} 3986getNavigationOptions(){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);},},},};} 3987onPropsUpdated(props){if(this.suggestions.length===0){this.suggestions=this.getSuggestions(props);} 3988this.updateStateValue(Time.from(props.value));} 3989getSuggestions(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}));}} 3990return suggestions;} 3991setValue(newValue,cleanValue=true){if(newValue&&cleanValue){if(this.props.minutesRounding>1){newValue.roundMinutes(this.props.minutesRounding);} 3992if(!this.props.showSeconds&&this.state.value){newValue.second=this.state.value.second;}} 3993const lastValue=this.lastValue;this.updateStateValue(newValue);if(newValue&&!newValue.equals(lastValue,this.props.showSeconds)){this.props.onChange(newValue.copy());}} 3994updateStateValue(newValue){if(newValue===this.lastValue||newValue?.equals(this.lastValue,this.props.showSeconds)){return;} 3995this.lastValue=newValue?.copy()??newValue;this.state.value=newValue;this.state.inputValue=newValue?newValue.toString(this.props.showSeconds):"";this.state.isValid=true;} 3996onItemSelected(value){this.setValue(value);this.close();} 3997onInput(event){this.ensureOpen();const value=parseTime(this.inputRef.el.value,this.props.showSeconds);this.state.isValid=value!==null;if(!this.navigator){return;} 3998let index=-1;if(this.state.isValid){index=this.suggestions.findIndex((s)=>s.equals(value));} 3999if(index===-1){this.navigator.activeItem?.setInactive();}else{this.navigator.items[index]?.setActive();}} 4000onChange(){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();}} 4001onKeydown(event){this.isNavigating=["arrowup","arrowdown"].includes(getActiveHotkey(event));} 4002ensureOpen(){if(!this.dropdownState.isOpen){this.isNavigating=false;
4002this.dropdownState.open();this.inputRef.el.select();}} 4003close(){this.dropdownState.close();} 4004getPlaceholder(){if(typeof this.props.placeholder==="string"){return this.props.placeholder;} 4005const seconds=this.props.showSeconds?":ss":"";return`hh:mm${seconds}`;} 4006onDropdownOpened(){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();}}} 4007return __exports;});; 4008 4009/* /web/static/src/core/tooltip/tooltip.js */ 4010odoo.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},};} 4011return __exports;});; 4012 4013/* /web/static/src/core/tooltip/tooltip_hook.js */ 4014odoo.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]);} 4015return __exports;});; 4016 4017/* /web/static/src/core/tooltip/tooltip_service.js */ 4018odoo.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")));} 4019function cleanup(){target=null;browser.clearTimeout(openTooltipTimeout);openTooltipTimeout=null;if(closeTooltip){closeTooltip();closeTooltip=null;}} 4020function shouldCleanup(){if(!target){return false;} 4021if(!document.body.contains(target)){return true;} 4022return false;} 4023function openTooltip(el,{tooltip="",template,info,position,delay=OPEN_DELAY}){cleanup();if(!tooltip&&!template){return;} 4024target=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);} 4025function openElementsTooltip(el){if(el.nodeType===Node.TEXT_NODE){return;} 4026const element=el.closest("[data-tooltip], [data-tooltip-template]");if(element&&element===target){return;} 4027if(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);} 4028if(dataset.tooltipDelay){params.delay=parseInt(dataset.tooltipDelay,10);} 4029openTooltip(element,params);}} 4030function onMouseenter(ev){openElementsTooltip(ev.target);} 4031function onClick(ev){if(isHelpNode(ev.target)){ev.preventDefault();} 4032cleanupTooltip(ev);} 4033function cleanupTooltip(ev){if(target==ev.target){cleanup();}} 4034function onTouchStart(ev){cleanup();const timeoutDelay=isHelpNode(ev.target)?0:SHOW_AFTER_DELAY;showTimer=browser.setTimeout(()=>{openElementsTooltip(ev.target);},timeoutDelay);} 4035whenReady(()=>{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;} 4036if(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;} 4037if(ev.target.closest("[data-tooltip], [data-tooltip-template]")){if(!ev.target.dataset.tooltipTouchTapToShow){browser.clearTimeout(showTimer);browser.clearTimeout(openTooltipTimeout);}}});} 4038document.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;});; 4039 4040/* /web/static/src/core/transition.js */ 4041odoo.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";},};} 4042let 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;} 4043browser.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";} 4044state.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;} 4045const 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;});}} 4046return __exports;});; 4047 4048/* /web/static/src/core/tree_editor/ast_utils.js */ 4049odoo.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;} 4050__exports.isNot=isNot;function isNot(ast){return ast.type===6&&ast.op==="not";} 4051__exports.not=not;function not(ast){if(isNot(ast)){return ast.right;} 4052if(ast.type===2){return{...ast,value:!ast.value};} 4053if(ast.type===7&&COMPARATORS.includes(ast.op)){return{...ast,op:TERM_OPERATORS_NEGATION_EXTENDED[ast.op]};}
4054return{type:6,op:"not",right:isBool(ast)?ast.args[0]:ast};} 4055__exports.isValidPath=isValidPath;function isValidPath(ast,options){const getFieldDef=options.getFieldDef||(()=>null);if(ast.type===5){return getFieldDef(ast.value)!==null;} 4056return false;} 4057return __exports;});; 4058 4059/* /web/static/src/core/tree_editor/condition_tree.js */ 4060odoo.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);} 4061this._ast=ast;this._expr=formatAST(ast);} 4062toAST(){return this._ast;} 4063toString(){return this._expr;}} 4064__exports.expression=expression;function expression(expr){return new Expression(expr);} 4065__exports.connector=connector;function connector(value,children=[],negate=false){return{type:"connector",value,children,negate};} 4066__exports.complexCondition=complexCondition;function complexCondition(value){parseExpr(value);return{type:"complex_condition",value};} 4067__exports.condition=condition;function condition(path,operator,value,negate=false,isProperty=false){return{type:"condition",path,operator,value,negate,isProperty};} 4068const 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());} 4069if(Array.isArray(value)){return value.map(cloneValue);} 4070return value;} 4071__exports.cloneTree=cloneTree;function cloneTree(tree){const clone={};for(const key in tree){clone[key]=cloneValue(tree[key]);} 4072return clone;} 4073const areEqualValues=(value,otherValue)=>formatValue(value)===formatValue(otherValue);const areEqualArraysOfTrees=(array,otherArray)=>{if(array.length!==otherArray.length){return false;} 4074for(let i=0;i<array.length;i++){const elem=array[i];const otherElem=otherArray[i];if(!areEqualTrees(elem,otherElem)){return false;}} 4075return true;};const areEqualTrees=__exports.areEqualTrees=(tree,otherTree)=>{if(tree.type!==otherTree.type){return false;} 4076if(tree.negate!==otherTree.negate){return false;} 4077if(tree.type==="condition"){if(!areEqualValues(tree.path,otherTree.path)){return false;} 4078if(!areEqualValues(tree.operator,otherTree.operator)){return false;} 4079if(isTree(tree.value)){if(isTree(otherTree.value)){return areEqualTrees(tree.value,otherTree.value);} 4080return false;}else if(isTree(otherTree.value)){return false;} 4081if(!areEqualValues(tree.value,otherTree.value)){return false;} 4082return true;} 4083if(!areEqualValues(tree.value,otherTree.value)){return false;} 4084if(tree.type==="complex_condition"){return true;} 4085return 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);}} 4086__exports.astFromValue=astFromValue;function astFromValue(value){if(value instanceof Expression){return value.toAST();} 4087if(Array.isArray(value)){return{type:4,value:value.map(astFromValue)};} 4088return toPyValue(value);} 4089__exports.formatValue=formatValue;function formatValue(value){return formatAST(astFromValue(value));} 4090__exports.normalizeValue=normalizeValue;function normalizeValue(value){return toValue(astFromValue(value));} 4091__exports.isTree=isTree;function isTree(value){return(typeof value==="object"&&!(value instanceof Domain)&&!(value instanceof Expression)&&!Array.isArray(value)&&value!==null);} 4092__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);}} 4093__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);} 4094return transformed;} 4095function normalizeConnector(connector){const newTree={...connector,children:[]};for(const child of connector.children){addChild(newTree,child);} 4096if(newTree.children.length===1){const child=newTree.children[0];if(newTree.negate){const newChild={...child,negate:!child.negate};if(newChild.type==="condition"){return newChild;} 4097return newChild;} 4098return child;} 4099return newTree;} 4100function makeOptions(path,options){return{...options,getFieldDef:(p)=>{if(typeof path==="string"&&typeof p==="string"){return options.getFieldDef?.(`${path}.${p}`)||null;} 4101return null;},};} 4102__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);} 4103return normalizeConnector(newTree);} 4104const clone=cloneTree(tree);if(traverseSubTrees&&tree.type==="condition"&&isTree(tree.value)){clone.value=operate(transformation,tree.value,makeOptions(tree.path,options),treeType,traverseSubTrees);} 4105if(treeType===tree.type){return transformation(clone,options)||clone;} 4106return clone;} 4107__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);} 4108if(replacement){children.push(replacement);i+=N-1;}else{children.push(NconsecutiveChildren[0]);}} 4109return{...c,children};};} 4110return __exports;});; 4111 4112/* /web/static/src/core/tree_editor/construct_domain_from_tree.js */ 4113odoo.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;} 4114return{type:8,fn:{type:5,value:"bool"},args:[ast],kwargs:{}};} 4115function getASTs(tree,isSubTree=false){const ASTs=[];if(tree.type==="condition"){if(tree.negate){ASTs.push(toAST("!"));} 4116ASTs.push({type:10,value:[tree.path,tree.operator,tree.value].map(toAST),});return ASTs;} 4117if(tree.type==="complex_condition"){const ast=parseExpr(tree.value);return getASTs(condition(new Expression(bool(ast)),"=",1));} 4118const 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):[];}} 4119if(tree.negate){ASTs.push(toAST("!"));} 4120for(let i=0;i<length-1;i++){ASTs.push(toAST(tree.value));} 4121for(const child of tree.children){ASTs.push(...getASTs(child,true));} 4122return ASTs;} 4123function toAST(value){if(isTree(value)){return{type:4,value:getASTs(value)};} 4124return astFromValue(value);} 4125__exports.constructDomainFromTree=constructDomainFromTree;function constructDomainFromTree(tree){return formatAST(toAST(tree));} 4126return __exports;});; 4127 4128/* /web/static/src/core/tree_editor/construct_expression_from_tree.js */ 4129odoo.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;} 4130return{...condition,operator,negate};} 4131function isX2Many(ast,options){if(isValidPath(ast,options)){const fieldDef=options.getFieldDef(ast.value);return["many2many","one2many"].includes(fieldDef.type);} 4132return false;} 4133function _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]}`;}}}}} 4134if(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";} 4135let expression=subExpressions.join(` ${connector} `);if(!isRoot||tree.negate){expression=`( ${expression} )`;}
4136if(tree.negate){expression=`not ${expression}`;} 4137return expression;} 4138if(tree.type==="complex_condition"){return tree.value;} 4139tree=getNormalizedCondition(tree);const{path,operator,value}=tree;if(path instanceof Expression&&operator==="="&&value===1){return path.toString();} 4140const op=operator==="="?"==":operator;if(typeof op!=="string"||!COMPARATORS.includes(op)){throw new Error("Invalid operator");} 4141if([0,1].includes(path)){if(operator!=="="||value!==1){return new Error("Invalid condition");} 4142return formatAST({type:2,value:Boolean(path)});} 4143const pathAST=astFromValue(path);if(typeof path=="string"&&isValidPath({type:5,value:path},options)){pathAST.type=5;} 4144if(value===false&&["=","!="].includes(operator)){return formatAST(operator==="="?not(pathAST):pathAST);} 4145if(isTree(value)){throw new Error("Invalid value");} 4146let valueAST=astFromValue(value);if(["in","not in"].includes(operator)&&!(value instanceof Expression)&&![4,10].includes(valueAST.type)){valueAST={type:4,value:[valueAST]};} 4147if(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);} 4148return formatAST({type:7,op,left:pathAST,right:valueAST,});} 4149__exports.constructExpressionFromTree=constructExpressionFromTree;function constructExpressionFromTree(tree,options={}){return _constructExpressionFromTree(tree,options,true);} 4150return __exports;});; 4151 4152/* /web/static/src/core/tree_editor/construct_tree_from_domain.js */ 4153odoo.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);} 4154const 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;} 4155tree.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];}}} 4156let 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);}} 4157return{tree,remaimingASTs};} 4158__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("&");} 4159const{tree}=_constructTree(initialASTs,distributeNot);return tree;} 4160return __exports;});; 4161 4162/* /web/static/src/core/tree_editor/construct_tree_from_expression.js */ 4163odoo.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};} 4164function and(left,right){return{type:14,op:"and",left,right};} 4165function isSet(ast){return ast.type===8&&ast.fn.type===5&&ast.fn.value==="set"&&ast.args.length<=1;} 4166function isValidPath2(ast,options){if(!ast){return null;} 4167if([4,10].includes(ast.type)&&ast.value.length===1){return isValidPath(ast.value[0],options);} 4168return isValidPath(ast,options);} 4169function _getConditionFromComparator(ast,options){if(["is","is not"].includes(ast.op)){return null;} 4170let operator=ast.op;if(operator==="=="){operator="=";} 4171let left=ast.left;let right=ast.right;if(isValidPath(left,options)==isValidPath(right,options)){return null;} 4172if(!isValidPath(left,options)){if(operator in EXCHANGE){const temp=left;
4172left=right;right=temp;operator=EXCHANGE[operator];}else{return null;}} 4173return condition(left.value,operator,toValue(right));} 4174function _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);} 4175if(isValidPath2(left,options)==isValidPath2(right,options)){return null;} 4176if(!isValidPath2(left,options)){const temp=left;left=right;right=temp;} 4177if([4,10].includes(left.type)&&left.value.length===1){left=left.value[0];} 4178if(!right){return condition(left.value,negate?"=":"!=",false);} 4179if(isSet(right)){if(!right.args[0]){right={type:4,value:[]};} 4180if([4,10].includes(right.args[0].type)){right=right.args[0];}} 4181if(![4,10].includes(right.type)){return null;} 4182return condition(left.value,negate?"not in":"in",toValue(right));} 4183function _leafFromAST(ast,options,negate=false){if(isNot(ast)){return _treeFromAST(ast.right,options,!negate);} 4184if(ast.type===5&&isValidPath(ast,options)){return condition(ast.value,negate?"=":"!=",false);} 4185const astValue=toValue(ast);if(["boolean","number","string"].includes(typeof astValue)){return condition(astValue?1:0,"=",1);} 4186if(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;}} 4187if(ast.type===7&&COMPARATORS.includes(ast.op)){if(negate){return _leafFromAST(not(ast),options);} 4188const tree=_getConditionFromComparator(ast,options);if(tree){return tree;}} 4189return complexCondition(formatAST(negate?not(ast):ast));} 4190function _treeFromAST(ast,options,negate=false){if(isNot(ast)){return _treeFromAST(ast.right,options,!negate);} 4191if(ast.type===14){const tree=connector(ast.op==="and"?"&":"|");if(options.distributeNot&&negate){tree.value=tree.value==="&"?"|":"&";}else{tree.negate=negate;} 4192const subASTs=[ast.left,ast.right];for(const subAST of subASTs){const child=_treeFromAST(subAST,options,options.distributeNot&&negate);addChild(tree,child);} 4193return tree;} 4194if(ast.type===13){const newAST=or(and(ast.condition,ast.ifTrue),and(not(ast.condition),ast.ifFalse));return _treeFromAST(newAST,options,negate);} 4195return _leafFromAST(ast,options,negate);} 4196__exports.constructTreeFromExpression=constructTreeFromExpression;function constructTreeFromExpression(expression,options={}){const ast=parseExpr(expression);return _treeFromAST(ast,options);} 4197return __exports;});; 4198 4199/* /web/static/src/core/tree_editor/domain_contains_expressions.js */ 4200odoo.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;} 4201return[path,operator,value].some((v)=>v instanceof Expression||(Array.isArray(v)&&v.some((w)=>w instanceof Expression)));} 4202for(const child of tree.children){if(treeContainsExpressions(child)){return true;}} 4203return false;} 4204__exports.domainContainsExpressions=domainContainsExpressions;function domainContainsExpressions(domain){let tree;try{tree=constructTreeFromDomain(domain);}catch{return null;} 4205return treeContainsExpressions(tree);} 4206return __exports;});; 4207 4208/* /web/static/src/core/tree_editor/domain_from_tree.js */ 4209odoo.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);} 4210return __exports;});; 4211 4212/* /web/static/src/core/tree_editor/expression_from_tree.js */ 4213odoo.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);} 4214return __exports;});; 4215 4216/* /web/static/src/core/tree_editor/operators.js */ 4217odoo.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;});; 4218 4219/* /web/static/src/core/tree_editor/tree_editor.js */ 4220odoo.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));} 4221async onPropsUpdated(props){if(this.tree){this.previousTree=this.tree;} 4222this.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]);} 4223if(this.previousTree&&areEquivalentTrees(this.tree,this.previousTree)){this.tree=this.previousTree;this.previousTree=null;} 4224await this.prepareInfo(props);} 4225async 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);}} 4226get className(){return`${this.props.readonly ? "o_read_mode" : "o_edit_mode"}`;} 4227get isDebugMode(){return this.props.isDebugMode!==undefined?this.props.isDebugMode:!!this.env.debug;} 4228notifyChanges(){this.props.update(this.tree);} 4229_updateConnector(node){node.value=node.value==="&"?"|":"&";node.negate=false;} 4230updateConnector(node){this.updateNode(node,()=>this._updateConnector(node));} 4231_updateComplexCondition(node,value){node.value=value;} 4232updateComplexCondition(node,value){this.updateNode(node,()=>this._updateComplexCondition(node,value));} 4233makeCondition(parent,condition){condition||=parent.children.findLast((c)=>c.type==="condition");return cloneTree(condition||this.defaultCondition);}
4234_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));}} 4235addNewCondition(parent,node){this.updateNode(parent,()=>this._addNewCondition(parent,node));} 4236_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)]));} 4237addNewConnector(parent,node){this.updateNode(parent,()=>this._addNewConnector(parent,node));} 4238_delete(ancestors,node){if(ancestors.length===0){return;} 4239const 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);}} 4240delete(ancestors,node){const upperNode=ancestors[0]||node;this.updateNode(upperNode,()=>this._delete(ancestors,node));} 4241getResModel(node){const fieldDef=this.getFieldDef(node.path);const resModel=getResModel(fieldDef);return resModel;} 4242getPathEditorInfo(){return this.props.getPathEditorInfo(this.props.resModel,this.defaultCondition);} 4243getOperatorEditorInfo(node){const fieldDef=this.getFieldDef(node.path);return this.props.getOperatorEditorInfo(fieldDef);} 4244getValueEditorInfo(node){const fieldDef=this.getFieldDef(node.path);return getValueEditorInfo(fieldDef,node.operator);} 4245async _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;} 4246async updatePath(node,path){this.updateNode(node,()=>this._updatePath(node,path));} 4247_updateLeafOperator(node,operator,negate){const fieldDef=this.getFieldDef(node.path);node.negate=negate;node.operator=operator;node.value=getDefaultValue(fieldDef,operator,node.value);} 4248updateLeafOperator(node,operator,negate){this.updateNode(node,()=>this._updateLeafOperator(node,operator,negate));} 4249_updateLeafValue(node,value){node.value=value;} 4250updateLeafValue(node,value){this.updateNode(node,()=>this._updateLeafValue(node,value));} 4251async updateNode(node,operation){const previousNode=cloneTree(node);await operation();if(areEquivalentTrees(node,previousNode)){await this.prepareInfo(this.props);this.render();} 4252this.notifyChanges();} 4253highlightNode(target){const nodeEl=target.closest(".o_tree_editor_node");nodeEl.classList.toggle("o_hovered_button");}} 4254return __exports;});; 4255 4256/* /web/static/src/core/tree_editor/tree_editor_autocomplete.js */ 4257odoo.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;} 4258return{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));} 4259getTags(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"),};});}} 4260const 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"";} 4261const{text}=getFormat(resId,displayNames);return text;} 4262getIds(props=this.props){if(isId(props.resId)){return[props.resId];} 4263return[];}} 4264return __exports;});; 4265 4266/* /web/static/src/core/tree_editor/tree_editor_components.js */ 4267odoo.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";} 4268const Select=__exports.Select=class Select extends Component{static props=["value","update","o
4268ptions","placeholder?","addBlankOption?"];static template="web.TreeEditor.Select";deserialize(value){return JSON.parse(value);} 4269serialize(value){return JSON.stringify(value);}} 4270const 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);}} 4271const 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]);}} 4272updateValues(values){const[fieldType,currentValueType]=this.props.value;return this.props.update([fieldType,currentValueType,...values]);}} 4273const 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),]);},}));}
4274update(newValue){return this.props.update([...this.props.value,newValue]);}} 4275return __exports;});; 4276 4277/* /web/static/src/core/tree_editor/tree_editor_operator_editor.js */ 4278odoo.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;} 4279return JSON.stringify([formatValue(operator),negate]);} 4280function toOperator(key){if(!key.includes("[")){return[key,false];} 4281const[expr,negate]=JSON.parse(key);return[toValue(parseExpr(expr)),negate];} 4282function getOperatorDescription(operator,fieldDefType){const description=OPERATOR_DESCRIPTIONS[operator];if(typeof description==="function"&&description.constructor?.name!=="LazyTranslatedString"){return description(fieldDefType);} 4283return description;} 4284__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);} 4285if(negate){return _t(`not %(operator_label)s`,{operator_label:label});} 4286return label;} 4287function getOperatorInfo(operator,fieldDefType,negate=false){const key=toKey(operator,negate);const label=getOperatorLabel(operator,fieldDefType,negate);return[key,label];} 4288__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]);} 4289return{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),};} 4290return __exports;});; 4291 4292/* /web/static/src/core/tree_editor/tree_editor_value_editors.js */ 4293odoo.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;}} 4294function isParsable(fieldType,value){const parser=parsers.get(fieldType,(value)=>value);try{parser(value);}catch{return false;} 4295return true;} 4296function genericSerializeDate(type,value){return type==="date"?serializeDate(value):serializeDateTime(value);} 4297function genericDeserializeDate(type,value){return type==="date"?deserializeDate(value):deserializeDateTime(value);} 4298function placeholderForSelect(displayPlaceholder){if(displayPlaceholder){return _t(`Select one or several criteria`);}} 4299function placeholderForInput(displayPlaceholder){if(displayPlaceholder){return _t(`Press "Enter" to add criterion`);}} 4300const 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:()=>
4300options[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"),};} 4301function getDomain(fieldDef){if(fieldDef.type==="many2one"){return[];} 4302try{return new Domain(fieldDef.domain||[]).toList();}catch{return[];}} 4303function 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:()=>[],};} 4304function isLitteralObject(value){return typeof value==="object"&&!Array.isArray(value)&&value!==null;} 4305function 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]),};} 4306case"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],};} 4307case"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);} 4308return{value,update,editorInfo,};},isSupported:(value)=>Array.isArray(value),defaultValue:()=>[],shouldResetValue:(value)=>!value.every(editorInfo.isSupported),};}}} 4309case"any":case"not any":{switch(fieldDef.type){case"many2one":case"many2many":case"one2many":{return{component:null,extractProps:null,isSupported:isTree,defaultValue:()=>connector("&"),};}}}} 4310const{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{}} 4311return 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,};} 4312case"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"));} 4313const start=genericSerializeDate(type,datetime.startOf("day"));if(params.forBetween){return{start,end:genericSerializeDate(type,datetime.endOf("day"))};} 4314return start;},shouldResetValue:()=>true,stringify:(value)=>{if(value===false){return _t("False");} 4315if(typeof value==="string"&&isParsable(type,value)){const formatter=formatters.get(type,formatValue);return formatter(genericDeserializeDate(type,value));} 4316return 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);} 4317break;} 4318case"many2many":case"one2many":if(["=","!="].includes(operator)){return makeAutoCompleteEditor(fieldDef);} 4319break;case"selection":{const options=fieldDef.selection||[];return makeSelectEditor(options,params);} 4320case undefined:{const options=[[1,"1"]];return makeSelectEditor(options,params);}} 4321return{component:Input,extractProps:({value,update})=>({value:String(value),update,}),isSupported:()=>true,defaultValue:()=>"",};} 4322__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);} 4323return String(val);},...info,};} 4324__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);} 4325return value;} 4326return __exports;});; 4327 4328/* /web/static/src/core/tree_editor/tree_from_domain.js */ 4329odoo.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);} 4330return __exports;});; 4331 4332/* /web/static/src/core/tree_editor/tree_from_expression.js */ 4333odoo.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);} 4334return __exports;});; 4335 4336/* /web/static/src/core/tree_editor/tree_processor.js */ 4337odoo.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");
4337function formatValue(val,disambiguate,fieldDef,displayNames){if(val instanceof Expression){return val.toString();} 4338if(displayNames&&isId(val)){if(typeof displayNames[val]==="string"){val=displayNames[val];}else{return _t("Inaccessible/missing record ID: %s",val);}} 4339if(fieldDef?.type==="selection"){const[,label]=(fieldDef.selection||[]).find(([v])=>v===val)||[];if(label!==undefined){val=label;}} 4340if(typeof val==="string"){if(fieldDef?.type==="datetime"){return formatDateTime(deserializeDateTime(val));} 4341if(fieldDef?.type==="date"){return formatDate(deserializeDate(val));}} 4342if(disambiguate&&typeof val==="string"){return JSON.stringify(val);} 4343return val;} 4344function 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}`);}}}} 4345if(tree.type==="connector"&&tree.children){for(const child of tree.children){paths.push(...getPathsInTree(child,lookInSubTrees));}} 4346return unique(paths);} 4347function simplifyTree(tree){if(tree.type==="condition"){return tree;} 4348const processedChildren=tree.children.map(simplifyTree);if(tree.value==="&"){return{...tree,children:processedChildren};} 4349const 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);} 4350childrenByPath[child.path].elems.push(child);}}
4351for(const path in childrenByPath){if(childrenByPath[path].elems.length===1){continue;} 4352const value=[];for(const child of childrenByPath[path].elems){if(child.operator==="="){value.push(child.value);}else{value.push(...child.value);}} 4353children[childrenByPath[path].index]=condition(path,"in",normalizeValue(unique(value)));} 4354if(children.length===1){return{...children[0]};} 4355return{...tree,children};} 4356function _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]=[];} 4357idsByModel[resModel].push(...ids);}}} 4358if(tree.type==="connector"){for(const child of tree.children){_extractIdsRecursive(child,getFieldDef,idsByModel);}} 4359return idsByModel;} 4360function extractIdsFromTree(tree,getFieldDef){const idsByModel=_extractIdsRecursive(tree,getFieldDef,{});for(const resModel in idsByModel){idsByModel[resModel]=unique(idsByModel[resModel]);} 4361return idsByModel;} 4362const 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));} 4363return Object.fromEntries(zip(resModels,await Promise.all(proms)));} 4364async 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 ")}${ 4365 displayNames.length > limit ? "..." : "" 4366 }`);}));} 4367await Promise.all(promises);return(path)=>pathDescriptions.get(path);} 4368async 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);} 4369function _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);} 4370if(["=","!="].includes(operator)&&value===false){operator=operator==="="?"not set":"set";} 4371const 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;} 4372if(["set","not set"].includes(operator)){return description;} 4373const 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):"...");} 4374let 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");} 4375description.valueDescription={values,join,addParenthesis};return description;} 4376async 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} )`;} 4377if(tree.negate){description=`! ${description}`;} 4378return description;} 4379const 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} )`);} 4380return stringDescription.join(" ");} 4381async 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");} 4382connector=`${tabs}${connector}`;const childrenTooltipLines=await Promise.all(tree.children.map((node)=>getTooltipLines(resModel,node,depth+1)));return[connector,...childrenTooltipLines].flat();} 4383const 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);} 4384descr.push(`${tabs}${stringDescriptions.join(" ")}`);
4384if(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);} 4385return descr;} 4386async function getDomainTreeTooltip(resModel,tree){const descriptions=await getTooltipLines(resModel,tree);return descriptions.join("\n");} 4387async 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;}));} 4388await Promise.all(promises);return(path)=>{if(typeof path==="string"){return fieldDefs[path];} 4389return null;};} 4390async function treeFromDomain(resModel,domain,distributeNot=true){const tree=constructTreeFromDomain(domain,distributeNot);const getFieldDef=await makeGetFieldDef(resModel,tree);return introduceVirtualOperators(tree,{getFieldDef});} 4391return{getDomainTreeDescription,getDomainTreeTooltip,makeGetConditionDescription,makeGetFieldDef,treeFromDomain,};},};registry.category("services").add("tree_processor",treeProcessorService);return __exports;});; 4392 4393/* /web/static/src/core/tree_editor/utils.js */ 4394odoo.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==="";} 4395let hasSomeString=false;let hasSomethingElse=false;for(const val of value){if(val===""){return true;} 4396if(typeof val==="string"||(displayNames&&isId(val))){hasSomeString=true;}else{hasSomethingElse=true;}} 4397return hasSomeString&&hasSomethingElse;} 4398__exports.isId=isId;function isId(value){return Number.isInteger(value)&&value>=1;} 4399__exports.getResModel=getResModel;function getResModel(fieldDef){if(fieldDef){return fieldDef.is_property?fieldDef.comodel:fieldDef.relation;} 4400return null;} 4401const 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;}} 4402const name=Object.keys(fieldDefs)[0];if(name){return name;} 4403throw new Error(`No field found`);} 4404return __exports;});; 4405 4406/* /web/static/src/core/tree_editor/virtual_operators.js */ 4407odoo.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:""};} 4408const pathParts=path.split(".");if(is_property&&pathParts.length>=2){return{initialPath:pathParts.slice(0,-2).join("."),lastPart:pathParts.slice(-2).join("."),};} 4409const lastPart=pathParts.pop()||"";const initialPath=pathParts.join(".");return{initialPath,lastPart};} 4410function isSimplePath(path,isProperty){return typeof path==="string"&&!splitPath(path,isProperty).initialPath;} 4411function wrapInAny(tree,initialPath,negate){let con=cloneTree(tree);if(initialPath){con=condition(initialPath,"any",con);} 4412con.negate=negate;return con;} 4413function 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);}}}} 4414return operate(_introduceSetOperator,tree,options);} 4415function 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);} 4416return condition(path,operator==="set"?"!=":"=",value,negate,isProperty);}} 4417return operate(_removeSetOperator,tree);} 4418function 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);}}} 4419return operate(_introduceStartsWithOperator,tree,options);} 4420function eliminateStartsWithOperators(tree){function _eliminateStartsWithOperator(c){const{negate,path,operator,value,isProperty}=c;if(operator==="starts with"){return condition(path,"=ilike",`${value}%`,negate,isProperty);}} 4421return operate(_eliminateStartsWithOperator,tree);} 4422function 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;} 4423return false;} 4424function 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};}} 4425return false;} 4426function makeBetween(path,value1,value2,isProperty){return connector("&",[condition(path,">=",value1,false,isProperty),condition(path,"<=",value2,false,isProperty),]);} 4427function 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};}} 4428return false;} 4429function makeStrictBetween(path,value1,value2,isProperty){return connector("&",[condition(path,">=",value1,false,isProperty),condition(path,"<",value2,false,isProperty),]);} 4430function boundDate(delta){if(!delta){return expression(`context_today().strftime("%Y-%m-%d")`);} 4431return expression(`(context_today() + relativedelta(${delta})).strftime('%Y-%m-%d')`);} 4432function 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")`);} 4433return expression(`datetime.datetime.combine(context_today() + relativedelta(${delta}), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")`);} 4434const 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
4434= 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;} 4435function 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);}}}} 4436const 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);}}} 4437return operate(rewriteNConsecutiveChildren(_introduceInRangeOperator),tree,options,"connector");} 4438function eliminateInRangeOperators(tree,options={}){function _eliminateInRangeOperator(c,options){const{negate,path,operator,value,isProperty}=c;if(operator!=="in range"){return;} 4439const{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);} 4440return wrapInAny(tree,initialPath,negate);} 4441return operate(_eliminateInRangeOperator,tree,options);} 4442function introduceBetweenOperators(tree,options={}){function _introduceBetweenOperator(c,options){const res=isBetween(c);if(!res){return;} 4443const{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]));}} 4444return operate(rewriteNConsecutiveChildren(_introduceBetweenOperator),tree,options,"connector");} 4445function eliminateBetweenOperators(tree){function _eliminateBetweenOperator(c){const{negate,path,operator,value,isProperty}=c;if(operator!=="between"){return;} 4446const{initialPath,lastPart}=splitPath(path,isProperty);return wrapInAny(makeBetween(lastPart,value[0],value[1],isProperty),initialPath,negate);} 4447return operate(_eliminateBetweenOperator,tree);} 4448function _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);}} 4449function eliminateAnyOperators(tree){return operate(_eliminateAnyOperator,tree);} 4450function 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?"&":"|",[]);} 4451if(areEqualTrees(condition(path,operator,value,false,isProperty),TRUE_TREE)){return connector(negate?"|":"&",[]);}} 4452return operate(_removeFalseTrueLeave,tree);} 4453__exports.introduceVirtualOperators=introduceVirtualOperators;function introduceVirtualOperators(tree,options={}){return applyTransformations([eliminateAnyOperators,introduceSetOperators,introduceStartsWithOperators,introduceBetweenOperators,introduceInRangeOperators,],tree,options);} 4454__exports.eliminateVirtualOperators=eliminateVirtualOperators;function eliminateVirtualOperators(tree,options={}){return applyTransformations([eliminateInRangeOperators,eliminateBetweenOperators,eliminateStartsWithOperators,eliminateSetOperators,],tree,options);} 4455__exports.areEquivalentTrees=areEquivalentTrees;function areEquivalentTrees(tree,otherTree){const simplifiedTree=removeFalseTrueLeaves(eliminateVirtualOperators(tree));const otherSimplifiedTree=removeFalseTrueLeaves(eliminateVirtualOperators(otherTree));return areEqualTrees(simplifiedTree,otherSimplifiedTree);} 4456return __exports;});; 4457 4458/* /web/static/src/core/ui/block_ui.js */ 4459odoo.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));} 4460replaceMessage(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);}} 4461block(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();} 4462if(ev.detail?.message){this.state.line1=ev.detail.message;}else{this.replaceMessage(0);}} 4463unblock(){this.state.blockState=this.BLOCK_STATES.UNBLOCKED;clearTimeout(this.showBlockedUITimer);clearTimeout(this.msgTimer);this.state.line1="";this.state.line2="";}} 4464return __exports;});; 4465 4466/* /web/static/src/core/ui/ui_service.js */ 4467odoo.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
4467otkeys/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]];} 4468__exports.useActiveElement=useActiveElement;function useActiveElement(refName){if(!refName){throw new Error("refName not given to useActiveElement");} 4469const uiService=useService("ui");const ref=useRef(refName);function trapFocus(e){const hotkey=getActiveHotkey(e);if(!["tab","shift+tab"].includes(hotkey)){return;} 4470const el=e.currentTarget;const[firstTabableEl,lastTabableEl]=getFirstAndLastTabableElements(el);if(!firstTabableEl&&!lastTabableEl){e.preventDefault();e.stopPropagation();return;} 4471switch(hotkey){case"tab":if(document.activeElement===lastTabableEl){firstTabableEl.focus();e.preventDefault();e.stopPropagation();} 4472break;case"shift+tab":if(document.activeElement===firstTabableEl){lastTabableEl.focus();e.preventDefault();e.stopPropagation();} 4473break;}} 4474useEffect((el)=>{if(el){const[firstTabableEl]=getFirstAndLastTabableElements(el);if(!firstTabableEl&&!isFocusable(el)){return;} 4475const 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();} 4476return async()=>{await Promise.resolve();uiService.deactivateElement(el);el.removeEventListener("keydown",trapFocus);if(el.contains(document.activeElement)||document.activeElement===document.body){oldActiveElement.focus();}};}},()=>[ref.el]);} 4477const 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)`);} 4478if(!minWidth){return window.matchMedia(`(max-width: ${maxWidth}px)`);} 4479return window.matchMedia(`(min-width: ${minWidth}px) and (max-width: ${maxWidth}px)`);});} 4480let 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);} 4481const 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,});}} 4482function 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;} 4483if(blockCount===0){bus.trigger("UNBLOCK");}} 4484let activeElems=[document];function activateElement(el){activeElems.push(el);bus.trigger("active-element-changed",el);} 4485function deactivateElement(el){activeElems=activeElems.filter((x)=>x!==el);bus.trigger("active-element-changed",ui.activeElement);} 4486function getActiveElementOf(el){for(const activeElement of[...activeElems].reverse()){if(activeElement.contains(el)){return activeElement;}}} 4487if(updateSizeHandler){MEDIAS.forEach((m)=>m.removeEventListener?.("change",updateSizeHandler));MEDIAS=getMediaQueryLists();} 4488const 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);
4488ui.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;});; 4489 4490/* /web/static/src/core/user.js */ 4491odoo.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);} 4492if(typeof cids==="number"){return[cids];}} 4493return[];} 4494__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];} 4495activeCompanies=[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");} 4496let 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));} 4497defaultCompany=allowedCompanies.find((c)=>c.id===userCompanies.current_company);updateActiveCompanies(getCookieCompanyIds(),allowedCompanies,defaultCompany);} 4498delete 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);} 4499return 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
4499ise.resolve(isInternalUser);} 4500if(isSystem!==undefined){groupCache.cache["base.group_system"]=Promise.resolve(isSystem);} 4501if(isAdmin!==undefined){groupCache.cache["base.group_erp_manager"]=Promise.resolve(isAdmin);} 4502if(isPublic!==undefined){groupCache.cache["base.group_public"]=Promise.resolve(isPublic);} 4503for(const group in groups){groupCache.cache[group]=Promise.resolve(!!groups[group]);} 4504const 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);}}} 4505if(options.includeChildCompanies){addCompanies(companyIds.flatMap((companyId)=>allowedCompanies.find((c)=>c.id===companyId).child_ids));} 4506updateActiveCompanies(newCompanyIds,allowedCompanies,defaultCompany);if(options.reload){browser.location.reload();}},};} 4507const 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);} 4508delete session.quick_login;return __exports;});; 4509 4510/* /web/static/src/core/user_switch/user_switch.js */ 4511odoo.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]);} 4512toggleFormDisplay(){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();} 4513getAvatarUrl({partnerId,partnerWriteDate:unique}){return imageUrl("res.partner",partnerId,"avatar_128",{unique});} 4514remove(deletedUser){this.state.users=this.state.users.filter((user)=>user!==deletedUser);setLastConnectedUsers(this.state.users);if(!this.state.users.length){this.fillForm();}} 4515fillForm(login=""){this.form.querySelector("input#login").value=login;this.form.querySelector("input#password").value="";this.toggleFormDisplay();}} 4516registry.category("public_components").add("web.user_switch",UserSwitch);return __exports;});; 4517 4518/* /web/static/src/core/utils/arrays.js */ 4519odoo.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];} 4520const firstArray=args.shift().map((elem)=>[elem]);if(args.length===0){return firstArray;} 4521const result=[];const productOfOtherArrays=_cartesian(...args);for(const array of firstArray){for(const tuple of productOfOtherArrays){result.push([...array,...tuple]);}} 4522return result;} 4523function _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;}}
4524__exports.ensureArray=ensureArray;function ensureArray(value){return isIterable(value)?[...value]:[value];} 4525__exports.intersection=intersection;function intersection(iter1,iter2){const set2=new Set(iter2);return unique(iter1).filter((v)=>set2.has(v));} 4526__exports.isIterable=isIterable;function isIterable(value){return Boolean(value&&typeof value==="object"&&value[Symbol.iterator]);} 4527__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]=[];} 4528groups[group].push(element);} 4529return groups;} 4530__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;} 4531return order==="asc"?result:-result;});} 4532__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)),];} 4533__exports.cartesian=cartesian;function cartesian(...args){if(args.length===0){return[undefined];}else if(args.length===1){return args[0];}else{return _cartesian(...args);}} 4534const 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));} 4535return sections;} 4536__exports.unique=unique;function unique(iterable){return[...new Set(iterable)];} 4537__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]]);} 4538return result;} 4539__exports.zipWith=zipWith;function zipWith(iter1,iter2,mapFn){return zip(iter1,iter2).map(([e1,e2])=>mapFn(e1,e2));} 4540__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));} 4541return res;} 4542__exports.rotate=rotate;function rotate(i,arr,inc=1){return(arr.length+i+inc)%arr.length;} 4543return __exports;});; 4544 4545/* /web/static/src/core/utils/autoresize.js */ 4546odoo.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;} 4547if(el instanceof HTMLInputElement){resizeInput(el);}else{resizeTextArea(el,options);} 4548options.onResize?.(el,options);};el.addEventListener("input",()=>resize(true));const resizeObserver=new ResizeObserver(()=>{if(wasProgrammaticallyResized){wasProgrammaticallyResized=false;return;} 4549resize();});resizeObserver.observe(el);return()=>{el.removeEventListener("input",resize);resizeObserver.unobserve(el);resizeObserver.disconnect();resize=null;};}},()=>[ref.el]);useEffect(()=>{if(resize){resize(true);}});} 4550const doesScrollWidthExcludePadding=memoize(()=>{const input=document.createElement("input");input.style.cssText=` 4551 position: absolute; 4552 visibility: hidden; 4553 padding: 0; 4554 border: 0; 4555 width: auto; 4556 `;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;} 4557let boxExtraWidth=parseFloat(style.borderLeftWidth)+parseFloat(style.borderRightWidth);if(doesScrollWidthExcludePadding()){const padding=parseFloat(style.paddingLeft)+parseFloat(style.paddingRight);boxExtraWidth+=padding;} 4558const desiredWidth=input.scrollWidth+boxExtraWidth+1;if(desiredWidth>maxWidth){input.style.width="100%";return;} 4559input.style.width=`${desiredWidth}px`;} 4560__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;} 4561const 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`;} 4562return __exports;});; 4563 4564/* /web/static/src/core/utils/binary.js */ 4565odoo.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);} 4566__exports.toBase64Length=toBase64Length;function toBase64Length(maxBytes){return Math.ceil(maxBytes*4/3);} 4567__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;} 4568return`${size.toFixed(2)} ${units[i].trim()}`;} 4569return __exports;});; 4570 4571/* /web/static/src/core/utils/cache.js */ 4572odoo.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;} 4573_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]]||{};} 4574key=path[path.length-1];} 4575return{cache,key};} 4576clear(...path){const{cache,key}=this._getCacheAndKey(...path);delete cache[key];} 4577invalidate(){this.cache={};} 4578read(...path){const{cache,key}=this._getCacheAndKey(...path);if(!(key in cache)){cache[key]=this.getValue(...path);} 4579return cache[key];}} 4580return __exports;});; 4581 4582/* /web/static/src/core/utils/classname.js */ 4583odoo.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());}}}} 4584__exports.mergeClasses=mergeClasses;function mergeClasses(...classes){const classObj={};for(const classDefinition of classes){Object.assign(classObj,toClassObj(classDefinition));} 4585return classObj;} 4586function toClassObj(classDefinition){if(!classDefinition){return{};}else if(typeof classDefinition==="object"){return classDefinition;}else if(typeof classDefinition==="string"){const classObj={};
4586classDefinition.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{};}} 4587return __exports;});; 4588 4589/* /web/static/src/core/utils/colors.js */ 4590odoo.define('@web/core/utils/colors',[],function(require){'use strict';let __exports={};__exports.applyOpacityToGradient=applyOpacityToGradient;function applyOpacityToGradient(gradient,opacity=100){if(opacity===100){return gradient;} 4591return gradient.replace(/rgb\(([^)]+)\)/g,`rgba($1, ${opacity / 100.0})`);} 4592__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;} 4593var 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;} 4594if(maxColor===green){hue=2+(blue-red)/delta;} 4595if(maxColor===blue){hue=4+(red-green)/delta;} 4596if(maxColor){saturation=delta/(1-Math.abs(2*lightness-1));}} 4597hue=60*hue;return{hue:hue<0?hue+360:hue,saturation:saturation*100,lightness:lightness*100,};} 4598__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;} 4599var 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,};} 4600if(huePrime>=1&&huePrime<2){return{red:secondComponent,green:chroma,blue:lightnessAdjustment,};} 4601if(huePrime>=2&&huePrime<3){return{red:lightnessAdjustment,green:chroma,blue:secondComponent,};} 4602if(huePrime>=3&&huePrime<4){return{red:lightnessAdjustment,green:secondComponent,blue:chroma,};} 4603if(huePrime>=4&&huePrime<5){return{red:secondComponent,green:lightnessAdjustment,blue:chroma,};} 4604if(huePrime>=5&&huePrime<=6){return{red:chroma,green:lightnessAdjustment,blue:secondComponent,};} 4605return false;} 4606__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;} 4607const 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();} 4608const alpha=Math.round((a/100)*255);const aa=alpha<16?"0"+alpha.toString(16):alpha.toString(16);return`#${rr}${gg}${bb}${aa}`.toUpperCase();} 4609__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;} 4610return{red:parseInt(rgba[1]),green:parseInt(rgba[2]),blue:parseInt(rgba[3]),opacity:Math.round(parseFloat(rgba[4])*100),};} 4611if(/^#([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,};} 4612if(/^#([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,};} 4613if(/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,};} 4614return false;} 4615__exports.normalizeCSSColor=normalizeCSSColor;function normalizeCSSColor(cssColor){const rgba=convertCSSColorToRgba(cssColor);if(!rgba){return cssColor;} 4616return convertRgbaToCSSColor(rgba.red,rgba.green,rgba.blue,rgba.opacity);} 4617__exports.isCSSColor=isCSSColor;function isCSSColor(cssColor){return convertCSSColorToRgba(cssColor)!==false;} 4618__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);} 4619__exports.isColorGradient=isColorGradient;function isColorGradient(value){return value&&value.includes("-gradient(");} 4620__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");} 4621return gradient;} 4622const 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)||[];
4622const alpha=parseFloat(values.pop());let bgRgbValues=[];if(node){let bgColor=getComputedStyle(node).backgroundColor;if(bgColor.startsWith("rgba")){bgColor=rgbToHex(bgColor,node.parentElement);} 4623if(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));}} 4624bgRgbValues=bgRgbValues.length?bgRgbValues:[255,255,255];return("#"+ 4625values.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("#"+ 4626(rgb.match(/\d{1,3}/g)||[]).map((x)=>{x=parseInt(x).toString(16);return x.length===1?"0"+x:x;}).join(""));}} 4627__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);}} 4628__exports.blendColors=blendColors;function blendColors(color,node){if(!color.startsWith("rgba")){return rgbaToHex(color);} 4629let bgRgbValues=[255,255,255];if(node){let bgColor=getComputedStyle(node).backgroundColor;if(bgColor.startsWith("rgba")){bgColor=blendColors(bgColor,node.parentElement);} 4630if(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));}} 4631const values=color.match(/[\d.]{1,5}/g)||[];const alpha=values.length===4?parseFloat(values.pop()):1;return("#"+ 4632values.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(""));} 4633return __exports;});; 4634 4635/* /web/static/src/core/utils/components.js */ 4636odoo.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);});}} 4637return __exports;});; 4638 4639/* /web/static/src/core/utils/concurrency.js */ 4640odoo.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);});} 4641const KeepLast=__exports.KeepLast=class KeepLast{constructor(){this._id=0;} 4642add(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);}});});}} 4643const Mutex=__exports.Mutex=class Mutex{constructor(){this._lock=Promise.resolve();this._queueSize=0;this._unlockedProm=undefined;this._unlock=undefined;} 4644async exec(action){this._queueSize++;if(!this._unlockedProm){this._unlockedProm=new Promise((resolve)=>{this._unlock=()=>{resolve();this._unlockedProm=undefined;};});} 4645const always=()=>{return Promise.resolve(action()).finally(()=>{if(--this._queueSize===0){this._unlock();}});};this._lock=this._lock.then(always,always);return this._lock;} 4646getUnlockedDef(){return this._unlockedProm||Promise.resolve();}} 4647const Race=__exports.Race=class Race{constructor(){this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;} 4648add(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);};});} 4649promise.then(this.currentPromResolver).catch(this.currentPromRejecter);return this.currentProm;} 4650getCurrentProm(){return this.currentProm;}} 4651const Deferred=__exports.Deferred=class Deferred extends Promise{constructor(){let resolve;let reject;
4651const prom=new Promise((res,rej)=>{resolve=res;reject=rej;});return Object.assign(prom,{resolve,reject});}} 4652return __exports;});; 4653 4654/* /web/static/src/core/utils/draggable.js */ 4655odoo.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;});; 4656 4657/* /web/static/src/core/utils/draggable_hook_builder.js */ 4658odoo.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();} 4659function getReturnValue(valueOrFn){if(typeof valueOrFn==="function"){return valueOrFn();} 4660return valueOrFn;} 4661function getScrollParents(el){return[closestScrollableX(el),closestScrollableY(el)];} 4662function makeCleanupManager(defaultCleanupFn){const add=(cleanupFn)=>typeof cleanupFn==="function"&&cleanups.push(cleanupFn);const cleanup=()=>{while(cleanups.length){cleanups.pop()();} 4663add(defaultCleanupFn);};const cleanups=[];add(defaultCleanupFn);return{add,cleanup};} 4664function makeDOMHelpers(cleanup){const addClass=(el,...classNames)=>{if(!el||!classNames.length){return;} 4665cleanup.add(()=>el.classList.remove(...classNames));el.classList.add(...classNames);};const addListener=(el,event,callback,options={})=>{if(!el||!event||!callback){return;} 4666const{noAddedStyle}=options;delete options.noAddedStyle;el.addEventListener(event,callback,options);if(!noAddedStyle&&/mouse|pointer|touch/.test(event)){addStyle(el,{pointerEvents:"auto"});} 4667cleanup.add(()=>el.removeEventListener(event,callback,options));};const addStyle=(el,style)=>{if(!el||!style||!Object.keys(style).length){return;} 4668cleanup.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{};} 4669const 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;} 4670return rect;};const removeAttribute=(el,attribute)=>{if(!el||!attribute){return;} 4671cleanup.add(saveAttribute(el,attribute));el.removeAttribute(attribute);};const removeClass=(el,...classNames)=>{if(!el||!classNames.length){return;} 4672cleanup.add(saveAttribute(el,"class"));el.classList.remove(...classNames);};const removeStyle=(el,...properties)=>{if(!el||!properties.length){return;} 4673cleanup.add(saveAttribute(el,"style"));for(const key of properties){el.style.removeProperty(camelToKebab(key));}};const setAttribute=(el,attribute,value)=>
4673{if(!el||!attribute){return;} 4674cleanup.add(saveAttribute(el,attribute));el.setAttribute(attribute,String(value));};return{addClass,addListener,addStyle,getRect,removeAttribute,removeClass,removeStyle,setAttribute,};} 4675function pixelValueToNumber(val){return Number(val.endsWith("px")?val.slice(0,-2):val);} 4676function safePrevent(ev,{stop}={}){if(ev.cancelable){ev.preventDefault();if(stop){ev.stopPropagation();}}} 4677function 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();} 4678const cache=elCache[attribute];if(cache.has(el)){return;} 4679cache.add(el);const hasAttribute=el.hasAttribute(attribute);const originalValue=el.getAttribute(attribute);return restoreAttribute;} 4680function toFunction(value){return typeof value==="function"?value:()=>value;} 4681__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]);}}} 4682return 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;} 4683const returnValue=hookParams[hookHandlerName]({ctx,...helpers,...arg});if(returnValue){callHandler(hookHandlerName,returnValue);}};const callHandler=(handlerName,arg)=>{if(typeof params[handlerName]!=="function"){return;} 4684try{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();} 4685dom.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");}}} 4686if(ctx.cursor){dom.addStyle(document.body,{cursor:ctx.cursor});} 4687if((ctx.current.scrollParentX||ctx.current.scrollParentY)&&ctx.edgeScrolling.enabled){const cleanupFn=setRecurringAnimationFrame(handleEdgeScrolling);cleanup.add(cleanupFn);} 4688dom.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});} 4689callBuildHandler("onDragEnd");}} 4690cleanup.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
4690Rect.y+=scrollParentYEl.scrollTop;} 4691const{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";}} 4692if(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";}} 4693const 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)});} 4694if((!direction||direction==="horizontal")&&diff.x){ctx.current.scrollParentX.scrollBy({left:diffToScroll(diff.x)});} 4695callBuildHandler("onDrag");};const onClick=(ev)=>{if(preventClick){safePrevent(ev,{stop:true});}};const onKeyDown=(ev)=>{if(!state.dragging||!ctx.enable()){return;} 4696if(!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;} 4697safePrevent(ev);ev.target.focus();let activeElement=document.activeElement;while(activeElement?.nodeName==="IFRAME"){activeElement=activeElement.contentDocument?.activeElement;} 4698if(activeElement&&!activeElement.contains(ev.target)){activeElement.blur();} 4699const{currentTarget,pointerId,target}=ev;ctx.current.initialPosition={...ctx.pointer};if(target.hasPointerCapture(pointerId)){target.releasePointerCapture(pointerId);} 4700if(initiationDelay){if(hasTouch()){if(ev.pointerType==="touch"){dom.addClass(target.closest(ctx.elementSelector),"o_touch_bounce");} 4701if(isBrowserFirefox()){const links=[...currentTarget.querySelectorAll("[href]")];if(currentTarget.hasAttribute("href")){links.unshift(currentTarget);} 4702for(const link of links){dom.removeAttribute(link,"href");}} 4703if(isIOS()){for(const image of currentTarget.getElementsByTagName("img")){dom.setAttribute(image,"draggable",false);}}} 4704ctx.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;} 4705safePrevent(ev);if(!state.dragging){if(!canStartDrag()){return;} 4706dragStart();}else if(!params.allowDisconnected&&!ctx.current.element.isConnected){return dragEnd(null);} 4707if(ctx.followCursor){updateElementPosition();} 4708callBuildHandler("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;} 4709const isContainerRTL=getComputedStyle(container).direction==="rtl";const containerBoxLeft=current.containerRect.x;const containerBoxRight=current.containerRect.x+current.containerRect.width;current.containerRect.width=container.scrollWidth;current.containerRect.height=container.scrollHeight;if(isContainerRTL){current.containerRect.x=containerBoxRight-container.scrollWidth;}
4710current.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 containerRight=isContainerRTL?containerBoxRight:containerBoxLeft+container.scrollWidth;const right=Math.min(containerRight,current.scrollParentXRect.right);current.containerRect.x=Math.max(current.containerRect.x,current.scrollParentXRect.x);current.containerRect.width=right-current.containerRect.x;} 4711if(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;}} 4712ctx.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( 4713 ", " 4714 )} } and got ${type}`);}}else if(MANDATORY_PARAMS.includes(prop)&&!defaultParams[prop]){throw makeError(`missing required property "${prop}" in parameters`);}} 4715const 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,};} 4716if(!ctx.ref.el){return;} 4717ctx.enable=actualParams.enable;if(actualParams.preventDrag){ctx.preventDrag=actualParams.preventDrag;} 4718ctx.elementSelector=actualParams.elements;if(!ctx.elementSelector){throw makeError(`no value found by "elements" selector: ${ctx.elementSelector}`);} 4719const allSelectors=[ctx.elementSelector];ctx.cursor=actualParams.cursor||null;if(actualParams.handle){allSelectors.push(actualParams.handle);} 4720if(actualParams.ignore){ctx.ignoreSelector=actualParams.ignore;} 4721ctx.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,});} 4722return cleanup;}},()=>[ctx.ref.el]);const addWindowListener=(type,listener,options)=>{if(params.iframeWindow){setupHooks.addListener(params.iframeWindow,type,listener,options);} 4723setupHooks.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];} 4724return __exports;});; 4725 4726/* /web/static/src/core/utils/draggable_hook_builder_owl.js */ 4727odoo.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,},});} 4728return __exports;});; 4729 4730/* /web/static/src/core/utils/dvu.js */ 4731odoo.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);}};}
4731,notifyListeners(){this.listeners.forEach((listener)=>listener());},};if(typeof window!=="undefined"){const throttledUpdate=throttleForAnimation(()=>viewport.notifyListeners());if(browser.visualViewport){browser.visualViewport.addEventListener("resize",throttledUpdate);} 4732if(isVirtualKeyboardSupported()){browser.navigator.virtualKeyboard.addEventListener("geometrychange",throttledUpdate);} 4733browser.addEventListener("resize",throttledUpdate);} 4734__exports.getViewportDimensions=getViewportDimensions;function getViewportDimensions(){return{width:browser.visualViewport?.width||browser.innerWidth,height:browser.visualViewport?.height||browser.innerHeight,};} 4735__exports.onViewportChange=onViewportChange;function onViewportChange(callback){return viewport.addListener(callback);} 4736__exports.useViewportChange=useViewportChange;function useViewportChange(callback){const removeListener=onViewportChange(callback);onWillUnmount(()=>removeListener());} 4737return __exports;});; 4738 4739/* /web/static/src/core/utils/files.js */ 4740odoo.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;} 4741return true;} 4742__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;}} 4743const fileData=await http.post(route,params,"text");const parsedFileData=JSON.parse(fileData);if(parsedFileData.error){throw new Error(parsedFileData.error);} 4744return parsedFileData;};} 4745__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")));} 4746const{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);});} 4747return __exports;});; 4748 4749/* /web/static/src/core/utils/functions.js */ 4750odoo.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));} 4751return cache.get(...args);},}[funcName];} 4752__exports.uniqueId=uniqueId;function uniqueId(prefix=""){return`${prefix}${++uniqueId.nextId}`;} 4753uniqueId.nextId=0;return __exports;});; 4754 4755/* /web/static/src/core/utils/hooks.js */ 4756odoo.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;} 4757if(!mobile&&isMobileOS()){return ref;} 4758function isFocusable(el){if(!el){return;} 4759if(!uiService.activeElement||uiService.activeElement.contains(el)){return true;} 4760const rootNode=el.getRootNode();return rootNode instanceof ShadowRoot&&uiService.activeElement.contains(rootNode.host);} 4761useEffect((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;} 4762__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);},()=>[]);} 4763const 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();} 4764const 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,});};} 4765const 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`);} 4766const 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]);} 4767return result;}} 4768if(toRaw(service)!==service){return useState(service);} 4769return service;}
4770__exports.useSpellCheck=useSpellCheck;function useSpellCheck({refName}={}){const elements=[];const ref=useRef(refName||"spellcheck");function toggleSpellcheck(ev){ev.target.spellcheck=document.activeElement===ev.target;} 4771useEffect((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);}});} 4772return()=>{elements.forEach((input)=>{input.removeEventListener("focus",toggleSpellcheck);input.removeEventListener("blur",toggleSpellcheck);});};},()=>[ref.el]);} 4773__exports.useChildRef=useChildRef;function useChildRef(){let defined=false;let value;return function ref(v){value=v;if(defined){return;} 4774Object.defineProperty(ref,"el",{get(){return value.el;},});defined=true;};} 4775__exports.useForwardRefToParent=useForwardRefToParent;function useForwardRefToParent(refName){const component=useComponent();const ref=useRef(refName);if(component.props[refName]){component.props[refName](ref);} 4776return ref;} 4777__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;} 4778__exports.useRefListener=useRefListener;function useRefListener(ref,...listener){useEffect((el)=>{el?.addEventListener(...listener);return()=>el?.removeEventListener(...listener);},()=>[ref.el]);} 4779return __exports;});; 4780 4781/* /web/static/src/core/utils/html.js */ 4782odoo.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");} 4783__exports.createElementWithContent=createElementWithContent;function createElementWithContent(elementName,content){const element=document.createElement(elementName);setElementContent(element,content);return element;} 4784__exports.highlightText=highlightText;function highlightText(query,text,classes){if(!query||!text){return text;} 4785let 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>`;});} 4786return result;} 4787__exports.htmlFormatList=htmlFormatList;function htmlFormatList(values,options){return markup(formatList(Array.from(values,htmlEscape),options));} 4788__exports.htmlJoin=htmlJoin;function htmlJoin(list,separator=""){return markup(Array.from(list,htmlEscape).join(htmlEscape(separator)));} 4789__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.");} 4790content=htmlEscape(content);if(typeof search==="string"||search instanceof String){search=htmlEscape(search);} 4791const safeReplacement=isReplacerFn?(...args)=>htmlEscape(replacer(...args)):htmlEscape(replacer);return markup(content.replace(search,safeReplacement));} 4792__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.");} 4793content=htmlEscape(content);
4793if(typeof search==="string"||search instanceof String){search=htmlEscape(search);} 4794const safeReplacement=isReplacerFn?(...args)=>htmlEscape(replacer(...args)):htmlEscape(replacer);return markup(content.replaceAll(search,safeReplacement));} 4795__exports.htmlSprintf=htmlSprintf;function htmlSprintf(str,...substitutions){const replaced=sprintf(htmlEscape(str),...mapSubstitutions(substitutions,htmlEscape));return markup(replaced);} 4796__exports.htmlTrim=htmlTrim;function htmlTrim(content){content=htmlEscape(content);return markup(content.trim());} 4797__exports.isHtmlEmpty=isHtmlEmpty;function isHtmlEmpty(content=""){return createElementWithContent("div",content).textContent.trim()==="";} 4798__exports.isMarkup=isMarkup;function isMarkup(content){return content instanceof Markup;} 4799__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);} 4800return text;} 4801__exports.setElementContent=setElementContent;function setElementContent(element,content){if(isMarkup(content)){element.innerHTML=content;}else{element.textContent=content;}} 4802return __exports;});; 4803 4804/* /web/static/src/core/utils/indexed_db.js */ 4805odoo.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{} 4806function formatStorageSize(size){const units=["b","Kb","Mb","Gb"];while(size>=1000&&units.length>1){size/=1000;units.splice(0,1);} 4807return`${size.toFixed(2)}${units[0]}`;} 4808const 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));} 4809async read(table,key){this._tables.add(table);return this.execute((db)=>{if(db){return this._read(db,table,key);}});} 4810async write(table,key,value){this._tables.add(table);return this.execute((db)=>{if(db){return this._write(db,table,key,value);}});} 4811async invalidate(tables=null){return this.execute((db)=>{if(db){return this._invalidate(db,typeof tables==="string"?[tables]:tables);}});} 4812async deleteDatabase(){return this.mutex.exec(()=>this._deleteDatabase(()=>{}));} 4813async execute(callback){return this.mutex.exec(()=>this._execute(callback));} 4814async _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);};});} 4815async _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();}});});} 4816async _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);}
4817Promise.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( 4818 usage 4819 )} 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);};});} 4820async _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();});} 4821async _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();} 4822const 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();});} 4823async _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);});}} 4824return __exports;});; 4825 4826/* /web/static/src/core/utils/misc.js */ 4827odoo.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;} 4828return eventHandledWeakMap.get(ev).includes(markName);} 4829__exports.markEventHandled=markEventHandled;function markEventHandled(ev,markName){if(!eventHandledWeakMap.get(ev)){eventHandledWeakMap.set(ev,[]);} 4830eventHandledWeakMap.get(ev).push(markName);} 4831return __exports;});; 4832 4833/* /web/static/src/core/utils/nested_sortable.js */ 4834odoo.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(" ");} 4835ctx.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;}} 4836if(ctx.nest){ctx.prevNestX=ctx.pointer.x;} 4837ctx.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");} 4838addCleanup(()=>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);} 4839return depth?result+1:result;},_hasReachMaxAllowedLevel(ctx){if(!ctx.nest||ctx.maxLevels<1){return false;} 4840let level=this._getDeepestChildLevel(ctx,ctx.current.element);let list=ctx.current.placeHolder.closest(ctx.listTagName);while(list){level++;list=list.parentNode.closest(ctx.listTagName);} 4841return 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;} 4842ctx.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);} 4843return 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;} 4844if(!nextElement){const newSibling=position.parent;if(newSibling){newSibling.after(ctx.current.placeHolder);onMove(position);}} 4845ctx.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;} 4846if(parent&&parent.matches(ctx.elementSelector)){getChildList(parent).appendChild(ctx.current.placeHolder);onMove(position);} 4847ctx.prevNestX=ctx.pointer.x;return;}} 4848const currentTop=ctx.pointer.y-ctx.current.offset.y;const closestEl=document.elementFromPoint(ctx.selectorX,currentTop);
4848if(!closestEl){return;} 4849const 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);} 4850ctx.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);} 4851ctx.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;} 4852const 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;});; 4853 4854/* /web/static/src/core/utils/numbers.js */ 4855odoo.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);} 4856__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);} 4857return array;} 4858__exports.roundPrecision=roundPrecision;function roundPrecision(value,precision,method="HALF-UP"){if(!value){return 0;}else if(!precision||precision<0){precision=1;} 4859let roundingFactor=precision;let normalize=(val)=>val/roundingFactor;let denormalize=(val)=>val*roundingFactor;if(roundingFactor<1){roundingFactor=invertFloat(roundingFactor);[normalize,denormalize]=[denormalize,normalize];} 4860const 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;} 4861case"HALF-DOWN":{roundedValue=Math.round(normalizedValue-sign*epsilon);break;} 4862case"HALF-UP":{roundedValue=Math.round(normalizedValue+sign*epsilon);break;} 4863case"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;} 4864case"UP":{roundedValue=Math.trunc(normalizedValue+sign*(1-epsilon));break;} 4865default:{throw new Error(`Unknown rounding method: ${method}`);}} 4866return denormalize(roundedValue);} 4867function 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}`;} 4868__exports.roundDecimals=roundDecimals;function roundDecimals(value,decimals){return roundPrecision(value,parseFloat("1e"+-decimals));} 4869__exports.floatIsZero=floatIsZero;function floatIsZero(value,decimals){return value===0||roundDecimals(value,decimals)===0;} 4870__exports.insertThousandsSep=insertThousandsSep;function insertThousandsSep(number,thousandsSep=",",grouping=[]){const negative=number[0]==="-";number=negative?number.slice(1):number;return(negative?"-":"")+intersperse(number,grouping,thousandsSep);} 4871__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}`;} 4872const 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);
4872if(s<=number/Math.pow(10,minDigits-1)){number=Math.round((number*d2)/s)/d2;symbol=unitSymbols[i-1];break;}} 4873const{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;} 4874return int+decimalPoint+decimalPart+symbol;} 4875__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;} 4876const 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;} 4877if(options.humanReadable){return humanNumber(value,options);} 4878const 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");}} 4879return formatted[1]?formatted.join(decimalPoint):formatted[0];} 4880const _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);} 4881return res;} 4882return __exports;});; 4883 4884/* /web/static/src/core/utils/objects.js */ 4885odoo.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;} 4886const obj1Keys=Reflect.ownKeys(obj1);return(obj1Keys.length===Reflect.ownKeys(obj2).length&&obj1Keys.every((key)=>comparisonFn(obj1[key],obj2[key])));} 4887const deepEqual=__exports.deepEqual=(obj1,obj2)=>shallowEqual(obj1,obj2,deepEqual);__exports.deepCopy=deepCopy;function deepCopy(object){return object&&JSON.parse(JSON.stringify(object));} 4888__exports.isObject=isObject;function isObject(value){return Object.prototype.toString.call(value)==="[object Object]";} 4889__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];}} 4890return result;} 4891__exports.pick=pick;function pick(object,...properties){return Object.fromEntries(properties.filter((prop)=>prop in object).map((prop)=>[prop,object[prop]]));} 4892__exports.deepMerge=deepMerge;function deepMerge(target,extension){if(!isObject(target)&&!isObject(extension)){return;} 4893target=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]});}}} 4894return output;} 4895return __exports;});; 4896 4897/* /web/static/src/core/utils/patch.js */ 4898odoo.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(),});} 4899return patchDescriptions.get(objToPatch);} 4900function isClassPrototype(objToPatch){return(Object.hasOwn(objToPatch,"constructor")&&objToPatch.constructor?.prototype===objToPatch);}
4901function findAncestorPropertyDescriptor(objToPatch,key){let descriptor=null;let prototype=objToPatch;do{descriptor=Object.getOwnPropertyDescriptor(prototype,key);prototype=Object.getPrototypeOf(prototype);}while(!descriptor&&prototype);return descriptor;} 4902__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`);} 4903const 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);} 4904if(!description.originalProperties.has(key)){description.originalProperties.set(key,oldProperty);} 4905if(isClassPrototype(objToPatch)){newProperty.enumerable=false;} 4906if((newProperty.get&&1)^(newProperty.set&&1
4906)){const ancestorProperty=findAncestorPropertyDescriptor(objToPatch,key);newProperty.get=newProperty.get??ancestorProperty?.get;newProperty.set=newProperty.set??ancestorProperty?.set;} 4907Object.defineProperty(objToPatch,key,newProperty);} 4908description.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];}} 4909description.extensions.delete(extension);for(const extension of description.extensions){patch(objToPatch,extension);}};} 4910return __exports;});; 4911 4912/* /web/static/src/core/utils/pdfjs.js */ 4913odoo.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"]);} 4914if(options.hidePrint||isMobileOS()){hiddenElements.push(["button#printButton","button#secondaryPrint"]);} 4915if(options.hidePresentation){hiddenElements.push("button#presentationMode");} 4916if(options.hideRotation){hiddenElements.push("button#pageRotateCw");hiddenElements.push("button#pageRotateCcw");} 4917const cssStyle=document.createElement("style");cssStyle.rel="stylesheet";cssStyle.textContent=`${hiddenElements.join(", ")} { 4918 display: none !important; 4919}`;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");}} 4920__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"),]);} 4921return __exports;});; 4922 4923/* /web/static/src/core/utils/reactive.js */ 4924odoo.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);}} 4925__exports.effect=effect;function effect(cb,deps){const reactiveDeps=reactive(deps,()=>{cb(...reactiveDeps);});cb(...reactiveDeps);} 4926__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]);} 4927return obj;} 4928return __exports;});; 4929 4930/* /web/static/src/core/utils/render.js */ 4931odoo.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.`);} 4932el?.remove();return el;} 4933__exports.renderToFragment=renderToFragment;function renderToFragment(template,context={}){const frag=document.createDocumentFragment();for(const el of[...render(template,context).children]){frag.appendChild(el);} 4934return frag;} 4935__exports.renderToString=renderToString;function renderToString(template,context={}){return render(template,context).innerHTML;} 4936let app;Object.defineProperty(renderToString,"app",{get:()=>{if(!app){app=new App(Component,{name:"renderToString",getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,});} 4937return 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;} 4938__exports.renderToMarkup=renderToMarkup;function renderToMarkup(template,context={}){return markup(renderToString(template,context));} 4939return __exports;});; 4940 4941/* /web/static/src/core/utils/scrolling.js */ 4942odoo.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);} 4943return false;} 4944__exports.couldBeScrollableX=couldBeScrollableX;function couldBeScrollableX(el){if(el){const overflow=getComputedStyle(el).getPropertyValue("overflow-x");
4944if(/\bauto\b|\bscroll\b/.test(overflow)){return true;}} 4945return false;} 4946__exports.closestScrollableX=closestScrollableX;function closestScrollableX(el){if(!el){return null;} 4947if(isScrollableX(el)){return el;} 4948return closestScrollableX(el.parentElement);} 4949__exports.isScrollableY=isScrollableY;function isScrollableY(el){if(el&&el.scrollHeight>el.clientHeight&&el.clientHeight>0){return couldBeScrollableY(el);} 4950return false;} 4951__exports.couldBeScrollableY=couldBeScrollableY;function couldBeScrollableY(el){if(el){const overflow=getComputedStyle(el).getPropertyValue("overflow-y");if(/\bauto\b|\bscroll\b/.test(overflow)){return true;}} 4952return false;} 4953__exports.closestScrollableY=closestScrollableY;function closestScrollableY(el){if(!el){return null;} 4954if(isScrollableY(el)){return el;} 4955return closestScrollableY(el.parentElement);} 4956__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;} 4957const 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+ 4958elementTop- 4959scrollBottom+ 4960Math.ceil(element.getBoundingClientRect().height)+ 4961offset,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,}));}}} 4962return Promise.all(scrollPromises);} 4963__exports.compensateScrollbar=compensateScrollbar;function compensateScrollbar(el,add=true,isScrollElement=true,cssProperty="padding-right"){if(!el){return;} 4964const scrollableEl=isScrollElement?el:closestScrollableY(el.parentElement);if(!scrollableEl){return;} 4965const isRTL=scrollableEl.classList.contains(".o_rtl");if(isRTL){cssProperty=cssProperty.replace("right","left");} 4966el.style.removeProperty(cssProperty);if(!add){return;} 4967const 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])+ 4968scrollableEl.offsetWidth- 4969scrollableEl.clientWidth- 4970bordersWidth;el.style.setProperty(cssProperty,`${newValue}px`,"important");} 4971__exports.getScrollingElement=getScrollingElement;function getScrollingElement(document=window.document){const baseScrollingElement=document.scrollingElement;if(isScrollableY(baseScrollingElement)){return baseScrollingElement;} 4972const bodyHeight=window.getComputedStyle(document.body).height;for(const el of document.body.children){if(bodyHeight-el.scrollHeight>1.5){continue;} 4973if(isScrollableY(el)){return el;}} 4974return baseScrollingElement;} 4975__exports.getScrollingTarget=getScrollingTarget;function getScrollingTarget(scrollingElement=window.document){const document=scrollingElement.ownerDocument;return scrollingElement===document.scrollingElement?document.defaultView:scrollingElement;} 4976return __exports;});; 4977 4978/* /web/static/src/core/utils/search.js */ 4979odoo.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];} 4980let globalScore=0;for(const str of strs){globalScore=Math.max(globalScore,_match(pattern,str));} 4981return globalScore;} 4982function _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++;
4982currentScore+=100+currentScore-i/200;}else{currentScore=0;} 4983totalScore=totalScore+currentScore;} 4984return patternIndex===pattern.length?totalScore:0;} 4985__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);} 4986__exports.fuzzyTest=fuzzyTest;function fuzzyTest(pattern,string){return _match(pattern,string)!==0;} 4987__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);} 4988function 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;}} 4989for(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);}}}} 4990return distanceMatrix[aLength][bLength];} 4991return __exports;});; 4992 4993/* /web/static/src/core/utils/sortable.js */ 4994odoo.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(" ");} 4995ctx.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);}} 4996callHandler("onElementEnter",{element});};const onElementPointerLeave=(ev)=>{const element=ev.currentTarget;callHandler("onElementLeave",{element});};const onElementComplexPointerEnter=(ev)=>{if(ctx.haveAlreadyChanged){return;} 4997const 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;}}} 4998callHandler("onElementEnter",{element});};const onElementComplexPointerLeave=(ev)=>{if(ctx.haveAlreadyChanged){return;} 4999const 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
4999ED_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;}} 5000callHandler("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`,});} 5001if(connectGroups&&groupSelector){for(const siblingGroup of ref.el.querySelectorAll(groupSelector)){addListener(siblingGroup,"pointerenter",onGroupPointerEnter);addListener(siblingGroup,"pointerleave",onGroupPointerLeave);}} 5002for(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);}}} 5003current.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);}} 5004return{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;}} 5005if(ctx.placeholderClone){current.placeHolder=current.element.cloneNode(false);}else{current.placeHolder=document.createElement("div");} 5006current.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;});; 5007 5008/* /web/static/src/core/utils/sortable_owl.js */ 5009odoo.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,},});} 5010return __exports;});; 5011 5012/* /web/static/src/core/utils/sortable_service.js */ 5013odoo.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],};},};}} 5014const 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);}} 5015cleanupFunctions.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});} 5016return{enable(){setupFunctions.forEach((dependenciesFn,setupFn)=>setupFn(...dependenciesFn()));return{cleanup,};},};},};},};registry.category("services").add("sortable",sortableService);return __exports;});; 5017 5018/* /web/static/src/core/utils/strings.js */ 5019odoo.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]);} 5020const 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):"";} 5021__exports.escape=escape;function escape(value){if(typeof value!=="string"){return String(value??"");} 5022for(const[char,replacer]of HTML_ESCAPED_CHARACTERS){value=value.replaceAll(char,replacer);} 5023return value;} 5024__exports.escapeRegExp=escapeRegExp;function escapeRegExp(pattern){return pattern.replaceAll(R_REGEX_SPECIAL_CHARS,"\\$&");} 5025__exports.exprToBoolean=exprToBoolean;function exprToBoolean(str,trueIfEmpty=false){return str?!R_FALSY.test(str):trueIfEmpty;} 5026__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;} 5027return(hash+16**8).toString(16).slice(-8);} 5028__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];} 5029result.unshift(str.substring(last-section,last));last-=section;} 5030const substr=str.substring(0,last);if(substr){result.unshift(substr);} 5031return result.join(separator||"");} 5032__exports.isEmail=isEmail;function isEmail(value){return R_EMAIL.test(value);} 5033__exports.isNumeric=isNumeric;function isNumeric(value){return R_NUMERIC.test(value);} 5034__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);} 5035return[substitutionDict];}else{return substitutions.map(mapFn);}} 5036__exports.sprintf=sprintf;function sprintf(str,...substitutions){if(!substitutions.length){return str;} 5037if(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;} 5038if(str[i+1]==="s"){i++;raw.push("");continue;}} 5039raw[raw.length-1]+=str[i];} 5040return String.raw({raw},...substitutions);}} 5041__exports.uuid=uuid;function uuid(){let id="";for(const b of crypto.getRandomValues(new Uint8Array(8))){id+=b.toString(16).padStart(2,"0");} 5042return id;} 5043return __exports;});; 5044 5045/* /web/static/src/core/utils/timing.js */ 5046odoo.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);}};} 5047__exports.debounce=debounce;function debounce(func,delay,options){let handle;const funcName=func.name?func.name+" (debounce)":"debounce";const useAnimationFrame=delay==="animationFrame";
5047const 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;} 5048return Object.assign({[funcName](...args){return new Promise((resolve)=>{if(leading&&!handle){Promise.resolve(func.apply(this,args)).then(resolve);}else{lastArgs=args;} 5049browser[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);}},});} 5050__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;} 5051__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;},});} 5052__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;} 5053__exports.useThrottleForAnimation=useThrottleForAnimation;function useThrottleForAnimation(func){const component=useComponent();const throttledForAnimation=throttleForAnimation(func.bind(component));onWillUnmount(()=>throttledForAnimation.cancel());return throttledForAnimation;} 5054return __exports;});; 5055 5056/* /web/static/src/core/utils/ui.js */ 5057odoo.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;}} 5058return closestEl;} 5059__exports.isVisible=isVisible;function isVisible(el){if(el===document||el===window){return true;} 5060if(!el){return false;} 5061let _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;} 5062if(!_isVisible&&getComputedStyle(el).display==="contents"){for(const child of el.children){if(isVisible(child)){return true;}}} 5063return _isVisible;} 5064__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;} 5065if(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;} 5066return q;} 5067__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);}} 5068return visibleElements;} 5069__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);});} 5070const 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]");} 5071__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]=[];} 5072byTabIndex[el.tabIndex].push(el);} 5073const withTabIndexZero=byTabIndex[0]||[];delete byTabIndex[0];return[...Object.values(byTabIndex).flat(),...withTabIndexZero];} 5074__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;} 5075__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;} 5076__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();};} 5077return __exports;});; 5078 5079/* /web/static/src/core/utils/urls.js */ 5080odoo.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
5080Error{} 5081__exports.objectToUrlEncodedString=objectToUrlEncodedString;function objectToUrlEncodedString(obj){return Object.entries(obj).map(([k,v])=>`${encodeURIComponent(k)}=${encodeURIComponent(v || "")}`).join("&");} 5082__exports.getOrigin=getOrigin;function getOrigin(origin){if(origin){origin=origin.replace(/\/+$/,"");}else{const{host,protocol}=browser.location;origin=`${protocol}//${host}`;} 5083return origin;} 5084__exports.url=url;function url(route,queryParams,options={}){const origin=getOrigin(options.origin??session.origin);if(!route){return origin;} 5085let 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}`;} 5086__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}`;} 5087if(filename){route=`${route}/${filename}`;} 5088const urlParams={};if(access_token){Object.assign(urlParams,{access_token});} 5089if(crop){Object.assign(urlParams,{crop});} 5090if(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;}}} 5091return url(route,urlParams);} 5092__exports.getDataURLFromFile=getDataURLFromFile;function getDataURLFromFile(file){if(!file){return Promise.reject();} 5093return 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);});} 5094__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");} 5095browser.location.assign(_url.href);} 5096__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);} 5097return __exports;});; 5098 5099/* /web/static/src/core/utils/xml.js */ 5100odoo.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;} 5101__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")}`);} 5102return xml.documentElement;} 5103__exports.serializeXML=serializeXML;function serializeXML(xml){return serializer.serializeToString(xml);} 5104__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);} 5105didVisitChildren=true;};const shouldVisitChildren=callback(el,visitChildren);if(shouldVisitChildren!==false&&!didVisitChildren){visitChildren();}}};const xmlDoc=typeof xml==="string"?parseXML(xml):xml;visit(xmlDoc);} 5106__exports.append=append;function append(parent,node){const nodes=Array.isArray(node)?node:[node];parent.append(...nodes.filter(Boolean));return parent;} 5107__exports.combineAttributes=combineAttributes;function combineAttributes(el,attr,parts,glue=" "){const allValues=[];if(el.hasAttribute(attr)){allValues.push(el.getAttribute(attr));}
5108parts=Array.isArray(parts)?parts:[parts];parts=parts.filter((part)=>!!part);allValues.push(...parts);el.setAttribute(attr,allValues.join(glue));} 5109__exports.createElement=createElement;function createElement(tagName,...args){const el=xmlDocument.createElement(tagName);for(const arg of args){if(!arg){continue;} 5110if(isIterable(arg)){el.append(...arg);}else if(typeof arg==="object"){for(const name in arg){el.setAttribute(name,arg[name]);}}} 5111return el;} 5112__exports.createTextNode=createTextNode;function createTextNode(data){return xmlDocument.createTextNode(data);} 5113__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);} 5114return attrs;} 5115__exports.getTag=getTag;function getTag(node,lower=false){const tag=(node&&node.nodeName)||"";return lower?tag.toLowerCase():tag;} 5116__exports.setAttributes=setAttributes;function setAttributes(node,attributes){for(const[name,value]of Object.entries(attributes)){node.setAttribute(name,value);}} 5117return __exports;});; 5118 5119/* /web/static/src/core/virtual_grid_hook.js */ 5120odoo.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[];} 5121if(sizes.at(-1)<span){return[0,sizes.length-1];} 5122const 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--;} 5123while(startIndex<sizes.length-1&&sizes[startIndex]<=bufferStart){startIndex++;} 5124let endIndex=startIndex;while(endIndex<sizes.length-1&&(sizes[endIndex-1]??0)<bufferEnd){endIndex++;} 5125while(endIndex>startIndex&&(sizes[endIndex-1]??0)>=bufferEnd){endIndex--;} 5126return[startIndex,endIndex];} 5127__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},};
5127const computeVirtualIndexes=()=>{const changed=[];const columnsVisibleIndexes=computeColumnsIndexes();if(!shallowEqual(columnsVisibleIndexes,current.columnsIndexes)){current.columnsIndexes=columnsVisibleIndexes;changed.push("columnsIndexes");} 5128const rowsVisibleIndexes=computeRowsIndexes();if(!shallowEqual(rowsVisibleIndexes,current.rowsIndexes)){current.rowsIndexes=rowsVisibleIndexes;changed.push("rowsIndexes");} 5129if(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;}
5130computeVirtualIndexes();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();},};} 5131return __exports;});; 5132 5133/* /web/static/src/views/fields/formatters.js */ 5134odoo.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"";} 5135const suffix=value<1024?" "+_t("Bytes"):"b";return(humanNumber(value,{decimals:2,})+suffix);} 5136__exports.formatBinary=formatBinary;function formatBinary(value){if(!isBinarySize(value)){return humanSize(value.length/1.37);} 5137return value;} 5138__exports.formatBoolean=formatBoolean;function formatBoolean(value){return markup` 5139 <div class="o-checkbox d-inline-block me-2"> 5140 <input id="boolean_checkbox" type="checkbox" class="form-check-input" disabled ${ 5141 value ? "checked" : "" 5142 }/> 5143 <label for="boolean_checkbox" class="form-check-label"/> 5144 </div>`;} 5145__exports.formatChar=formatChar;function formatChar(value,options){if(options&&options.isPassword){return"*".repeat(value?value.length:0);} 5146return value||"";} 5147formatChar.extractOptions=({attrs})=>({isPassword:exprToBoolean(attrs.password),});__exports.formatDate=formatDate;function formatDate(value,options={}){if(options.numeric){return _formatDate(value,options);}else{return toLocaleDateString(value);}} 5148formatDate.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);} 5149return _formatDateTime(value,options);}else{return toLocaleDateTimeString(value,options);}} 5150formatDateTime.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"";} 5151if(!options.digits&&options.field){options.digits=options.field.digits;} 5152if(!options.minDigits&&options.field){options.minDigits=options.field.min_display_digits;} 5153return formatFloatNumber(value,options);} 5154formatFloat.extractOptions=({attrs,options})=>{let digits;if(attrs.digits){digits=JSON.parse(attrs.digits);}else if(options.digits){digits=options.digits;} 5155const 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"";} 5156const factor=options.factor||1;if(!options.digits&&options.field){options.digits=options.field.digits;} 5157return formatFloatNumber(value*factor,options);} 5158formatFloatFactor.extractOptions=({attrs,options})=>({...formatFloat.extractOptions({attrs,options}),factor:options.factor,});__exports.formatFloatTime=formatFloatTime;function formatFloatTime(value,options={}){if(value===false){return"";} 5159const 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);} 5160if(min===60){min=0;hour=hour+1;} 5161min=String(min).padStart(2,"0");if(!options.noLeadingZeroHour){hour=String(hour).padStart(2,"0");} 5162let sec="";if(options.displaySeconds){sec=":"+String(Math.floor((milliSecLeft%60000)/1000)).padStart(2,"0");} 5163return`${isNegative ? "-" : ""}${hour}:${min}${sec}`;} 5164formatFloatTime.extractOptions=({options})=>({displaySeconds:options.displaySeconds,});__exports.formatInteger=formatInteger;function formatInteger(value,options={}){if(value===false||value===null){return"";} 5165if(options.isPassword){return"*".repeat(value.length);} 5166if(options.humanReadable){return humanNumber(value,options);} 5167const grouping=options.grouping||l10n.grouping;
5167const thousandsSep="thousandsSep"in options?options.thousandsSep:l10n.thousandsSep;return insertThousandsSep(value.toFixed(0),thousandsSep,grouping);} 5168formatInteger.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");} 5169if(options&&options.escape){value=encodeURIComponent(value);} 5170return value;} 5171__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);}} 5172__exports.formatMonetary=formatMonetary;function formatMonetary(value,options={}){if(value===false){return"";} 5173let 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;} 5174return formatCurrency(value,currencyId,options);} 5175formatMonetary.extractOptions=({options})=>
5175({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;} 5176const formatted=formatFloatNumber(value*100,options);return`${formatted}${options.noSymbol ? "" : "%"}`;} 5177formatPercentage.extractOptions=formatFloat.extractOptions;function formatProperties(value,field){if(!value||!value.length){return"";} 5178return value.map((property)=>property["string"]).join(", ");} 5179__exports.formatReference=formatReference;function formatReference(value,options){return formatMany2one(value?{id:value.resId,display_name:value.displayName}:false,options);} 5180__exports.formatMany2oneReference=formatMany2oneReference;function formatMany2oneReference(value){return value?formatMany2one({id:value.resId,display_name:value.displayName}):"";} 5181__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]:"";} 5182__exports.formatText=formatText;function formatText(value){return value?value.toString():"";} 5183__exports.formatHtml=formatHtml;function formatHtml(value){return value||"";} 5184__exports.formatJson=formatJson;function formatJson(value){return(value&&JSON.stringify(value))||"";} 5185registry.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;});; 5186 5187/* /web/static/src/views/fields/file_handler.js */ 5188odoo.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,});} 5189async onFileChange(ev){const files=[...ev.target.files].filter(file=>this.validFileType(file));if(!files.length){return;} 5190const{target}=ev;for(const file of files){if(this.props.checkSize&&!checkFileSize(file.size,this.notification)){return null;} 5191this.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",});} 5192try{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;}} 5193target.value=null;if(this.props.multiUpload&&this.props.onUploadComplete){this.props.onUploadComplete({});}} 5194validFileType(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;} 5195return true;} 5196async onSelectFileButtonClick(ev){if(this.props.onClick){const ok=await this.props.onClick(ev);if(ok!==undefined&&!ok){return;}} 5197this.fileInputRef.el.click();}} 5198return __exports;});; 5199 5200/* /bus/static/src/bus_parameters_service.js */ 5201odoo.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;});; 5202 5203/* /bus/static/src/legacy_multi_tab_service.js */ 5204odoo.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;} 5205function getItemFromStorage(key,defaultValue){const item=browser.localStorage.getItem(generateLocalStorageKey(key));try{return item?JSON.parse(item):defaultValue;}catch{return item;}} 5206function setItemInStorage(key,value){browser.localStorage.setItem(generateLocalStorageKey(key),JSON.stringify(value));} 5207function onStorage({key,newValue}){if(key&&key.includes(localStoragePrefix)){const baseKey=key.replace(localStoragePrefix,"");bus.trigger("shared_value_updated",{key:baseKey,newValue});}} 5208browser.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);} 5209setItemInStorage(key,value);},removeSharedValue(key){browser.localStorage.removeItem(generateLocalStorageKey(key));},};},};registry.category("services").add("legacy_multi_tab",legacyMultiTabService);return __exports;});; 5210 5211/* /bus/static/src/misc.js */ 5212odoo.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={};} 5213const 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;}
5214const remaining=wait-(_now-previous);context=this;args=arguments;if(remaining<=0||remaining>wait){if(timeout){browser.clearTimeout(timeout);timeout=null;} 5215previous=_now;result=func.apply(context,args);if(!timeout){context=args=null;}}else if(!timeout&&options.trailing!==false){timeout=browser.setTimeout(later,remaining);} 5216return result;};throttled.cancel=function(){browser.clearTimeout(timeout);previous=0;timeout=context=args=null;};return throttled;} 5217const timings=__exports.timings={throttle,};return __exports;});; 5218 5219/* /bus/static/src/multi_tab_fallback_service.js */ 5220odoo.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;} 5221const 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;} 5222newMain=tab;break;} 5223if(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));}} 5224function 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);} 5225if(_isOnMainTab){const cleanedTabs={};for(const[tabId,lastPresence]of Object.entries(lastPresenceByTab)){if(lastPresence+HEARTBEAT_KILL_OLD_PERIOD>now){cleanedTabs[tabId]=lastPresence;}} 5226if(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));} 5227const hbPeriod=_isOnMainTab?MAIN_TAB_HEARTBEAT_PERIOD:TAB_HEARTBEAT_PERIOD;heartbeatTimeout=browser.setTimeout(heartbeat,hbPeriod);} 5228function onStorage({key,newValue}){if(key==="multi_tab_service.main"&&!newValue){startElection();}} 5229function 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");}} 5230browser.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();} 5231heartbeat();return{bus,async isOnMainTab(){return _isOnMainTab;},unregister,};},};return __exports;});; 5232 5233/* /bus/static/src/multi_tab_service.js */ 5234odoo.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;});; 5235 5236/* /bus/static/src/multi_tab_shared_worker_service.js */ 5237odoo.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");
5237const 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;} 5238switch(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;} 5239bus.trigger("no_longer_main_tab");break;default:console.warn("multiTabSharedWorkerService received unknown message type:",type);}} 5240async function startWorker(){await workerService.ensureWorkerStarted();await workerService.registerHandler(messageHandler);workerService.send("ELECTION:REGISTER");state=STATE.REGISTERED;} 5241function unregister(){workerService.send("ELECTION:UNREGISTER");state=STATE.UNREGISTERED;} 5242return{bus,isOnMainTab:async()=>{if(state===STATE.UNREGISTERED){return false;} 5243if(state===STATE.INIT){await startWorker();} 5244if(!responseDeferred){responseDeferred=new Deferred();workerService.send("ELECTION:IS_MASTER?");} 5245return responseDeferred;},unregister,};},};return __exports;});; 5246 5247/* /bus/static/src/services/bus_monitoring_service.js */ 5248odoo.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;} 5249setup(env,{bus_service}){bus_service.addEventListener("BUS:WORKER_STATE_UPDATED",({detail})=>this.workerStateOnChange(detail));browser.addEventListener("offline",()=>(this.isReconnecting=false));} 5250workerStateOnChange(state){switch(state){case WORKER_STATE.CONNECTING:{this.isReconnecting=true;break;} 5251case WORKER_STATE.CONNECTED:{this.isReconnecting=false;this.isConnectionLost=false;break;} 5252case WORKER_STATE.DISCONNECTED:{if(this.isReconnecting){this.isConnectionLost=true;this.isReconnecting=false;} 5253break;}}}} 5254const busMonitoringservice=__exports.busMonitoringservice={dependencies:["bus_service"],start(env,services){return new BusMonitoringService(env,services);},};registry.category("services").add("bus.monitoring_service",busMonitoringservice);return __exports;});; 5255 5256/* /bus/static/src/services/bus_service.js */ 5257odoo.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( 5258 "yyyy-LL-dd-HH-mm-ss" 5259 )}.json`;a.click();URL.revokeObjectURL(url);break;} 5260case"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);} 5261break;} 5262case"BUS:INITIALIZED":{connectionInitializedDeferred.resolve();break;}
5263case"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;}} 5264if(!INTERNAL_EVENTS.has(type)){bus.trigger(type,data);}} 5265async 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;} 5266await workerService.ensureWorkerStarted();await workerService.registerHandler(handleMessage);workerService.send("BUS:INITIALIZE_CONNECTION",{websocketURL:`${params.serverURL.replace("http", "ws")}/websocket?version=${ 5267 session.websocket_worker_version 5268 }`,db:session.db,debug:odoo.debug,lastNotificationId:legacyMultiTab.getSharedValue("last_notification_id",0),uid,startTs:startedAt.valueOf(),});} 5269await connectionInitializedDeferred;} 5270browser.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;});; 5271 5272/* /bus/static/src/services/presence_service.js */ 5273odoo.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");} 5274function onFocusChange(isFocused){try{isFocused=parent.document.hasFocus();}catch{} 5275isOdooFocused=isFocused;browser.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}.focus`,isOdooFocused);if(isOdooFocused){lastPresenceTime=luxon.DateTime.now().ts;env.bus.trigger("window_focus",isOdooFocused);}} 5276function onStorage({key,newValue}){if(key===`${LOCAL_STORAGE_PREFIX}.focus`){isOdooFocused=JSON.parse(newValue);env.bus.trigger("window_focus",newValue);} 5277if(key===`${LOCAL_STORAGE_PREFIX}.lastPresence`){lastPresenceTime=JSON.parse(newValue);bus.trigger("presence");}} 5278browser.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;});; 5279 5280/* /bus/static/src/services/worker_service.js */ 5281odoo.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",});
5281const 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();} 5282startWorker(){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);} 5283const 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();} 5284this._send("BASE:INIT");} 5285async ensureWorkerStarted(){if(this._state===WORKER_STATE.UNINITIALIZED){this.startWorker();} 5286await this.connectionInitializedDeferred;} 5287onInitError(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);}} 5288_registerHandler(handler){if(this.isUsingSharedWorker){this.worker.port.addEventListener("message",handler);}else{this.worker.addEventListener("message",handler);}} 5289_send(action,data){const message={action,data};if(this.isUsingSharedWorker){this.worker.port.postMessage(message);}else{this.worker.postMessage(message);}} 5290async send(action,data){if(this._state===WORKER_STATE.UNINITIALIZED){return;} 5291await this.connectionInitializedDeferred;if(this._state===WORKER_STATE.FAILED){console.warn("Worker service failed to initialize, cannot send message.");} 5292this._send(action,data);} 5293async registerHandler(handler){if(this._state===WORKER_STATE.UNINITIALIZED){this.startWorker();} 5294await this.connectionInitializedDeferred;if(this._state===WORKER_STATE.FAILED){console.warn("Worker service failed to initialize, cannot register handler.");} 5295this._registerHandler(handler);} 5296get state(){return this._state;}} 5297const workerService=__exports.workerService={dependencies:["bus.parameters"],start(env,services){return new WorkerService(env,services);},};registry.category("services").add("worker_service",workerService);return __exports;});; 5298 5299/* /bus/static/src/workers/base_worker.js */ 5300odoo.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;} 5301handleMessage(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"});}}}} 5302return __exports;});; 5303 5304/* /bus/static/src/workers/bus_worker_utils.js */ 5305odoo.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);}} 5306const callNow=immediate&&!timeout;clearTimeout(timeout);timeout=setTimeout(later,wait);if(callNow){func.apply(context,args);}};} 5307const 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});}} 5308const Logger=__exports.Logger=class Logger{static LOG_TTL=24*60*60*1000;static gcInterval=null;static instances=[];_db;_dbPromise;static async gcOutdatedLogs(){const threshold=Date.now()-Logger.LOG_TTL;for(const logger of this.instances){try{const transaction=await logger._getTransaction("readwrite");await new Promise((res,rej)=>{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);}}} 5309constructor(name){this._name=name;Logger.instances.push(this);Logger.gcOutdatedLogs();clearInterval(Logger.gcInterval);Logger.gcInterval=setInterval(()=>Logger.gcOutdatedLogs(),Logger.LOG_TTL);} 5310async _ensureDatabaseAvailable(){this._dbPromise||=new Promise((res,rej)=>{const request=indexedDB.open(this._name,1);request.onsuccess=(event)=>{const db=event.target.result;db.onclose=()=>this._resetDatabase(db);this._db=db;res(db);};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=(event)=>{this._dbPromise=null;rej(event);};});return this._dbPromise;} 5311_resetDatabase(db){if(this._db===db){this._db=null;this._dbPromise=null;}} 5312async _getTransaction(mode,retry=true){const db=await this._ensureDatabaseAvailable();try{return db.transaction("logs",mode);}catch(error){if(!retry||error.name!=="InvalidStateError"){throw error;} 5313this._resetDatabase(db);return this._getTransaction(mode,false);}} 5314async log(message){const transaction=await this._getTransaction("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;});} 5315async getLogs(){await Logger.gcOutdatedLogs();const transaction=await this._getTransaction("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;});}} 5316return __exports;});; 5317 5318/* /bus/static/src/workers/election_worker.js */ 5319odoo.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);} 5320requestHeartbeat(messagePort){if(messagePort){messagePort.postMessage({type:"ELECTION:HEARTBEAT_REQUEST"});return;} 5321for(const candidate of this.candidates){candidate.postMessage({type:"ELECTION:HEARTBEAT_REQUEST"});}} 5322async ensureMasterPresence(){this.masterReplyDeferred??=new Deferred();if(this.masterTab){this.requestHeartbeat(this.masterTab);}else{this.startElection();} 5323await this.masterReplyDeferred;} 5324startElection(){clearInterval(this.heartbeatRequestInterval);this.masterTab?.postMessage({type:"ELECTION:UNASSIGN_MASTER"});this.masterTab=null;this.electionDeferred??=new Deferred();this.requestHeartbeat();} 5325finishElection(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);} 5326async handleMessage(event){const{action}=event.data;if(!action?.startsWith("ELECTION:")){return;} 5327switch(action){case"ELECTION:REGISTER":this.candidates.add(event.target);await this.electionDeferred;if(!this.masterTab){this.startElection();} 5328break;case"ELECTION:UNREGISTER":this.candidates.delete(event.target);if(this.masterTab===event.target){this.startElection();} 5329break;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);} 5330if(this.masterTab===event.target){this.lastHeartbeat=Date.now();this.masterReplyDeferred?.resolve();this.masterReplyDeferred=null;} 5331break;default:console.warn("Unknown message action:",action);}}} 5332return __exports;});; 5333 5334/* /bus/static/src/workers/websocket_worker.js */ 5335odoo.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);});} 5336broadcast(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});}} 5337registerClient(messagePort){messagePort.addEventListener("message",(ev)=>{this._onClientMessage(messagePort,ev.data);});this.channelsByClient.set(messagePort,[]);} 5338sendToClient(client,type,data){if(type!=="BUS:PROVIDE_LOGS"){this._logDebug("sendToClient",type,data);} 5339client.postMessage({type,data:data?JSON.parse(JSON.stringify(data)):undefined});} 5340_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);} 5341return;} 5342case"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);}} 5343_addChannel(client,channel){this.channelsByClient.get(client).push(channel);this._debouncedUpdateChannels();} 5344_deleteChannel(client,channel){const clientChannels=this.channelsByClient.get(client);if(!clientChannels){return;} 5345const channelIndex=clientChannels.indexOf(channel);if(channelIndex!==-1){clientChannels.splice(channelIndex,1);this._debouncedUpdateChannels();}} 5346_forceUpdateChannels(){this._updateChannels({force:true});} 5347_unregisterClient(client){this.channelsByClient.delete(client);this.debugModeByClient.delete(client);this.isDebug=[...this.debugModeByClient.values()].some(Boolean);this._debouncedUpdateChannels();} 5348_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;} 5349this.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;} 5350this.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);} 5351this.channelsByClient.forEach((_,key)=>this.channelsByClient.set(key,[]));} 5352this.sendToClient(client,"BUS:WORKER_STATE_UPDATED",this.state);this.sendToClient(client,"BUS:INITIALIZED");if(!this.active){this.sendToClient(client,"BUS:OUTDATED");}} 5353_isWebsocketConnected(){return this.websocket&&this.websocket.readyState===1;} 5354_isWebsocketConnecting(){return this.websocket&&this.websocket.readyState===0;} 5355_isWebsocketClosing(){return this.websocket&&this.websocket.readyState===2;}
5356_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;} 5357if(this.isReconnecting){if(code===WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED){this._retryConnectionWithDelay();} 5358return;} 5359this.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");} 5360return;} 5361this.broadcast("BUS:RECONNECTING",{closeCode:code});this.isReconnecting=true;if(code===WEBSOCKET_CLOSE_CODES.SESSION_EXPIRED){this.isWaitingForNewUID=true;} 5362this._retryConnectionWithDelay();} 5363_onWebsocketError(){this._logDebug("_onWebsocketError");this._retryConnectionWithDelay();} 5364_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);} 5365async _logDebug(title,...args){if(this.loggingEnabled){try{await logger.log({dt:new Date().toISOString(),event:title,args,worker:UUID,});}catch(e){console.error(e);}}} 5366_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;} 5367this.messageWaitQueue.forEach((msg)=>this.websocket.send(msg));this.messageWaitQueue=[];});this._restartConnectionCheckInterval();} 5368_restartConnectionCheckInterval(){clearInterval(this._connectionCheckInterval);this._connectionCheckInterval=setInterval(()=>{if(this._isWebsocketConnected()){this.websocket.send(new Uint8Array([0x00]));this._logDebug("connection_checked");}},this.CONNECTION_CHECK_DELAY);} 5369_retryConnectionWithDelay(){clearTimeout(this.connectTimeout);this.connectRetryDelay=Math.min(this.connectRetryDelay,MAXIMUM_RECONNECT_DELAY)+ 5370this.RECONNECT_JITTER*Math.random();this._logDebug("_retryConnectionWithDelay",this.connectRetryDelay);this.connectTimeout=setTimeout(this._start.bind(this),this.connectRetryDelay);} 5371_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));} 5372this._restartConnectionCheckInterval();}} 5373_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);} 5374_start(){this._logDebug("_start");if(!this.active||this._isWebsocketConnected()||this._isWebsocketConnecting()){return;} 5375this._removeWebsocketListeners();if(this._isWebsocketClosing()){this._onWebsocketClose(new CloseEvent("close",{code:WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED}));this.websocket=null;return;} 5376this._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);} 5377_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});}} 5378_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();}} 5379_updateState(newState){this.state=newState;this.broadcast("BUS:WORKER_STATE_UPDATED",newState);}} 5380return __exports;});; 5381 5382/* /mail_enterprise/static/src/core/common/message_patch.js */ 5383odoo.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;});; 5384 5385/* /hr/static/src/core/common/hr_department_model.js */ 5386odoo.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;} 5387HrDepartment.register();return __exports;});; 5388 5389/* /hr/static/src/core/common/hr_employee_model.js */ 5390odoo.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");
5390work_phone;} 5391HrEmployee.register();return __exports;});; 5392 5393/* /hr/static/src/core/common/hr_work_location_model.js */ 5394odoo.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;} 5395HrWorkLocation.register();return __exports;});; 5396 5397/* /hr/static/src/core/common/res_partner_model_patch.js */ 5398odoo.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;});; 5399 5400/* /hr/static/src/core/common/res_users_model_patch.js */ 5401odoo.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;});; 5402 5403/* /hr_holidays/static/src/core/common/hr_employee_model_patch.js */ 5404odoo.define('@hr_holidays/core/common/hr_employee_model_patch',['@web/core/utils/patch','@mail/model/misc','@hr/core/common/hr_employee_model'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{fields}=require("@mail/model/misc");const{HrEmployee}=require("@hr/core/common/hr_employee_model");patch(HrEmployee.prototype,{setup(){super.setup();this.leave_date_to=fields.Date();},});return __exports;});; 5405 5406/* /hr_holidays/static/src/core/common/res_users_model_patch.js */ 5407odoo.define('@hr_holidays/core/common/res_users_model_patch',['@mail/core/common/res_users_model','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ResUsers}=require("@mail/core/common/res_users_model");const{patch}=require("@web/core/utils/patch");const resUsersPatch={setup(){super.setup(...arguments);this.leave_date_to=undefined;},};patch(ResUsers.prototype,resUsersPatch);return __exports;});; 5408 5409/* /whatsapp/static/src/core/common/channel_member_list_patch.js */ 5410odoo.define('@whatsapp/core/common/channel_member_list_patch',['@mail/discuss/core/common/channel_member_list','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChannelMemberList}=require("@mail/discuss/core/common/channel_member_list");const{patch}=require("@web/core/utils/patch");const channelMemberListPatch={canOpenChatWith(member){return(super.canOpenChatWith(member)&&member.partner_id.notEq(member.channel_id.whatsapp_partner_id));},};patch(ChannelMemberList.prototype,channelMemberListPatch);return __exports;});; 5411 5412/* /whatsapp/static/src/core/common/chat_window_patch.js */ 5413odoo.define('@whatsapp/core/common/chat_window_patch',['@mail/core/common/chat_window','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{ChatWindow}=require("@mail/core/common/chat_window");const{patch}=require("@web/core/utils/patch");patch(ChatWindow.prototype,{get showImStatus(){return(super.showImStatus||(this.thread?.channel_type==="whatsapp"&&this.thread.correspondent));},});return __exports;});; 5414 5415/* /whatsapp/static/src/core/common/composer_actions_patch.js */ 5416odoo.define('@whatsapp/core/common/composer_actions_patch',['@mail/core/common/composer_actions','@web/core/utils/patch','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{ComposerAction,registerComposerAction}=require("@mail/core/common/composer_actions");const{patch}=require("@web/core/utils/patch");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"whatsapp",...args);registerComposerAction("revive-whatsapp-conversation",{condition:({composer,owner})=>composer.thread?.channel_type==="whatsapp"&&!owner.state.active,icon:"fa fa-whatsapp",name:_t("Revive WhatsApp Conversation"),onSelected:({owner})=>owner.onclickWhatsAppChat(),sequenceQuick:10,});patch(ComposerAction.prototype,{_condition({composer,owner}){if(["upload-files","voice-start"].includes(this.id)&&composer.targetThread?.channel_type==="whatsapp"&&(composer.attachments.length>0||owner.voiceRecorder?.recording)){return false;} 5417return super._condition(...arguments);},_disabledCondition({composer,owner}){const inactiveActions=["revive-whatsapp-conversation","more-actions"];if(composer.targetThread?.channel_type==="whatsapp"&&owner.state&&!owner.state.active&&!inactiveActions.includes(this.id)){return true;} 5418return super._disabledCondition(...arguments);},});return __exports;});; 5419
5420/* /whatsapp/static/src/core/common/composer_model_patch.js */ 5421odoo.define('@whatsapp/core/common/composer_model_patch',['@mail/core/common/composer_model'],function(require){'use strict';let __exports={};const{Composer}=require("@mail/core/common/composer_model");Object.assign(Composer.prototype,"whatsapp_composer_model",{threadExpired:false,});return __exports;});; 5422 5423/* /whatsapp/static/src/core/common/composer_patch.js */ 5424odoo.define('@whatsapp/core/common/composer_patch',['@mail/core/common/composer','@web/core/l10n/translation','@web/core/utils/patch','@odoo/owl'],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,"whatsapp",...args);const{patch}=require("@web/core/utils/patch");const{onWillDestroy,useEffect}=require("@odoo/owl");patch(Composer.prototype,{setup(){super.setup();this.composerDisableCheckTimeout=null;useEffect(()=>{clearTimeout(this.composerDisableCheckTimeout);this.checkComposerDisabled();},()=>[this.thread?.whatsapp_channel_valid_until]);onWillDestroy(()=>clearTimeout(this.composerDisableCheckTimeout));},get allowUpload(){if(this.thread?.channel_type==="whatsapp"&&this.props.composer.attachments.length>0){return false;} 5425return super.allowUpload;},get areAllActionsDisabled(){if(this.thread?.channel_type==="whatsapp"&&!this.state.active&&!this.isRevivingWhatsapp){return true;} 5426return super.areAllActionsDisabled;},get isRevivingWhatsapp(){return false;},get isMultiUpload(){if(this.thread?.channel_type==="whatsapp"){return false;} 5427return super.isMultiUpload;},get placeholder(){if(this.thread?.channel_type==="whatsapp"){if(!this.state.active&&this.props.composer.threadExpired){return _t("Conversation closed.");} 5428return _t("Answer as %(whatsapp_account_name)s",{whatsapp_account_name:this.thread.wa_account_id.name,});} 5429return super.placeholder;},checkComposerDisabled(){if(this.thread&&this.thread.channel_type==="whatsapp"){const datetime=this.thread.whatsappChannelValidUntilDatetime;if(!datetime){return;} 5430const delta=datetime.ts-Date.now();if(delta<=0){this.state.active=false;this.props.composer.threadExpired=true;}else{this.state.active=true;this.props.composer.threadExpired=false;this.composerDisableCheckTimeout=setTimeout(()=>{this.checkComposerDisabled();},delta);}}},get isSendButtonDisabled(){const whatsappInactive=this.thread&&this.thread.channel_type==="whatsapp"&&!this.state.active;return super.isSendButtonDisabled||whatsappInactive;},onclickWhatsAppChat(){this.action.doAction({type:"ir.actions.act_window",name:_t("Send WhatsApp Message"),res_model:"whatsapp.composer",view_mode:"form",views:[[false,"form"]],target:"new",context:{active_model:"discuss.channel",active_id:this.thread.id,},},{onClose:()=>{this.thread.fetchMessages();},});},onDropFile(ev){this.processFileUploading(ev,super.onDropFile.bind(this));},onPaste(ev){if(ev.clipboardData.files.length===0){return super.onPaste(ev);} 5431this.processFileUploading(ev,super.onPaste.bind(this));},processFileUploading(ev,superCb){if(this.thread?.channel_type==="whatsapp"){const files=ev.dataTransfer?.files||ev.clipboardData?.files||[];if(this.props.composer.attachments.length>0||files.length>1){ev.preventDefault();this.env.services.notification.add(_t("Only one attachment is allowed for each message"),{type:"warning"});return;}} 5432superCb(ev);},});return __exports;});; 5433 5434/* /whatsapp/static/src/core/common/message_model_patch.js */ 5435odoo.define('@whatsapp/core/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={get editable(){if(this.thread?.channel_type==="whatsapp"){return false;} 5436return super.editable;},canReplyTo(thread){return super.canReplyTo(thread)&&!this.thread?.composer?.threadExpired;},isTranslatable(thread){return(super.isTranslatable(thread)||(this.store.hasMessageTranslationFeature&&thread?.channel_type==="whatsapp"&&this.store.self?.main_user_id?.share===false));},};patch(Message.prototype,messagePatch);return __exports;});; 5437
5438/* /whatsapp/static/src/core/common/message_patch.js */ 5439odoo.define('@whatsapp/core/common/message_patch',['@mail/core/common/message','@web/core/l10n/translation','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Message}=require("@mail/core/common/message");const{appTranslateFn}=require("@web/core/l10n/translation");const _t=(str,...args)=>appTranslateFn(str,"whatsapp",...args);const{patch}=require("@web/core/utils/patch");patch(Message.prototype,{get showSeenIndicator(){return super.showSeenIndicator&&this.message.whatsappStatus!=="error";},async onClick(ev){const id=Number(ev.target.dataset.oeId);if(ev.target.closest(".o_whatsapp_channel_redirect")){ev.preventDefault();let thread=await this.store.Thread.getOrFetch({model:"discuss.channel",id});if(!thread?.hasSelfAsMember){await this.env.services.orm.call("discuss.channel","add_members",[[id]],{partner_ids:[this.store.self.id],});thread=await this.store.Thread.getOrFetch({model:"discuss.channel",id});} 5440thread.open();return;} 5441super.onClick(ev);},getWhatsappStatusClass(){const statusClasses={outgoing:"text-warning",sent:"text-success",delivered:"text-success",read:"text-success",replied:"text-success",received:"text-success",error:"text-danger",bounced:"text-danger",cancel:"text-danger",};return statusClasses[this.message.whatsappStatus]||"text-muted";},getWhatsappStatusTitle(){const statusTitles={outgoing:_t("The message is being processed."),sent:_t("The message has been sent."),delivered:_t("The message has been successfully delivered."),read:_t("The message has been read by the recipient."),replied:_t("The recipient has replied to the message."),received:_t("The message has been successfully received."),error:_t("There was an issue sending this message."),bounced:_t("The message has been bounced."),cancel:_t("The message has been canceled."),};return(statusTitles[this.message.whatsappStatus]||_t("The status of this message is currently unknown."));},});return __exports;});; 5442 5443/* /whatsapp/static/src/core/common/store_service_patch.js */ 5444odoo.define('@whatsapp/core/common/store_service_patch',['@mail/core/common/store_service','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Store}=require("@mail/core/common/store_service");const{patch}=require("@web/core/utils/patch");patch(Store.prototype,{async getMessagePostParams({thread}){const params=await super.getMessagePostParams(...arguments);if(thread.channel_type==="whatsapp"){params.post_data.message_type="whatsapp_message";} 5445return params;},});return __exports;});; 5446 5447/* /whatsapp/static/src/core/common/thread_action_patch.js */ 5448odoo.define('@whatsapp/core/common/thread_action_patch',['@web/core/utils/patch','@mail/core/common/thread_actions'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{ThreadAction}=require("@mail/core/common/thread_actions");patch(ThreadAction.prototype,{_condition({action,owner,store,thread}){if(thread?.channel_type==="whatsapp"){if(action.id==="create-lead"&&store.has_access_create_lead&&!owner.isDiscussSidebarChannelActions){return true;} 5449if(action.id==="create-ticket"&&store.has_access_create_ticket&&store.helpdesk_livechat_active&&!owner.isDiscussSidebarChannelActions){return true;}} 5450return super._condition(...arguments);},});return __exports;});; 5451 5452/* /whatsapp/static/src/core/common/thread_model_patch.js */ 5453odoo.define('@whatsapp/core/common/thread_model_patch',['@mail/core/common/record','@mail/core/common/thread_model','@web/core/utils/patch','@web/core/l10n/dates','@odoo/owl'],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{deserializeDateTime}=require("@web/core/l10n/dates");const{toRaw}=require("@odoo/owl");patch(Thread.prototype,{setup(){super.setup();this.wa_account_id=fields.One("whatsapp.account");},get importantCounter(){if(this.channel_type==="whatsapp"){return this.self_member_id?.message_unread_counter||this.message_needaction_counter;} 5454return super.importantCounter;},get autoOpenChatWindowOnNewMessage(){return this.channel_type==="whatsapp"||super.autoOpenChatWindowOnNewMessage;},get canLeave(){return this.channel_type!=="whatsapp"&&super.canLeave;},get allowedToUnpinChannelTypes(){return[...super.allowedToUnpinChannelTypes,"whatsapp"];},get avatarUrl(){if(this.channel_type==="whatsapp"&&this.correspondent){return this.correspondent.avatarUrl;} 5455return super.avatarUrl;},get isChatChannel(){return this.channel_type==="whatsapp"||super.isChatChannel;},get whatsappChannelValidUntilDatetime(){if(!this.whatsapp_channel_valid_until){return undefined;} 5456return toRaw(deserializeDateTime(this.whatsapp_channel_valid_until));},});return __exports;});; 5457
5458/* /whatsapp/static/src/core/common/thread_patch.js */ 5459odoo.define('@whatsapp/core/common/thread_patch',['@mail/core/common/thread','@web/core/utils/patch'],function(require){'use strict';let __exports={};const{Thread}=require("@mail/core/common/thread");const{patch}=require("@web/core/utils/patch");patch(Thread.prototype,{isSquashed(msg,prevMsg){if(msg.whatsappStatus==="error"){return false;} 5460return super.isSquashed(msg,prevMsg);},get isWhatsAppThreadExpired(){return(this.props.thread.channel_type==="whatsapp"&&this.props.thread.composer.threadExpired);},});return __exports;});; 5461 5462/* /whatsapp/static/src/core/common/whatsapp_account_model.js */ 5463odoo.define('@whatsapp/core/common/whatsapp_account_model',['@mail/core/common/record'],function(require){'use strict';let __exports={};const{Record}=require("@mail/core/common/record");const WhatsAppAccount=__exports.WhatsAppAccount=class WhatsAppAccount extends Record{static id="id";static _name="whatsapp.account";id;name;} 5464WhatsAppAccount.register();return __exports;});; 5465 5466/* /whatsapp/static/src/discuss/core/common/thread_model_patch.js */ 5467odoo.define('@whatsapp/discuss/core/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 threadPatch={setup(){super.setup(...arguments);this.whatsapp_partner_id=fields.One("res.partner");this.whatsappMember=fields.One("discuss.channel.member",{compute(){return(this.channel_type==="whatsapp"&&this.channel_member_ids.find((member)=>member.partner_id?.eq(this.whatsapp_partner_id)));},});},_computeOfflineMembers(){const res=super._computeOfflineMembers();if(this.channel_type==="whatsapp"){return res.filter((member)=>member.partner_id?.notEq(this.whatsapp_partner_id));} 5468return res;},computeCorrespondent(){const correspondent=super.computeCorrespondent();if(this.channel_type==="whatsapp"&&!correspondent){return this.whatsappMember;} 5469return correspondent;},get hasMemberList(){return this.channel_type==="whatsapp"||super.hasMemberList;},};patch(Thread.prototype,threadPatch);return __exports;});; 5470 5471/* /web/static/lib/dompurify/DOMpurify.js */ 5472(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;};} 5473if(!seal){seal=function seal(x){return x;};} 5474if(!apply){apply=function apply(fun,thisValue,args){return fun.apply(thisValue,args);};} 5475if(!construct){construct=function construct(Func,args){return new Func(...args);};} 5476const 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 5476-5494
5476const 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];} 5477return apply(func,thisArg,args);};} 5478function unconstruct(func){return function(){for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++){args[_key2]=arguments[_key2];} 5479return construct(func,args);};} 5480function addToSet(set,array){let transformCaseFunc=arguments.length>2&&arguments[2]!==undefined?arguments[2]:stringToLowerCase;if(setPrototypeOf){setPrototypeOf(set,null);} 5481let 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;} 5482element=lcElement;}} 5483set[element]=true;} 5484return set;} 5485function cleanArray(array){for(let index=0;index<array.length;index++){const isPropertyExist=objectHasOwnProperty(array,index);if(!isPropertyExist){array[index]=null;}} 5486return array;} 5487function 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;}}} 5488return newObject;} 5489function lookupGetter(object,prop){while(object!==null){const desc=getOwnPropertyDescriptor(object,prop);if(desc){if(desc.get){return unapply(desc.get);} 5490if(typeof desc.value==='function'){return unapply(desc.value);}} 5491object=getPrototypeOf(object);} 5492function fallbackValue(){return null;} 5493return fallbackValue;} 5494const 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
5494pictureinpicture','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 5494-5594
5494const 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;} 5495let suffix=null;const ATTR_NAME='data-tt-policy-suffix';if(purifyHostElement&&purifyHostElement.hasAttribute(ATTR_NAME)){suffix=purifyHostElement.getAttribute(ATTR_NAME);} 5496const 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;} 5497let{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;}} 5498let 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;} 5499if(!cfg||typeof cfg!=='object'){cfg={};} 5500cfg=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;} 5501if(cfg.CUSTOM_ELEMENT_HANDLING&&isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)){CUSTOM_ELEMENT_HANDLING.attributeNameCheck=cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;} 5502if(cfg.CUSTOM_ELEMENT_HANDLING&&typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements==='boolean'){CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;} 5503if(SAFE_FOR_TEMPLATES){ALLOW_DATA_ATTR=false;} 5504if(RETURN_DOM_FRAGMENT){RETURN_DOM=true;} 5505if(USE_PROFILES){ALLOWED_TAGS=addToSet({},text);ALLOWED_ATTR=[];if(USE_PROFILES.html===true){addToSet(ALLOWED_TAGS,html$1);addToSet(ALLOWED_ATTR,html);} 5506if(USE_PROFILES.svg===true){addToSet(ALLOWED_TAGS,svg$1);addToSet(ALLOWED_ATTR,svg);addToSet(ALLOWED_ATTR,xml);} 5507if(USE_PROFILES.svgFilters===true){addToSet(ALLOWED_TAGS,svgFilters);addToSet(ALLOWED_ATTR,svg);addToSet(ALLOWED_ATTR,xml);} 5508if(USE_PROFILES.mathMl===true){addToSet(ALLOWED_TAGS,mathMl$1);addToSet(ALLOWED_ATTR,mathMl);addToSet(ALLOWED_ATTR,xml);}} 5509if(cfg.ADD_TAGS){if(ALLOWED_TAGS===DEFAULT_ALLOWED_TAGS){ALLOWED_TAGS=clone(ALLOWED_TAGS);} 5510addToSet(ALLOWED_TAGS,cfg.ADD_TAGS,transformCaseFunc);} 5511if(cfg.ADD_ATTR){if(ALLOWED_ATTR===DEFAULT_ALLOWED_ATTR){ALLOWED_ATTR=clone(ALLOWED_ATTR);} 5512addToSet(ALLOWED_ATTR,cfg.ADD_ATTR,transformCaseFunc);} 5513if(cfg.ADD_URI_SAFE_ATTR){addToSet(URI_SAFE_ATTRIBUTES,cfg.ADD_URI_SAFE_ATTR,transformCaseFunc);} 5514if(cfg.FORBID_CONTENTS){if(FORBID_CONTENTS===DEFAULT_FORBID_CONTENTS){FORBID_CONTENTS=clone(FORBID_CONTENTS);} 5515addToSet(FORBID_CONTENTS,cfg.FORBID_CONTENTS,transformCaseFunc);} 5516if(KEEP_CONTENT){ALLOWED_TAGS['#text']=true;} 5517if(WHOLE_DOCUMENT){addToSet(ALLOWED_TAGS,['html','head','body']);} 5518if(ALLOWED_TAGS.table){addToSet(ALLOWED_TAGS,['tbody']);delete FORBID_TAGS.tbody;} 5519if(cfg.TRUSTED_TYPES_POLICY){if(typeof cfg.TRUSTED_TYPES_POLICY.createHTML!=='function'){throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');} 5520if(typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL!=='function'){throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');} 5521trustedTypesPolicy=cfg.TRUSTED_TYPES_POLICY;emptyHTML=trustedTypesPolicy.createHTML('');}else{if(trustedTypesPolicy===undefined){trustedTypesPolicy=_createTrustedTypesPolicy(trustedTypes,currentScript);} 5522if(trustedTypesPolicy!==null&&typeof emptyHTML==='string'){emptyHTML=trustedTypesPolicy.createHTML('');}} 5523if(freeze){freeze(cfg);} 5524CONFIG=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'};} 5525const tagName=stringToLowerCase(element.tagName);const parentTagName=stringToLowerCase(parent.tagName);if(!ALLOWED_NAMESPACES[element.namespaceURI]){return false;} 5526if(element.namespaceURI===SVG_NAMESPACE){if(parent.namespaceURI===HTML_NAMESPACE){return tagName==='svg';} 5527if(parent.namespaceURI===MATHML_NAMESPACE){return tagName==='svg'&&(parentTagName==='annotation-xml'||MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);} 5528return Boolean(ALL_SVG_TAGS[tagName]);} 5529if(element.namespaceURI===MATHML_NAMESPACE){if(parent.namespaceURI===HTML_NAMESPACE){return tagName==='math';} 5530if(parent.namespaceURI===SVG_NAMESPACE){return tagName==='math'&&HTML_INTEGRATION_POINTS[parentTagName];} 5531return Boolean(ALL_MATHML_TAGS[tagName]);} 5532if(element.namespaceURI===HTML_NAMESPACE){if(parent.namespaceURI===SVG_NAMESPACE&&!HTML_INTEGRATION_POINTS[parentTagName]){return false;} 5533if(parent.namespaceURI===MATHML_NAMESPACE&&!MATHML_TEXT_INTEGRATION_POINTS[parentTagName]){return false;} 5534return!ALL_MATHML_TAGS[tagName]&&(COMMON_SVG_AND_HTML_ELEMENTS[tagName]||!ALL_SVG_TAGS[tagName]);} 5535if(PARSER_MEDIA_TYPE==='application/xhtml+xml'&&ALLOWED_NAMESPACES[element.namespaceURI]){return true;} 5536return 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});} 5537node.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];} 5538if(PARSER_MEDIA_TYPE==='application/xhtml+xml'&&NAMESPACE===HTML_NAMESPACE){dirty='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+dirty+'</body></html>';} 5539const dirtyPayload=trustedTypesPolicy?trustedTypesPolicy.createHTML(dirty):dirty;if(NAMESPACE===HTML_NAMESPACE){try{doc=new DOMParser().parseFromString(dirtyPayload,PARSER_MEDIA_TYPE);}catch(_){}} 5540if(!doc||!doc.documentElement){doc=implementation.createDocument(NAMESPACE,'template',null);try{doc.documentElement.innerHTML=IS_EMPTY_INPUT?emptyHTML:dirtyPayload;}catch(_){}} 5541const body=doc.body||doc.documentElement;if(dirty&&leadingWhitespace){body.insertBefore(document.createTextNode(leadingWhitespace),body.childNodes[0]||null);} 5542if(NAMESPACE===HTML_NAMESPACE){return getElementsByTagName.call(doc,WHOLE_DOCUMENT?'html':'body')[0];} 5543return 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;} 5544arrayForEach(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;} 5545const 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;} 5546if(currentNode.nodeType===NODE_TYPE.progressingInstruction){_forceRemove(currentNode);return true;} 5547if(SAFE_FOR_XML&¤tNode.nodeType===NODE_TYPE.comment&®ExpTest(/<[/\w]/g,currentNode.data)){_forceRemove(currentNode);return true;} 5548if(!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;} 5549if(CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function&&CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)){return false;}} 5550if(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));}}} 5551_forceRemove(currentNode);return true;} 5552if(currentNode instanceof Element&&!_checkValidNamespace(currentNode)){_forceRemove(currentNode);return true;} 5553if((tagName==='noscript'||tagName==='noembed'||tagName==='noframes')&®ExpTest(/<\/no(script|embed|frames)/i,currentNode.innerHTML)){_forceRemove(currentNode);return true;} 5554if(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;}} 5555_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;} 5556if(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;} 5557const 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;} 5558_removeAttribute(name,currentNode);if(!hookEvent.keepAttr){continue;} 5559if(!ALLOW_SELF_CLOSE_IN_ATTR&®ExpTest(/\/>/i,value)){_removeAttribute(name,currentNode);continue;} 5560if(SAFE_FOR_TEMPLATES){arrayForEach([MUSTACHE_EXPR,ERB_EXPR,TMPLIT_EXPR],expr=>{value=stringReplace(value,expr,' ');});} 5561const lcTag=transformCaseFunc(currentNode.nodeName);if(!_isValidAttribute(lcTag,lcName,value)){continue;} 5562if(SANITIZE_NAMED_PROPS&&(lcName==='id'||lcName==='name')){_removeAttribute(name,currentNode);value=SANITIZE_NAMED_PROPS_PREFIX+value;} 5563if(SAFE_FOR_XML&®ExpTest(/((--!?|])>)|<\/(style|title)/i,value)){_removeAttribute(name,currentNode);continue;} 5564if(trustedTypesPolicy&&typeof trustedTypes==='object'&&typeof trustedTypes.getAttributeType==='function'){if(namespaceURI);else{switch(trustedTypes.getAttributeType(lcTag,lcName)){case'TrustedHTML':{value=trustedTypesPolicy.createHTML(value);break;} 5565case'TrustedScriptURL':{value=trustedTypesPolicy.createScriptURL(value);break;}}}} 5566try{if(namespaceURI){currentNode.setAttributeNS(namespaceURI,name,value);}else{currentNode.setAttribute(name,value);} 5567if(_isClobbered(currentNode)){_forceRemove(currentNode);}else{arrayPop(DOMPurify.removed);}}catch(_){}} 5568_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;} 5569if(shadowNode.content instanceof DocumentFragment){_sanitizeShadowDOM(shadowNode.content);} 5570_sanitizeAttributes(shadowNode);} 5571_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='<!-->';} 5572if(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');}} 5573if(!DOMPurify.isSupported){return dirty;} 5574if(!SET_CONFIG){_parseConfig(cfg);} 5575DOMPurify.removed=[];if(typeof dirty==='string'){IN_PLACE=false;} 5576if(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;} 5577body=_initDocument(dirty);if(!body){return RETURN_DOM?null:RETURN_TRUSTED_TYPE?emptyHTML:'';}} 5578if(body&&FORCE_BODY){_forceRemove(body.firstChild);} 5579const nodeIterator=_createNodeIterator(IN_PLACE?dirty:body);while(currentNode=nodeIterator.nextNode()){if(_sanitizeElements(currentNode)){continue;} 5580if(currentNode.content instanceof DocumentFragment){_sanitizeShadowDOM(currentNode.content);} 5581_sanitizeAttributes(currentNode);} 5582if(IN_PLACE){return dirty;} 5583if(RETURN_DOM){if(RETURN_DOM_FRAGMENT){returnNode=createDocumentFragment.call(body.ownerDocument);while(body.firstChild){returnNode.appendChild(body.firstChild);}}else{returnNode=body;} 5584if(ALLOWED_ATTR.shadowroot||ALLOWED_ATTR.shadowrootmode){returnNode=importNode.call(originalDocument,returnNode,true);} 5585return returnNode;} 5586let 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;} 5587if(SAFE_FOR_TEMPLATES){arrayForEach([MUSTACHE_EXPR,ERB_EXPR,TMPLIT_EXPR],expr=>{serializedHTML=stringReplace(serializedHTML,expr,' ');});} 5588return 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({});} 5589const lcTag=transformCaseFunc(tag);const lcName=transformCaseFunc(attr);return _isValidAttribute(lcTag,lcName,value);};DOMPurify.addHook=function(entryPoint,hookFunction){if(typeof hookFunction!=='function'){return;} 5590hooks[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;} 5591var purify=createDOMPurify();return purify;}));; 5592 5593/* /html_editor/static/src/components/switch/switch.js */ 5594odoo.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}
5594,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` 5595 <label t-att-class="'o_switch' + extraClasses"> 5596 <input type="checkbox" 5597 name="switch" 5598 class="visually-hidden" 5599 t-att-checked="props.value" 5600 t-att-disabled="props.disabled" 5601 t-on-change="(ev) => props.onChange(ev.target.checked)" 5602 t-on-keyup="onKeyup"/> 5603 <span/> 5604 <span t-if="props.label" t-esc="props.label" class="ms-2"/> 5605 <span t-if="props.description" class="text-muted ms-2" t-esc="props.description"/> 5606 </label> 5607 `;setup(){this.extraClasses=this.props.extraClasses?` ${this.props.extraClasses}`:"";} 5608onKeyup(ev){if(ev.key==="Enter"){ev.currentTarget.checked=!ev.currentTarget.checked;}}} 5609return __exports;});; 5610 5611/* /html_editor/static/src/main/media/media_dialog/document_selector.js */ 5612odoo.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";} 5613const 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");} 5614get 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;} 5615async onClickDocument(document){this.selectAttachment(document);await this.props.save();} 5616selectInitialMedia(){return super.selectInitialMedia()&&this.props.media.classList.contains("o_file_box");} 5617async 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);}}} 5618return attachments;} 5619static async createElements(selectedMedia,{orm}){return Promise.all(selectedMedia.map(async(attachment)=>{let url=`/web/content/${encodeURIComponent( 5620 attachment.id 5621 )}?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,]);} 5622url+=`&access_token=${encodeURIComponent(accessToken)}`;} 5623return this.renderFileElement(attachment,url);}));} 5624static renderFileElement(attachment,downloadUrl){return renderStaticFileBox(attachment.name,attachment.mimetype,downloadUrl,attachment.id);}} 5625__exports.renderStaticFileBox=renderStaticFileBox;
5625function 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;} 5626return __exports;});; 5627 5628/* /html_editor/static/src/main/media/media_dialog/file_selector.js */ 5629odoo.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.");}} 5630remove(ev){ev.stopPropagation();this.props.remove();}} 5631const AttachmentError=__exports.AttachmentError=class AttachmentError extends Component{static components={Dialog};static template="html_editor.AttachmentError";static props=["views","close"];setup(){this.title=_t("Alert");}} 5632const Attachment=__exports.Attachment=class Attachment extends Component{static template="";static components={RemoveButton,};static props=["*"];setup(){this.dialogs=useService("dialog");} 5633remove(){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],});}},});}} 5634const 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]);} 5635get showSearchServiceSelect(){return this.props.searchService&&this.props.needle;} 5636get enableUrlUploadClick(){return(!this.state.showUrlInput||(this.state.urlInput&&this.state.isValidUrl&&this.state.isValidFileFormat));} 5637async onUrlUploadClick(){if(!this.state.showUrlInput){this.state.showUrlInput=true;}else{await this.props.uploadUrl(this.state.urlInput);this.state.urlInput="";}} 5638async 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;}
5639onClickUpload(){this.fileInput.el.click();} 5640async onChangeFileInput(){const inputFiles=this.fileInput.el.files;if(!inputFiles.length){return;} 5641await this.props.uploadFiles(inputFiles);const fileInputEl=this.fileInput.el;if(fileInputEl){fileInputEl.value="";}}} 5642const 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]);} 5643get canLoadMore(){return this.state.canLoadMoreAttachments;} 5644get hasContent(){return this.state.attachments.length;} 5645get isFetching(){return this.state.isFetchingAttachments;} 5646get selectedAttachmentIds(){return this.props.selectedMedia[this.props.id].filter((media)=>media.mediaType==="attachment").map(({id})=>id);} 5647get 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;} 5648get allAttachments(){return this.state.attachments;} 5649validateUrl(url){const path=url.split("?")[0];const isValidUrl=/^.+\..+$/.test(path);const isValidFileFormat=true;return{isValidUrl,isValidFileFormat,path};} 5650async 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;}} 5651this.state.canLoadMoreAttachments=attachments.length>=this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY;this.state.isFetchingAttachments=false;return attachments;} 5652async handleLoadMore(){await this.loadMore();} 5653async loadMore(){return this.keepLast.add(this.fetchAttachments(this.NUMBER_OF_ATTACHMENTS_TO_DISPLAY,this.state.attachments.length)).then((newAttachments)=>{this.state.attachments.push(...newAttachments);});} 5654async handleSearch(needle){await this.search(needle);} 5655async 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;});} 5656async uploadFiles(files){await this.uploadService.uploadFiles(files,{resModel:this.props.resModel,resId:this.props.resId},(attachment)=>this.onUploaded(attachment));} 5657async 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;});});} 5658async onLoadUploadedUrl(url,resolve){await this.uploadService.uploadUrl(url,{resModel:this.props.resModel,resId:this.props.resId,},(attachment)=>this.onUploaded(attachment));resolve();} 5659async 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();} 5660if(this.props.onAttachmentChange){this.props.onAttachmentChange(attachment);}} 5661onRemoved(attachmentId){this.state.attachments=this.state.attachments.filter((attachment)=>attachment.id!==attachmentId);} 5662selectAttachment(attachment){this.props.selectMedia({...attachment,mediaType:"attachment"});} 5663selectInitialMedia(){return(this.props.media&&this.constructor.tagNames.includes(this.props.media.tagName)&&!this.selectedAttachmentIds.length);}
5664updateScroll(){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");} 5665isAttachmentHidden(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;} 5666handleScrollAttachments(){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;} 5667scrollToEl.scrollIntoView({block:"end",inline:"nearest",behavior:"smooth"});}} 5668return __exports;});; 5669 5670/* /html_editor/static/src/main/media/media_dialog/icon_selector.js */ 5671odoo.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:"",});} 5672get selectedMediaIds(){return this.props.selectedMedia[this.props.id].map(({id})=>id);} 5673search(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};});}} 5674async 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();} 5675static createElements(selectedMedia){return selectedMedia.map((icon)=>{const iconEl=document.createElement("span");iconEl.classList.add(icon.fontBase,icon.names[0]);return iconEl;});} 5676static 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;}} 5677return __exports;});; 5678 5679/* /html_editor/static/src/main/media/media_dialog/image_selector.js */ 5680odoo.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,});} 5681async onImageLoaded(){if(!this.image.el){return;} 5682if(this.props.onLoaded){await this.props.onLoaded(this.image.el);if(!this.image.el){return;}} 5683const 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;}} 5684const newLocal="img-fluid";const ImageSelector=__exports.ImageSelector=class ImageSelector extends FileSelector{static mediaSpecificClasse
5684s=["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;} 5685get canLoadMore(){if(this.state.searchService==="media-library"){return(this.state.libraryResults&&this.state.libraryMedia.length<this.state.libraryResults);} 5686return super.canLoadMore;} 5687get 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;} 5688return super.hasContent;} 5689get isFetching(){return super.isFetching||this.state.isFetchingLibrary;} 5690get selectedMediaIds(){return this.props.selectedMedia[this.props.id].filter((media)=>media.mediaType==="libraryMedia").map(({id})=>id);} 5691get allAttachments(){return[...super.allAttachments,...this.state.libraryMedia];} 5692get 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/%"]);} 5693domain.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);} 5694domain.push(["original_id","in",subDomain]);} 5695return domain;} 5696async 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;} 5697async 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};} 5698async 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();} 5699super.onLoadUploadedUrl(url,resolve);} 5700isInitialMedia(attachment){if(this.props.media.dataset.originalSrc){return this.props.media.dataset.originalSrc===attachment.image_src;} 5701return this.props.media.getAttribute("src")===attachment.image_src;} 5702async 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;}}} 5703const primaryColors={};const htmlStyle=getHtmlStyle(document);for(let color=1;color<=5;color++){primaryColors[color]=getCSSVariableValue("o-color-"+color,htmlStyle);} 5704return 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
5704h((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);} 5705attachment.thumbnail_src=newURL.pathname+newURL.search;} 5706if(this.selectInitialMedia()&&this.isInitialMedia(attachment)){this.selectAttachment(attachment);} 5707return attachment;});} 5708async fetchLibraryMedia(offset){if(!this.state.needle){return{media:[],results:null};} 5709this.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};}} 5710async loadMore(...args){await super.loadMore(...args);if(!this.props.useMediaLibrary||this.state.searchService!=="media-library"){return;} 5711return this.keepLastLibraryMedia.add(this.fetchLibraryMedia(this.state.libraryMedia.length)).then(({media})=>{this.state.libraryMedia.push(...media);});} 5712async search(...args){await super.search(...args);if(!this.props.useMediaLibrary){return;} 5713if(!this.state.needle){this.state.searchService="all";} 5714this.state.libraryMedia=[];this.state.libraryResults=0;return this.keepLastLibraryMedia.add(this.fetchLibraryMedia(0)).then(({media,results})=>{this.state.libraryMedia=media;this.state.libraryResults=results;});} 5715async onClickAttachment(attachment){if(this.isProcessingClick){return;} 5716this.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;} 5717this.selectAttachment(attachment);if(!this.props.multiSelect){await this.props.save();} 5718requestAnimationFrame(()=>{this.isProcessingClick=false;});} 5719async onClickMedia(media){this.props.selectMedia({...media,mediaType:"libraryMedia"});if(!this.props.multiSelect){await this.props.save();}} 5720static 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});} 5721const 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;} 5722return 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,]);} 5723src+=`?access_token=${encodeURIComponent(accessToken)}`;} 5724imageEl.src=src;imageEl.alt=attachment.description||"";imageEl.dataset.attachmentId=attachment.id;return imageEl;}));} 5725async onImageLoaded(imgEl,attachment){this.debouncedScrollUpdate();if(attachment.mediaType==="libraryMedia"&&!imgEl.src.startsWith("blob")){await this.onLibraryImageLoaded(imgEl,attachment);}} 5726async 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.");}}} 5727return __exports;});; 5728 5729/* /html_editor/static/src/main/media/media_dialog/media_dialog.js */ 5730odoo.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)=>
5730sequence(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;} 5731get initialActiveTab(){if(this.props.activeTab){return this.props.activeTab;} 5732if(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;}} 5733return this.notebookPages[0].id;} 5734addTab(tab,additionalProps={}){if(this.props.visibleTabs&&!this.props.visibleTabs.includes(tab.id)){return;} 5735this.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,},});} 5736addTabs(){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,});} 5737if(onlyImages){return;} 5738const 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);}}} 5739this.props.extraTabs.forEach((tab)=>this.addTab(tab));} 5740async 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);}} 5741for(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);} 5742element.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);}}}} 5743element.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;}}} 5744return true;}));} 5745element.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
5745s);});return elements;} 5746selectMedia(media,tabId,multiSelect){if(media&&!Object.keys(media).length){this.selectedMedia[tabId]=[];return;} 5747if(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];}} 5748async save(){if(this.errorMessages[this.state.activeTab]){this.notificationService.add(this.errorMessages[this.state.activeTab],{type:"danger",});return;} 5749const 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);}} 5750this.props.close();this.state.isSaving=false;} 5751onTabChange(tab){this.state.activeTab=tab;} 5752async close(){if(this.abortUploads){this.abortUploads();delete this.abortUploads;} 5753this.state.isSaving=false;await this.props.close();}} 5754return __exports;});; 5755 5756/* /html_editor/static/src/main/media/media_dialog/search_media.js */ 5757odoo.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]);}} 5758return __exports;});; 5759 5760/* /html_editor/static/src/main/media/media_dialog/upload_progress_toast/upload_progress_toast.js */ 5761odoo.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");} 5762get progress(){return Math.round(this.props.progress);}} 5763const 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);}} 5764return __exports;});; 5765 5766/* /html_editor/static/src/main/media/media_dialog/upload_progress_toast/upload_service.js */ 5767odoo.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;
5767const 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
5767);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;} 5768let fileSize=file.size;if(!checkFileSize(fileSize,notification)){return null;} 5769if(!fileSize){fileSize="";}else{fileSize=humanNumber(fileSize)+"B";} 5770const id=++fileId;file.progressToastId=id;addFile({id,name:file.name,size:fileSize,});} 5771for(const sortedFile of sortedFiles){if(signal.aborted){break;} 5772const 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;} 5773currentXHR=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;} 5774if(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);}} 5775file.uploaded=true;await onUploaded(attachment);}}catch(err){if(signal.aborted){break;} 5776file.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;}} 5777currentXHR=null;addAttachmentRpc=null;},};},};registry.category("services").add("upload",uploadService);return __exports;});; 5778 5779/* /html_editor/static/src/main/media/media_dialog/video_selector.js */ 5780odoo.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";}} 5781class VideoIframe extends Component{static template="html_editor.VideoIframe";static props={src:{type:String},};} 5782const VideoSelector=__exports.VideoSelector=class VideoSelector extends Component{static mediaSpecificClasse
5782s=["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;} 5783await this.syncOptionsWithUrl();if(status(this)==="destroyed"){return;}}} 5784await 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};} 5785return option;});await this.updateVideo();this.state.urlInput="https:"+this.state.src;},1000);} 5786get shownOptions(){if(this.props.isForBgVideo){return[];} 5787return this.state.options.filter((option)=>!this.OPTIONS[option.id].isHidden||!this.OPTIONS[option.id].isHidden());} 5788get value(){if(this.option.id==="start_from"&&this.option.value!=="00:00"){return this.convertSecondsToTimestamp(this.option.value);} 5789return this.option.value;} 5790async onChangeOption(optionId){this.state.options=this.state.options.map((option)=>{if(option.id===optionId){return{...option,value:!option.value?"00:00":""};} 5791return option;});await this.updateVideo();this.state.urlInput="https:"+this.state.src;} 5792async onClickSuggestion(src){this.state.urlInput=src;await this.updateVideo();} 5793async 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;} 5794const embedMatch=this.state.urlInput.match(/(src|href)=["']?([^"']+)?/);if(embedMatch&&embedMatch[2].length>0&&embedMatch[2].indexOf("instagram")){embedMatch[1]=embedMatch[2];} 5795const 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;}} 5796const{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
5796id");}else if(!platform){this.state.errorMessage=_t("The provided url does not reference any supported video");}else{this.state.errorMessage="";} 5797this.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});}});} 5798this.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;}} 5799async _getVideoURLData(url,options){return await rpc("/html_editor/video_url/data",{video_url:url,...options,});} 5800static 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;});} 5801async 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( 5802 videoId 5803 )}`);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}`);}}));} 5804async syncOptionsWithUrl(){await this.updateVideo();if(!URL.canParse(this.state.urlInput)){return;} 5805const 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":"";} 5806if(option.id==="start_from"&&value==="0"){return{...option,value:"00:00"};} 5807return{...option,value:value||""};});await this.updateVideo();} 5808convertTimestampToSeconds(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)+"");} 5809if(isNaN(timestamp)){return"0";} 5810return timestamp;} 5811convertSecondsToTimestamp(value){if(!value){return"";} 5812const match=value.match(/^\d+s?$/);if(!match){return"";} 5813const totalSeconds=parseInt(match[0],10);if(!Number.isFinite(totalSeconds)||totalSeconds<=0){return value;} 5814const 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)}`;} 5815return`${minutes}:${pad(seconds)}`;} 5816parseTimeToSeconds(value){const match=value?.match(/^(?:(\d+)m(\d+)s|(\d+)m|(\d+)s|(\d+))$/);if(!match){return value;} 5817let 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);}} 5818return __exports;});; 5819 5820/* /website/static/src/components/media_dialog/image_selector.js */ 5821odoo.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;});; 5822 5823/* /web_unsplash/static/src/media_dialog/image_selector_patch.js */ 5824odoo.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);} 5825return 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;} 5826return super.hasContent;},get errorTitle(){if(this.errorMessages[this.unsplashState.unsplashError]){return this.errorMessages[this.unsplashState.unsplashError].title;} 5827return _t("Something went wrong");},get errorSubtitle(){if(this.errorMessages[this.unsplashState.unsplashError]){return this.errorMessages[this.unsplashState.unsplashError].subtitle;} 5828return _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;}
5828,get combinedRecords(){function alternate(a,b){return[a.map((v,i)=>(i<b.length?[v,b[i]]:v)),b.slice(a.length)].flat(2);} 5829return 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};} 5830this.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;} 5831existingIds.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;} 5832return{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;} 5833return 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;});; 5834 5835/* /web_unsplash/static/src/media_dialog/media_dialog_patch.js */ 5836odoo.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",})));});}} 5837return super.save(...arguments);},});return __exports;});; 5838 5839/* /web_unsplash/static/src/unsplash_credentials/unsplash_credentials.js */ 5840odoo.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,});} 5841submitCredentials(){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);}}} 5842return __exports;});; 5843 5844/* /web_unsplash/static/src/unsplash_error/unsplash_error.js */ 5845odoo.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},};} 5846return __exports;});; 5847 5848/* /web_unsplash/static/src/unsplash_service.js */ 5849odoo.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();
5849const 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,};} 5850const 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);} 5851setTimeout(()=>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,};} 5852cachedData=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,};} 5853const cachedData=_cache[key];const payload={query:query,page:cachedData.pageCached+1,per_page:30,};if(orientation){payload.orientation=orientation;} 5854const result=await rpc("/web_unsplash/fetch_images",payload);if(result.error){return Promise.reject(result.error);} 5855cachedData.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;});; 5856 5857/* /html_editor/static/src/components/html_viewer/html_viewer.js */ 5858odoo.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();} 5859if(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]);} 5860onMounted(()=>{scrollAndHighlightHeading(this.readonlyElementRef?.el||this.iframeRef?.el);});if(this.props.config.cssAssetId){onWillStart(async()=>{this.cssAsset=await getBundle(this.props.config.cssAssetId);});} 5861if(this.props.config.embeddedComponents){this.embeddedComponents=memoize((embeddedComponents=[])=>{const result={};for(const embedding of embeddedComponents){result[embedding.name]=embedding;} 5862return result;});useEffect(()=>{if(this.readonlyElementRef?.el){this.mountComponents();}},()=>[this.props.config.value.toString(),this.readonlyElementRef?.el]);this.tocManager=new TableOfContentManager(this.readonlyElementRef);}} 5863addDomListener(target,eventName,fn,capture=false){const handler=(ev)=>
5863{fn?.call(this,ev);};target.addEventListener(eventName,handler,capture);this._cleanups.push(()=>target.removeEventListener(eventName,handler,capture));} 5864get showIframe(){return this.props.config.hasFullHtml||this.props.config.cssAssetId;} 5865formatValue(value){let newVal=fixInvalidHTML(value);if(this.props.migrateHTML){newVal=this.htmlUpgradeManager.processForUpgrade(newVal,{containsComplexHTML:this.props.config.hasFullHtml,env:this.env,});} 5866if(instanceofMarkup(value)){return markup(newVal);} 5867return newVal;} 5868processReadonlyContent(container){this.retargetLinks(container);this.applyAccessibilityAttributes(container);this.addDomListener(container,"copy",this.onCopy);} 5869onCopy(ev){ev.preventDefault();const selection=ev.target.ownerDocument.defaultView.getSelection();const clonedContents=selection.getRangeAt(0).cloneContents();fillHtmlTransferData(ev,"clipboardData",clonedContents,{textContent:selection.toString(),});} 5870applyAccessibilityAttributes(container){for(const el of container.querySelectorAll("[data-oe-role]")){el.setAttribute("role",el.dataset.oeRole);} 5871for(const el of container.querySelectorAll("[data-oe-aria-label]")){el.setAttribute("aria-label",el.dataset.oeAriaLabel);}} 5872retargetLinks(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);}} 5873retargetLink(link){link.setAttribute("target","_blank");link.setAttribute("rel","noreferrer");} 5874updateIframeContent(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);} 5875onLoadIframe(value){const contentWindow=this.iframeRef.el.contentWindow;if(!this.props.config.hasFullHtml){contentWindow.document.open("text/html","replace").write(`<!DOCTYPE html><html> 5876 <head> 5877 <meta charset="utf-8"/> 5878 <meta http-equiv="X-UA-Compatible" content="IE=edge"/> 5879 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/> 5880 </head> 5881 <body class="o_in_iframe o_readonly" style="overflow: hidden;"> 5882 <div id="iframe_target"></div> 5883 </body> 5884 </html>`);} 5885if(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);}} 5886this.updateIframeContent(this.state.value);this.state.iframeVisible=true;} 5887destroyComponent({root,host}){const{getEditableDescendants}=this.getEmbedding(host);const editableDescendants=getEditableDescendants?.(host)||{};root.destroy();this.components.delete(arguments[0]);host.append(...Object.values(editableDescendants));} 5888destroyComponents(){for(const cleanup of this._cleanups){cleanup();} 5889for(const info of[...this.components]){this.destroyComponent(info);}} 5890forEachEmbeddedComponentHost(elem,callback){const selector=`[data-embedded]`;const targets=[...elem.querySelectorAll(selector)];if(elem.matches(selector)){targets.unshift(elem);} 5891for(const host of targets){const embedding=this.getEmbedding(host);if(!embedding){continue;} 5892callback(host,embedding);}} 5893getEmbedding(host){return this.embeddedComponents(this.props.config.embeddedComponents)[host.dataset.embedded];} 5894setupNewComponent({name,env,props}){if(name==="tableOfContent"){Object.assign(props,{manager:this.tocManager,});}} 5895mountComponent(host,{Component,getEditableDescendants,getProps,name}){const props=getProps?.(host)||{};const env=Object.create(this.env);if(getEditableDescendants){env.getEditableDescendants=getEditableDescendants;} 5896this.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);} 5897mountComponents(){this.forEachEmbeddedComponentHost(this.readonlyElementRef.el,(host,embedding)=>{this.mountComponent(host,embedding);});}} 5898return __exports;});; 5899 5900/* /html_editor/static/src/local_overlay_container.js */ 5901odoo.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},});} 5902this.Components=useRegistry(overlayComponents);useForwardRefToParent("localOverlay");}} 5903return __exports;});; 5904 5905/* /html_editor/static/src/position_hook.js */ 5906odoo.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");} 5907addDomListener(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);}} 5908return()=>{resizeObserver.disconnect();for(const cleanup of cleanups.toReversed()){cleanup();cleanups.pop();}};},()=>[containerRef.el]);} 5909return __exports;});; 5910 5911/* /html_editor/static/src/html_migrations/html_migrations_utils.js */ 5912odoo.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);} 5913const VERSION_SELECTOR=__exports.VERSION_SELECTOR="[data-oe-version]";__exports.stripVersion=stripVersion;function stripVersion(element){element.querySelectorAll(VERSION_SELECTOR).forEac
5913h((el)=>{delete el.dataset.oeVersion;});} 5914__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;}} 5915return __exports;});; 5916 5917/* /html_editor/static/src/html_migrations/html_upgrade_manager.js */ 5918odoo.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={};} 5919get value(){return this.upgradedValue;} 5920processForUpgrade(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;} 5921this.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;} 5922try{const upgradeSequence=VERSIONS.filter((subVersion)=>compareVersions(subVersion,version)>0);this.upgradedValue=this.upgrade(upgradeSequence);}catch{} 5923return this.value;} 5924upgrade(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.`);} 5925migrate(this.element,this.env);}} 5926return markup(this.element[this.containsComplexHTML?"outerHTML":"innerHTML"]);}} 5927return __exports;});; 5928 5929/* /html_editor/static/src/html_migrations/manifest.js */ 5930odoo.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;});; 5931 5932/* /html_editor/static/src/html_migrations/migration-1.1.js */ 5933odoo.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();}} 5934return __exports;});; 5935 5936/* /html_editor/static/src/html_migrations/migration-1.2.js */ 5937odoo.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;}}} 5938__exports.migrate=migrate;function migrate(container){const bannerContainers=container.querySelectorAll(".o_editor_banner");
5938for(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;}} 5939const 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");}}} 5940return __exports;});; 5941 5942/* /html_editor/static/src/others/embedded_component_utils.js */ 5943odoo.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;}} 5944return editableDescendants;} 5945__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`.");} 5946const 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]);} 5947let _restoreSelection;const restoreSelection=()=>{if(_restoreSelection){_restoreSelection();_restoreSelection=undefined;}};if(component.env.editorShared?.selection){onRendered(()=>{_restoreSelection=component.env.editorShared.selection.preserveSelection().restore;});} 5948onMounted(()=>{for(const render of Object.values(renders)){render();} 5949restoreSelection();});onPatched(()=>{for(const[name,render]of Object.entries(renders)){if(!host.contains(editableDescendants[name])){render();}} 5950restoreSelection();});return editableDescendants;} 5951function 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));} 5952return Reflect.set(target,key,value,receiver);},deleteProperty(target,key){if(Reflect.has(target,key)&&!stateChangeManager.previousEmbeddedState){stateChangeManager.previousEmbeddedState=JSON.parse(JSON.stringify(stateChangeManager.embeddedState));} 5953return 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);},};} 5954function observeAllKeys(reactive){for(const key in reactive){const prop=reactive[key];if(prop instanceof Object){observeAllKeys(prop);}}} 5955__exports.getEmbeddedProps=getEmbeddedProps;function getEmbeddedProps(host){return host.dataset.embeddedProps?JSON.parse(host.dataset.embeddedProps):{};} 5956function sortedCopy(obj){const result={};const propNames=Object.keys(obj).sort();for(const propName of propNames){result[propName]=obj[propName];} 5957return result;} 5958__exports.applyObjectPropertyDifference=applyObjectPropertyDifference;function applyObjectPropertyDifference(container,key,previous,next){if(!container[key]){container[key]={};} 5959const 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];} 5960delete obj1[key];} 5961for(const key in obj1){delete dest[key];} 5962if(!Object.keys(dest).length&&!next){delete container[key];}} 5963__exports.replaceProperty=replaceProperty;function replaceProperty(container,key,value){if(value===undefined){delete container[key];}else{container[key]=value;}} 5964const StateChangeManager=__exports.StateChangeManager=class StateChangeManager{constructor(config){this.config=config;} 5965setup(){const defaultState=sortedCopy(this.getEmbeddedState());const defaultStateChange={stateChangeId:null,previous:defaultState,next:defaultState,};this.defaultStateChange=defaultStateChange;this.previousStateChange=defaultStateChange;this.batchId=0;this.setupUnmounted();} 5966setupUnmounted(){this.previousEmbeddedState=null;this.state=null;this.embeddedState=null;this.embeddedStateProxy=null;this.isLiveComponent=false;this.batchId+=1;} 5967constructEmbeddedState(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;} 5968getState(){let state=this.state;if(!this.isLiveComponent){state=this.getEmbeddedState();} 5969return state;} 5970onStateChanged(attrState,{reverse=false,forNewStep=false}={}){const stateChange=attrState?JSON.parse(attrState):this.defaultStateChange;const state=this.getState();if(reverse){this.reverseStateChange(stateChange);} 5971if(!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);} 5972if(!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);}}}} 5973batchedChangeState(){let scheduled=false;const batchId=this.batchId;return async()=>
5973{if(this.isLiveComponent&&!scheduled){scheduled=true;await Promise.resolve();scheduled=false;if(batchId===this.batchId){this.changeState();}}};} 5974changeState(){if(!this.previousEmbeddedState){return;} 5975const 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();} 5976observeAllKeys(this.embeddedStateProxy);} 5977areStateChangesEqual(sc1,sc2){return(sc1.stateChangeId===sc2.stateChangeId&&JSON.stringify(sc1.previous)===JSON.stringify(sc2.previous)&&JSON.stringify(sc1.next)===JSON.stringify(sc2.next));} 5978reverseStateChange(stateChange){const previous=stateChange.previous;stateChange.previous=stateChange.next;stateChange.next=previous;} 5979assignDeepProxyCopy(target,source){for(const key of Object.keys(target)){delete target[key];} 5980for(const key of Object.keys(source)){target[key]=this.deepProxyCopy(source[key]);} 5981return target;} 5982deepProxyCopy(value){if(value instanceof Object){const copy=value instanceof Array?[]:{};for(const prop in value){copy[prop]=this.deepProxyCopy(value[prop]);} 5983return new Proxy(copy,embeddedStateProxyHandler(value,this));} 5984return value;} 5985generateId(){return Math.floor(Math.random()*Math.pow(2,52));} 5986commitStateChange(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]);}}} 5987getEmbeddedState(){const host=this.config.host;return this.config.getEmbeddedState?.(host)||getEmbeddedProps(host);} 5988stateToEmbeddedProps(host,state){const props=this.config.stateToEmbeddedProps?.(host,state)||state;for(const key of Object.keys(props)){if(props[key]===undefined){delete props[key];}} 5989return props;}} 5990__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`.");} 5991const stateChangeManager=component.env.getStateChangeManager(host);onWillDestroy(()=>stateChangeManager.setupUnmounted());const state=useState(stateChangeManager.getEmbeddedState());return stateChangeManager.constructEmbeddedState(state);} 5992return __exports;});; 5993 5994/* /html_editor/static/src/others/embedded_components/core/embedded_component_toolbar/embedded_component_toolbar.js */ 5995odoo.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";} 5996const 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");}} 5997return __exports;});; 5998 5999/* /html_editor/static/src/others/embedded_components/core/file/readonly_file.js */ 6000odoo.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();} 6001async 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"),});}} 6002onClickFileImage(){if(this.fileModel.isViewable){this.attachmentViewer.open(this.fileModel);}else{this.download();}}} 6003const readonlyFileEmbedding=__exports.readonlyFileEmbedding={name:"file",Component:ReadonlyEmbeddedFileComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),};return __exports;});; 6004 6005/* /html_editor/static/src/others/embedded_components/core/file/state_file_model.js */ 6006odoo.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","
6006id","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,});}} 6007get urlRoute(){if(this.isUrl&&!this.id){return this.url;} 6008return super.urlRoute;}} 6009return __exports;});; 6010 6011/* /html_editor/static/src/others/embedded_components/core/syntax_highlighting/readonly_syntax_highlighting.js */ 6012odoo.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);});}} 6013const readonlySyntaxHighlightingEmbedding=__exports.readonlySyntaxHighlightingEmbedding={name:"readonlySyntaxHighlighting",Component:ReadonlySyntaxHighlightingComponent,getProps:(host)=>({host,languageId:host.dataset.languageId||DEFAULT_LANGUAGE_ID,value:getPreValue(host),}),};return __exports;});; 6014 6015/* /html_editor/static/src/others/embedded_components/core/syntax_highlighting/syntax_highlighting_utils.js */ 6016odoo.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");} 6017if(!node.textContent){node.remove();}} 6018const trailingBr=lastLeaf(element);if(trailingBr?.nodeName==="BR"){element.append(trailingBr);trailingBr.after(doc.createElement("BR"));} 6019fillEmpty(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);} 6020return 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;} 6021newlinesToLineBreaks(fakeElement,pre.ownerDocument);[...pre.childNodes].forEach((child)=>child.remove());[...fakeElement.childNodes].forEach((child)=>pre.append(child));};return __exports;});; 6022 6023/* /html_editor/static/src/others/embedded_components/core/table_of_content/table_of_content.js */ 6024odoo.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();});} 6025displayTocHint(){return this.state.toc.headings.length<2&&!this.props.readonly;} 6026onTocLinkClick(heading){this.props.manager.scrollIntoView(heading);}} 6027const tableOfContentEmbedding=__exports.tableOfContentEmbedding={name:"tableOfContent",Component:EmbeddedTableOfContentComponent,};const readonlyTableOfContentEmbedding=__exports.readonlyTableOfContentEmbedding={name:"tableOfContent",Component:EmbeddedTableOfContentComponent,getProps:(host)=>({readonly:true,}),};return __exports;});; 6028 6029/* /html_editor/static/src/others/embedded_components/core/table_of_content/table_of_content_manager.js */ 6030odoo.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
6030=containerRef;this.structure=reactive({headings:[],});this.batchedUpdateStructure=batched(this.updateStructure.bind(this));} 6031getContainerEl(){return this.containerRef.el;} 6032fetchValidHeadings(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));} 6033scrollIntoView(heading){if(!heading){return;} 6034const{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));}} 6035const{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"});});} 6036target.classList.add("o_embedded_toc_header_highlight");window.setTimeout(()=>{target.classList.remove("o_embedded_toc_header_highlight");},2000);} 6037updateStructure(){const container=this.getContainerEl();if(!container){return;} 6038const tagDepthStack=[];this.structure.headings=this.fetchValidHeadings(container).map((heading)=>{while(tagDepthStack.at(-1)>=heading.tagName){tagDepthStack.pop();} 6039const depth=tagDepthStack.length;tagDepthStack.push(heading.tagName);return{depth,name:heading.innerText,target:heading,};});}} 6040return __exports;});; 6041 6042/* /html_editor/static/src/others/embedded_components/core/toggle_block/toggle_block.js */ 6043odoo.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]);} 6044get toggleStorageKey(){return`html_editor.ToggleBlock${this.props.toggleBlockId}.showContent`;} 6045onToggle(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();}}} 6046const toggleBlockEmbedding=__exports.toggleBlockEmbedding={name:"toggleBlock",Component:EmbeddedToggleBlockComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),getEditableDescendants:getEditableDescendants,};return __exports;});; 6047 6048/* /html_editor/static/src/others/embedded_components/core/video/readonly_video.js */ 6049odoo.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();}} 6050const readonlyVideoEmbedding=__exports.readonlyVideoEmbedding={name:"video",Component:ReadonlyEmbeddedVideoComponent,getProps:(host)=>({...getEmbeddedProps(host)}),};return __exports;});; 6051 6052/* /html_editor/static/src/utils/base_container.js */ 6053odoo.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;
6053function getBaseContainerSelector(nodeName){if(!nodeName){return baseContainerGlobalSelector;} 6054nodeName=SUPPORTED_BASE_CONTAINER_NAMES.includes(nodeName)?nodeName:"P";let suffix="";if(nodeName!=="P"){suffix=`.${BASE_CONTAINER_CLASS}`;} 6055return`${nodeName}${suffix}`;} 6056const baseContainerGlobalSelector=__exports.baseContainerGlobalSelector=`:is(${SUPPORTED_BASE_CONTAINER_NAMES.map((name) => 6057 getBaseContainerSelector(name) 6058).join(",")})`;__exports.createBaseContainer=createBaseContainer;function createBaseContainer(nodeName,document){if(!document&&window){document=window.document;} 6059nodeName=nodeName&&SUPPORTED_BASE_CONTAINER_NAMES.includes(nodeName)?nodeName:"P";const el=document.createElement(nodeName);if(nodeName!=="P"){el.className=BASE_CONTAINER_CLASS;} 6060return el;} 6061return __exports;});; 6062 6063/* /html_editor/static/src/utils/blocks.js */ 6064odoo.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;} 6065const tagName=node.nodeName.toUpperCase();if(tagName==="BR"){return false;} 6066if(!node.isConnected){return blockTagNames.includes(tagName);} 6067let display=computedStyleDisplayCache.get(node);if(display===undefined){const style=node.ownerDocument.defaultView.getComputedStyle(node);display=style.display;computedStyleDisplayCache.set(node,display);} 6068if(display&&display!=="none"){return!display.includes("inline")&&display!=="contents";} 6069return blockTagNames.includes(tagName);} 6070__exports.closestBlock=closestBlock;function closestBlock(node){return findNode(closestPath(node),(node)=>isBlock(node));} 6071return __exports;});; 6072 6073/* /html_editor/static/src/utils/clipboard.js */ 6074odoo.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);}});} 6075__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);} 6076ev[transferObjectProperty].setData("text/html",htmlContent);if(setEditorTransferData){ev[transferObjectProperty].setData("application/vnd.odoo.odoo-editor",htmlContent);}} 6077return __exports;});; 6078 6079/* /html_editor/static/src/utils/color.js */ 6080odoo.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`);} 6081for(let i=100;i<=900;
6081i+=100){EDITOR_COLOR_CSS_VARIABLES.push(`${i}`);} 6082EDITOR_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;} 6083const 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;} 6084const 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]));} 6085__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;} 6086if(isColorGradient(style["background-image"])){if(element.classList.contains("text-gradient")){if(mode==="color"){return true;}}else{if(mode!=="color"){return true;}}} 6087return((style[mode]&&style[mode]!=="inherit"&&(!parent||style[mode]!==parent.style[mode]))||hasTextColorClass(element,mode));} 6088__exports.hasAnyNodesColor=hasAnyNodesColor;function hasAnyNodesColor(nodes,mode){for(const node of nodes){if(hasColor(closestElement(node),mode)){return true;}} 6089return false;} 6090__exports.getTextColorOrClass=getTextColorOrClass;function getTextColorOrClass(node){if(!node){return null;} 6091if(node.style.color){return{type:"style",value:node.style.color};} 6092const textColorClass=[...node.classList].find((cls)=>TEXT_CLASSES_REGEX.test(cls));if(textColorClass){return{type:"class",value:textColorClass};} 6093return null;} 6094return __exports;});; 6095 6096/* /html_editor/static/src/utils/content_types.js */ 6097odoo.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);} 6098const CTGROUPS=__exports.CTGROUPS={INLINE:CTYPES.CONTENT|CTYPES.SPACE,BLOCK:CTYPES.BLOCK_OUTSIDE|CTYPES.BLOCK_INSIDE,BR:CTYPES.BR,};return __exports;});; 6099 6100/* /html_editor/static/src/utils/dom.js */ 6101odoo.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"));} 6102currentNode=unwrapContents(currentNode)[0];}else{currentNode=currentNode.nextSibling;}}} 6103__exports.wrapInlinesInBlocks=wrapInlinesInBlocks;function wrapInlinesInBlocks(element,{baseContainerNodeName="P",cursors={update:()=>{}}}={}
6103){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);} 6104block.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);} 6105cursors.update(callbacksForCursorUpdate.remove(currentBlock));currentBlock.remove();currentBlock=block;} 6106cursors.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);}}} 6107__exports.unwrapContents=unwrapContents;function unwrapContents(node){const contents=childNodes(node);for(const child of contents){node.parentNode.insertBefore(child,node);} 6108node.parentNode.removeChild(node);return contents;} 6109__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);}} 6110__exports.removeStyle=removeStyle;function removeStyle(element,...styleProperties){styleProperties.forEach((prop)=>element.style.removeProperty(prop));if(element.getAttribute("style")===""){element.removeAttribute("style");}} 6111__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();} 6112return{zws};}else{return fillShrunkPhrasingParent(el);}} 6113__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;} 6114return fillers;} 6115__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;}} 6116__exports.toggleClass=toggleClass;function toggleClass(element,className,force){element.classList.toggle(className,force);if(!element.className){element.removeAttribute("class");}} 6117__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;}} 6118__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;}});}} 6119__exports.removeEmptyTextNodes=removeEmptyTextNodes;function removeEmptyTextNodes(root,cursors){for(const node of childNodes(root).filter((n)=>isEmptyTextNode(n))){cursors?.update(callbacksForCursorUpdate.remove(node));node.remove();}} 6120__exports.splitTextNode=splitTextNode;function splitTextNode(textNode,offset,originalNodeSide=DIRECTIONS.RIGHT){const document=textNode.ownerDocument;let parentOffset=childNodeIndex(textNode);
6120if(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;}}} 6121return parentOffset;} 6122__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;} 6123removedTrailingSpaceBefore=!!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();} 6124index+=1;}} 6125__exports.mergeAdjacentTextNodes=mergeAdjacentTextNodes;function mergeAdjacentTextNodes(node,cursor){let child=node.firstChild;while(child){if(isElement(child)){mergeAdjacentTextNodes(child,cursor);} 6126const 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;} 6127if(cursor.focus.node===next){cursor.focus.node=child;cursor.focus.offset=child.textContent.length+cursor.focus.offset;} 6128child.textContent+=next.textContent;next.remove();}else{child=next;}}} 6129return __exports;});; 6130 6131/* /html_editor/static/src/utils/dom_info.js */ 6132odoo.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;} 6133const content=el.innerHTML.trim();if(content===""||content==="<br>"){return true;} 6134return false;} 6135__exports.isEmptyTextNode=isEmptyTextNode;function isEmptyTextNode(node){if(node.nodeType!==Node.TEXT_NODE){return false;} 6136if(!node.textContent){return true;} 6137const trimmedContent=node.textContent.trim();if(!trimmedContent){if(node.textContent.includes("\n")){return true;} 6138if(node.textContent){return false;}} 6139return!trimmedContent;} 6140__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;} 6141__exports.isItalic=isItalic;function isItalic(node){return getComputedStyle(closestElement(node)).fontStyle==="italic";} 6142__exports.isUnderline=isUnderline;function isUnderline(node){let parent=closestElement(node);while(parent){if(getComputedStyle(parent).textDecorationLine.includes("underline")){return true;} 6143parent=parent.parentElement;} 6144return false;} 6145__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;} 6146parent=parent.parentElement;} 6147return false;} 6148__exports.isFontSize=isFontSize;function isFontSize(node,props){const element=closestElement(node);return getComputedStyle(element)["font-size"]===props.size;} 6149__exports.hasClass=hasClass;function hasClass(node,props){const element=closestElement(node);return element.classList.contains(props.className);} 6150__exports.isDirectionSwitched=isDirectionSwitched;function isDirectionSwitched(node,editable){const defaultDirection=editable.getAttribute("dir")||"ltr";return getComputedStyle(closestElement(node)).direction!==defaultDirection;} 6151__exports.isRow=isRow;function isRow(node){return["TH","TD"].includes(node.tagName);} 6152__exports.isZWS=isZWS;function isZWS(node){return node&&node.textContent==="\u200B";} 6153__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"));} 6154const 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);} 6155const visibleCharRegex=/[^\s\u200b]|[\u00A0\u0009]$/;__exports.isVisibleTextNode=isVisibleTextNode;function isVisibleTextNode(testedNode){if(!testedNode||!testedNode.length||testedNode.nodeType!==Node.TEXT_NODE){return false;} 6156if(isProtected(testedNode)){return true;} 6157if(visibleCharRegex.test(testedNode.textContent)||(isInPre(testedNode)&&isWhitespace(testedNode))){return true;} 6158if(ZERO_WIDTH_CHARS.includes(testedNode.textContent)){return false;} 6159let preceding;let following;let foundTestedNode;const currentNodeParentBlock=closestBlock(testedNode);if(!currentNodeParentBlock){return false;} 6160const 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;}} 6161while(following&&!visibleCharRegex.test(following.textContent)){following=following.nextSibling;}
6162if(!(preceding&&following)||currentNodeParentBlock!==closestBlock(preceding)||currentNodeParentBlock!==closestBlock(following)){return false;} 6163return!isWhitespace(preceding);} 6164const selfClosingElementTags=["BR","IMG","INPUT","HR"];__exports.isSelfClosingElement=isSelfClosingElement;function isSelfClosingElement(node){return node&&selfClosingElementTags.includes(node.nodeName);} 6165__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"))));} 6166__exports.hasVisibleContent=hasVisibleContent;function hasVisibleContent(node){return(node?childNodes(node):[]).some((n)=>isVisible(n));} 6167__exports.isButton=isButton;function isButton(node){if(!node||node.nodeType!==Node.ELEMENT_NODE){return false;} 6168return node.nodeName==="BUTTON"||node.classList.contains("btn");} 6169__exports.isZwnbsp=isZwnbsp;function isZwnbsp(node){return node?.nodeType===Node.TEXT_NODE&&node.textContent==="\ufeff";} 6170__exports.isTangible=isTangible;function isTangible(node){return isVisible(node)||isZwnbsp(node)||hasTangibleContent(node);} 6171__exports.hasTangibleContent=hasTangibleContent;function hasTangibleContent(node){return(node?childNodes(node):[]).some((n)=>isTangible(n));} 6172const 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)));} 6173__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");} 6174__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;} 6175return nonEmptyContent.every((el)=>{if(isMediaElement(el)||el.tagName==="IMG"){return true;} 6176if(el.tagName==="A"){return hasMediaOnly(el,requiresSingleMedia);}});} 6177const 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;} 6178return false;} 6179__exports.containsAnyInline=containsAnyInline;function containsAnyInline(element){if(!element){return false;} 6180let child=element.firstChild;while(child){if((!isBlock(child)&&child.nodeType===Node.ELEMENT_NODE)||(child.nodeType===Node.TEXT_NODE&&child.textContent.trim()!=="")){return true;} 6181child=child.nextSibling;} 6182return false;} 6183__exports.containsAnyNonPhrasingContent=containsAnyNonPhrasingContent;function containsAnyNonPhrasingContent(element){if(!element){return false;} 6184let child=element.firstChild;while(child){if(!isPhrasingContent(child)){return true;} 6185child=child.nextSibling;} 6186return false;} 6187__exports.isEmbeddedComponent=isEmbeddedComponent;function isEmbeddedComponent(node){return node.nodeType===Node.ELEMENT_NODE&&node.matches("[data-embedded]");} 6188__exports.isProtected=isProtected;function isProtected(node){if(!node){return false;} 6189const candidate=node.parentElement?closestElement(node.parentElement,"[data-oe-protected]"):null;if(!candidate||candidate.dataset.oeProtected==="false"){return false;} 6190return true;} 6191__exports.isProtecting=isProtecting;function isProtecting(node){if(!node){return false;} 6192return(node.nodeType===Node.ELEMENT_NODE&&node.dataset.oeProtected!=="false"&&node.dataset.oeProtected!==undefined);} 6193__exports.isUnprotecting=isUnprotecting;function isUnprotecting(node){if(!node){return false;} 6194return node.nodeType===Node.ELEMENT_NODE&&node.dataset.oeProtected==="false";} 6195const paragraphRelatedElements=__exports.paragraphRelatedElements=["P","H1","H2","H3","H4","H5","H6","PRE"];__exports.allowsParagraphRelatedElements=allowsParagraphRelatedElements;function allowsParagraphRelatedElements(node){return!isParagraphRelatedElement(node)&&isBlock(node);} 6196const 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;} 6197return(paragraphRelatedElements.includes(node.nodeName)||(node.nodeType===Node.ELEMENT_NODE&&node.matches(baseContainerGlobalSelector)));} 6198const paragraphRelatedElementsSelector=__exports.paragraphRelatedElementsSelector=[...paragraphRelatedElements,baseContainerGlobalSelector,].join(",");__exports.isListItemElement=isListItemElement;function isListItemElement(node){return[...listItem].includes(node.nodeName);} 6199const listItemElementSelector=__exports.listItemElementSelector=[...listItem].join(",");__exports.isListElement=isListElement;function isListElement(node){return[...listContainers].includes(node.nodeName);} 6200const listElementSelector=__exports.listElementSelector=[...listContainers].join(",");__exports.isTableCell=isTableCell;function isTableCell(node){return["TH","TD"].includes(node.nodeName);} 6201__exports.isAllowedContent=isAllowedContent;function isAllowedContent(parentBlock,nodes){let allowedContentSet=allowedContent[parentBlock.nodeName];if(!allowedContentSet){return true;} 6202if(parentBlock.matches(baseContainerGlobalSelector)){allowedContentSet=phrasingContent;} 6203return nodes.every((node)=>allowedContentSet.has(node.nodeName));} 6204__exports.isEmptyBlock=isEmptyBlock;function isEmptyBlock(blockEl){if(!blockEl||blockEl.nodeType!==Node.ELEMENT_NODE){return false;} 6205if(visibleCharRegex.test(blockEl.textContent)){return false;} 6206if(blockEl.querySelectorAll("br").length>=2){return false;} 6207if(isProtecting(blockEl)||isProtected(blockEl)){return false;} 6208const nodes=blockEl.querySelectorAll("*");for(const node of nodes){if(node.nodeName!="BR"&&(isSelfClosingElement(node)||isMediaElement(node)||isProtecting(node)||isButton(node))){return false;}} 6209return isBlock(blockEl);} 6210__exports.isShrunkBlock=isShrunkBlock;function isShrunkBlock(blockEl){return(isElement(blockEl)&&!blockEl.querySelector("br")&&!isSelfClosingElement(blockEl)&&isEmptyBlock(blockEl));} 6211__exports.isEditorTab=isEditorTab;function isEditorTab(node){return node&&node.nodeName==="SPAN"&&node.classList.contains("oe-tabs");} 6212__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)];} 6213const 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;} 6214next=!isSelfClosingElement(next)&&next;} 6215return[node,offset];} 6216__exports.getDeepestEditablePosition=getDeepestEditablePosition;function getDeepestEditablePosition(node,offset){const[deepNode,deepOffset]=getDeepestPosition(node,offset);if(isContentEditable(deepNode)){return[deepNode,deepOffset];} 6217const 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
6217deSize(previousSiblingOfNonEditable)];}else if(isElement(previousSiblingOfNonEditable)&&previousSiblingOfNonEditable.childNodes.length){return getDeepestEditablePosition(previousSiblingOfNonEditable,nodeSize(previousSiblingOfNonEditable));}}} 6218return[deepEditableNode,deepEditableOffset];} 6219__exports.previousLeaf=previousLeaf;function previousLeaf(node,editable,skipInvisible=false){let ancestor=node;while(ancestor&&!ancestor.previousSibling&&ancestor!==editable){ancestor=ancestor.parentElement;} 6220if(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;}}}} 6221__exports.nextLeaf=nextLeaf;function nextLeaf(node,editable,skipInvisible=false){let ancestor=node;while(ancestor&&!ancestor.nextSibling&&ancestor!==editable){ancestor=ancestor.parentElement;} 6222if(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;}}}} 6223function hasPseudoElementContent(node,pseudoSelector){const content=getComputedStyle(node,pseudoSelector).getPropertyValue("content");return content&&content!=="none";} 6224const NOT_A_NUMBER=/[^\d]/g;__exports.areSimilarElements=areSimilarElements;function areSimilarElements(node,node2){if(![node,node2].every((n)=>n?.nodeType===Node.ELEMENT_NODE)){return false;} 6225if(node.nodeName!==node2.nodeName){return false;} 6226for(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;}} 6227if([node,node2].some((n)=>hasPseudoElementContent(n,":before")||hasPseudoElementContent(n,":after"))){return false;} 6228if(isBlock(node)){return false;} 6229const 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;}} 6230return(!+nodeStyle.padding.replace(NOT_A_NUMBER,"")&&!+node2Style.padding.replace(NOT_A_NUMBER,"")&&!+nodeStyle.margin.replace(NOT_A_NUMBER,"")&&!+node2Style.margin.replace(NOT_A_NUMBER,""));} 6231__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)));} 6232__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)));} 6233__exports.isTextNode=isTextNode;function isTextNode(node){return node.nodeType===Node.TEXT_NODE;} 6234__exports.isElement=isElement;function isElement(node){return node.nodeType===Node.ELEMENT_NODE;} 6235__exports.isContentEditable=isContentEditable;function isContentEditable(node){const element=isTextNode(node)?node.parentElement:node;return element&&element.isContentEditable;} 6236__exports.isContentEditableAncestor=isContentEditableAncestor;function isContentEditableAncestor(node){if(node.nodeType!==Node.ELEMENT_NODE){return false;} 6237return node.isContentEditable&&node.matches("[contenteditable]");} 6238function 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));} 6239function hasStylesSubset(node,node2){const getNodeStyles=(n)=>(n||"").split(";").map((s)=>
6239s.trim()).filter(Boolean);const[nodeStyles,node2Styles]=[node,node2].map(getNodeStyles);return nodeStyles.every((style)=>node2Styles.includes(style));} 6240__exports.isRedundantElement=isRedundantElement;function isRedundantElement(node){if(!node||node.nodeType!==Node.ELEMENT_NODE||!node.parentElement){return false;} 6241const closestEl=closestElement(node.parentElement,node.tagName);if(!closestEl){return false;} 6242for(const{name:attrName,value:nodeAttrVal}of node.attributes){const closestElAttrVal=closestEl.getAttribute(attrName);if(!closestElAttrVal){return false;} 6243if(attrName==="class"){if(!hasClassesSubset(nodeAttrVal,closestElAttrVal)){return false;}}else if(attrName==="style"){if(!hasStylesSubset(nodeAttrVal,closestElAttrVal)){return false;}}else{if(nodeAttrVal!==closestElAttrVal){return false;}}} 6244return true;} 6245const PROTECTED_QWEB_SELECTOR=__exports.PROTECTED_QWEB_SELECTOR="[t-esc], [t-raw], [t-out], [t-field]";return __exports;});; 6246 6247/* /html_editor/static/src/utils/dom_state.js */ 6248odoo.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: "+ 6249options.label+ 6250(options.label===hash?"":` (${hash})`)+"%c"+ 6251(isPrepareUpdateLocked?" LOCKED":""),"color: cyan;","color: white;","color: red; font-weight: bold;");} 6252if(isPrepareUpdateLocked){return()=>{if(options.debug){console.log("%cRestoring%c update: "+ 6253options.label+ 6254(options.label===hash?"":` (${hash})`)+"%c LOCKED","color: lightgreen;","color: white;","color: red; font-weight: bold;");}};} 6255if(!options.allowReenter&&closestRoot){prepareUpdateLockedEditables.add(close
6255stRoot);} 6256const 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;} 6257restoreData.push(left,right);} 6258return function restoreStates(){if(options.debug){console.log("%cRestoring%c update: "+ 6259options.label+ 6260(options.label===hash?"":` (${hash})`),"color: lightgreen;","color: white;");} 6261for(const data of restoreData){restoreState(data,options.debug);} 6262if(!options.allowReenter&&closestRoot){prepareUpdateLockedEditables.delete(closestRoot);}};} 6263const 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);} 6264const 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;} 6265break;} 6266if(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;} 6267if(!isWhitespace(value)){cType=CTYPES.CONTENT;break;}}}else if(node.nodeName==="BR"){cType=CTYPES.BR;break;}else if(isVisible(node)){cType=CTYPES.CONTENT;break;}} 6268if(cType===undefined){cType=reasons.includes(PATH_END_REASONS.BLOCK_HIT)?CTYPES.BLOCK_OUTSIDE:CTYPES.BLOCK_INSIDE;} 6269return{node:boundaryNode,direction:direction,cType:cType,};} 6270const 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}`;} 6271const allRestoreStateRules=(function(){const map=new Map();const keys=["direction","cType1","cType2"];
6271for(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;}}} 6272if(priority>=0){matchedRules.push([priority,entry[1]]);}} 6273const finalRule={};for(let p=0;p<=keys.length;p++){for(const entry of matchedRules){if(entry[0]===p){Object.assign(finalRule,entry[1]);}}} 6274const hashCode=restoreStateRuleHashCode(direction,cType1,cType2);map.set(hashCode,finalRule);}}} 6275return map;})();__exports.restoreState=restoreState;function restoreState(prevStateData,debug=false){const{node,direction,cType:cType1,oldEditableHTML}=prevStateData;if(!node||!node.parentNode){return;} 6276const[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"+ 6277node.textContent.replaceAll(" ","_").replaceAll("\u200B","ZWS")+"\n"+"%c"+ 6278(direction===DIRECTIONS.LEFT?"left":"right")+"\n"+"%c"+ 6279ctypeToString(cType1)+"\n"+"%c"+ 6280ctypeToString(cType2)+"\n"+"%c"+"BEFORE: "+ 6281(oldEditableHTML||"(unavailable)")+"\n"+"%c"+"AFTER: "+ 6282(editable?editable.innerHTML.replaceAll(" ","_").replaceAll("\u200B","ZWS"):"(unavailable)")+"\n","color: white; display: block; width: 100%;","color: "+ 6283(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);} 6284if(Object.values(rule).filter((x)=>x!==undefined).length){const inverseDirection=direction===DIRECTIONS.LEFT?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;enforceWhitespace(el,offset,inverseDirection,rule);} 6285return rule;} 6286__exports.isFakeLineBreak=isFakeLineBreak;function isFakeLineBreak(brEl){return!(getState(...rightPos(brEl),DIRECTIONS.RIGHT).cType&(CTYPES.CONTENT|CTGROUPS.BR));} 6287__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+"+");} 6288const invisibleSpaceTextNodes=[];let foundVisibleSpaceTextNode=null;for(const node of domPath){if(node.nodeName==="BR"){if(rule.brVisibility===undefined){break;} 6289if(rule.brVisibility){node.before(document.createElement("br"));}else{if(!rule.extraBRRemovalCondition||rule.extraBRRemovalCondition(node)){node.remove();}} 6290break;}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;}} 6291if(rule.spaceVisibility===undefined){return;} 6292if(!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();} 6293if(pNode.childNodes.length===1&&!isBlock(pNode)){pNode.after(node);toRemove=pNode;}else{break;}}}} 6294const 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;} 6295spaceNode.nodeValue=spaceNode.nodeValue.replace(whitespaceAtEdgeRegex,spaceVisibility?"\u00A0":"");}} 6296__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;};} 6297return __exports;});; 6298 6299/* /html_editor/static/src/utils/dom_traversal.js */ 6300odoo.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;} 6301if(stopCallback(node)){break;}} 6302return null;} 6303__exports.findUpTo=findUpTo;function findUpTo(node,limitAncestor,predicate){while(node!==limitAncestor){if(predicate(node)){return node;} 6304node=node.parentElement;} 6305return null;} 6306__exports.findFurthest=findFurthest;function findFurthest(node,limitAncestor,predicate){const nodes=[];while(node!==limitAncestor){nodes.push(node);node=node.parentNode;} 6307return nodes.findLast(predicate);} 6308__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);} 6309if(element&&((editable&&editable.contains(element))||!node.isConnected)){return element;} 6310return null;} 6311__exports.ancestors=ancestors;function ancestors(node,editable){const result=[];while(node&&node.parentElement&&node!==editable){result.push(node.parentElement);node=node.parentElement;} 6312return result;} 6313__exports.children=children;function children(elem){const children=[];let child=elem.firstElementChild;while(child){children.push(child);child=child.nextElementSibling;} 6314return children;} 6315__exports.childNodes=childNodes;function childNodes(node){const childNodes=[];let child=node.firstChild;while(child){childNodes.push(child);child=child.nextSibling;} 6316return childNodes;} 6317__exports.descendants=descendants;function descendants(node,posterity=[]){let child=node.firstChild;while(child){posterity.push(child);
6317descendants(child,posterity);child=child.nextSibling;} 6318return posterity;} 6319const 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;} 6320while(currentNode){if(stopFunction&&stopFunction(currentNode)){reasons.push(movedUp?PATH_END_REASONS.BLOCK_OUT:PATH_END_REASONS.BLOCK_HIT);break;} 6321if(inScope&¤tNode===node){reasons.push(PATH_END_REASONS.OUT_OF_SCOPE);break;} 6322if(!(leafOnly&&movedUp)){yield currentNode;} 6323movedUp=false;let nextNode=nextDeepest(currentNode);if(!nextNode){movedUp=true;nextNode=currentNode.parentNode;} 6324currentNode=nextNode;} 6325reasons.push(PATH_END_REASONS.NO_NODE);};} 6326__exports.lastLeaf=lastLeaf;function lastLeaf(node,stopTraverseFunction){while(node&&node.lastChild&&!(stopTraverseFunction&&stopTraverseFunction(node))){node=node.lastChild;} 6327return node;} 6328__exports.firstLeaf=firstLeaf;function firstLeaf(node,stopTraverseFunction){while(node&&node.firstChild&&!(stopTraverseFunction&&stopTraverseFunction(node))){node=node.firstChild;} 6329return node;} 6330__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;} 6331return list;} 6332__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;} 6333return list;} 6334__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]:[];} 6335__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;} 6336let commonAncestor=null;while(candidate&&pathsToRoot.every((path)=>path.at(-1)===candidate)){commonAncestor=candidate;pathsToRoot.forEach((path)=>path.pop());candidate=pathsToRoot[0].at(-1);} 6337return commonAncestor;} 6338const selectElements=__exports.selectElements=function*(root,selector){if(root.matches(selector)){yield root;} 6339for(const elem of root.querySelectorAll(selector)){yield elem;}};return __exports;});; 6340 6341/* /html_editor/static/src/utils/drag_and_drop.js */ 6342odoo.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}
6342)(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;} 6343function updateElementPosition(el,{x,y},styleFn,offset={x:0,y:0}){return styleFn(el,{top:`${y - offset.y}px`,left:`${x - offset.x}px`});} 6344const 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"});} 6345addCleanup(()=>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();} 6346if(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");} 6347if(ctx.current.dropzone&&dropzoneEl!==ctx.current.dropzone.el){callHandler("dropzoneOut",{dropzone:ctx.current.dropzone,helper:ctx.current.helper,});delete ctx.current.dropzone;} 6348if(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,});} 6349return 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);} 6350return __exports;});; 6351 6352/* /html_editor/static/src/utils/fonts.js */ 6353odoo.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];} 6354this.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;} 6355if(!rules){continue;} 6356for(var r=0;r<rules.length;r++){var selectorText=rules[r].selectorText;if(!selectorText){continue;} 6357var 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;} 6358if(!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]);}} 6359if(data){this.cacheCssSelectors[filter].push(data);}}} 6360return 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;});; 6361 6362/* /html_editor/static/src/utils/formatting.js */ 6363odoo.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)=>{const boundaryElement=closestBlock(node)?.parentElement;const styledElement=findNode(closestPath(node),(el)=>[...FONT_SIZE_CLASSES,...DEFAULT_FONT_SIZE_CLASSES,...TEXT_STYLE_CLASSES,].some((cls)=>el.classList?.contains(cls)),(el)=>el===boundaryElement)??closestElement(node,"li");const activeFontSizeClass=styledElement&&FONT_SIZE_CLASSES.find((cls)=>styledElement.classList.contains(cls));if(props?.className){return props.className===activeFontSizeClass;} 6364return!!activeFontSizeClass;},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;} 6365if(node.getAttribute("style")===""){node.removeAttribute("style");}} 6366__exports.getCSSVariableValue=getCSSVariableValue;function getCSSVariableValue(key,htmlStyle){let value=htmlStyle.getPropertyValue(`--${key}`).trim();value=normalizeCSSColor(value);return value.replace(/"/g,"'");} 6367const 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;} 6368const converter=CSS_UNITS_CONVERSION[`${unitFrom}-${unitTo}`];if(converter===undefined){throw new Error(`Cannot convert '${unitFrom}' units into '${unitTo}' units !`);} 6369return value*converter(htmlStyle);} 6370__exports.getHtmlStyle=getHtmlStyle;function getHtmlStyle(document){return document.defaultView.getComputedStyle(document.documentElement);} 6371__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"),
6371(n)=>n.matches(` 6372 [style*='font-size'], 6373 ${FONT_SIZE_CLASSES.map((className) => `.${className}`)}, 6374 ${TEXT_STYLE_CLASSES.map((className) => `.${className}`)}, 6375 ${DEFAULT_FONT_SIZE_CLASSES.map((className) => `.${className}`)}, 6376 ${tagNameRelatedToFontSize} 6377 `));let remValue;const htmlStyle=getHtmlStyle(document);if(closestFontSizedEl){const useFontSizeInput=closestFontSizedEl.style.fontSize;if(useFontSizeInput){return parseFloat(getComputedStyle(closestStartContainerEl).fontSize);} 6378const activeClass=[...FONT_SIZE_CLASSES,...DEFAULT_FONT_SIZE_CLASSES,...TEXT_STYLE_CLASSES,].find((cls)=>closestFontSizedEl.classList.contains(cls));let fsName;if(activeClass==="o_default_font_size"||activeClass==="base-fs"){fsName="font-size-base";}else if(activeClass){fsName=`${activeClass.replace(/^o_/, "").replace(/-fs$/, "")}-font-size`;}else{fsName=`${closestFontSizedEl.tagName.toLowerCase()}-font-size`;} 6379remValue=parseFloat(getCSSVariableValue(fsName,htmlStyle));} 6380const pxValue=remValue&&convertNumericToUnit(remValue,"rem","px",htmlStyle);return pxValue||parseFloat(getComputedStyle(closestStartContainerEl).fontSize);} 6381__exports.getFontSizeOrClass=getFontSizeOrClass;function getFontSizeOrClass(node){if(!node){return null;} 6382if(node.style.fontSize){return{type:"font-size",value:node.style.fontSize};} 6383const fontSizeClass=FONT_SIZE_CLASSES.find((cls)=>node.classList.contains(cls));if(fontSizeClass){return{type:"class",value:fontSizeClass};} 6384return null;} 6385return __exports;});; 6386 6387/* /html_editor/static/src/utils/functions.js */ 6388odoo.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));} 6389return cache.get(firstArg);},}[funcName];} 6390return __exports;});; 6391 6392/* /html_editor/static/src/utils/html.js */ 6393odoo.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;} 6394__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;} 6395return __exports;});; 6396 6397/* /html_editor/static/src/utils/image.js */ 6398odoo.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"});} 6399return 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):"";} 6400if(isColorGradient(css)){parts.gradient=css.trim();} 6401return parts;} 6402__exports.backgroundImagePartsToCss=backgroundImagePartsToCss;function backgroundImagePartsToCss(parts){return[parts.url,parts.gradient].filter(Boolean).join(", ")||"";} 6403__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);} 6404__exports.getFetchedMimetype=getFetchedMimetype;async function getFetchedMimetype(image,data=image.dataset){const mimetypeOnData=data.mimetype||data.mimetypeBeforeConversion;if(mimetypeOnData){return mimetypeOnData;} 6405const src=getImageSrc(image);if(!src){return;}
6406try{const response=await headResponseCache.read(src);if(!response.ok){return null;} 6407const contentType=response.headers.get("content-type");if(!SUPPORTED_MIMETYPES.some((mimetype)=>contentType.startsWith(mimetype))){return null;} 6408if(contentType.startsWith("image/svg+xml")){return"image/svg+xml";} 6409return contentType;}catch{return null;}} 6410__exports.isImageCorsProtected=isImageCorsProtected;async function isImageCorsProtected(img){const src=img.getAttribute("src");if(!src){return false;} 6411let isCorsProtected=false;if(!src.startsWith("/")||/\/web\/image\/\d+-redirect\//.test(src)){isCorsProtected=await headResponseCache.read(src).then(()=>false).catch(()=>true);} 6412return isCorsProtected;} 6413__exports.isSrcCorsProtected=isSrcCorsProtected;async function isSrcCorsProtected(src){const dummyImg=document.createElement("img");dummyImg.src=src;return isImageCorsProtected(dummyImg);} 6414__exports.getImageSrc=getImageSrc;function getImageSrc(el){if(el.tagName==="IMG"){return el.getAttribute("src");} 6415if(el.querySelector(".s_parallax_bg")){el=el.querySelector(".s_parallax_bg");} 6416const url=backgroundImageCssToParts(el.style.backgroundImage).url;return url&&getBgImageURLFromURL(url);} 6417__exports.getBgImageURLFromURL=getBgImageURLFromURL;function getBgImageURLFromURL(url){const match=url.match(/^url\((['"])(.*?)\1\)$/);if(!match){return"";} 6418const matchedURL=match[2];const fullURL=new URL(matchedURL,window.location.origin);if(fullURL.origin===window.location.origin){return fullURL.href.slice(fullURL.origin.length);} 6419return matchedURL;} 6420return __exports;});; 6421 6422/* /html_editor/static/src/utils/image_processing.js */ 6423odoo.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;} 6424try{const canvas=document.createElement("canvas");_isWebGLEnabled=!!(window.WebGLRenderingContext&&(canvas.getContext("webgl")||canvas.getContext("experimental-webgl")));}catch{_isWebGLEnabled=false;} 6425return _isWebGLEnabled;} 6426const 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];} 6427const prom=new Promise((resolve)=>{if(!src){resolve(placeholderHref);return;} 6428fetch(src).then((response)=>{resolve(response.ok?src:placeholderHref);}).catch(()=>{resolve(placeholderHref);});});cache[src]=prom;return prom;} 6429__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;});} 6430const imageCache=new Map();function _loadImageObjectURL(src){return _updateImageData(src);} 6431__exports.loadImageDataURL=loadImageDataURL;function loadImageDataURL(src){return _updateImageData(src,"dataURL");} 6432async function _updateImageData(src,key="objectURL"){const currentImageData=imageCache.get(src);if(currentImageData&¤tImageData[key]){return currentImageData[key];} 6433let value="";const blob=await fetch(src).then((res)=>res.blob());if(key==="dataURL"){value=await createDataURL(blob);}else{value=URL.createObjectURL(blob);} 6434imageCache.set(src,Object.assign(currentImageData||{},{[key]:value,size:blob.size}));return value;} 6435__exports.getImageSizeFromCache=getImageSizeFromCache;function getImageSizeFromCache(src){return imageCache.get(src).size;} 6436__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;} 6437await readyPromise;return cropper;} 6438__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;} 6439let docHref=el.ownerDocument.defaultView.location.href;if(docHref.startsWith("about:")){docHref=window.location.href;} 6440const 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);} 6441relativeSrc=`/web/image/${encodeURIComponent(match)}`;} 6442const{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;} 6443return newDataset;} 6444__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);
6444reader.readAsDataURL(blob);});} 6445__exports.getDataURLBinarySize=getDataURLBinarySize;function getDataURLBinarySize(dataURL){return(dataURL.split(",")[1].length/4)*3;} 6446__exports.getAspectRatio=getAspectRatio;function getAspectRatio(ratio){if(typeof ratio==="number"){return ratio;} 6447const[a,b]=ratio.split(/[:/]/).map((n)=>parseFloat(n));if(!b){return a;} 6448return a/b;} 6449return __exports;});; 6450 6451/* /html_editor/static/src/utils/perspective_utils.js */ 6452odoo.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];} 6453function 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,],];} 6454function 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],];} 6455__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);} 6456__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],]));} 6457return __exports;});; 6458 6459/* /html_editor/static/src/utils/position.js */ 6460odoo.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)];} 6461__exports.rightPos=rightPos;function rightPos(node){return[node.parentElement,childNodeIndex(node)+1];} 6462__exports.boundariesOut=boundariesOut;function boundariesOut(node){const index=childNodeIndex(node);return[node.parentElement,index,node.parentElement,index+1];} 6463__exports.boundariesIn=boundariesIn;function boundariesIn(node){return[node,0,node,nodeSize(node)];} 6464__exports.startPos=startPos;function startPos(node){return[node,0];} 6465__exports.endPos=endPos;function endPos(node){return[node,nodeSize(node)];} 6466__exports.childNodeIndex=childNodeIndex;function childNodeIndex(node){let i=0;while(node.previousSibling){i++;node=node.previousSibling;} 6467return i;} 6468__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;}} 6469return __exports;});; 6470 6471/* /html_editor/static/src/utils/regex.js */ 6472odoo.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;});; 6473 6474/* /html_editor/static/src/utils/resource.js */ 6475odoo.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}).`);} 6476return{[resourceSequenceSymbol]:sequenceNumber,object,};} 6477return __exports;});; 6478 6479/* /html_editor/static/src/utils/sanitize.js */ 6480odoo.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",});} 6481for(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");
6481img.style.setProperty("width",isNaN(width)?width:`${width}px`);img.style.setProperty("height",isNaN(height)?height:`${height}px`);}} 6482__exports.fixInvalidHTML=fixInvalidHTML;function fixInvalidHTML(content){if(!content){return content;} 6483const 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}>`;});} 6484let Markup=null;__exports.instanceofMarkup=instanceofMarkup;function instanceofMarkup(value){if(!Markup){Markup=markup("").constructor;} 6485return value instanceof Markup;} 6486return __exports;});; 6487 6488/* /html_editor/static/src/utils/selection.js */ 6489odoo.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;} 6490return anchorOffset<focusOffset?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;} 6491return anchorNode.compareDocumentPosition(focusNode)&Node.DOCUMENT_POSITION_FOLLOWING?DIRECTIONS.RIGHT:DIRECTIONS.LEFT;} 6492__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)));}} 6493const 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);} 6494return[node,offset];} 6495__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;} 6496return[node,offset];} 6497__exports.normalizeCursorPosition=normalizeCursorPosition;function normalizeCursorPosition(node,offset,position="right"){[node,offset]=normalizeSelfClosingElement(node,offset);[node,offset]=normalizeNotEditableNode(node,offset,position);return[node,offset];} 6498__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--;} 6499return[node,offset];} 6500__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;}} 6501if(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);} 6502if(!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);}}}} 6503return[node,offset];}
6504function 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;}}} 6505function 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;}} 6506function 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;}} 6507function 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--;}}} 6508const 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];} 6509if(!adjacentCharacter){if(side==="previous"){focusNode=previousLeaf(focusNode,editable);focusOffset=focusNode&&nodeSize(focusNode);}else{focusNode=nextLeaf(focusNode,editable);focusOffset=0;} 6510const characterIndex=side==="previous"?focusOffset-1:focusOffset;adjacentCharacter=focusNode&&focusNode.textContent[characterIndex];}} 6511if(!focusNode||!isContentEditable(focusNode)||closestBlock(focusNode)!==originalBlock){return undefined;} 6512return adjacentCharacter;} 6513return __exports;});; 6514 6515/* /html_editor/static/src/utils/table.js */ 6516odoo.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;} 6517__exports.getColumnIndex=getColumnIndex;function getColumnIndex(td){return td.cellIndex;} 6518__exports.getTableCells=getTableCells;function getTableCells(table){return[...table.querySelectorAll("td, th")].filter((cell)=>closestElement(cell,"table")===table);} 6519return __exports;});; 6520 6521/* /html_editor/static/src/utils/tracking.js */ 6522odoo.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;} 6523visited.add(key);return true;};} 6524__exports.trackOccurrencesPair=trackOccurrencesPair;function trackOccurrencesPair(){const visited=new Map();return function isFirstOccurrence(a,b){if(!visited.has(a)){visited.set(a,trackOccurrences());} 6525return visited.get(a)(b);};} 6526return __exports;});; 6527 6528/* /html_editor/static/src/utils/url.js */ 6529odoo.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;} 6530if(hostnameList.includes(potentialURL.hostname)){return`https://${potentialURL.hostname}${potentialURL.pathname}`;}} 6531return false;} 6532__exports.isImageUrl=isImageUrl;function isImageUrl(url){const urlFileExtention=url.split(".").pop();return["jpg","jpeg","png","gif","svg","webp"].includes(urlFileExtention.toLowerCase());} 6533__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}`);} 6534url.search=new URLSearchParams(params);return url;} 6535__exports.isAbsoluteURLInCurrentDomain=isAbsoluteURLInCurrentDomain;function isAbsoluteURLInCurrentDomain(url,env=null){let hasProtocol;try{hasProtocol=!!new URL(url).protocol;}catch{hasProtocol=false;} 6536if(!hasProtocol){return false;} 6537const urlObj=new URL(url,window.location.origin);return(urlObj.origin===window.location.origin||ODOO_DOMAIN_REGEX.test(urlObj.origin));} 6538__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);}} 6539return __exports;});; 6540 6541/* /html_editor/static/src/dropdown_autovisibility_hook.js */ 6542odoo.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;} 6543const state=useState(overlayState);useEffect(()=>{if(popoverRef.el){if(!state.isOverlayVisible){popoverRef.el.style.visibility="hidden";}else{popoverRef.el.style.visibility="visible";}}},()=>[state.isOverlayVisible]);} 6544return __exports;});; 6545 6546/* /html_editor/static/src/editor.js */ 6547odoo.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;}}}
6548while((P=findPlugin())){inResult.add(P.id);result.push(P);} 6549if(initialPlugins.size){const messages=[];for(const P of initialPlugins){messages.push(`"${P.id}" is missing (${P.dependencies 6550 .filter((d) => !inResult.has(d)) 6551 .join(", ")})`);} 6552throw new Error(`Missing dependencies: ${messages.join(", ")}`);} 6553return result;} 6554const 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={};} 6555attachTo(editable){if(this.isDestroyed||this.editable){throw new Error("Cannot re-attach an editor");} 6556this.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);}} 6557editable.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);} 6558if(this.config.height){editable.style.height=this.config.height;} 6559if(!this.config.baseContainers.every((name)=>SUPPORTED_BASE_CONTAINER_NAMES.includes(name))){throw new Error(`Invalid baseContainers: ${this.config.baseContainers.join( 6560 ", " 6561 )}. Supported: ${SUPPORTED_BASE_CONTAINER_NAMES.join(", ")}`);} 6562this.startPlugins();this.isReady=true;this.config.onEditorReady?.();} 6563preparePlugins(){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})`);} 6564if(this.pluginsMap.has(P.id)){throw new Error(`Duplicate plugin id: ${P.id}`);} 6565this.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}`);} 6566exports[h]=plugin[h].bind(plugin);} 6567this.shared[P.id]=exports;} 6568const resources=this.createResources();for(const plugin of this.plugins){plugin._resources=resources;} 6569this.resources=resources;} 6570startPlugins(){for(const plugin of this.plugins){plugin.setup();} 6571this.resources["normalize_handlers"].forEach((cb)=>cb(this.editable));this.resources["start_edition_handlers"].forEach((cb)=>cb());} 6572getDependencies(dependencies){const deps={};for(const depName of dependencies){if(!(depName in this.shared)){throw new Error(`Missing dependency: ${depName}`);} 6573deps[depName]=this.shared[depName];} 6574return deps;} 6575createResources(){const resources={};function registerResources(obj){for(const key in obj){if(!(key in resources)){resources[key]=[];} 6576resources[key].push(obj[key]);}} 6577if(this.config.resources){registerResources(this.config.resources);} 6578for(const plugin of this.plugins){if(plugin.resources){registerResources(plugin.resources);}} 6579for(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]);} 6580return Object.freeze(resources);} 6581getEditorContext(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),};} 6582getResource(resourceId){return this.resources[resourceId]||[];} 6583dispatchTo(resourceId,...args){this.getResource(resourceId).forEac
6583h((handler)=>handler(...args));} 6584delegateTo(resourceId,...args){return this.getResource(resourceId).some((fn)=>fn(...args));} 6585checkPredicates(resourceId,...args){const results=this.getResource(resourceId).map((predicate)=>predicate(...args)).filter((result)=>result!==undefined);return results.length?results.every(Boolean):undefined;} 6586getContent(){return this.getElContent().innerHTML;} 6587getElContent(){const el=this.editable.cloneNode(true);this.resources["clean_for_save_handlers"].forEach((cb)=>cb({root:el}));return el;} 6588destroy(willBeRemoved){if(this.editable){let plugin;while((plugin=this.plugins.pop())){plugin.destroy();} 6589this.shared={};if(!willBeRemoved){this.editable.removeAttribute("contenteditable");removeClass(this.editable,"odoo-editor-editable");} 6590this.editable=null;} 6591this.isDestroyed=true;}} 6592return __exports;});; 6593 6594/* /html_editor/static/src/plugin.js */ 6595odoo.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;} 6596setup(){} 6597isValidTargetForDomListener(ev){return isValidTargetForDomListener(ev.target);} 6598addDomListener(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));} 6599addGlobalDomListener(eventName,fn,capture=false){this.addDomListener(this.document,eventName,fn,capture,true);} 6600destroy(){for(const cleanup of this._cleanups){cleanup();} 6601this.isDestroyed=true;}} 6602return __exports;});; 6603 6604/* /html_editor/static/src/plugin_sets.js */ 6605odoo.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;});; 6606 6607/* /html_editor/static/src/wysiwyg.js */ 6608odoo.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);} 6609const cssRules=rules.join(" ");
6609const styleTag=targetDoc.createElement("style");styleTag.appendChild(targetDoc.createTextNode(cssRules));targetDoc.head.appendChild(styleTag);}} 6610const 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);} 6611const additionalClasses=el.dataset.class?.trim().split(" ");if(additionalClasses){for(const c of additionalClasses){el.contentDocument.body.classList.add(c);}} 6612this.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));} 6613getEditorConfig(){return{...this.props.config,localOverlayContainers:{key:this.env.localOverlayContainerKey,ref:this.overlayRef,},};}} 6614return __exports;});; 6615 6616/* /html_editor/static/src/components/history_dialog/history_dialog.js */ 6617odoo.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_
6617id:revisionId});revisionId=metadata["revision_id"];} 6618const 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();});} 6619resize(){const dialogContainer=document.querySelector(".html-history-dialog-container");const computedStyle=getComputedStyle(dialogContainer);this.state.cssMaxHeight=parseInt(computedStyle.height.replace("px",""))-160;} 6620getConfig(value){return{value:this.state[value],embeddedComponents:this.props.embeddedComponents,};} 6621async init(){if(this.env.debug){await loadBundle("html_editor.assets_history_diff");} 6622await this.updateCurrentRevision(this.state.revisionsData[0]["revision_id"]);this.resize();} 6623async updateCurrentRevision(revisionId){if(this.state.revisionId===revisionId){return;} 6624this.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;} 6625getRevisionComparison=memoize(async function getRevisionComparison(revisionId){if(revisionId===-1){return"";} 6626const 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"";} 6627let 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;} 6628return this._removeExternalBlockHtml(markup(curentContent[0][this.props.versionedFieldName]));} 6629const 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();} 6630_removeExternalBlockHtml(baseHtml){const filteringRegex=/<[a-z ]+data-embedded="(?:(?!<).)+<\/[a-z]+>/gim;
6630const placeholderHtml=markup`<div class="embedded-history-dialog-placeholder">${_t( 6631 "Dynamic element" 6632 )}</div>`;return htmlReplaceAll(baseHtml,filteringRegex,()=>placeholderHtml);} 6633getRevisionDate(revision){if(!revision||!revision["create_date"]){return"--";} 6634const userTZ=user.tz||"local";return formatDateTime(DateTime.fromISO(revision["create_date"],{zone:"utc"}).setZone(userTZ),{showSeconds:false});} 6635getRevisionClasses(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";} 6636return classesStr;} 6637getRevisionAuthorAvatar(revision){if(!revision||!revision["create_uid"]){return this.DEFAULT_AVATAR;} 6638return`${browser.location.origin}/web/image?model=res.users&field=avatar_128&id=${revision["create_uid"]}`;} 6639get currentRevision(){const id=this.state?.revisionId||this.state.revisionsData[0]["revision_id"];return this.state.revisionsData.find((revision)=>
6639revision["revision_id"]===id);}} 6640return __exports;});; 6641 6642/* /html_editor/static/src/core/base_container_plugin.js */ 6643odoo.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;} 6644this.cleanEmptyStructuralContainers();},unsplittable_node_predicates:(node)=>{if(node.nodeName!=="DIV"){return false;} 6645return!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);} 6646getDefaultNodeName(){return this.config.baseContainers[0];} 6647cleanEmptyStructuralContainers(){const node=this.document.getSelection().anchorNode;if(!isElement(node)||!isEmpty(node)){return;} 6648const closestEditable=(n)=>isContentEditable(n.parentElement)?closestEditable(n.parentElement):n;const isUnsplittable=this.isUnsplittablePredicate(node);const isCandidateForBase=this.isCandidateForBaseContainerAllowUnsplittable(node);if(isUnsplittable||!isCandidateForBase){return;} 6649let anchorNode=node.parentElement;if(anchorNode===closestEditable(node)||!this.config.baseContainers.includes(anchorNode.nodeName)||this.getResource("unremovable_node_predicates").some((p)=>p(anchorNode))){return;} 6650if(isEmpty(anchorNode)){fillEmpty(anchorNode);} 6651let anchorOffset=childNodeIndex(node);node.remove();[anchorNode,anchorOffset]=getDeepestPosition(anchorNode,anchorOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset,});} 6652isCandidateForBaseContainer(element){return!this.getResource("invalid_for_base_container_predicates").some((fn)=>fn(element));} 6653isCandidateForBaseContainerAllowUnsplittable(element){for(const predicate of this.getResource("invalid_for_base_container_predicates")){if(predicate===this.isUnsplittablePredicate){continue;} 6654if(predicate(element)){return false;}} 6655return true;} 6656shallowIsCandidateForBaseContainer(element){const predicates=this.getResource("invalid_for_base_container_predicates");for(const predicate of predicates){if(predicate===this.hasNonPhrasingContentPredicate){continue;} 6657if(predicate(element)){return false;}} 6658return true;} 6659cleanForSave({root}){for(const baseContainer of selectElements(root,`.${BASE_CONTAINER_CLASS}`)){baseContainer.classList.remove(BASE_CONTAINER_CLASS);if(baseContainer.classList.length===0){baseContainer.removeAttribute("class");}}} 6660normalizeDivBaseContainers(element=this.editable){if(this.config.baseContainers&&!this.config.baseContainers.includes("DIV")){return;} 6661const 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);}}}}} 6662return __exports;});; 6663 6664/* /html_editor/static/src/core/clipboard_plugin.js */ 6665odoo.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','@html_editor/main/link/utils'],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{EMAIL_REGEX}=require("@html_editor/main/link/utils");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=new RegExp(`^(https?:\\/\\/)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-./?%&=]*)?$|${EMAIL_REGEX.source}`,"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);} 6666onCut(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();} 6667onCopy(ev){ev.preventDefault();this.setSelectionTransferData(ev,"clipboardData");} 6668setSelectionTransferData(ev,transferObjectProperty){const selection=this.dependencies.selection.getEditableSelection();let clonedContents=selection.cloneContents();if(!clonedContents.hasChildNodes()){return;} 6669let textContent=selection.textContent();for(const processor of this.getResource("clipboard_text_processors")){textContent=processor(textContent);} 6670for(const processor of this.getResource("clipboard_content_processors")){clonedContents=processor(clonedContents,selection)||clonedContents;} 6671this.dependencies.dom.removeSystemProperties(clonedContents);fillHtmlTransferData(ev,transferObjectProperty,clonedContents,{setEditorTransferData:isContentEditable(selection.commonAncestorContainer)||this.dependencies.selection.isNodeEditable(selection.commonAncestorContainer),textContent,});} 6672onPaste(ev){let selection=this.dependencies.selection.getEditableSelection();if(!selection.anchorNode.isConnected||!closestElement(selection.anchorNode).isContentEditable){return;} 6673ev.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);} 6674this.dispatchTo("after_paste_handlers",selection);this.dependencies.history.addStep();} 6675handlePasteUnsupportedHtml(selection,clipboardData){if(!isHtmlContentSupported(selection)){const text=clipboardData.getData("text/plain");this.dependencies.dom.insert(text);return true;}} 6676handlePasteOdooEditorHtml(clipboardData){const odooEditorHtml=clipboardData.getData("application/vnd.odoo.odoo-editor");const textContent=clipboardData.getData("text/plain");if(ONLY_LINK_REGEX.test(textContent)){return false;} 6677if(odooEditorHtml){const fragment=parseHTML(this.document,odooEditorHtml);this.dependencies.sanitize.sanitize(fragment);if(this.delegateTo("handle_paste_html_override",fragment)){return true;} 6678if(fragment.hasChildNodes()){this.dependencies.dom.insert(fragment);} 6679return true;}} 6680handlePasteHtml(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;} 6681const fragment=parseHTML(this.document,clipboardHtml);this.dependencies.sanitize.sanitize(fragment);if(this.delegateTo("handle_paste_html_override",fragment)){return true;} 6682if(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);}} 6683return true;}} 6684handlePasteText(selection,clipboardData){const text=clipboardData.getData("text/plain");if(this.delegateTo("paste_text_overrides",selection,text)){return;}else{this.pasteText(text);}} 6685pasteText(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;
6685if(!preEl){modifiedTextFragment=textFragment.replace(/( {2,})/g,(match)=>{let alternateValue=false;return match.replace(/ /g,()=>{alternateValue=!alternateValue;const replaceContent=alternateValue?"\u00A0":" ";return replaceContent;});});} 6686this.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(
6686);}}} 6687textIndex++;}} 6688prepareClipboardData(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");} 6689if(this.delegateTo("bypass_paste_image_files")){for(const imgElement of container.querySelectorAll("img")){imgElement.remove();}} 6690const 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);}}} 6691const childContent=childNodes(container);for(const child of childContent){this.cleanForPaste(child);} 6692const 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();}}} 6693return result;} 6694cleanForPaste(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>");} 6695const baseContainer=this.dependencies.baseContainer.createBaseContainer();const dir=node.getAttribute("dir");if(dir){baseContainer.setAttribute("dir",dir);} 6696baseContainer.append(...node.childNodes);node.replaceWith(baseContainer);childrenNodes=childNodes(baseContainer);}else{childrenNodes=unwrapContents(node);}}else{childrenNodes=unwrapContents(node);} 6697for(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");} 6698if(isEmptyBlock(node)){const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);node.replaceChildren(baseContainer);} 6699if(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");} 6700if(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");} 6701node.remove();node=checklist;}} 6702for(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);}} 6703for(const klass of[...node.classList]){if(!this.isWhitelisted(klass)){node.classList.remove(klass);}} 6704for(const child of childNodes(node)){this.cleanForPaste(child);}}} 6705isWhitelisted(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(","));}} 6706isBlacklisted(node){return(!isTextNode(node)&&node.matches([].concat(...Object.values(CLIPBOARD_BLACKLISTS)).join(",")));} 6707onDragStart(ev){const selection=this.dependencies.selection.getEditableSelection();this.dispatchTo("before_drag_handlers",selection);this.setSelectionTransferData(ev,"dataTransfer");} 6708async onDrop(ev){ev.preventDefault();const selection=this.dependencies.selection.getEditableSelection();if(!isHtmlContentSupported(selection)){return;} 6709const 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);
6709selectionToRestore.restore();} 6710const 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);} 6711if(dropRange){this.dependencies.delete.deleteSelection();this.dependencies.selection.setSelection({anchorNode:dropRange.startContainer,anchorOffset:dropRange.startOffset,});}} 6712if(this.delegateTo("html_drop_overrides",this.dependencies.selection.getEditableSelection(),ev.dataTransfer)){this.dependencies.history.addStep();return;} 6713if(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();});}} 6714async 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;}));} 6715const nodes=await Promise.all(promises);const fragment=this.document.createDocumentFragment();fragment.append(...nodes);return fragment;}} 6716function getImageFiles(dataTransfer){return[...dataTransfer.items].filter((item)=>item.kind==="file"&&item.type.includes("image/")).map((item)=>item.getAsFile());} 6717function getImageUrl(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.readAsDataURL(file);reader.onloadend=(e)=>{if(reader.error){return reject(reader.error);} 6718resolve(e.target.result);};});} 6719return __exports;});; 6720 6721/* /html_editor/static/src/core/comment_plugin.js */ 6722odoo.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();}}}} 6723return __exports;});; 6724 6725/* /html_editor/static/src/core/content_editable_plugin.js */ 6726odoo.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));} 6727for(const contentNotEditableEl of contentNotEditableEls){contentNotEditableEl.setAttribute("contenteditable","false");} 6728const contentEditableEls=[];for(const fn of this.getResource("content_editable_providers")){contentEditableEls.push(...fn(root));} 6729const 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;} 6730if(!contentNotEditableEls.includes(contentEditableEl)){contentEditableEl.setAttribute("contenteditable",true);}}}} 6731cleanForSave({root}){const toRemoveSelector=this.getResource("contenteditable_to_remove_selector").join(",");const contenteditableEls=toRemoveSelector?[...selectElements(root,toRemoveSelector)]:[];for(const contenteditableEl of contenteditableEls){contenteditableEl.removeAttribute("contenteditable");}}} 6732return __exports;});; 6733 6734/* /html_editor/static/src/core/delete_plugin.js */ 6735odoo.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");} 6736if(event.altKey&&event.key==="Delete"){return runCommand("deleteForwardWord");} 6737if(event.metaKey&&event.key==="Backspace"){return runCommand("deleteBackwardLine");} 6738if(event.metaKey&&event.key==="Delete"){return runCommand("deleteForwardLine");}});}} 6739getNormalizedRange(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);} 6740const range=this.document.createRange();range.setStart(startContainer,startOffset);range.setEnd(endContainer,endOffset);return range;} 6741deleteSelection(selection=this.dependencies.selection.getEditableSelection()){let range=this.getNormalizedRange(selection);if(range.collapsed){return;} 6742const 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
6742stElement(node,(node)=>isEditableOrFullySelected(node))));};if(selectedNodes.some((node)=>!canBeDeleted(node))){return;} 6743range=this.adjustRange(range,[this.expandRangeToIncludeNonEditables,this.includeEndOrStartBlock,this.fullyIncludeLinks,]);if(this.delegateTo("delete_range_overrides",range)){return;} 6744range=this.deleteRange(range);this.setCursorFromRange(range);} 6745delete(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");} 6746this.dispatchTo("delete_handlers");this.dependencies.history.addStep();} 6747deleteBackward(selection,granularity){const{endContainer,endOffset}=this.getNormalizedRange(selection);if(!closestElement(endContainer).isContentEditable){return;} 6748let 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;} 6749range=this.adjustRange(range,[this.includeEmptyInlineEnd,this.includePreviousZWS,this.includeEndOrStartBlock,]);range=this.deleteRange(range);this.document.getSelection()?.removeAllRanges();this.setCursorFromRange(range,{collapseToEnd:true});} 6750deleteForward(selection,granularity){const{startContainer,startOffset}=this.getNormalizedRange(selection);if(!closestElement(startContainer).isContentEditable){return;} 6751let 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;} 6752range=this.adjustRange(range,[this.includeEmptyInlineStart,this.includeNextZWS,this.includeEndOrStartBlock,]);range=this.deleteRange(range);this.setCursorFromRange(range);} 6753getRangeForDelete(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";}} 6754switch(granularity){case"character":[destContainer,destOffset]=this.findAdjacentPosition(node,offset,direction);break;case"word":({focusNode:destContainer,focusOffset:destOffset}=this.dependencies.selection.modifySelection("extend",direction,"w
6754ord"));break;case"line":[destContainer,destOffset]=this.findLineBoundary(node,offset,direction);break;default:throw new Error("Invalid granularity");} 6755if(!destContainer){[destContainer,destOffset]=[node,offset];} 6756const[startContainer,startOffset,endContainer,endOffset]=direction==="forward"?[node,offset,destContainer,destOffset]:[destContainer,destOffset,node,offset];return{startContainer,startOffset,endContainer,endOffset};} 6757deleteRange(range){if(range.startContainer===range.endContainer&&range.startOffset===range.endOffset){return range;} 6758range=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);} 6759restoreFakeBRs();this.fillShrunkBlocks(originalCommonAncestor);restoreSpaces();return range;} 6760splitTextNodes({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;} 6761return[textNode.parentElement,offset,didSplit];};if(endContainer.nodeType===Node.TEXT_NODE){[endContainer,endOffset]=split(endContainer,endOffset);} 6762if(startContainer.nodeType===Node.TEXT_NODE){let didSplit;[startContainer,startOffset,didSplit]=split(startContainer,startOffset);if(startContainer===endContainer&&didSplit){endOffset+=1;}} 6763return{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer:getCommonAncestor([startContainer,endContainer],this.editable),};} 6764removeFakeBRs(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;} 6765lastBR.remove();} 6766visitedNodes.add(node);node=node.parentNode;} 6767return[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;} 6768const lastBR=childNodes(node).findLast((child)=>child.nodeName==="BR");if(lastBR&&isFakeLineBreak(lastBR)){lastBR.after(this.document.createElement("br"));}}};return{restoreFakeBRs,range};} 6769fillEmptyInlines(range){const nodes=[range.startContainer];if(range.endContainer!==range.startContainer){nodes.push(range.endContainer);} 6770for(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","");}}} 6771fillShrunkBlocks(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);}} 6772const containingBlock=closestBlock(commonAncestor);if(isShrunkBlock(containingBlock)){fillBlock(containingBlock);}} 6773removeNodes(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]);} 6774startRemoveIndex=childNodeIndex(node)+1;node=node.parentElement;} 6775node=endContainer;let endRemoveIndex=endOffset;while(node!==commonAncestorContainer){for(let i=0;i<endRemoveIndex;i++){nodesToRemove.push(node.childNodes[i]);} 6776endRemoveIndex=childNodeIndex(node);node=node.parentElement;} 6777for(let i=startRemoveIndex;i<endRemoveIndex;i++){nodesToRemove.push(commonAncestorContainer.childNodes[i]);} 6778let allNodesRemoved=true;for(const node of nodesToRemove){const parent=node.parentNode;const didRemove=this.removeNode(node);allNodesRemoved&&=didRemove;if(didRemove&&endContainer===parent){endOffset-=1;}} 6779const 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};} 6780return{allNodesRemoved,range:{...range,endOffset}};} 6781isUnremovable(node,root=undefined){return this.getResource("unremovable_node_predicates").some((p)=>p(node,root));} 6782removeNode(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);} 6783customHandling=true;customIsUnremovable=this.isUnremovable(node,root);if(!customIsUnremovable){node.remove();}}} 6784if(customHandling){return!customIsUnremovable;} 6785for(const child of[...node.childNodes]){remove(child);} 6786if(this.isUnremovable(node,root)||(!this.dependencies.selection.isNodeEditable(node)&&!node.parentElement?.isContentEditable)){return false;} 6787if(node.hasChildNodes()&&node.isContentEditable){node.before(...node.childNodes);node.remove();return false;} 6788node.remove();return true;};return remove(node);} 6789joinFragments(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;} 6790getJoinableFragment(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"};} 6791return{node:null,type:"null"};} 6792let last;let element=container;while(element!==commonAncestor){if(isBlock(element)){return{node:element,type:"block"};} 6793last=element;element=element.parentElement;} 6794return{node:last,type:"inline"};} 6795getJoinOperation(leftType,rightType){return({"block + block":this.joinBlocks,"block + inline":this.joinInlineIntoBlock,"inline + block":this.joinBlockIntoInline,}[leftType+" + "+rightType]||(()=>true)).bind(this);} 6796isUnmergeable(node){return this.getResource("unsplittable_node_predicates").some((p)=>p(node));} 6797joinBlocks(left,right,commonAncestor){const canMerge=(n)=>!findUpTo(n,commonAncestor,this.isUnmergeable.bind(this));if(!canMerge(left)||!canMerge(right)){return false;} 6798const rightChildNodes=childNodes(right);if(!isAllowedContent(left,rightChildNodes)){return false;} 6799left.append(...rightChildNodes);let toRemove=right;let parent=right.parentElement;while(parent!==commonAncestor&&parent.childNodes.length===1){toRemove=parent;parent=parent.parentElement;} 6800toRemove.remove();return true;} 6801joinInlineIntoBlock(leftBlock,rightInline,commonAncestor){if(findUpTo(leftBlock,commonAncestor,(node)=>this.isUnmergeable(node))){return false;} 6802while(rightInline&&!isBlock(rightInline)){const toAppend=rightInline;rightInline=rightInline.nextSibling;leftBlock.append(toAppend);} 6803return true;} 6804joinBlockIntoInline(leftInline,rightBlock,commonAncestor){if(findUpTo(rightBlock,commonAncestor,(node)=>this.isUnmergeable(node))){return false;} 6805leftInline.after(...childNodes(rightBlock));let toRemove=rightBlock;let parent=rightBlock.parentElement;while(parent!==commonAncestor&&parent.childNodes.length===1){toRemove=parent;parent=parent.parentElement;} 6806if(parent===commonAncestor){const rightSibling=toRemove.nextSibling;if(rightSibling&&!isBlock(rightSibling)){rightSibling.before(this.document.createElement("br"));}} 6807toRemove.remove();return true;} 6808adjustRange({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);} 6809({startContainer,startOffset,endOffset,endContainer}=range);return{startContainer,startOffset,endOffset,endContainer};} 6810includeBlockStart(block,range){const{startContainer,startOffset,commonAncestorContainer}=range;if(block===commonAncestorContainer||!this.isCursorAtStartOfElement(block,startContainer,startOffset)){return range;} 6811range.setStartBefore(block);return this.includeBlockStart(block.parentNode,range);} 6812includeBlockEnd(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;} 6813range.setEndAfter(block);return this.includeBlockEnd(block.parentNode,range);} 6814includeEndOrStartBlock(range){const{startContainer,endContainer,commonAncestorContainer}=range;const startBlock=findUpTo(startContainer,commonAncestorContainer,isBlock);const endBlock=findUpTo(endContainer,commonAncestorContainer,isBlock);if(!startBlock||!endBlock){return range;} 6815range=this.includeBlockEnd(endBlock,range);if(range.endContainer===endContainer){range=this.includeBlockStart(startBlock,range);} 6816return range;} 6817fullyIncludeLinks(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);} 6818if(endLink&&this.isCursorAtEndOfElement(endLink,endContainer,endOffset)){range.setEndAfter(endLink);} 6819return range;} 6820includeEmptyInlineStart(range){const element=closestElement(range.startContainer);if(this.isEmptyInline(element)){range.setStartBefore(element);} 6821return range;}
6822includeEmptyInlineEnd(range){const element=closestElement(range.endContainer);if(this.isEmptyInline(element)){range.setEndAfter(element);} 6823return range;} 6824includeNextZWS(range){const{endContainer,endOffset}=range;if(isTextNode(endContainer)&&endContainer.textContent[endOffset]==="\u200B"){range.setEnd(endContainer,endOffset+1);} 6825return range;} 6826includePreviousZWS(range){const{startContainer,startOffset}=range;if(isTextNode(startContainer)&&startContainer.textContent[startOffset-1]==="\u200B"){range.setStart(startContainer,startOffset-1);} 6827return range;} 6828expandRangeToIncludeNonEditables(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);} 6829const endUneditable=endOffset===nodeSize(endContainer)&&!nextLeaf(endContainer,closestBlock(endContainer))&&findFurthest(endContainer,commonAncestor,isNonEditable);if(endUneditable){range.setEndAfter(endUneditable);} 6830return range;} 6831findAdjacentPosition(node,offset,direction){return direction==="forward"?this.findNextPosition(node,offset):this.findPreviousPosition(node,offset);} 6832makeFindPositionFn(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)];}} 6833const 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;} 6834if(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);} 6835leaf=adjacentLeaf(leaf,editableRoot);} 6836return[null,null];};} 6837findLineBoundary(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);} 6838if(last===container&&offset===edgeIndex(container)){return this.findAdjacentPosition(container,offset,direction);} 6839return direction==="forward"?rightPos(last):leftPos(last);} 6840isVisibleChar(char,textNode,offset){if(isProtected(textNode)){return true;} 6841const isEmptyButton=(node)=>isButton(node)&&/^\ufeff*$/.test(node.textContent);if(isZwnbsp(textNode)&&(isButton(textNode.previousSibling)||isEmptyButton(textNode.nextSibling))){return true;} 6842if(["\u200B","\uFEFF"].includes(char)){return false;} 6843if(!isWhitespace(char)||isInPre(textNode)){return true;} 6844if(offset){return!isWhitespace(textNode.textContent[offset-char.length]);}else if(!(getState(...leftPos(textNode),DIRECTIONS.LEFT).cType&CTYPES.CONTENT)){return false;} 6845const charsToTheRight=textNode.textContent.slice(offset+char.length);for(char of charsToTheRight){if(!isWhitespace(char)){return true;}} 6846if(getState(...rightPos(textNode),DIRECTIONS.RIGHT).cType&CTYPES.CONTENT){return true;} 6847return false;} 6848shouldSkip(leaf,blockSwitch){const systemNodeSelectors=this.getResource("system_node_selectors").join(",");if(systemNodeSelectors&&closestElement(leaf,systemNodeSelectors)){return true;} 6849if(leaf.nodeType===Node.TEXT_NODE){return false;} 6850if(blockSwitch){return false;} 6851if(leaf.nodeName==="BR"&&isFakeLineBreak(leaf)){return true;} 6852if(this.getResource("functional_empty_node_predicates").some((predicate)=>predicate(leaf))){return false;} 6853if(isEmpty(leaf)||isZWS(leaf)){return true;} 6854return false;} 6855findPreviousVisibleChar(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];} 6856char=chars.pop();}
6857return[null,null];} 6858findNextVisibleChar(textNode,index){for(const char of textNode.textContent.slice(index)){if(this.isVisibleChar(char,textNode,index)){return[char,index];} 6859index+=char.length;} 6860return[null,null];} 6861adjustedLeaf(leaf,refEditableRoot){const isNonEditable=(node)=>!isContentEditable(node);const nonEditableRoot=leaf&&findFurthest(leaf,refEditableRoot,isNonEditable);return nonEditableRoot||leaf;} 6862previousLeaf(node,editableRoot){return this.adjustedLeaf(previousLeaf(node,editableRoot),editableRoot);} 6863nextLeaf(node,editableRoot){return this.adjustedLeaf(nextLeaf(node,editableRoot),editableRoot);} 6864previousLeafFromPos(node,offset,editableRoot){const leaf=node.hasChildNodes()&&offset>0?lastLeaf(node.childNodes[offset-1]):previousLeaf(node,editableRoot);return this.adjustedLeaf(leaf,editableRoot);} 6865nextLeafFromPos(node,offset,editableRoot){const leaf=node.hasChildNodes()&&offset<nodeSize(node)?firstLeaf(node.childNodes[offset]):nextLeaf(node,editableRoot);return this.adjustedLeaf(leaf,editableRoot);} 6866onBeforeInputDelete(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);}}} 6867onBeforeInputInsertText(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);}}}} 6868preventDefaultDeleteAndroidChrome(beforeInputEvent){const restoreDOM=this.dependencies.history.makeSavePoint();this.onAndroidChromeInput=(ev)=>{if(ev.inputType!==beforeInputEvent.inputType){return;} 6869restoreDOM();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);};} 6870deleteBackwardUnmergeable(range){const{startContainer,startOffset,endContainer,endOffset}=range;return this.deleteCharUnmergeable(endContainer,endOffset,startContainer,startOffset);} 6871deleteForwardUnmergeable(range){const{startContainer,startOffset,endContainer,endOffset}=range;return this.deleteCharUnmergeable(startContainer,startOffset,endContainer,endOffset);} 6872deleteCharUnmergeable(sourceContainer,sourceOffset,destContainer,destOffset){if(!destContainer){return;} 6873const commonAncestor=getCommonAncestor([sourceContainer,destContainer],this.editable);const closestUnmergeable=findUpTo(sourceContainer,commonAncestor,(node)=>this.isUnmergeable(node));if(!closestUnmergeable){return;} 6874if((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,});} 6875return true;} 6876isEmptyInline(element){if(isBlock(element)){return false;} 6877if(isZWS(element)){return true;} 6878return element.innerHTML.trim()==="";} 6879isCursorAtStartOfElement(element,cursorNode,cursorOffset){const[node]=this.findPreviousPosition(cursorNode,cursorOffset);return!element.contains(node);} 6880isCursorAtEndOfElement(element,cursorNode,cursorOffset){const[node]=this.findNextPosition(cursorNode,cursorOffset);return!element.contains(node);}
6881setCursorFromRange(range,{collapseToEnd=false}={}){range=this.collapseRange(range,{toEnd:collapseToEnd});const[anchorNode,anchorOffset]=this.normalizeEnterBlock(range.startContainer,range.startOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset});} 6882normalizeEnterBlock(node,offset){while(isBlock(node.childNodes[offset])&&!isSelfClosingElement(node.childNodes[offset])){[node,offset]=[node.childNodes[offset],0];} 6883return[node,offset];} 6884collapseRange(range,{toEnd=false}={}){let{startContainer,startOffset,endContainer,endOffset}=range;if(toEnd){[startContainer,startOffset]=[endContainer,endOffset];}else{[endContainer,endOffset]=[startContainer,startOffset];} 6885const commonAncestorContainer=startContainer;return{startContainer,startOffset,endContainer,endOffset,commonAncestorContainer};}} 6886return __exports;});; 6887 6888/* /html_editor/static/src/core/dialog_plugin.js */ 6889odoo.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,});});}} 6890return __exports;});; 6891 6892/* /html_editor/static/src/core/dom_plugin.js */ 6893odoo.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);}} 6894return parents;} 6895const 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(",");} 6896insert(content){if(!content){return;} 6897let selection=this.dependencies.selection.getEditableSelection();if(!selection.isCollapsed){this.dependencies.delete.deleteSelection();selection=this.dependencies.selection.getEditableSelection();} 6898let 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);}} 6899container.replaceChildren(content);} 6900const block=closestBlock(selection.anchorNode);for(const cb of this.getResource("before_insert_processors")){container=cb(container,block);} 6901if(!container.hasChildNodes()){return[];} 6902selection=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);} 6903startNode=selection.startContainer;} 6904const allInsertedNodes=[];const hasSingleChild=nodeSize(container)===1;const closestList=(node)=>{if(isBlock(node)){return node&&isListItemElement(node);} 6905return closestList(node.parentElement);};
6905if(closestList(selection.anchorNode)&&isListElement(container.firstChild)){unwrapContents(container.firstChild);} 6906if(closestList(selection.focusNode)&&isListElement(container.lastChild)&&!hasSingleChild){unwrapContents(container.lastChild);} 6907startNode=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);} 6908const lastLeafNode=lastLeaf(container);if(isBlock(lastLeafNode)&&!(closestElement(lastLeafNode,"[contenteditable]")?.contentEditable==="false")){fillEmpty(lastLeafNode);} 6909if(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));} 6910containerFirstChild.replaceChildren(...childNodes(container.firstElementChild));container.firstElementChild.remove();} 6911if(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));} 6912containerLastChild.replaceChildren(...childNodes(container.lastElementChild));container.lastElementChild.remove();}} 6913const 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);} 6914startNode=textNode;allInsertedNodes.push(textNode);}else{startNode=childNodes(startNode).at(selection.anchorOffset-1);}} 6915let 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];} 6916const firstInsertedNodes=childNodes(containerFirstChild);if(containerFirstChild.hasChildNodes()){const toInsert=childNodes(containerFirstChild);_insertAt(currentNode,[...toInsert],insertBefore);currentNode=toInsert[toInsert.length-1];insertBefore=false;} 6917allInsertedNodes.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,});}} 6918let nodeToInsert;let doesCurrentNodeAllowsP=allowsParagraphRelatedElements(currentNode);const candidatesForRemoval=[];const insertedNodes=childNodes(container);while((nodeToInsert=container.firstChild)){if(isBlock(nodeToInsert)&&!
6918doesCurrentNodeAllowsP){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;} 6919currentNode=currentNode.parentElement;doesCurrentNodeAllowsP=allowsParagraphRelatedElements(currentNode);continue;}else{makeContentsInline(container);nodeToInsert=container.firstChild;break;}} 6920let offset=childNodeIndex(currentNode);if(!insertBefore){offset+=1;} 6921if((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);} 6922candidatesForRemoval.push(right);}else{if(isBlock(currentNode)){fillShrunkPhrasingParent(currentNode);} 6923currentNode=currentNode.parentElement;} 6924doesCurrentNodeAllowsP=allowsParagraphRelatedElements(currentNode);} 6925if(isListItemElement(currentNode.parentElement)&&isBlock(nodeToInsert)&&this.dependencies.split.isUnsplittable(nodeToInsert)){const br=document.createElement("br");currentNode[isEmptyBlock(currentNode)||!isTangible(currentNode)?"before":"after"](br);}} 6926const block=closestBlock(currentNode);for(const processor of this.getResource("node_to_insert_processors")){nodeToInsert=processor({nodeToInsert,container:block});} 6927if(insertBefore){currentNode.before(nodeToInsert);insertBefore=false;}else{currentNode.after(nodeToInsert);} 6928allInsertedNodes.push(nodeToInsert);if(currentNode.tagName!=="BR"&&isShrunkBlock(currentNode)){currentNode.remove();} 6929currentNode=nodeToInsert;} 6930textNode.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(),});}} 6931insertedNodesParents=getConnectedParents(allInsertedNodes);for(const parent of insertedNodesParents){if(!isProtecting(parent)&&!(isProtected(parent)&&!isUnprotecting(parent))&&parent.isContentEditable){cleanTrailingBR(parent);}} 6932for(const candidateForRemoval of candidatesForRemoval){if(candidateForRemoval.isConnected&&(isParagraphRelatedElement(candidateForRemoval)||isListItemElement(candidateForRemoval))&&candidateForRemoval.parentElement.isContentEditable&&isEmptyBlock(candidateForRemoval)){candidateForRemoval.remove();}} 6933const lastInsertedNode=allInsertedNodes.findLast((node)=>node.isConnected);if(!lastInsertedNode){return;} 6934let 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);} 6935this.dependencies.selection.setSelection({anchorNode:lastPosition[0],anchorOffset:lastPosition[1]},{normalize:false});return firstInsertedNodes.concat(insertedNodes).concat(lastInsertedNodes);} 6936isEditionBoundary(node){if(!node){return false;} 6937if(node===this.editable){return true;} 6938return isContentEditableAncestor(node);} 6939areInlinesAllowedAtRoot(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;} 6940return results.every((r)=>r);} 6941copyAttributes(source,target){if(source?.nodeType!==Node.ELEMENT_NODE||target?.nodeType!==Node.ELEMENT_NODE){return;} 6942const ignoredAttrs=new Set(this.getResource("system_attributes"));const ignoredClasses=new Set(this.getResource("system_classes"));
6942for(const attr of source.attributes){if(ignoredAttrs.has(attr.name)){continue;} 6943if(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);}}}}} 6944setTagName(el,newTagName){const document=el.ownerDocument;if(el.tagName===newTagName){return el;} 6945const newEl=document.createElement(newTagName);const content=childNodes(el);if(isListItemElement(el)){el.append(newEl);newEl.replaceChildren(...content);}else{if(el.parentElement){el.before(newEl);} 6946this.copyAttributes(el,newEl);newEl.replaceChildren(...content);el.remove();} 6947return newEl;} 6948removeSystemProperties(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);} 6949for(const element of root.querySelectorAll(this.systemPropertiesSelector)){clean(element);}} 6950insertFontAwesome({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});} 6951isRetaggingSafe(block){return!((isParagraphRelatedElement(block)||isListItemElement(block)||isPhrasingContent(block))&&this.getResource("unremovable_node_predicates").some((predicate)=>predicate(block)));} 6952getBlocksToSet(){const targetedBlocks=[...this.dependencies.selection.getTargetedBlocks()];return targetedBlocks.filter((block)=>this.isRetaggingSafe(block)&&!descendants(block).some((descendant)=>targetedBlocks.includes(descendant))&&block.isContentEditable);} 6953canSetBlock(){return this.getBlocksToSet().length>0;} 6954setBlock({tagName,extraClass=""}){let newCandidate=this.document.createElement(tagName.toUpperCase());if(extraClass){newCandidate.classList.add(extraClass);} 6955if(this.dependencies.baseContainer.isCandidateForBaseContainer(newCandidate)){const baseContainer=this.dependencies.baseContainer.createBaseContainer(newCandidate.nodeName);this.copyAttributes(newCandidate,baseContainer);newCandidate=baseContainer;} 6956const 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;} 6957this.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);} 6958newEls.push(newEl);}else{newCandidate.append(...childNodes(block));block.append(newCandidate);cursors.remapNode(block,newCandidate);}} 6959cursors.restore();this.dependencies.history.addStep();} 6960removeEmptyClassAndStyleAttributes(root){for(const node of[root,...descendants(root)]){if(node.classList&&!node.classList.length){node.removeAttribute("class");} 6961if(node.style&&!node.style.length){node.removeAttribute("style");}}}} 6962return __exports;});; 6963 6964/* /html_editor/static/src/core/editor_version_plugin.js */ 6965odoo.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;} 6966stripVersion(element);} 6967cleanForSave({root}){const VERSIONS=htmlEditorVersions();const firstChild=root.firstElementChild;const version=VERSIONS.at(-1);if(firstChild&&version){firstChild.dataset.oeVersion=version;}}} 6968return __exports;});; 6969 6970/* /html_editor/static/src/core/format_plugin.js */ 6971odoo.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)=>
6971formatPlugin.isSelectionFormat(format,nodes);} 6972const 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;} 6973this.formatSelection(format,{applyStyle:false,removeFormat:true});}} 6974unwrapEmptyFormat(insertedNode){const anchorNode=this.dependencies.selection.getEditableSelection().anchorNode;if(!allWhitespaceRegex.test(insertedNode.textContent)){return insertedNode;} 6975const emptyZWS=closestElement(anchorNode,"[data-oe-zws-empty-inline]");if(!emptyZWS||!emptyZWS.parentElement.isContentEditable||this.getResource("unremovable_node_predicates").some((p)=>p(emptyZWS))){return insertedNode;} 6976const cursors=this.dependencies.selection.preserveSelection();cursors.update(callbacksForCursorUpdate.remove(emptyZWS));emptyZWS.remove();cursors.restore();return insertedNode;} 6977removeAllFormats(){const targetedNodes=this.dependencies.selection.getTargetedNodes();this.removeFormats(Object.keys(formatsSpecs),targetedNodes);this.dispatchTo("remove_all_formats_handlers");this.dependencies.history.addStep();} 6978removeFontSizeFormat(el){for(const node of[el,...descendants(el)]){removeFormat(node,formatsSpecs.fontSize);removeFormat(node,formatsSpecs.setFontSizeClassName);}} 6979hasSelectionFormat(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}));} 6980isSelectionFormat(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})));}
6981hasAnyFormat(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;}} 6982return editableTargetedNodes.some((node)=>this.getResource("has_format_predicates").some((predicate)=>predicate(node)));} 6983formatSelection(formatName,options){this.dispatchTo("format_selection_handlers",formatName,options);if(this._formatSelection(formatName,options)&&!options?.removeFormat){this.dependencies.history.addStep();}} 6984_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;} 6985this.dependencies.selection.selectAroundNonEditable();const selection=this.dependencies.split.splitSelection();if(typeof applyStyle==="undefined"){applyStyle=!this.isSelectionFormat(formatName);} 6986let 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();}} 6987const 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;} 6988const 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;}} 6989return 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,formatProps?.className)));if(parentNode&&!isBlock(parentNode)&&this.dependencies.split.isUnsplittable(parentNode)&&this.dependencies.selection.areNodeContentsFullySelected(parentNode)&&!isContentEditableAncestor(parentNode)){inlineAncestors.push(parentNode);} 6990while(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");} 6991if(!applyStyle&&isNodeUnsplittable&&this.dependencies.selection.areNodeContentsFullySelected(parentNode)){currentNode=currentNode.parentElement;}else{break;}} 6992parentNode=currentNode.parentElement;} 6993const firstBlockOrClassHasFormat=formatSpec.isFormatted(parentNode,formatProps);
6993if(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);}}} 6994for(const targetedFieldNode of tagetedFieldNodes){if(applyStyle){formatSpec.addStyle(targetedFieldNode,formatProps);}else{formatSpec.removeStyle(targetedFieldNode);}} 6995if(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);}} 6996cursor.restore();if(unformattedTextNodes.length===1&&unformattedTextNodes[0]&&unformattedTextNodes[0].textContent==="\u200B"){this.dependencies.selection.setCursorEnd(unformattedTextNodes[0]);return!!tagetedFieldNodes.size;} 6997return true;} 6998normalize(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);}}} 6999this.mergeAdjacentInlines(root);} 7000cleanForSave({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;} 7001if(currentElement&&isBlock(currentElement)){fillEmpty(currentElement);}} 7002this.mergeAdjacentInlines(root,{preserveSelection});} 7003removeEmptyInlineElement(selectionData){const{anchorNode}=selectionData.editableSelection;const blockEl=closestBlock(anchorNode);if(!blockEl){return;} 7004const inlineElement=findFurthest(closestElement(anchorNode),blockEl,(e)=>!isBlock(e)&&e.textContent==="\u200b");if(this.lastEmptyInlineElement?.isConnected&&this.lastEmptyInlineElement!==inlineElement){this.cleanElement(this.lastEmptyInlineElement,{preserveSelection:true});} 7005if(inlineElement&&!isEmptyBlock(blockEl)){this.lastEmptyInlineElement=inlineElement;}else{this.lastEmptyInlineElement=null;}} 7006cleanElement(element,{preserveSelection}){if(!allWhitespaceRegex.test(element.textContent)){delete element.dataset.oeZwsEmptyInline;this.cleanZWS(element,{preserveSelection});return;} 7007if(this.getResource("unremovable_node_predicates").some((p)=>p(element))){return;} 7008if(![...element.classList].every((c)=>this.getResource("format_class_predicates").some((p)=>p(c)))){return;} 7009delete element.dataset.oeZwsEmptyInline;const restore=prepareUpdate(...leftPos(element),...rightPos(element));element.remove();restore();} 7010cleanZWS(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);}
7011cursors?.restore();} 7012insertText(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});} 7013const 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;} 7014insertAndSelectZws(){const selection=this.dependencies.selection.getEditableSelection();const zws=this.insertText(selection,"\u200B");splitTextNode(zws,selection.anchorOffset);return zws;} 7015onBeforeInput(ev){if(ev.inputType.startsWith("format")&&!isHtmlContentSupported(this.dependencies.selection.getEditableSelection())){ev.preventDefault();} 7016if(ev.inputType==="insertText"){const selection=this.dependencies.selection.getEditableSelection();if(!selection.isCollapsed){return;} 7017const 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,});}}} 7018mergeAdjacentInlines(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));} 7019if(node.matches("code.o_inline_code")){while(node.previousSibling?.nodeType===Node.TEXT_NODE&&/^\uFEFF*$/.test(node.previousSibling.nodeValue)){node.previousSibling.remove();}} 7020node.previousSibling.append(...childNodes(node));node.remove();}} 7021selectionToRestore?.restore();} 7022shouldBeMergedWithPreviousSibling(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;}} 7023return(!isSelfClosingElement(node)&&isMergeable(node)&&areSimilarElements(node,previousSibling));}} 7024function 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);} 7025return span;}} 7026function 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);}} 7027if(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);} 7028for(let index=node.attributes.length-1;index>=0;--index){newNode.attributes.setNamedItem(node.attributes[index].cloneNode());} 7029cursor?.remapNode(node,newNode);node.parentNode.replaceChild(newNode,node);}else{cursor?.update(callbacksForCursorUpdate.unwrap(node));unwrapContents(node);}}} 7030return __exports;});; 7031 7032/* /html_editor/static/src/core/history_plugin.js */ 7033odoo.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();}});
7033this.observer=new MutationObserver((records)=>this.handleNewRecords(records));this.enableObserverCallbacks=new Set();this._cleanups.push(()=>this.observer.disconnect());this.clean();} 7034getIsPreviewing(){return this.isPreviewing;} 7035clean(){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");} 7036getNodeById(id){return this.nodeMap.getNode(id);} 7037reset(content){this.clean();this.stageSelection();this.steps.push(this.makeSnapshotStep());this.dispatchTo("history_reset_handlers",content);} 7038resetFromSteps(steps){this.withObserverOff(()=>{this.editable.replaceChildren();this.clean();this.stageSelection();for(const step of steps){this.applyMutations(step.mutations);} 7039this.steps=steps;this.dispatchTo("history_reset_from_steps_handlers");});this.dispatchTo("history_reset_from_steps_handlers");} 7040makeSnapshotStep(){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,};} 7041getHistorySteps(){return this.steps;} 7042processHistoryStep(step){for(const fn of this.getResource("history_step_processors")){step=fn(step);} 7043return step;} 7044enableObserver(){this.observer.observe(this.editable,{childList:true,subtree:true,attributes:true,attributeOldValue:true,characterData:true,characterDataOldValue:true,});} 7045disableObserver(){const enableObserver=()=>{this.enableObserverCallbacks.delete(enableObserver);if(this.enableObserverCallbacks.size>0){return;} 7046this.handleObserverRecords();this.isObserverDisabled=false;};this.enableObserverCallbacks.add(enableObserver);this.handleObserverRecords();this.isObserverDisabled=true;return enableObserver;} 7047ignoreDOMMutations(callback){const enableObserver=this.disableObserver();try{return callback();}finally{enableObserver();}} 7048withObserverOff(callback){this.handleObserverRecords();this.observer.disconnect();callback();this.enableObserver();} 7049handleObserverRecords(dispatch=true){this.handleNewRecords(this.observer.takeRecords(),dispatch);} 7050processNewRecords(mutationRecords){if(this.observer.takeRecords().length){throw new Error("MutationObserver has pending records");} 7051mutationRecords=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;} 7052isValidRecord(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));}} 7053dispatchContentUpdated(){if(!this.currentStep?.mutations?.length){return;} 7054const root=this.getMutationsRoot(this.currentStep.mutations);if(!root){return;} 7055this.dispatchTo("content_updated_handlers",root);} 7056handleNewRecords(records,dispatch=true){const processedRecords=this.processNewRecords(records);if(processedRecords.length){if(dispatch){const stepType=this.currentStep.type;this.dispatchTo("handleNewRecords",processedRecords,stepType);} 7057this.processNewRecords(this.observer.takeRecords());this.dispatchContentUpdated();}} 7058setIdOnAddedNodes(record){if(record.type!=="childList"){return;} 7059record.addedTrees.flatMap(treeToNodes).filter((node)=>
7059!this.nodeMap.hasNode(node)).forEach((node)=>this.nodeMap.set(this.generateId(),node));} 7060filterMutationRecords(records){records=this.filterAttributeMutationRecords(records);records=this.filterSameTextContentMutationRecords(records);records=this.filterOutIntermediateStateMutationRecords(records);return records;} 7061filterAttributeMutationRecords(records){return records.filter((record)=>{if(record.type!=="attributes"){return true;} 7062if(record.target===this.editable){return false;} 7063if(record.attributeName==="contenteditable"){return false;} 7064return true;});} 7065filterSameTextContentMutationRecords(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;}} 7066filteredRecords.push(record);} 7067return filteredRecords;} 7068filterOutIntermediateStateMutationRecords(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);}} 7069return filteredRecords;} 7070transformToHistoryMutationRecords(records){records=this.transformChildListRecords(records);return records.flatMap((record)=>{if(record.type==="attributes"){if(record.attributeName==="class"){return this.splitClassMutationRecord(record);} 7071const oldValue=record.oldValue===undefined?null:record.oldValue;const value=record.target.getAttribute(record.attributeName);return{...pick(record,"type","target","attributeName"),oldValue,value};} 7072if(record.type==="characterData"){const value=record.target.textContent;return{...pick(record,"type","target","oldValue"),value};} 7073return record;});} 7074transformChildListRecords(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;} 7075const 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();} 7076splitClassMutationRecord(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)),];} 7077isSystemMutationRecord(record){if(record.type==="attributes"){return this.mutationFilteredAttributes.has(record.attributeName);} 7078if(record.type==="classList"){return this.mutationFilteredClasses.has(record.className);} 7079return false;} 7080filterAndAdjustHistoryMutationRecords(records){this.dispatchTo("before_filter_mutation_record_handlers",records);const savableRecordPredicates=this.getResource("savable_mutation_record_predicates");
7080const isRecordSavable=(record)=>savableRecordPredicates.every((p)=>p(record));const result=[];for(const record of records){if(!this.isObservedNode(record.target)){continue;} 7081if(this.isObserverDisabled||!isRecordSavable(record)){if(record.type!=="childList"){this.storeOldValue(record);} 7082continue;} 7083const updatedRecord=record.type==="childList"?this.updateChildListRecord(record):this.updateOldValue(record);if(this.isValidRecord(updatedRecord)){this.setIdOnAddedNodes(record);result.push(updatedRecord);}} 7084return result;} 7085isObservedNode(node){return this.nodeMap.hasNode(node);} 7086storeOldValue(record){const{stateMap,key}=this.getObservedStateStorage(record);if(!stateMap.has(key)){stateMap.set(key,record.oldValue);}} 7087updateOldValue(record){const{stateMap,key}=this.getObservedStateStorage(record);if(!stateMap.has(key)){return record;} 7088const lastObservedValue=stateMap.get(key);stateMap.delete(key);return{...record,oldValue:lastObservedValue};} 7089getObservedStateStorage(record){if(!this.lastObservedState.has(record.target)){this.lastObservedState.set(record.target,{attributes:new Map(),classList:new Map(),characterData:new Map(),});} 7090const 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}`);}} 7091updateChildListRecord(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;} 7092return{node:tree.node,children:tree.children.map(removeUnobservedNodes).filter(Boolean),};};const removedTrees=record.removedTrees.map(removeUnobservedNodes).filter(Boolean);return{...record,previousSibling,nextSibling,removedTrees,};} 7093isSameTextContentMutation(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);} 7094stageSelection(){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;} 7095this.currentStep.selection=this.serializeSelection(selection);} 7096stageFocus(){let activeElement=this.document.activeElement;if(activeElement.contains(this.editable)){activeElement=this.editable;} 7097if(this.editable.contains(activeElement)){this.currentStep.activeElementId=this.setNodeId(activeElement);}} 7098stageRecords(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;} 7099case"childList":{this.currentStep.mutations.push(...this.splitChildListRecord(record));break;}}}} 7100splitChildListRecord(record){const parentNodeId=this.nodeMap.getId(record.target);if(!parentNodeId){throw new Error("Unknown parent node");} 7101const 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"),];} 7102applyCustomMutation({apply,revert}){apply();this.addCustomMutation({apply,revert});} 7103addCustomMutation({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);} 7104setNodeId(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;}} 7105return id;} 7106generateId(){return Math.floor(Math.random()*Math.pow(2,52)).toString();} 7107addStep({type="original",extraStepInfos}={}){const currentStep=this.currentStep;currentStep.type=type;this.handleObserverRecords();const currentMutationsCount=currentStep.mutations.length;if(currentMutationsCount===0){return false;} 7108const stepCommonAncestor=this.getMutationsRoot(currentStep.mutations)||this.editable;this.dispatchTo("normalize_handlers",stepCommonAncestor,type);this.handleObserverRecords(false);
7108if(currentMutationsCount===currentStep.mutations.length){this.dispatchContentUpdated();} 7109currentStep.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;} 7110this.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;} 7111canUndo(){return this.getNextUndoIndex()>0;} 7112canRedo(){return this.getNextRedoIndex()>0;} 7113undo(){if(this.steps.length===1){return;} 7114this.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});} 7115this.dispatchTo("post_undo_handlers",revertedStep);} 7116redo(){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});} 7117this.dispatchTo("post_redo_handlers",revertedStep);} 7118setSerializedSelection(selection){if(!selection.anchorNodeId){return;} 7119const anchorNode=this.nodeMap.getNode(selection.anchorNodeId);if(!anchorNode){return;} 7120const newSelection={anchorNode,anchorOffset:selection.anchorOffset,};const focusNode=this.nodeMap.getNode(selection.focusNodeId);if(focusNode){newSelection.focusNode=focusNode;newSelection.focusOffset=selection.focusOffset;} 7121this.dependencies.selection.setSelection(newSelection,{normalize:false});} 7122setSerializedFocus(activeElementId){const elementToFocus=activeElementId==="root"?this.editable:activeElementId&&this.nodeMap.getNode(activeElementId);if(elementToFocus?.isConnected&&elementToFocus!==this.document.activeElement){elementToFocus.focus();}} 7123getNextUndoIndex(){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;} 7124if(["original","redo"].includes(step.type)&&!this.revertedSteps.has(step.id)){return index;}} 7125return-1;} 7126isReversibleStep(index){const step=this.steps[index];if(!step){return false;} 7127return!this.getResource("unreversible_step_predicates").some((predicate)=>predicate(step));} 7128getNextRedoIndex(){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;} 7129if(step.type==="original"){return-1;} 7130if(step.type==="undo"&&!this.revertedSteps.has(step.id)){return index;}} 7131return-1;} 7132addExternalStep(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);} 7133this.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);} 7134this.applyMutations(this.currentStep.mutations);this.dispatchTo("external_step_added_handlers");});} 7135applyMutations(mutations,{forNewStep=false,reverse}={}){if(forNewStep){this.fixClassListMutationsForNewStep(mutations);} 7136for(const mutation of mutations){switch(mutation.type){case"custom"
7136:{mutation.apply();break;} 7137case"characterData":{const node=this.nodeMap.getNode(mutation.nodeId);if(node){node.textContent=mutation.value;} 7138break;} 7139case"classList":{const node=this.nodeMap.getNode(mutation.nodeId);if(node){toggleClass(node,mutation.className,mutation.value);} 7140break;} 7141case"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});} 7142this.setAttribute(node,mutation.attributeName,value);} 7143break;} 7144case"remove":{this.applyRemoveMutation(mutation);break;} 7145case"add":{this.applyAddMutation(mutation);break;}}}} 7146fixClassListMutationsForNewStep(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));}} 7147applyRemoveMutation(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;} 7148if(toRemove.parentElement!==parent){console.warn("Mutation could not be applied, parent node does not match.",mutation);return;} 7149toRemove.remove();} 7150applyAddMutation(mutation){const{nodeId,serializedNode,parentNodeId,nextNodeId,previousNodeId}=mutation;const toAdd=this.nodeMap.getNode(nodeId)||this.unserializeNode(serializedNode);if(!toAdd){return;} 7151const parent=this.nodeMap.getNode(parentNodeId);if(!parent){console.warn("Mutation could not be applied, parent node is missing.",mutation);return;} 7152if(previousNodeId===null){parent.prepend(toAdd);return;} 7153if(nextNodeId===null){parent.append(toAdd);return;} 7154const isValid=(node)=>node?.parentNode===parent;const previousNode=this.nodeMap.getNode(previousNodeId);if(isValid(previousNode)){previousNode.after(toAdd);return;} 7155const nextNode=this.nodeMap.getNode(nextNodeId);if(isValid(nextNode)){nextNode.before(toAdd);return;} 7156console.warn("Mutation could not be applied, reference nodes are invalid.",mutation);} 7157revertMutations(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});} 7158serializeSelection(selection){return{anchorNodeId:this.nodeMap.getId(selection.anchorNode),anchorOffset:selection.anchorOffset,focusNodeId:this.nodeMap.getId(selection.focusNode),focusOffset:selection.focusOffset,};} 7159getMutationsRoot(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;} 7160return commonAncestor;} 7161makeSavePoint(){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;} 7162applied=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;});} 7163this.applyMutations(draftMutations,{forNewStep:true});this.handleObserverRecords();
7163selectionToRestore.restore();this.currentStep.extraStepInfos=extraToRestore;this.dispatchTo("restore_savepoint_handlers");};} 7164makePreviewableOperation(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;},};} 7165makePreviewableAsyncOperation(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();} 7166if(this.isDestroyed){return;} 7167this.addStep();},commit:async(...args)=>{await revertOperation();this.isPreviewing=false;const revertSavePoint=this.makeSavePoint();try{await operation(...args);}catch(error){revertSavePoint();throw error;} 7168if(this.isDestroyed){return;} 7169this.addStep();},revert:async()=>{await revertOperation();revertOperation=()=>{};this.isPreviewing=false;},};} 7170restoreToStep(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;} 7171for(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;}} 7172for(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());}} 7173this.setSerializedSelection(lastRevertedStep.selection);this.dispatchContentUpdated();this.addStep({type:"restore"});return lastRevertedStep;} 7174setStepExtra(key,value){this.currentStep.extraStepInfos[key]=value;} 7175disableIsCurrentStepModifiedWarning(){this.ignoreIsCurrentStepModified=true;return()=>{this.ignoreIsCurrentStepModified=false;};} 7176getIsCurrentStepModified(){if(this.ignoreIsCurrentStepModified){return false;} 7177return this.currentStep.mutations.find((m)=>["characterData","remove","add"].includes(m.type));} 7178setAttribute(node,attributeName,attributeValue){if(this.delegateTo("set_attribute_overrides",node,attributeName,attributeValue)){return;} 7179if(attributeValue!==null){node.setAttribute(attributeName,attributeValue);}else{node.removeAttribute(attributeName);}} 7180serializeNode(node){return this.serializeTree(nodeToTree(node));} 7181unserializeNode(node){let[unserializedNode,newNodesMap]=this._unserializeNode(node,this.nodeMap);if(!unserializedNode){return null;} 7182const fakeNode=this.document.createElement("fake-el");fakeNode.appendChild(unserializedNode);this.dependencies.sanitize.sanitize(fakeNode,{IN_PLACE:true});unserializedNode=fakeNode.firstChild;if(!unserializedNode){return null;} 7183for(const node of[unserializedNode,...descendants(unserializedNode)]){if(this.nodeMap.hasNode(node)){continue;} 7184const id=newNodesMap.get(node);if(id){this.nodeMap.set(id,node);}} 7185return unserializedNode;} 7186serializeTree(tree){const node=tree.node;const nodeId=this.nodeMap.getId(node);if(!nodeId){return null;} 7187const 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);} 7188result.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);} 7189return result;} 7190_unserializeNode(serializedNode,nodeMap=new NodeMap(),_map=new Map()){let node=nodeMap.getNode(serializedNode.nodeId);if(node){return[node,_map];} 7191if(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]);} 7192node.append(...serializedNode.children.map((child)=>
7192this._unserializeNode(child,nodeMap,_map)[0]).filter(Boolean));}else{console.warn("unknown node type");return[null,_map];} 7193_map.set(node,serializedNode.nodeId);return[node,_map];} 7194_onDocumentBeforeInput(ev){if(this.editable.contains(ev.target)){return;} 7195if(["historyUndo","historyRedo"].includes(ev.inputType)){this._onKeyupResetContenteditableNodes.push(...this.editable.querySelectorAll("[contenteditable=true]"));if(this.editable.getAttribute("contenteditable")==="true"){this._onKeyupResetContenteditableNodes.push(this.editable);} 7196for(const node of this._onKeyupResetContenteditableNodes){node.setAttribute("contenteditable",false);}}} 7197_onDocumentInput(ev){if(["historyUndo","historyRedo"].includes(ev.inputType)&&this._onKeyupResetContenteditableNodes.length){for(const node of this._onKeyupResetContenteditableNodes){node.setAttribute("contenteditable",true);} 7198this._onKeyupResetContenteditableNodes=[];}}} 7199__exports.nodeToTree=nodeToTree;function nodeToTree(node){return{node,children:childNodes(node).map(nodeToTree),};} 7200function treeToNodes(tree){return[tree.node,...tree.children.flatMap(treeToNodes)];} 7201class 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");} 7202const 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);}} 7203return __exports;});; 7204 7205/* /html_editor/static/src/core/input_plugin.js */ 7206odoo.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);} 7207onKeyDown(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(),});}} 7208onBeforeInput(ev){this.dependencies.history.stageSelection();this.dispatchTo("beforeinput_handlers",ev);this.dependencies.selection.setCachedSelection(null);} 7209onInput(ev){this.dependencies.history.addStep();this.dispatchTo("input_handlers",ev);}} 7210return __exports;});; 7211 7212/* /html_editor/static/src/core/line_break_plugin.js */ 7213odoo.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();}
7213else if(!closestElement(selection.anchorNode).isContentEditable){selection=this.dependencies.selection.getEditableSelection();} 7214const targetNode=selection.anchorNode;const targetOffset=selection.anchorOffset;this.insertLineBreakNode({targetNode,targetOffset});this.dependencies.history.addStep();} 7215insertLineBreakNode({targetNode,targetOffset}){const closestEl=closestElement(targetNode);if(closestEl&&!closestEl.isContentEditable){return;} 7216if(targetNode.nodeType===Node.TEXT_NODE){targetOffset=splitTextNode(targetNode,targetOffset);targetNode=targetNode.parentElement;} 7217if(this.delegateTo("insert_line_break_element_overrides",{targetNode,targetOffset})){return;} 7218this.insertLineBreakElement({targetNode,targetOffset});} 7219insertLineBreakElement({targetNode,targetOffset}){const closestEl=closestElement(targetNode);if(closestEl&&!closestEl.isContentEditable){return;} 7220const 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]);} 7221if(isFakeLineBreak(brEl)&&!(getState(...leftPos(brEl),DIRECTIONS.LEFT).cType&(CTGROUPS.BLOCK|CTYPES.BR))){const brEl2=this.document.createElement("br");brEl.before(brEl2);brEls.unshift(brEl2);} 7222restore();for(const el of brEls){if(el.parentNode){const pos=rightPos(el);this.dependencies.selection.setSelection({anchorNode:pos[0],anchorOffset:pos[1],});break;}}} 7223onBeforeInput(e){if(e.inputType==="insertLineBreak"){e.preventDefault();this.insertLineBreak();}}} 7224return __exports;});; 7225 7226/* /html_editor/static/src/core/no_inline_root_plugin.js */ 7227odoo.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;});} 7228fixSelectionOnEditableRoot(selection){if(!selection.isCollapsed||selection.anchorNode!==this.editable){return false;} 7229const 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,
7229nodeBeforeCursor,key);} 7230return this.fixSelectionOnEditableRootGeneric(nodeAfterCursor,nodeBeforeCursor);} 7231fixSelectionOnEditableRootArrowKeys(nodeAfterCursor,nodeBeforeCursor,key){if(!["ArrowRight","ArrowLeft","ArrowUp","ArrowDown"].includes(key)){return false;} 7232const directionForward=["ArrowRight","ArrowDown"].includes(key);let node=directionForward?nodeAfterCursor:nodeBeforeCursor;while(node&&isNotAllowedContent(node)){node=directionForward?node.nextElementSibling:node.previousElementSibling;} 7233if(!node){return false;} 7234let[anchorNode,anchorOffset]=directionForward?startPos(node):endPos(node);[anchorNode,anchorOffset]=getDeepestPosition(anchorNode,anchorOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset});return true;} 7235fixSelectionOnEditableRootGeneric(nodeAfterCursor,nodeBeforeCursor){if(isParagraphRelatedElement(nodeAfterCursor)){this.dependencies.selection.setCursorStart(nodeAfterCursor);return true;} 7236if(isParagraphRelatedElement(nodeBeforeCursor)){this.dependencies.selection.setCursorEnd(nodeBeforeCursor);return true;} 7237return false;}} 7238return __exports;});; 7239 7240/* /html_editor/static/src/core/overlay.js */ 7241odoo.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` 7242 <div t-ref="root" class="overlay" t-att-class="props.className" t-on-pointerdown.stop="() => {}"> 7243 <t t-component="props.Component" t-props="props.props"/> 7244 </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);} 7245useExternalListener(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]);} 7246if(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);}} 7247if(this.props.hasAutofocus){useActiveElement("root");} 7248const 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});} 7249getSelectionTarget(){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;} 7250const inEditable=selectionData.currentSelectionIsInEditable;let range;if(inEditable){range=selection.getRangeAt(0);this.lastSelection={range};}else{if(!this.lastSelection){return null;} 7251range=this.lastSelection.range;} 7252let 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("|");
7252clonedRange.insertNode(shadowCaret);clonedRange.selectNode(shadowCaret);rect=clonedRange.getBoundingClientRect();shadowCaret.remove();clonedRange.detach();});} 7253this.rangeElement.getBoundingClientRect=()=>rect;return this.rangeElement;} 7254updateVisibility(overlayElement,solution,scrollContainer){if(this.env.isSmall){return;} 7255const shouldBeVisible=this.shouldOverlayBeVisible(overlayElement,solution,scrollContainer);overlayElement.style.visibility=shouldBeVisible?"visible":"hidden";this.overlayState.isOverlayVisible=shouldBeVisible;} 7256shouldOverlayBeVisible(overlayElement,solution,scrollContainer){if(!scrollContainer){return true;} 7257const scrollContainerRect=scrollContainer.getBoundingClientRect();let scrollContainerTop=scrollContainerRect.top;if(scrollContainer.ownerDocument!==overlayElement.ownerDocument){const frameElement=scrollContainer.ownerDocument.defaultView?.frameElement;if(frameElement){scrollContainerTop+=frameElement.getBoundingClientRect().top;}} 7258const 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;} 7259if(solution.direction==="top"&&canFlip){return true;} 7260return false;} 7261if(overflowsBottom){if(solution.direction==="bottom"&&canFlip){return true;} 7262return false;} 7263return true;}} 7264__exports.getScrollContainer=getScrollContainer;function getScrollContainer(el){const isScrollable=(el)=>{if(el.tagName==="HTML"){return el.scrollHeight>el.ownerDocument.defaultView.visualViewport.height;} 7265return(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;} 7266if(isFixed(el)){el=el.ownerDocument.defaultView.frameElement;continue;} 7267el=el.parentElement||el.ownerDocument.defaultView.frameElement;} 7268return null;} 7269return __exports;});; 7270 7271/* /html_editor/static/src/core/overlay_plugin.js */ 7272odoo.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");} 7273destroy(){super.destroy();for(const overlay of this.overlays){overlay.close();}} 7274createOverlay(Component,props={},options){const overlay=new Overlay(this,Component,props,options);this.overlays.push(overlay);return overlay;} 7275getCustomRect(){for(const cb of this.targetRectProviders){const rect=cb();if(rect){return rect;}}}} 7276const 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();} 7277open({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,};} 7278this._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,});}} 7279close(){this.isOpen=false;if(this._remove){this._remove();}} 7280isOverlayOpen(){return this.isOpen;} 7281updatePosition(){this.bus.trigger("updatePosition");}} 7282return __exports;});; 7283 7284/* /html_editor/static/src/core/protected_node_plugin.js */ 7285odoo.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=""]`;
7285const 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();} 7286filterDescendantsToRemove(elem){if(isProtecting(elem)){const descendantsToRemove=[];for(const candidate of elem.querySelectorAll(UNPROTECTED_SELECTOR)){if(candidate.closest(PROTECTED_SELECTOR)===elem){descendantsToRemove.push(...childNodes(candidate));}} 7287return descendantsToRemove;}} 7288protectNode(node){if(node.nodeType===Node.ELEMENT_NODE){if(node.matches(UNPROTECTED_SELECTOR)){this.unProtectDescendants(node);}else if(!this.protectedNodes.has(node)){this.protectDescendants(node);}} 7289this.protectedNodes.add(node);} 7290unProtectNode(node){if(node.nodeType===Node.ELEMENT_NODE){if(node.matches(PROTECTED_SELECTOR)){this.protectDescendants(node);}else if(this.protectedNodes.has(node)){this.unProtectDescendants(node);}} 7291this.protectedNodes.delete(node);} 7292protectDescendants(node){let child=node.firstChild;while(child){this.protectNode(child);child=child.nextSibling;}} 7293unProtectDescendants(node){let child=node.firstChild;while(child){this.unProtectNode(child);child=child.nextSibling;}} 7294beforeFilteringMutationRecords(records){for(const record of records){if(record.type==="childList"){if(record.target.nodeType!==Node.ELEMENT_NODE){return;} 7295const 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);}}}}} 7296isMutationRecordSavable(record){if(record.type==="childList"){return!((this.protectedNodes.has(record.target)&&!record.target.matches(UNPROTECTED_SELECTOR))||record.target.matches(PROTECTED_SELECTOR));} 7297return!this.protectedNodes.has(record.target);} 7298forEachProtectingElem(elem,callback){const selector=`[data-oe-protected]`;
7298const protectingNodes=[...elem.querySelectorAll(selector)].reverse();if(elem.matches(selector)){protectingNodes.push(elem);} 7299for(const protectingNode of protectingNodes){if(protectingNode.dataset.oeProtected==="false"){callback(protectingNode,false);}else{callback(protectingNode,true);}}} 7300normalize(elem){this.forEachProtectingElem(elem,this.setProtectingNode.bind(this));} 7301setProtectingNode(elem,protecting){elem.dataset.oeProtected=protecting;if(protecting){elem.setAttribute("contenteditable","false");this.protectDescendants(elem);}else{elem.setAttribute("contenteditable","true");this.unProtectDescendants(elem);}} 7302cleanForSave(clone){this.forEachProtectingElem(clone,(protectingNode)=>{protectingNode.removeAttribute("contenteditable");});}} 7303return __exports;});; 7304 7305/* /html_editor/static/src/core/sanitize_plugin.js */ 7306odoo.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");} 7307this.DOMPurify=DOMPurify(this.window);} 7308sanitize(elem){for(const cb of this.getResource("before_sanitize_processors")){elem=cb(elem);} 7309elem=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);} 7310return elem;} 7311normalize(element){for(const el of selectElements(element,".o-contenteditable-false, .o-contenteditable-true")){el.contentEditable=el.matches(".o-contenteditable-true");} 7312for(const el of selectElements(element,"[data-oe-role]")){el.setAttribute("role",el.dataset.oeRole);} 7313for(const el of selectElements(element,"[data-oe-aria-label]")){el.setAttribute("aria-label",el.dataset.oeAriaLabel);}} 7314cleanForSave({root}){for(const el of selectElements(root,".o-contenteditable-false, .o-contenteditable-true")){el.removeAttribute("contenteditable");} 7315for(const el of selectElements(root,"[data-oe-role]")){el.removeAttribute("role");} 7316for(const el of selectElements(root,"[data-oe-aria-label]")){el.removeAttribute("aria-label");}}} 7317return __exports;});; 7318 7319/* /html_editor/static/src/core/selection_plugin.js */ 7320odoo.define('@html_editor/core/selection_plugin',['@html_editor/utils/blocks','@html_editor/utils/dom_info','@html_editor/utils/dom_traversal','@web/core/h
7320otkeys/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";} 7321__exports.isNotAllowedContent=isNotAllowedContent;function isNotAllowedContent(node){return isArtificialVoidElement(node)||VOID_ELEMENT_NAMES.includes(node.nodeName);} 7322const isHtmlContentSupported=__exports.isHtmlContentSupported=weakMemoize((selection)=>
7322!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));} 7323function scrollToSelection(selection){const range=selection.getRangeAt(0);const container=closestScrollableY(range.startContainer.parentElement);if(!container){return;} 7324let rect=range.getBoundingClientRect();if(rect.width===0&&rect.height===0&&selection.isCollapsed){rect=closestElement(selection.anchorNode).getBoundingClientRect();} 7325const 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;} 7326if(rect.top<containerRect.top){container.scrollTo({top:offsetTop,behavior:"instant"});}else if(rect.bottom>containerRect.bottom){container.scrollTo({top:offsetBottom-container.clientHeight,behavior:"instant"});}} 7327const 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);} 7328if(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;} 7329const preventClosing=ev.target?.closest?.("[data-prevent-closing-overlay]");if(preventClosing?.dataset?.preventClosingOverlay==="true"){return;} 7330this.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});} 7331this.preservedCursors=[];this.editableOriginalFocus=this.editable.focus;this.editable.focus=()=>this.focusEditable();} 7332destroy(){if(this.editableOriginalFocus){this.editable.focus=this.editableOriginalFocus;} 7333super.destroy();} 7334getCachedSelection(){return this._cachedSelection;} 7335setCachedSelection(value){this._cachedSelection=value;} 7336selectAll(){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
7336sNode,focusOffset,})){return;} 7337this.setSelection({anchorNode,anchorOffset,focusNode,focusOffset});} 7338resetSelection(){this.activeSelection=this.makeActiveSelection();} 7339onDoubleClick(ev){const selectionData=this.getSelectionData();if(selectionData.documentSelectionIsInEditable){if(this.delegateTo("double_click_overrides",ev)){return;}}} 7340onTripleClick(ev){const selectionData=this.getSelectionData();if(selectionData.documentSelectionIsInEditable){if(this.delegateTo("triple_click_overrides",ev)){return;} 7341const{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;}} 7342updateActiveSelection(){if(this.getCachedSelection()){this.setCachedSelection(this.document.getSelection());} 7343this.previousActiveSelection=this.activeSelection;const selectionData=this.getSelectionData();if(this.fixSelectionOnEditableRoot(selectionData)){return;} 7344this.dispatchTo("selectionchange_handlers",selectionData);} 7345makeActiveSelection(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;} 7346const isSelectionUncorrectable=direction?anchorNode!==range.startContainer:anchorNode!==range.endContainer;if(this.activeSelection&&(isSelectionUncorrectable||isProtecting(anchorNode)||(isProtected(anchorNode)&&!isUnprotecting(anchorNode)))){return this.activeSelection;} 7347anchorOffset=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),};} 7348Object.freeze(activeSelection);return activeSelection;} 7349extractContent(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();} 7350createEditorSelection(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];} 7351range.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(),});}
7352getEditableSelection(){return this.getSelectionData().editableSelection;} 7353getSelectionData(){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;} 7354return 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();} 7355let{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);} 7356validateSelection({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;} 7357return true;};const validateOffset=(node,offset)=>{if(offset<0||offset>nodeSize(node)){console.warn("Invalid selection. Offset is out of bounds:",offset,node);return false;} 7358return true;};const isCollapsed=anchorNode===focusNode&&anchorOffset===focusOffset;return(validateNode(anchorNode)&&(focusNode===anchorNode||validateNode(focusNode))&&validateOffset(anchorNode,anchorOffset)&&(isCollapsed||validateOffset(focusNode,focusOffset)));} 7359setSelection({anchorNode,anchorOffset,focusNode=anchorNode,focusOffset=anchorOffset},{normalize=true}={}){if(!this.validateSelection({anchorNode,anchorOffset,focusNode,focusOffset})){return null;} 7360const 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);} 7361[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);}} 7362this.activeSelection=this.makeActiveSelection({anchorNode,anchorOffset,focu
7362sNode,focusOffset,getRangeAt:()=>range,rangeCount:1,});}} 7363restore();return this.activeSelection;} 7364preserveTextareaSelections(){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();} 7365for(const{textarea,start,end,direction}of selections){textarea.setSelectionRange(start,end,direction);}};} 7366setCursorStart(node){return this.setSelection({anchorNode:node,anchorOffset:0});} 7367setCursorEnd(node){return this.setSelection({anchorNode:node,anchorOffset:nodeSize(node)});} 7368preserveSelection(){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);} 7369if(!hadSelection){return;} 7370this.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;} 7371areNodeContentsFullySelected(node){const selection=this.getEditableSelection();if(selection.isCollapsed){return false;} 7372const 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);} 7373if(this.getResource("fully_selected_node_predicates")?.some((cb)=>cb(node,selection,range))){return true;} 7374const firstLeafNode=firstLeaf(node);const lastLeafNode=lastLeaf(node);return(range.isPointInRange(firstLeafNode,0)&&range.isPointInRange(lastLeafNode,nodeSize(lastLeafNode)));} 7375getTargetedNodes(){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];} 7376for(const node of descendants(root)){targetedNodes.push(node);} 7377if(!targetedNodes.length){targetedNodes=[root];} 7378targetedNodes=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);} 7379return targetedNodes;} 7380getTargetedBlocks(){return new Set(this.getTargetedNodes().map(closestBlock).filter(Boolean));} 7381fixSelectionOnEditableRoot(selectionData){const{editableSelection,documentSelectionIsInEditable}=selectionData;if(this.config.allowInlineAtRoot||!documentSelectionIsInEditable){return false;} 7382const isSelectionOnEditableRoot=(s)=>s.isCollapsed&&s.anchorNode===this.editable;if(!isSelectionOnEditableRoot(editableSelection)){return false;} 7383if(this.delegateTo("fix_selection_on_editable_root_overrides",editableSelection)){return true;} 7384if(isSelectionOnEditableRoot(this.previousActiveSelection)){return false;} 7385const selection=this.document.getSelection();if(!selection){return false;}
7386const{anchorNode,anchorOffset,focusNode,focusOffset}=this.previousActiveSelection;selection.setBaseAndExtent(anchorNode,anchorOffset,focusNode,focusOffset);return true;} 7387rectifySelection(selection){if(!this.isSelectionInEditable(selection)){return null;} 7388const 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;} 7389if(focusSize<focusOffset){focusOffset=focusSize;} 7390const 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;} 7391if(protectionCheck(anchorNode)||protectionCheck(focusNode)){return;} 7392return this.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});} 7393modifySelection(alter,direction,granularity){const selectionData=this.getSelectionData();if(!selectionData.documentSelectionIsInEditable){return selectionData.editableSelection;} 7394const selection=this.document.getSelection();if(!selection){return selectionData.editableSelection;} 7395selection.modify(alter,direction,granularity);if(!this.isSelectionInEditable(selection)){return this.setSelection(selectionData.editableSelection);} 7396this.activeSelection=this.makeActiveSelection(selection);return this.activeSelection;} 7397onKeyDownArrows(ev){const selection=this.document.getSelection();if(!selection||!this.isSelectionInEditable(selection)){return;} 7398const 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));}} 7399const{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);} 7400selection.extend(leafNode,offset);ev.preventDefault();}}} 7401isSelectionInEditable({anchorNode,focusNode}={}){return(!!anchorNode&&!!focusNode&&this.editable.contains(anchorNode)&&(focusNode===anchorNode||this.editable.contains(focusNode)));} 7402isNodeEditable(node){const results=this.getResource("is_node_editable_predicates").map((p)=>p(node)).filter((r)=>r!==undefined);if(!results.length){return node.parentElement?.isContentEditable;} 7403return results.every((r)=>r);} 7404focusEditable(){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);} 7405return;} 7406const{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});} 7407const closestNonEditable=closestElement(editableSelection.commonAncestorContainer,(el)=>!el.isContentEditable);if(closestNonEditable){this.setSelection(editableSelection,{normalize:false});} 7408if(!currentSelectionIsInEditable){const{anchorNode,anchorOffset,focu
7408sNode,focusOffset}=editableSelection;const selection=this.document.getSelection();if(selection){selection.setBaseAndExtent(anchorNode,anchorOffset,focusNode,focusOffset);}}} 7409selectAroundNonEditable(){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;} 7410let{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});}} 7411return __exports;});; 7412 7413/* /html_editor/static/src/core/shortcut_plugin.js */ 7414odoo.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");} 7415this.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});} 7416for(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,});} 7417this.shorthands=this.getResource("shorthands");} 7418destroy(){super.destroy();this.removeEditorCommandPalette();} 7419addShortcut(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)),}));} 7420onInput(ev){if(ev.data!==" "){return;} 7421const selection=this.dependencies.selection.getEditableSelection();if(!(this.checkPredicates("are_shorthands_available_predicates",selection.anchorNode)??true)){return;} 7422const 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;} 7423const 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);}}}} 7424return __exports;});; 7425 7426/* /html_editor/static/src/core/split_plugin.js */ 7427odoo.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)=>
7427node.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);}} 7428splitBlock(){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();} 7429return this.splitBlockNode({targetNode:selection.anchorNode,targetOffset:selection.anchorOffset,});} 7430splitBlockNode({targetNode,targetOffset}){if(targetNode.nodeType===Node.TEXT_NODE){targetOffset=splitTextNode(targetNode,targetOffset);targetNode=targetNode.parentElement;} 7431const blockToSplit=closestElement(targetNode,isBlock);const params={targetNode,targetOffset,blockToSplit};if(this.delegateTo("split_element_block_overrides",params)){return[undefined,undefined];} 7432return this.splitElementBlock(params);} 7433splitElementBlock({targetNode,targetOffset,blockToSplit}){if(this.isUnsplittable(blockToSplit)||findUpTo(targetNode,blockToSplit,(el)=>this.isUnsplittable(el))){this.dependencies.lineBreak.insertLineBreakElement({targetNode,targetOffset});return[undefined,undefined];} 7434const 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;} 7435fillEmpty(node);}};fillEmptyElement(lastLeaf(beforeElement));fillEmptyElement(firstLeaf(afterElement));this.dependencies.selection.setCursorStart(afterElement);return[beforeElement,afterElement];} 7436isUnsplittable(node){return this.getResource("unsplittable_node_predicates").some((p)=>p(node));} 7437splitElement(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);} 7438for(const node of children.slice(offset)){cursor.update(callbacksForCursorUpdate.append(secondPart,node));secondPart.appendChild(node);} 7439cursor.update(callbacksForCursorUpdate.remove(element));element.remove();this.dispatchTo("after_split_element_handlers",{firstPart,secondPart});cursor.restore();return[firstPart,secondPart];} 7440splitElementUntil(element,offset,limitAncestor){if(element===limitAncestor){return[element,element];} 7441let[before,after]=this.splitElement(element,offset);if(after.parentElement!==limitAncestor){const afterIndex=childNodeIndex(after);[before,after]=this.splitElementUntil(after.parentElement,afterIndex,limitAncestor);} 7442return[before,after];} 7443splitAroundUntil(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;} 7444let 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);} 7445while(after&&after.parentElement!==limitAncestor){afterSplit=this.splitElement(after.parentElement,childNodeIndex(after))[0];after=afterSplit.nextSibling;} 7446if(after){afterSplit=this.splitElement(limitAncestor,childNodeIndex(after))[0];limitAncestor=afterSplit;} 7447while(before&&before.parentElement!==limitAncestor){beforeSplit=this.splitElement(before.parentElement,childNodeIndex(before)+1)[1];before=beforeSplit.previousSibling;} 7448if(before){beforeSplit=this.splitElement(limitAncestor,childNodeIndex(before)+1)[1];} 7449return beforeSplit||afterSplit||limitAncestor;} 7450splitSelection(){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;} 7451endOffset=endContainer.textContent.length;} 7452if(isTextNode(startContainer)&&startOffset>0&&startOffset<nodeSize(startContainer)){splitTextNode(startContainer,startOffset);startOffset=0;if(isInSingleContainer){endOffset=startContainer.textContent.length;}} 7453const selection=direction===DIRECTIONS.RIGHT?{anchorNode:startContainer,anchorOffset:startOffset,focu
7453sNode:endContainer,focusOffset:endOffset,}:{anchorNode:endContainer,anchorOffset:endOffset,focusNode:startContainer,focusOffset:startOffset,};return this.dependencies.selection.setSelection(selection,{normalize:false});} 7454onBeforeInput(e){if(e.inputType==="insertParagraph"){e.preventDefault();if(this.forceLineBreak){this.forceLineBreak=false;this.dependencies.lineBreak.insertLineBreak();return;} 7455this.splitBlock();this.dependencies.history.addStep();}} 7456onKeyDown(e){this.forceLineBreak=e.key==="Enter"&&e.shiftKey;}} 7457return __exports;});; 7458 7459/* /html_editor/static/src/core/style_plugin.js */ 7460odoo.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;} 7461el.style["background-image"]=backgroundImagePartsToCss(parts);}} 7462return __exports;});; 7463 7464/* /html_editor/static/src/core/user_command_plugin.js */ 7465odoo.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}`);} 7466this.commands[command.id]=command;} 7467Object.freeze(this.commands);} 7468getCommand(commandId){const command=this.commands[commandId];if(!command){throw new Error(`Unknown user command id: ${commandId}`);} 7469return command;}} 7470return __exports;});; 7471 7472/* /html_editor/static/src/main/align/align_plugin.js */ 7473odoo.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
7473s.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);} 7474get 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";} 7475getTextAlignment(block){const{direction,textAlign}=getComputedStyle(block);if(textAlign==="start"){return direction==="rtl"?"right":"left";}else if(textAlign==="end"){return direction==="rtl"?"left":"right";} 7476return textAlign;} 7477getBlocksToAlign(){return this.dependencies.selection.getTargetedNodes().filter((node)=>isVisibleTextNode(node)||node.nodeName==="BR").map((node)=>closestBlock(node)).filter((block)=>block.isContentEditable);} 7478setAlignment(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");}} 7479visitedBlocks.add(block);}} 7480if(mode&&isAlignmentUpdated){this.dependencies.history.addStep();} 7481this.updateAlignmentParams();} 7482canSetAlignment(selection){return this.canSetAlignmentMemoized(selection);} 7483updateAlignmentParams(){this.alignment.displayName=this.alignmentMode;}} 7484return __exports;});; 7485 7486/* /html_editor/static/src/main/align/align_selector.js */ 7487odoo.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);} 7488onSelected(item){this.props.onSelected(item);}} 7489return __exports;});; 7490 7491/* /html_editor/static/src/main/banner_plugin.js */ 7492odoo.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));} 7493const 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})=>
7493!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);}});} 7494insertBanner(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);} 7495const baseContainerHtml=baseContainer.outerHTML;const emojiHtml=emoji?`<i class="o_editor_banner_icon mb-3 fst-normal" data-oe-aria-label="${htmlEscape( 7496 title 7497 )}">${emoji}</i>`:"";const bannerElement=parseHTML(this.document,`<div class="${containerClass}o_editor_banner user-select-none o-contenteditable-false ${ 7498 emoji ? "lh-1 " : "" 7499 }d-flex align-items-center alert alert-${alertClass} pb-0 pt-3 ps-3 pe-3" data-oe-role="status"> 7500 ${emojiHtml} 7501 <div class="${contentClass}o_editor_banner_content o-contenteditable-true w-100 px-3"> 7502 ${baseContainerHtml} 7503 </div> 7504 </div>`).childNodes[0];this.dependencies.dom.insert(bannerElement);this.dependencies.selection.setCursorEnd(bannerElement.querySelector(`.o_editor_banner_content > ${baseContainer.tagName}`));this.dependencies.history.addStep();} 7505onBannerEmojiChange(iconElement){this.dependencies.emoji.showEmojiPicker({target:iconElement,onSelect:(emoji)=>{iconElement.textContent=emoji;this.dependencies.history.addStep();},});} 7506handleDeleteBackward(range){const editorBannerContent=closestElement(range.endContainer,".o_editor_banner_content");if(!isEmptyBlock(editorBannerContent)){return;} 7507const bannerElement=closestElement(editorBannerContent,".o_editor_banner");const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);bannerElement.replaceWith(baseContainer);this.dependencies.selection.setCursorStart(baseContainer);return true;} 7508handle_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);}} 7509handleShiftTab(){const selection=this.dependencies.selection.getEditableSelection();const monospaceBannerElement=closestElement(selection.anchorNode,".font-monospace.o_editor_banner");if(!monospaceBannerElement){return;} 7510const 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,"");}}}}} 7511return __exports;});; 7512 7513/* /html_editor/static/src/main/chatgpt/chatgpt_dialog.js */ 7514odoo.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);} 7515const 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);} 7516lineIndex+=1;} 7517[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());} 7518selectMessage(ev){this.state.selectedMessageId=+ev.currentTarget.getAttribute("data-message-id");} 7519insertMessage(ev){this.selectMessage(ev);this._confirm();} 7520formatContent(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;} 7521return markup(result);} 7522generate(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));} 7523_cancel(){this.props.close();} 7524_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;}}} 7525return __exports;});; 7526 7527/* /html_editor/static/src/main/chatgpt/chatgpt_translate_dialog.js */ 7528odoo.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. \
7528n"+"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();} 7529async 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.";} 7530this.state.translationInProgress=false;if(!isError){this.state.conversationHistory.push({role:"user",content:query,},{role:"assistant",content,});} 7531this.state.messages.push({author:"assistant",text:translatedText,id:messageId,isError,});this.state.selectedMessageId=messageId;});}} 7532return __exports;});; 7533 7534/* /html_editor/static/src/main/chatgpt/chatgpt_translate_plugin.js */ 7535odoo.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;} 7536openDialog(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;} 7537let[endParent,endTop]=[end.offsetParent,end.offsetTop-end.scrollTop];while(endParent&&!endParent.contains(divContainer)){endTop+=endParent.offsetTop-endParent.scrollTop;endParent=endParent.offsetParent;} 7538const 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=`${ 7539 Math.max(start.offsetWidth, end.offsetWidth) + FRAME_PADDING * 2 7540 }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();});}}} 7541return __exports;});; 7542 7543/* /html_editor/static/src/main/chatgpt/language_selector.js */ 7544odoo.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);} 7545this.state.languages=res;});}});} 7546onSelected(language){this.props.onSelected(language);}} 7547return __exports;});; 7548 7549/* /html_editor/static/src/main/column_plugin.js */ 7550odoo.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;} 7551if(!root){return true;} 7552const closestColumnContainer=closestElement(node,"div.o_text_columns");return!root.contains(closestColumnContainer);} 7553function columnIsAvailable(numberOfColumns){return(selection)=>
7553{const row=closestElement(selection.anchorNode,".o_text_columns .row");return row?row.childElementCount!==numberOfColumns:closestBlock(selection.anchorNode)?.parentNode?.isContentEditable;};} 7554const 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-'], 7555 .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})=>
7555!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[];} 7556const anchorNode=selectionData.documentSelection.anchorNode;const columnContainer=closestElement(anchorNode,"div.o_text_columns");if(!columnContainer){return[];} 7557const 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));} 7558columnize(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;} 7559this.createColumns(anchor,numberOfColumns);} 7560if(!anchor.isConnected){cursors.remapNode(anchor,cursorFallbackNode);cursors.setOffset(cursorFallbackNode,nodeSize(cursorFallbackNode));} 7561cursors.restore();this.dependencies.history.addStep();} 7562createColumnsFromList(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);} 7563newList.prepend(nextLi);listBeforeBlock=newList.previousElementSibling;} 7564const{container,columns}=this.buildColumnsContainer(anchor,numberOfColumns);for(const column of columns){column.append(this.createEmptyParagraph());} 7565listBeforeBlock.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();} 7566removeColumns(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);}}} 7567if(!contents.length){contents.push(this.createEmptyParagraph());} 7568container.replaceWith(...contents);return contents;} 7569createColumns(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());} 7570this.dependencies.dom.insert(container);} 7571buildColumnsContainer(anchor,numberOfColumns){const container=this.document.createElement("div");if(!closestElement(anchor,".container")){container.classList.add("container");} 7572container.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);} 7573return{container,columns};} 7574createEmptyParagraph(){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(this.document.createElement("br"));return baseContainer;} 7575changeColumnsNumber(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;} 7576for(const column of columns){column.className=column.className.replace(REGEX_BOOTSTRAP_COLUMN,`$1col$2-${columnSize}`);} 7577if(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);} 7578column.remove();} 7579const targetColumn=columns[columns.length-1];targetColumn.append(...contents);return targetColumn;}}} 7580return __exports;});; 7581 7582/* /html_editor/static/src/main/emoji_plugin.js */ 7583odoo.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",});} 7584showEmojiPicker({target,onSelect}={}){this.overlay.open({props:{close:()=>{this.overlay.close();this.dependencies.selection.focusEditable();},onSelect:(str)=>{if(onSelect){onSelect(str);return;} 7585this.dependencies.dom.insert(str);this.dependencies.history.addStep();},},target,});}} 7586return __exports;});; 7587 7588/* /html_editor/static/src/main/feff_plugin.js */ 7589odoo.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");
7589const{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);}} 7590removeFeffs(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();}} 7591addFeff(element,position,cursors){const feff=this.document.createTextNode("\ufeff");cursors?.update(callbacksForCursorUpdate[position](element,feff));element[position](feff);return feff;} 7592surroundWithFeffs(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);} 7593return zwnbspNodes;} 7594padWithFeffs(root,cursors){const combinedSelector=this.getResource("selectors_for_feff_providers").map((provider)=>provider()).join(", ");if(!combinedSelector){return[];} 7595const 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;} 7596updateFeffs(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();} 7597getCursors(){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;} 7598processContentForClipboard(clonedContent){descendants(clonedContent).filter(isTextNode).filter((node)=>
7598node.textContent.includes("\ufeff")).forEach((node)=>(node.textContent=node.textContent.replace(/\ufeff/g,"")));return clonedContent;}} 7599function areCloseSiblings(a,b){let next=a.nextSibling;while(next&&isTextNode(next)&&!next.textContent){next=next.nextSibling;} 7600return next===b;} 7601return __exports;});; 7602 7603/* /html_editor/static/src/main/font/color_picker_gradient_tab.js */ 7604odoo.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;} 7605getCurrentGradientColor(){if(isColorGradient(this.props.selectedColor)){return this.props.selectedColor;}} 7606toggleGradientPicker(){this.state.showGradientPicker=!this.state.showGradientPicker;}} 7607registry.category("color_picker_tabs").add("html_editor.gradient",{id:"gradient",name:_t("Gradient"),component:ColorPickerGradientTab,},{sequence:60});return __exports;});; 7608 7609/* /html_editor/static/src/main/font/color_plugin.js */ 7610odoo.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);}}} 7611getElementColors(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);} 7612return{color:hasGradient&&hasTextGradientClass?gradient:normalizeCSSColor(elStyle.color),backgroundColor:hasGradient&&!hasTextGradientClass?gradient:normalizeCSSColor(backgroundColor),};} 7613removeAllColor(){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));
7613return hasAnyNodesColor(nodes,mode);};while(hasAnySelectedNodeColor(mode)&&max>0){this.applyColor("",mode);someColorWasRemoved=true;max--;} 7614if(max===0){someColorWasRemoved=false;throw new Error("Infinite Loop in removeAllColor().");}}}} 7615applyColor(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);}} 7616if(this.delegateTo("color_apply_overrides",color,mode,previewMode)){return;} 7617const 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();} 7618this.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));}} 7619const 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;} 7620if(!(this.checkPredicates("is_formattable_node_predicates",node)??true)){return false;} 7621if(mode==="backgroundColor"&&color){return!closestElement(node,"table.o_selected_table");} 7622if(closestElement(node).classList.contains("o_default_color")){return false;} 7623const 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;} 7624return 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;} 7625if(isIconElement(node)){return node;} 7626const 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);}} 7627font.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;} 7628const 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);
7628if(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;}} 7629if(node.nodeName==="BR"||node.textContent){font.appendChild(node);}else{fillEmpty(font);}}else{font=[];} 7630return font;});for(const fieldNode of targetedFieldNodes){this.colorElement(fieldNode,color,mode);} 7631let fonts=getFonts(selectedNodes);if(!fonts.every((font)=>font.isConnected)){fonts=getFonts(selectedNodes);} 7632const 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);}} 7633cursors.restore();} 7634colorElement(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);} 7635const hasGradientStyle=element.style.backgroundImage.includes("-gradient");if(mode==="backgroundColor"){if(!color){removeClass(element,"o_cc",...COLOR_COMBINATION_CLASSES);} 7636const hasGradient=getComputedStyle(element).backgroundImage.includes("-gradient");delete parts.gradient;let newBackgroundImage=backgroundImagePartsToCss(parts);if(hasGradient&&!newBackgroundImage){newBackgroundImage="none";} 7637if(newBackgroundImage){element.style.backgroundImage=newBackgroundImage;}else{removeStyle(element,"background-image");} 7638removeStyle(element,styleMode);if(!color&&!element.style.backgroundImage){const leftovers=[...element.style].filter((prop)=>prop.startsWith("background-")&&element.style.getPropertyValue(prop)==="initial");removeStyle(element,...leftovers);}} 7639const 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");} 7640this.applyColorStyle(element,"background-image",backgroundImagePartsToCss(parts));}else{delete parts.gradient;if(hasGradientStyle&&!backgroundImagePartsToCss(parts)){removeStyle(element,"background-image");} 7641if(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);}} 7642if(color.startsWith("o_cc")){parts=backgroundImageCssToParts(element.style["background-image"]);removeClass(element,...COLOR_COMBINATION_CLASSES);element.classList.add("o_cc",color);
7642const 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";}} 7643this.fixColorCombination(element,color);} 7644fixColorCombination(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);}} 7645getColorCombination(el,actionParam){for(const handler of this.getResource("color_combination_getters")){const value=handler(el,actionParam);if(value){return value;}}} 7646applyColorStyle(element,mode,color){if(this.delegateTo("apply_color_style_overrides",element,mode,color)){return;} 7647element.style[mode]=color;}} 7648function getColorCombinationFromClass(el){return el.className.match?.(COLOR_COMBINATION_CLASSES_REGEX)?.[0];} 7649function 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");}}} 7650return __exports;});; 7651 7652/* /html_editor/static/src/main/font/color_selector.js */ 7653odoo.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);} 7654getCorrespondingColorTab(color){if(!color||this.solidColors.includes(color.toUpperCase())){return"solid";}else if(isColorGradient(color)){return"gradient";}else{return"custom";}} 7655getSelectedColorStyle(){if(isColorGradient(this.state.selectedColor)){return`border-bottom: 2px solid transparent; border-image: ${this.state.selectedColor}; border-image-slice: 1`;} 7656return`border-bottom: 2px solid ${this.state.selectedColor}`;}} 7657return __exports;});; 7658 7659/* /html_editor/static/src/main/font/color_ui_plugin.js */ 7660odoo.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
7660d 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));} 7661getPropsForColorSelector(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));},};} 7662applyColorCommit({color,mode}){this.previewableApplyColor.commit(color,mode);this.updateSelectedColor();} 7663applyColorPreview({color,mode}){this.previewableApplyColor.preview(color,mode,true);this.updateSelectedColor();} 7664applyColorResetPreview(){this.previewableApplyColor.revert();this.updateSelectedColor();} 7665getUsedCustomColors(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]));}} 7666return usedCustomColors;} 7667computeBackgroundColorForTextNode(){const nodes=this.dependencies.selection.getTargetedNodes().filter(isTextNode);if(nodes.length===0){return;} 7668const el=closestElement(nodes[0]);if(!el){return;} 7669return this.dependencies.color.getElementColors(el).backgroundColor;} 7670updateSelectedColor(){let backgroundColor;for(const provider of this.getResource("selected_background_color_providers")){const providedBackgroundColor=provider();if(providedBackgroundColor){backgroundColor=providedBackgroundColor;break;}} 7671this.selectedColors.backgroundColor=backgroundColor||"#00000000";const nodes=this.dependencies.selection.getTargetedNodes().filter(isTextNode);if(nodes.length===0){this.selectedColors.color="";return;} 7672const el=closestElement(nodes[0]);if(!el){this.selectedColors.color="";return;} 7673this.selectedColors.color=this.dependencies.color.getElementColors(el).color;} 7674getActiveColorTabEl(){return document.querySelector(".o_font_color_selector .btn-tab.active");} 7675getBackgroundColorProcessor(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(", ")})`;}} 7676return backgroundColor;} 7677applyBackgroundColorProcessor(brackgroundColor){const activeTab=this.getActiveColorTabEl();if(activeTab?.classList.contains("solid-tab")&&brackgroundColor.startsWith("#")){brackgroundColor+=HEX_OPACITY;} 7678return brackgroundColor;}} 7679return __exports;});; 7680 7681/* /html_editor/static/src/main/font/font_family_plugin.js */ 7682odoo.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;} 7683const 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;}} 7684return __exports;});; 7685 7686/* /html_editor/static/src/main/font/font_family_selector.js */ 7687odoo.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);}} 7688return __exports;});; 7689 7690/* /html_editor/static/src/main/font/font_plugin.js */ 7691odoo.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,DEFAULT_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),],remove_all_formats_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,targetClassName)=>FONT_SIZE_CLASSES.includes(className)||className==="o_default_font_siz
7691e"||(DEFAULT_FONT_SIZE_CLASSES.includes(className)&&DEFAULT_FONT_SIZE_CLASSES.includes(targetClassName)),};setup(){this.fontSize=reactive({displayName:""});this.font=reactive({displayName:""});this.blockFormatIsAvailableMemoized=weakMemoize((selection)=>isHtmlContentSupported(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()));} 7692normalize(root){for(const el of selectElements(root,"strong, b, span[style*='font-weight: bolder'], small")){if(isRedundantElement(el)){unwrapContents(el);}}} 7693get 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");} 7694return(matchingItems.find((item)=>block.classList.contains(item.extraClass))||(matchingItemsWitoutExtraClass.length&&matchingItemsWitoutExtraClass[0])).name;} 7695get fontSizeName(){const sel=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!sel){return fontSizeItems[0].name;} 7696return Math.round(getFontSizeDisplayValue(sel,this.document));} 7697get fontSizeItems(){const style=getHtmlStyle(this.document);const nameAlreadyUsed=new Set();return fontSizeItems.flatMap((item)=>{const strValue=getCSSVariableValue(item.variableName,style);if(!strValue){return[];} 7698const remValue=parseFloat(strValue);const pxValue=convertNumericToUnit(remValue,"rem","px",style);const roundedValue=Math.round(pxValue);if(nameAlreadyUsed.has(roundedValue)){return[];} 7699nameAlreadyUsed.add(roundedValue);return[{...item,tagName:"span",name:roundedValue}];}).sort((a,b)=>a.name-b.name);} 7700blockFormatIsAvailable(selection){return this.blockFormatIsAvailableMemoized(selection);} 7701handleSplitBlockPRE({targetNode,targetOffset}){const closestPre=closestElement(targetNode,"pre");const closestBlockNode=closestBlock(targetNode);if(!closestPre||(closestBlockNode.nodeName!=="PRE"&&((closestBlockNode.textContent&&!isZWS(closestBlockNode))||closestBlockNode.nextSibling))){return;} 7702const 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);} 7703const dir=closestBlockNode.getAttribute("dir")||closestPre.getAttribute("dir");if(dir){baseContainer.setAttribute("dir",dir);} 7704this.dependencies.selection.setCursorStart(baseContainer);}else{const lineBreak=this.document.createElement("br");targetNode.insertBefore(lineBreak,targetNode.childNodes[targetOffset]);this.dependencies.selection.setCursorEnd(lineBreak);} 7705return true;} 7706handleSplitBlockquote({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);} 7707this.dependencies.selection.setSelection({anchorNode:closestBlockNode,anchorOffset:0,});return true;} 7708return;} 7709const 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;} 7710this.dependencies.lineBreak.insertLineBreakElement({targetNode,targetOffset});return true;} 7711handleSplitBlockHeading(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");
7711if(dir){baseContainer.setAttribute("dir",dir);} 7712newElement.replaceWith(baseContainer);baseContainer.replaceChildren(this.document.createElement("br"));this.dependencies.selection.setCursorStart(baseContainer);} 7713return true;}} 7714handleDeleteBackward({startContainer,startOffset,endContainer,endOffset}){const rangeIsCollapsed=startContainer===endContainer&&startOffset===endOffset;const closestHandledElement=closestElement(endContainer,handledElemSelector);if(!rangeIsCollapsed&&closestHandledElement?.tagName!=="BLOCKQUOTE"){return;} 7715if(!closestHandledElement||!isEmptyBlock(closestHandledElement)){return;} 7716if(this.getResource("unremovable_node_predicates").some((p)=>p(closestHandledElement))){return;} 7717const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.append(...closestHandledElement.childNodes);closestHandledElement.after(baseContainer);closestHandledElement.remove();this.dependencies.selection.setCursorStart(baseContainer);return true;} 7718updateFontSelectorParams(){this.font.displayName=this.fontName;} 7719updateFontSizeSelectorParams(){this.fontSize.displayName=this.fontSizeName;} 7720processContentForClipboard(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;} 7721if(!isBlock(ancestor)||isParagraphRelatedElement(ancestor)){const clone=ancestor.cloneNode();clone.append(...childNodes(clonedContents));clonedContents.appendChild(clone);}}} 7722return clonedContents;} 7723handleInsertWithinPre(insertContainer,block){if(block.nodeName!=="PRE"){return insertContainer;} 7724for(const cb of this.getResource("before_insert_within_pre_processors")){insertContainer=cb(insertContainer);} 7725const 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);} 7726if(node.nodeType===Node.ELEMENT_NODE){unwrapContents(node);} 7727for(const child of children){processNode(child);}};for(const node of childNodes(insertContainer)){processNode(node);} 7728return insertContainer;}} 7729return __exports;});; 7730 7731/* /html_editor/static/src/main/font/font_selector.js */ 7732odoo.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);} 7733onSelected(item){this.props.onSelected(item);}} 7734return __exports;});; 7735 7736/* /html_editor/static/src/main/font/font_size_selector.js */ 7737odoo.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);
7737this.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;} 7738this.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();} 7739iframeEl.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]);} 7740onCustomFontSizeInput(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;}} 7741this.fontSizeInput.focus();} 7742onKeyDownFontSizeInput(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;} 7743ev.target.blur();const fontSizeMenuItemToFocus=ev.key==="ArrowUp"?fontSizeSelectorMenu.lastElementChild:fontSizeSelectorMenu.firstElementChild;if(fontSizeMenuItemToFocus){fontSizeMenuItemToFocus.focus();}}} 7744onSelected(item){this.props.onSelected(item);}} 7745return __exports;});; 7746 7747/* /html_editor/static/src/main/font/gradient_picker/gradient_picker.js */ 7748odoo.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();} 7749onWillUpdateProps((newProps)=>
7749{if(newProps.selectedGradient){this.setGradientFromString(newProps.selectedGradient);}});} 7750setGradientFromString(gradient){if(!gradient||!isColorGradient(gradient)){return;} 7751gradient=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("%","")});} 7752const 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];} 7753this.updateCssGradients();} 7754selectType(type){this.state.type=type;this.onColorGradientChange();} 7755onAngleChange(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();}} 7756onPositionChange(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();}} 7757onColorChange(color){const hex=rgbaToHex(color.cssColor);this.colors[this.state.currentColorIndex].hex=hex;this.onColorGradientChange();} 7758onColorPreview(color){const hex=rgbaToHex(color.cssColor);this.colors[this.state.currentColorIndex].hex=hex;this.onColorGradientPreview();} 7759onSizeChange(size){this.state.size=size;this.onColorGradientChange();} 7760onColorPercentageChange(colorIndex,ev){this.state.currentColorIndex=colorIndex;this.colors[colorIndex].percentage=ev.target.value;this.sortColors();this.onColorGradientChange();} 7761onGradientPreviewClick(ev){const width=parseInt(window.getComputedStyle(ev.target).width,10);const percentage=Math.round((100*ev.offsetX)/width);this.addColorStop(percentage);} 7762addColorStop(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})`;} 7763this.colors.push({hex:color,percentage});this.sortColors();this.state.currentColorIndex=this.colors.findIndex((color)=>color.percentage===percentage);this.onColorGradientChange();} 7764removeColor(colorIndex){if(this.colors.length<=2){return;} 7765this.colors.splice(colorIndex,1);this.state.currentColorIndex=0;this.onColorGradientChange();} 7766sortColors(){this.colors=this.colors.sort((a,b)=>a.percentage-b.percentage);} 7767updateCssGradients(){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`;} 7768this.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;} 7769onColorGradientChange(){this.updateCssGradients();this.props?.onGradientChange(this.cssGradients[this.state.type]);} 7770onColorGradientPreview(){this.updateCssGradients();this.props.onGradientPreview?.({gradient:this.cssGradients[this.state.type]});} 7771get currentColorHex(){return this.colors?.[this.state.currentColorIndex]?.hex||"#000000";} 7772onKnobMouseDown(ev){const knobEl=this.knobRef.el;if(!knobEl){return;} 7773const knobRadius=knobEl.offsetWidth/2;
7773const 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});}} 7774return __exports;});; 7775 7776/* /html_editor/static/src/main/hint_plugin.js */ 7777odoo.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[];} 7778const 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);}} 7779destroy(){super.destroy();this.clearHints();} 7780normalize(){this.clearHints();this.updateHints();} 7781triggerDebouncedUpdateHints(selectionData=this.dependencies.selection.getSelectionData()){if(selectionData.documentSelectionIsInEditable){this.clearHints();} 7782this.debouncedUpdateHints();} 7783updateHints(){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);}}}}} 7784makeHint(el,text){this.dispatchTo("make_hint_handlers",el);el.setAttribute("o-we-hint-text",text);el.classList.add("o-we-hint");} 7785removeHint(el){el.removeAttribute("o-we-hint-text");removeClass(el,"o-we-hint");this.getResource("system_style_properties").forEach((n)=>el.style.removeProperty(n));} 7786clearHints(root=this.editable){for(const elem of selectElements(root,".o-we-hint")){this.removeHint(elem);}}} 7787return __exports;});; 7788 7789/* /html_editor/static/src/main/inline_code.js */ 7790odoo.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)=>
7790this.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));} 7791handleSelectionChange(){if(this.historySavePointRestore){delete this.historySavePointRestore;}} 7792onKeyDown(){const selection=this.dependencies.selection.getEditableSelection();if(selection.isCollapsed||closestElement(selection.anchorNode,"code")||closestElement(selection.focusNode,"code")){return;} 7793const targetBlocks=this.dependencies.selection.getTargetedBlocks();const hasTextNode=this.dependencies.selection.getTargetedNodes().some(isTextNode);if(targetBlocks.size===1&&hasTextNode){this.historySavePointRestore=this.dependencies.history.makeSavePoint();}} 7794onInput(ev){const selection=this.dependencies.selection.getEditableSelection();if(ev.data!=="`"||closestElement(selection.anchorNode,"code")){return;} 7795if(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,];} 7796const 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];}} 7797const 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);} 7798codeElement.appendChild(start);} 7799if(start===end){break;} 7800start=next;} 7801this.dispatchTo("to_inline_code_processors",codeElement);this.dependencies.selection.setSelection({anchorNode:codeElement,anchorOffset:nodeSize(codeElement),});this.dependencies.history.addStep();delete this.historySavePointRestore;return;} 7802let 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;} 7803sibling.textContent+=textNode.textContent;textNode.remove();textNode=sibling;sibling=sibling.previousSibling;} 7804sibling=textNode.nextSibling;while(sibling&&sibling.nodeType===Node.TEXT_NODE){if(!isZwnbsp(sibling)){textNode.textContent+=sibling.textContent;} 7805sibling.remove();sibling=sibling.nextSibling;} 7806this.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("`");} 7807if(endOffset&&endOffset<textNode.textContent.length){splitTextNode(textNode,endOffset+1,DIRECTIONS.LEFT);} 7808if(startOffset){splitTextNode(textNode,startOffset);} 7809const 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
7809orOffset: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,});}}} 7810normalize(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();}}}} 7811return __exports;});; 7812 7813/* /html_editor/static/src/main/link/command_category.js */ 7814odoo.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;});; 7815 7816/* /html_editor/static/src/main/link/link_paste_plugin.js */ 7817odoo.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,deduceURLfromText}=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);} 7818if(!splitAroundUrl||splitAroundUrl.length<3||closestElement(selection.anchorNode,"pre")){return false;} 7819if(splitAroundUrl.length===3&&!splitAroundUrl[0]&&!splitAroundUrl[2]){this.handlePasteTextUrl(selection,text);}else{this.handlePasteTextMultiUrl(selection,splitAroundUrl);} 7820return true;} 7821handlePasteTextUrl(selection,text){const selectionIsInsideALink=!!closestElement(selection.anchorNode,"a");const url=deduceURLfromText(text);if(selectionIsInsideALink){this.handlePasteTextUrlInsideLink(text,url);return;} 7822if(this.delegateTo("paste_url_overrides",text,url)){return;} 7823this.dependencies.link.insertLink(url,text);} 7824handlePasteTextUrlInsideLink(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);}} 7825handlePasteTextMultiUrl(selection,splitAroundUrl){const selectionIsInsideALink=!!closestElement(selection.anchorNode,"a");for(let i=0;i<splitAroundUrl.length;i++){if(i%2&&!selectionIsInsideALink){const url=deduceURLfromText(splitAroundUrl[i]);this.dependencies.dom.insert(this.dependencies.link.createLink(url,splitAroundUrl[i]));}else if(splitAroundUrl[i]!==""){this.dependencies.clipboard.pasteText(splitAroundUrl[i]);}}} 7826selectFullySelectedLink(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),});}}} 7827return __exports;});; 7828 7829/* /html_editor/static/src/main/link/link_plugin.js */ 7830odoo.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;} 7831if(linkElementAnchor||linkElementFocus){return true;} 7832return false;} 7833function isPositionAtEdgeofLink(link,offset){const childNodes=[...link.childNodes];if(!childNodes.length){return"end";}
7834let firstVisibleIndex=childNodes.findIndex(isVisible);firstVisibleIndex=firstVisibleIndex===-1?0:firstVisibleIndex;if(offset<=firstVisibleIndex){return"start";} 7835let lastVisibleIndex=childNodes.reverse().findIndex(isVisible);lastVisibleIndex=lastVisibleIndex===-1?0:childNodes.length-lastVisibleIndex;if(offset>=lastVisibleIndex){return"end";} 7836return false;} 7837async function fetchExternalMetaData(url){try{return await rpc("/html_editor/link_preview_external",{preview_url:url,});}catch{return;}} 7838async function fetchInternalMetaData(url){const keepLastPromise=new KeepLast();const urlParsed=new URL(url);if(urlParsed.protocol!==window.location.protocol){urlParsed.protocol=window.location.protocol;} 7839const 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;} 7840async 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"};}} 7841const 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)=>
7841{if(!isHtmlContentSupported(selection)){return false;} 7842for(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,});} 7843ev.preventDefault();}});this.addDomListener(this.editable,"pointerdown",(ev)=>{const clickedEl=this.document.elementFromPoint(ev.clientX,ev.clientY);if(!clickedEl||!isContentEditable(clickedEl)){return;} 7844let 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;} 7845const link=caretPosition?.offsetNode&&closestElement(caretPosition.offsetNode,"A");if(clickedEl.closest("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.closest("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);
7845this.getInternalMetaData=memoize(fetchInternalMetaData);this.getAttachmentMetadata=memoize((url)=>fetchAttachmentMetaData(url,this.services.orm));this.LinkPopoverState={editing:false};this.newlyInsertedLinks=new Set();} 7846destroy(){this.unregisterLinkCommandCallback?.();} 7847createLink(url,label=""){const link=this.document.createElement("a");if(url!==undefined){link.setAttribute("href",url);} 7848for(const[param,value]of Object.entries(this.config.defaultLinkAttributes||{})){link.setAttribute(param,`${value}`);} 7849link.innerText=label;this.dispatchTo("create_link_handlers",link);return link;} 7850insertLink(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);} 7851this.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});} 7852getPathAsUrlCommand(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;} 7853isLinkAllowedOnSelection(){const isLinkCompatible=this.checkPredicates("link_compatible_selection_predicates");if(isLinkCompatible!==undefined){return isLinkCompatible;} 7854const 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));} 7855openLinkTools(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"});} 7856let 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();} 7857this.linkInDocument=linkElement;if(!linkElement){linkElement=this.createLink(undefined,selection.textContent());} 7858const 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");} 7859if(relValue){this.linkInDocument.setAttribute("rel",relValue);}else{this.linkInDocument.removeAttribute("rel");} 7860if(linkTarget){this.linkInDocument.setAttribute("target",linkTarget);}else{this.linkInDocument.removeAttribute("target");} 7861if(!isImage){if(classes){this.linkInDocument.className=classes;}else{this.linkInDocument.removeAttribute("class");} 7862if(customStyle){this.linkInDocument.setAttribute("style",customStyle);}else{this.linkInDocument.removeAttribute("style");} 7863if(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);} 7864const 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);
7864if(commonAncestor!==anchorClosestElement){const[anchorNode,anchorOffset]=rightPos(anchorClosestElement);this.dependencies.selection.setSelection({anchorNode,anchorOffset},{normalize:false});} 7865this.dependencies.dom.insert(link);} 7866this.linkInDocument=link;}else if(label){const link=this.createLink(url,label);if(classes){link.className=classes;} 7867if(customStyle){link.setAttribute("style",customStyle);} 7868if(linkTarget){link.setAttribute("target",linkTarget);} 7869this.linkInDocument=link;cursorsToRestore=null;this.dependencies.dom.insert(link);}} 7870if(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();} 7871this.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;} 7872this.currentOverlay.open({props:popover.getProps(props)});if(this.linkInDocument){if(this.newlyInsertedLinks.has(this.linkInDocument)){this.newlyInsertedLinks.delete(this.linkInDocument);}}}} 7873closeLinkTools(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);} 7874if(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);}}}} 7875normalizeLink(root){for(const anchorEl of selectElements(root,"a")){if(/btn(-[a-z0-9_-]*)custom/.test(anchorEl.className)){continue;} 7876const{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;} 7877const newFont=this.document.createElement("font");newFont.append(...childNodes);anchorEl.appendChild(newFont);this.dependencies.color.colorElement(newFont,color,"color");} 7878const hasUnsupportedMedia=anchorEl.querySelector("a, iframe");
7878if(hasUnsupportedMedia){this.removeLinkInDocument(anchorEl);}}} 7879handleSelectionChange(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;} 7880this.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();}}} 7881extendLinkToSelection(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;} 7882let after=linkElement.nextSibling;while(after&&selectedNodes.includes(after)){linkElement.appendChild(after);after=linkElement.nextSibling;} 7883this.dependencies.selection.setCursorEnd(linkElement);} 7884isUnremovable(linkEl){return this.getResource("unremovable_node_predicates").some((p)=>p(linkEl));} 7885removeLinkInDocument(link=this.linkInDocument){if(!link.parentElement.isContentEditable||this.isUnremovable(link)){return;} 7886const cursors=this.dependencies.selection.preserveSelection();if(link&&link.isContentEditable&&link.parentElement.isContentEditable){cursors.update(callbacksForCursorUpdate.unwrap(link));unwrapContents(link);} 7887cursors.restore();this.linkInDocument=null;this.dependencies.selection.focusEditable();this.dependencies.history.addStep();} 7888removeLinkFromSelectionIsDisabled(selection){for(const node of this.dependencies.selection.getTargetedNodes()){const linkEl=closestElement(node,"a");if(linkEl&&!this.isLinkImmutable(linkEl)&&!this.isUnremovable(linkEl)){return false;}} 7889return true;} 7890removeLinkFromSelection(){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();} 7891if(endLink&&startLink!==endLink){cursors=this.dependencies.selection.preserveSelection();this.dependencies.feff.removeFeffs(endLink,cursors);cursors.restore();} 7892({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");
7892if(direction===DIRECTIONS.RIGHT){imageLink=this.dependencies.split.splitAroundUntil(figure||imageNode,endLink);}else{imageLink=this.dependencies.split.splitAroundUntil(figure||imageNode,startLink);} 7893cursors.update(callbacksForCursorUpdate.unwrap(imageLink));unwrapContents(imageLink);if(figure&&figure.parentElement!==this.editable){unwrapContents(figure.parentElement);} 7894[startLink,endLink]=[closestElement(anchorNode,"a"),closestElement(focusNode,"a"),];} 7895cursors.restore();if(selectedImageNodes.length===1&&selectedImageNodes.length===targetedNodes.length){this.dependencies.history.addStep();return;}} 7896const 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});} 7897if(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});} 7898targetedNodes=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);} 7899cursors.restore();} 7900if(startBlock){this.removeEmptyLinks(startBlock);} 7901if(endBlock&&endBlock!==startBlock){this.removeEmptyLinks(endBlock);} 7902this.dependencies.history.addStep();} 7903removeEmptyLinks(root){const remove=(node)=>{for(const child of node.childNodes){remove(child);} 7904if(!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;} 7905remove(link);}} 7906updateCurrentLinkSyncState(){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;}}} 7907onBeforeInputPrepareConvertToLink(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;}}} 7908onBeforeInputFixFirefoxSelection(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);} 7909this.updateCurrentLinkSyncState();} 7910onBeforeInputConvertToLink(ev){if(this.convertToLink){if(ev.inputType==="insertParagraph"||ev.inputType==="insertLineBreak"){this.convertToLink();this.dependencies.history.addStep();delete this.convertToLink;}}} 7911onInputConvertToLink(ev){if(this.convertToLink){if(ev.inputType==="insertText"&&ev.data===" "){this.convertToLink();this.dependencies.history.addStep();delete this.convertToLink;}}} 7912onInputDeleteNormalizeLink(){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();}}}} 7913onPasteNormalizeLink(){this.updateCurrentLinkSyncState();this.onInputDeleteNormalizeLink();} 7914deleteImageLink(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;} 7915return false;} 7916handleAutomaticLinkInsertion(){const convertToLink=this.prepareConvertToLink();if(convertToLink){return convertToLink();}} 7917prepareConvertToLink(){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();
7917mergeAdjacentTextNodes(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];} 7918const 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);} 7919return nodeForSelectionRestore;};}}} 7920handleSplitBlock(params){return this.handleEnterAtEdgeOfLink(params,this.dependencies.split.splitElementBlock);} 7921handleInsertLineBreak(params){return this.handleEnterAtEdgeOfLink(params,this.dependencies.lineBreak.insertLineBreakElement);} 7922handleEnterAtEdgeOfLink(params,splitOrLineBreakCallback){let{targetNode,targetOffset,blockToSplit}=params;if(targetNode.tagName!=="A"){return;} 7923const edge=isPositionAtEdgeofLink(targetNode,targetOffset);if(!edge){return;} 7924[targetNode,targetOffset]=edge==="start"?leftPos(targetNode):rightPos(targetNode);blockToSplit=targetNode;splitOrLineBreakCallback({...params,targetNode,targetOffset,blockToSplit});return true;} 7925handleDeleteBackward({startContainer,startOffset,endContainer,endOffset}){if(startContainer!==endContainer||startOffset!==0||endOffset!==1){return;} 7926if(startContainer.nodeType!==Node.TEXT_NODE||startContainer.textContent!="\uFEFF"){return;} 7927const previousSibling=startContainer.previousSibling;if(previousSibling?.nodeType!==Node.ELEMENT_NODE||!previousSibling.matches("a.btn")){return;} 7928this.dependencies.selection.setSelection({anchorNode:startContainer.previousSibling,anchorOffset:startContainer.previousSibling.childNodes.length-1,});return true;} 7929handleAfterInsert(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);}}}}} 7930initializePopovers(){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,}),});});} 7931getActivePopover(linkElement){return this.overlays.find((overlay)=>overlay.isAvailable(linkElement));} 7932isLinkImmutable(linkEl){return this.getResource("immutable_link_selectors").some((s)=>linkEl.matches(s));} 7933doubleClickLinkOverrides(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
7933sNode,focusOffset,});} 7934return true;}} 7935tripleClickButtonOverrides(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;}}} 7936return __exports;});; 7937 7938/* /html_editor/static/src/main/link/link_popover.js */ 7939odoo.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})`;} 7940if(color.match(/^\d{3}$/gm)){return`var(--${color})`;} 7941return color;};function useContentChange(el,callback){onMounted(()=>{el.addEventListener("keyup",callback);});onWillUnmount(()=>{el.removeEventListener("keyup",callback);});} 7942const 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",
7942isImage: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");} 7943this.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();} 7944const onPointerDown=(ev)=>{if(this.state.isImage){return;} 7945this.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);} 7946useContentChange(this.props.linkElement,()=>{this.state.urlTitle=this.props.linkElement.textContent;});} 7947toggleAdvancedOptions(){this.state.showAdvancedOptions=!this.state.showAdvancedOptions;} 7948toggleRelAttr(attr){const option=this.state.relAttributeOptions[attr];option.isChecked=!option.isChecked;} 7949discard(){this.props.onDiscard();this.cancelUpload?.();} 7950onChange(){this.props.onChange(this.state.url,this.state.label,this.classes,this.customStyles,this.state.linkTarget,this.state.attachmentId);this.updateDocumentState();} 7951onClickApply(){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);} 7952applyDeducedUrl(){if(this.state.label===""){this.state.label=this.state.url;} 7953this.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,"");}} 7954onClickEdit(){this.state.editing=true;this.props.onEdit();this.updateUrlAndLabel();} 7955updateUrlAndLabel(){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;} 7956async 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();} 7957onClickRemove(){this.props.onRemove();} 7958onKeydownEnter(ev){const isAutoCompleteDropdownOpen=document.querySelector(".o-autocomplete--dropdown-menu");if(ev.key==="Enter"&&!isAutoCompleteDropdownOpen&&this.state.url){ev.preventDefault();this.onClickApply();}} 7959onKeydown(ev){if(!this.editingWrapper?.el){return;} 7960if(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);
7960const nextIndex=(currentIndex+(ev.shiftKey?-1:1)+focusableElements.length)%focusableElements.length;focusableElements[nextIndex].focus();}} 7961onInput(){this.onChange();} 7962onClickReplaceTitle(){this.state.label=this.state.urlTitle;this.onClickApply();} 7963onClickDirectDownload(checked){this.state.directDownload=checked;this.state.url=this.state.url.replace("&download=true","");if(this.state.directDownload){this.state.url+="&download=true";}} 7964onClickNewWindow(checked){this.state.linkTarget=checked?"_blank":"";if(!checked){this.state.relAttributeOptions.noopener.isChecked=false;}} 7965onClickStripDomain(checked){this.state.stripDomain=checked;} 7966async 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;}} 7967getButtonShape(){const shapeToRegex=(shape)=>{const parts=shape.trim().split(/\s+/);const regexParts=parts.map((cls)=>{if(["outline","fill"].includes(cls)){cls=`btn-${cls}`;} 7968return`(?=.*\\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;} 7969const{regex,nbParts}=shapeToRegex(shape);if(regex.test(this.props.linkElement.className)){if(matchScore<nbParts){matchScore=nbParts;shapeMatched=shape;}}} 7970return shapeMatched;} 7971resetPreview(){this.state.previewIcon={type:"fa",value:"fa-globe"};this.state.urlTitle=this.state.url||_t("No URL specified");this.state.urlDescription="";this.state.linkPreviewName="";} 7972async loadAsyncLinkPreview(){let url;if(this.state.url===""){this.resetPreview();this.state.previewIcon.value="fa-question-circle-o";return;} 7973if(this.isLogoutUrl()){this.resetPreview();this.state.urlTitle=_t("Logout");this.state.previewIcon.value="fa-sign-out";return;} 7974if(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;} 7975try{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;} 7976this.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?.trim()||this.state.url;this.state.urlDescription=externalMetadata?.og_description?.trim()||"";this.state.imgSrc=externalMetadata?.og_image?.trim()||"";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);} 7977return{};});if(internalMetadata.favicon){this.state.previewIcon={type:"imgSrc",value:internalMetadata.favicon.href,};} 7978if(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: "+ 7979internalMetadata.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;} 7980if((internalMetadata.ogTitle||internalMetadata.title)&&!this.state.linkPreviewName){this.state.urlTitle=internalMetadata.ogTitle?internalMetadata.ogTitle.getAttribute("content"):internalMetadata.title.text.trim();}}} 7981get 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}`);} 7982if(this.state.buttonShape){const buttonShape=this.state.buttonShape.split(" ");if(["outline","fill"].includes(buttonShape[0])){stylePrefix=`${buttonShape[0]}-`;}
7983classes.push(buttonShape.slice(stylePrefix?1:0).join(" "));} 7984classes.push(`btn`,`btn-${stylePrefix}${this.state.type}`);} 7985const textColor=this.customTextColorState.selectedColor;if(isCSSVariable(textColor)){classes.push(`text-${textColor}`);} 7986const fillColor=this.customFillColorState.selectedColor;if(isCSSVariable(fillColor)){classes.push(`bg-${fillColor}`);} 7987return classes.filter(Boolean).join(" ");} 7988get customStyles(){if(!this.props.allowCustomStyle||this.state.type!=="custom"){return false;} 7989let customStyles="";const textColor=this.customTextColorState.selectedColor;if(!isCSSVariable(textColor)){customStyles+=`color: ${textColor}; `;} 7990const fillColor=this.customFillColorState.selectedColor;if(!isCSSVariable(fillColor)){const backgroundProperty=fillColor.includes("gradient")?"background-image":"background-color";customStyles+=`${backgroundProperty}: ${fillColor}; `;} 7991const borderColor=this.customBorderColorState.selectedColor;customStyles+=`border-width: ${this.state.customBorderSize}px; `;customStyles+=`border-color: ${formatColor(borderColor)}; `;customStyles+=`border-style: ${this.state.customBorderStyle}; `;return customStyles;} 7992async 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;} 7993this.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();} 7994isLogoutUrl(){return!!this.state.url.match(/\/web\/session\/logout\b/);} 7995isAttachmentUrl(){return!!this.state.url.match(/\/web\/content\/\d+/);} 7996isAbsoluteURLInCurrentDomain(){let hasProtocol;try{hasProtocol=!!new URL(this.state.url).protocol;}catch{hasProtocol=false;} 7997if(!hasProtocol){return false;} 7998const 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));}} 7999return __exports;});; 8000 8001/* /html_editor/static/src/main/link/link_selection_odoo_plugin.js */ 8002odoo.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"),};} 8003return __exports;});; 8004 8005/* /html_editor/static/src/main/link/link_selection_plugin.js */ 8006odoo.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));} 8007padLinkWithZwnbsp(link){const cursors=this.dependencies.selection.preserveSelection();this.dependencies.feff.surroundWithFeffs(link,cursors);
8007cursors.restore();} 8008isLinkEligibleForZwnbsp(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)));} 8009isLinkEligibleForVisualIndication(link){return(this.isLinkEligibleForZwnbsp(link)&&!this.getResource("ineligible_link_for_selection_indication_predicates").some((predicate)=>predicate(link)));} 8010resetLinkInSelection(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");}} 8011clearLinkInSelectionClass(root){for(const link of selectElements(root,".o_link_in_selection")){removeClass(link,"o_link_in_selection");}}} 8012return __exports;});; 8013 8014/* /html_editor/static/src/main/link/powerbox_url_paste_plugin.js */ 8015odoo.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;}}} 8016return __exports;});; 8017 8018/* /html_editor/static/src/main/link/utils.js */ 8019odoo.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( 8020 "|" 8021)})\\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,"");} 8022__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];} 8023match=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];}} 8024match=label.match(PHONE_REGEX);if(match){return(match[1]?match[0]:"tel:"+match[0]).replace(/\s+/g,"");} 8025return null;} 8026function correctLinkUrl(url){if(url&&!url.startsWith("tel:")&&!url.startsWith("mailto:")&&!url.includes("://")&&!url.startsWith("/")&&!url.startsWith("#")&&!url.startsWith("${")){url="https://"+url;} 8027if(url&&(url.startsWith("http:")||url.startsWith("https:"))){url=URL.parse(url)?url:"";} 8028return url;} 8029__exports.deduceLinkUrl=deduceLinkUrl;function deduceLinkUrl(text,link){text=text.trim();if(/^(https?:|mailto:|tel:)/.test(text)){return text;} 8030return deduceURLfromText(text,link)||"";} 8031__exports.normalizeLinkUrlInput=normalizeLinkUrlInput;function normalizeLinkUrlInput(text,link){return correctLinkUrl(deduceLinkUrl(text,link)||text);} 8032return __exports;});; 8033 8034/* /html_editor/static/src/main/list/list_plugin.js */ 8035odoo.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;} 8036const startLeaf=firstLeaf(nonListChildren[0]);const endLeaf=lastLeaf(nonListChildren[nonListChildren.length-1]);return(range.isPointInRange(startLeaf,0)&&range.isPointInRange(endLeaf,no
8036deSize(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);} 8037toggleListCommand({mode,listStyle}={}){this.toggleList(mode,listStyle);this.dependencies.history.addStep();} 8038getBlocksToToggleList(){const targetedBlocks=[...this.dependencies.selection.getTargetedBlocks()];return targetedBlocks.filter((block)=>!descendants(block).some((descendant)=>targetedBlocks.includes(descendant))&&block.isContentEditable&&!["OL","UL"].includes(block.tagName));} 8039canToggleList(selection){return this.canToggleListMemoized(selection);} 8040toggleList(mode,listStyle){if(!["UL","OL","CL"].includes(mode)){throw new Error(`Invalid list type: ${mode}`);} 8041if(mode==="CL"&&!!listStyle){throw new Error(`listStyle is not compatible with "CL" list type`);} 8042const 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);}} 8043if(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();} 8044for(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);}}} 8045normalize(root=this.editable){const closestNestedLI=closestElement(root,"li:has(ul, ol)");if(closestNestedLI&&closestNestedLI.closest("ul, ol")){root=closestNestedLI.parentElement;} 8046for(let element of selectElements(root,"ul, ol, li")){if(isProtected(element)||isProtecting(element)){continue;} 8047for(const fn of[this.liWithoutParentToP,this.mergeSimilarLists,this.normalizeLI,this.normalizeNestedList,]){const updatedElement=fn.call(this,element);if(updatedElement){element=updatedElement;}}} 8048for(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);}} 8049for(const el of selectElements(root,`:not(.${parentClass}) > .${floatClass}`)){el.parentElement.classList.add(parentClass);}}} 8050blockToList(element,mode){if(element.matches(baseContainerGlobalSelector)){return this.baseContainerToList(element,mode);} 8051if(element.matches("td, th, li.nav-item, blockquote")){return this.blockContentsToList(element,mode);} 8052let 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"));}} 8053this.adjustListPadding(list);cursors.restore();return list;} 8054baseContainerToList(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");} 8055this.dependencies.dom.copyAttributes(baseContainer,list);this.adjustListPadding(list);baseContainer.remove();
8055cursors.remapNode(baseContainer,list.firstChild).restore();return list;} 8056blockContentsToList(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;} 8057convertList(node,newMode){if(!["UL","OL","LI"].includes(node.tagName)){return;} 8058const listMode=this.getListMode(node);if(listMode&&newMode!==listMode){node=this.switchListMode(node,newMode);} 8059for(const child of node.children){this.convertList(child,newMode);} 8060return node;} 8061getListMode(listContainerEl){if(!["UL","OL"].includes(listContainerEl.tagName)){return;} 8062if(listContainerEl.tagName==="OL"){return"OL";} 8063return listContainerEl.classList.contains("o_checklist")?"CL":"UL";} 8064switchListMode(list,newMode){if(this.getListMode(list)===newMode){return;} 8065const 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");}} 8066removeClass(newList,"o_checklist");if(newMode==="CL"){newList.classList.add("o_checklist");} 8067this.adjustListPadding(newList);return newList;} 8068liToBlocks(li){while(li){li=this.outdentLI(li);}} 8069liWithoutParentToP(element){const isOrphan=element.nodeName==="LI"&&!element.closest("ul, ol");if(!isOrphan){return;} 8070const cursors=this.dependencies.selection.preserveSelection();wrapInlinesInBlocks(element,{baseContainerNodeName:this.dependencies.baseContainer.getDefaultNodeName(),cursors,});cursors.update(callbacksForCursorUpdate.unwrap(element));unwrapContents(element);cursors.restore();} 8071mergeSimilarLists(element){if(!element.matches("ul, ol, li.oe-nested")||(element.matches("li.oe-nested")&&!element.querySelector("ul, ol"))){return;} 8072const 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;}} 8073normalizeLI(element){if(!isListItem(element)){return;} 8074if(element.firstChild?.nodeType===Node.ELEMENT_NODE&&isListElement(element.firstChild)){element.classList.add("oe-nested");} 8075element.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();}} 8076normalizeNestedList(element){if(element.tagName==="LI"){return;} 8077if(["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");} 8078element.parentElement.insertBefore(li,element);li.appendChild(element);cursors.restore();}} 8079indentLI(li){const lip=li.previousElementSibling||this.document.createElement("li");if(!lip.hasChildNodes()){lip.classList.add("oe-nested");} 8080const 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);
8080if(cursor.offset===childIndex){[cursor.node,cursor.offset]=[ul,0];}else if(cursor.offset===childIndex+1){[cursor.node,cursor.offset]=[ul,1];}}});cursors.restore();} 8081outdentLI(li){const listToSplit=li.querySelector("ol, ul")||li.nextElementSibling;if(listToSplit){this.splitList(listToSplit);} 8082if(isListItem(li.parentNode.parentNode)){this.outdentNestedLI(li);return li;} 8083this.outdentTopLevelLI(li);return null;} 8084splitList(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);} 8085const moveFrom=isList?node.parentElement:node;while(moveFrom.nextSibling){cursors.update(callbacksForCursorUpdate.append(newList,moveFrom.nextSibling));newList.append(moveFrom.nextSibling);} 8086const moveTo=isList?wrapperLi:newList;cursors.update(callbacksForCursorUpdate.prepend(moveTo,node));moveTo.prepend(node);cursors.restore();this.adjustListPadding(currentList);this.adjustListPadding(newList);return newList;} 8087outdentNestedLI(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);} 8088if(!ul.children.length){cursors.update(callbacksForCursorUpdate.remove(ul));ul.remove();} 8089if(!lip.children.length&&lip.classList.contains("oe-nested")){cursors.update(callbacksForCursorUpdate.remove(lip));lip.remove();} 8090this.adjustListPadding(li.parentElement);cursors.restore();} 8091outdentTopLevelLI(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);} 8092if(isShrunkBlock(baseContainer)){baseContainer.append(this.document.createElement("br"));} 8093li.append(baseContainer);cursors.remapNode(li,baseContainer);} 8094const blocksToMove=childNodes(li);for(const block of blocksToMove.toReversed()){cursors.update(callbacksForCursorUpdate.after(ul,block));ul.after(block);} 8095const 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);} 8096if(textAlign&&!block.style.getPropertyValue("text-align")){block.style.setProperty("text-align",textAlign);} 8097if(liColorStyle){const font=wrapChildren(block,"font");this.dependencies.color.colorElement(font,liColorStyle.value,"color");} 8098if(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);}}} 8099cursors.update(callbacksForCursorUpdate.remove(li));li.remove();if(!ul.firstElementChild){cursors.update(callbacksForCursorUpdate.remove(ul));ul.remove();}else{this.adjustListPadding(ul);}
8100cursors.restore();} 8101indentListNodes(listNodes){for(const li of listNodes){this.indentLI(li);}} 8102outdentListNodes(listNodes){for(const li of listNodes){this.outdentLI(li);}} 8103separateListItems(){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);}} 8104return{listItems:[...listItems],navListItems:[...navListItems],nonListItems};} 8105processNodeToInsert({nodeToInsert,container}){if(isListItemElement(container)&&isParagraphRelatedElement(nodeToInsert)){nodeToInsert=this.dependencies.dom.setTagName(nodeToInsert,"LI");} 8106const listEl=container&&closestElement(container,listElementSelector);if(!listEl){return nodeToInsert;} 8107const mode=container&&this.getListMode(listEl);if(isListItemElement(nodeToInsert)&&nodeToInsert.querySelector("ol, ul")){return this.convertList(nodeToInsert,mode);} 8108if(isListElement(nodeToInsert)){return this.convertList(nodeToInsert,this.getListMode(nodeToInsert));} 8109return nodeToInsert;} 8110handleTab(){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;}} 8111const{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);} 8112this.dependencies.history.addStep();return true;}} 8113handleShiftTab(){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;}} 8114const{listItems,navListItems,nonListItems}=this.separateListItems();if(listItems.length||navListItems.length){this.outdentListNodes(listItems);this.dependencies.tabulation.outdentBlocks(nonListItems);this.dependencies.history.addStep();return true;}} 8115handleSplitBlock(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;} 8116if(isEmptyBlock(closestLI)){this.outdentLI(closestLI);return true;} 8117const[,newLI]=this.dependencies.split.splitElementBlock({...params,blockToSplit:closestLI,});if(newLI){if(closestLI.classList.contains("o_checked")){removeClass(newLI,"o_checked");} 8118const[anchorNode,anchorOffset]=getDeepestPosition(newLI,0);this.dependencies.selection.setSelection({anchorNode,anchorOffset});this.adjustListPadding(newLI.parentElement);} 8119return true;} 8120handleDeleteBackward(range){const{startContainer,startOffset,endContainer,endOffset}=range;const closestLIendContainer=closestElement(endContainer,"LI");if(!closestLIendContainer){return;} 8121const isCursorAtStartofLI=(startContainer===endContainer&&startOffset===endOffset)||closestElement(startContainer,"LI")!==closestLIendContainer;if(!isCursorAtStartofLI){return;} 8122let element=closestLIendContainer;while(["LI","UL","OL"].includes(element.tagName)){if(this.dependencies.split.isUnsplittable(element)){return;} 8123element=element.parentElement;} 8124if(!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");
8124if(dir){closestLIendContainer.setAttribute("dir",dir);} 8125this.liToBlocks(closestLIendContainer);} 8126return true;} 8127handleDeleteRange(range){const{startContainer,endContainer}=range;const startCheckedLi=closestElement(startContainer,"li.o_checked");if(!startCheckedLi){return;} 8128const endLi=closestElement(endContainer,"li");if(startCheckedLi===endLi){return;} 8129range=this.dependencies.delete.deleteRange(range);this.dependencies.selection.setSelection({anchorNode:range.startContainer,anchorOffset:range.startOffset,});if(isEmptyBlock(startCheckedLi)){removeClass(startCheckedLi,"o_checked");} 8130return true;} 8131processContentForClipboard(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));} 8132list.append(li);return(clonedContents=list);}} 8133if(clonedContents.firstChild.nodeName==="LI"){const list=selection.commonAncestorContainer.cloneNode();list.replaceChildren(...childNodes(clonedContents));clonedContents=list;} 8134return clonedContents;} 8135insertListWithinPre(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="* ";} 8136const prefix=" ".repeat(nestingLvl*4)+char;li.prepend(this.document.createTextNode(prefix));} 8137return node;} 8138onPointerdown(ev){const node=ev.target;const isChecklistItem=node.tagName=="LI"&&this.getListMode(node.parentElement)=="CL";if(!isChecklistItem){return;} 8139let 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;} 8140if(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});} 8141ev.preventDefault();this.dependencies.history.addStep();}} 8142handleTripleClick(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;}} 8143isPointerInsideCheckbox(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);} 8144applyColorToListItem(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;} 8145const 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");} 8146if(node.style.backgroundColor){removeStyle(node,"background-color");}} 8147if(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);
8147cursors.update(callbacksForCursorUpdate.append(font,node));}}} 8148cursors.restore();} 8149applyFormatToListItem(formatName,{formatProps,applyStyle}={}){if(!["setFontSizeClassName","fontSize"].includes(formatName)){return;} 8150this.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;} 8151const 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;} 8152removeEmptyTextNodes(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="";}} 8153if(applyStyle){if(formatName==="setFontSizeClassName"){listItem.classList.add(formatProps.className);}else if(formatName==="fontSize"){listItem.style.fontSize=formatProps.size;} 8154const 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));}} 8155listsSet.add(listItem.parentElement);} 8156cursors.restore();for(const list of listsSet){this.adjustListPadding(list);} 8157return true;} 8158adjustListPadding(list){if(!isListElement(list)||![...list.children].some(getFontSizeOrClass)){return;} 8159list.style.removeProperty("padding-inline-start");if(list.classList.contains("o_checklist")){return;} 8160const 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`;}} 8161adjustListPaddingOnDelete(){const selection=this.document.getSelection();if(!selection.isCollapsed||!selection.anchorNode){return;} 8162const listItem=closestElement(selection.anchorNode);if(isListItem(listItem)){this.adjustListPadding(listItem.parentElement);}} 8163updateToolbarButtons(){this.toolbarListSelectorKey.value++;} 8164getListSelectorButtons(){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,};});} 8165handleInsert(container,block){if(!this.config.allowChecklist){for(const list of container.querySelectorAll(".o_checklist > li")){this.liToBlocks(list);}} 8166return container;}} 8167return __exports;});; 8168 8169/* /html_editor/static/src/main/list/list_selector.js */ 8170odoo.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);} 8171getActiveMode(){const{editableSelection:selection}=this.props.getSelection();const closestLI=closestElement(selection.anchorNode,"LI");return closestLI&&this.props.getListMode(closestLI.parentNode);}} 8172return __exports;});; 8173 8174/* /html_editor/static/src/main/list/utils.js */ 8175odoo.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");} 8176return node;} 8177__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");
8177if(!firstClosestFont.hasAttributes()){unwrapContents(firstClosestFont);}} 8178const 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);} 8179unwrapContents(firstClosestSpan);}} 8180list.append(li);return list;} 8181__exports.compareListTypes=compareListTypes;function compareListTypes(a,b){if(!a||!b||a.tagName!==b.tagName){return false;} 8182if(a.classList.contains("o_checklist")!==b.classList.contains("o_checklist")){return false;} 8183if(a.tagName==="LI"){if(a.classList.contains("oe-nested")!==b.classList.contains("oe-nested")){return false;} 8184return compareListTypes(a.firstElementChild,b.firstElementChild);} 8185return true;} 8186__exports.isListItem=isListItem;function isListItem(node){return node.nodeName==="LI"&&!node.classList.contains("nav-item");} 8187return __exports;});; 8188 8189/* /html_editor/static/src/main/local_overlay_plugin.js */ 8190odoo.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();} 8191makeLocalOverlay(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);} 8192return container;} 8193destroy(){for(const container of this.localOverlays){container.remove();} 8194this.localOverlays.clear();super.destroy();}} 8195return __exports;});; 8196 8197/* /html_editor/static/src/main/media/dblclick_image_preview_plugin.js */ 8198odoo.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();}});}} 8199return __exports;});; 8200 8201/* /html_editor/static/src/main/media/file_plugin.js */ 8202odoo.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")
8202],},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);} 8203onClick(ev){const fileNameEl=closestElement(ev.target,".o_file_name_container .o_link_readonly");if(!fileNameEl||fileNameEl.isContentEditable){return;} 8204ev.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;} 8205if(anchorNode&&fileNameEl.contains(anchorNode)){this.dependencies.selection.setSelection({anchorNode,anchorOffset});}else{this.dependencies.selection.setCursorStart(fileNameEl);}} 8206onKeyDown(ev){const fileNameEl=closestElement(ev.target,".o_file_name_container .o_link_readonly");if(!fileNameEl){return;} 8207const 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();} 8208break;case"ArrowRight":if(selection.isCollapsed&&(isEmpty(fileNameEl)||(selection.anchorNode===lastLeafNode&&selection.anchorOffset===nodeSize(lastLeafNode)))){ev.preventDefault();} 8209break;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;}} 8210onPointerDown(ev){const activeElement=this.document.activeElement;const fileNameEl=closestElement(activeElement,".o_file_name_container .o_link_readonly");if(!fileNameEl||fileNameEl.contains(ev.target)){return;} 8211activeElement.setAttribute("contenteditable","false");} 8212get recordInfo(){return this.config.getRecordInfo?.()||{};} 8213isUploadCommandAvailable(){return this.config.allowFile;} 8214get componentForMediaDialog(){return DocumentSelector;} 8215async 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;} 8216if(this.config.onAttachmentChange){attachments.forEach(this.config.onAttachmentChange);} 8217const fileCards=attachments.map(this.renderDownloadBox.bind(this));fileCards.forEach(this.dependencies.dom.insert);this.dependencies.history.addStep();} 8218renderDownloadBox(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);}} 8219return __exports;});; 8220 8221/* /html_editor/static/src/main/media/icon_color_plugin.js */ 8222odoo.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
8222d Color"),Component:ColorSelector,props:this.dependencies.colorUi.getPropsForColorSelector("background"),isAvailable:isHtmlContentSupported,},],};} 8223return __exports;});; 8224 8225/* /html_editor/static/src/main/media/icon_plugin.js */ 8226odoo.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;} 8227const 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;} 8228if(isZwnbsp(node)&&isIconInTargetedNodes){return(node.nextElementSibling?.classList?.contains("fa")||node.previousElementSibling?.classList?.contains("fa"));} 8229if(isElement(node)&&node.children.length===1&&isIconElement(node.children[0])){return true;} 8230return 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));} 8231resizeIcon({size}){const targetedIcon=this.getTargetedIcon();if(!targetedIcon){return;} 8232for(const classString of targetedIcon.classList){if(classString.match(/^fa-[2-5]x$/)){targetedIcon.classList.remove(classString);}} 8233if(size!=="1"){targetedIcon.classList.add(`fa-${size}x`);} 8234this.dependencies.history.addStep();} 8235toggleSpinIcon(){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8236selectedIcon.classList.toggle("fa-spin");this.dependencies.history.addStep();} 8237hasIconSize(size){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8238if(size==="1"){return![...selectedIcon.classList].some((classString)=>classString.match(/^fa-[2-5]x$/));} 8239return selectedIcon.classList.contains(`fa-${size}x`);} 8240hasSpinIcon(){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8241return selectedIcon.classList.contains("fa-spin");} 8242openIconDialog(){const selectedIcon=this.getTargetedIcon();if(!selectedIcon){return;} 8243this.dependencies.dialog.addDialog(MediaDialog,{visibleTabs:["ICONS"],media:selectedIcon,save:(el)=>this.onSaveIcon(el,selectedIcon),});} 8244onSaveIcon(icon,prevIcon){for(const attribute of icon.attributes){prevIcon.setAttribute(attribute.no
8244deName,attribute.nodeValue);} 8245this.dependencies.history.addStep();} 8246computeBackgroundColorForIcon(){const nodes=this.dependencies.selection.getTargetedNodes().filter((node)=>node.classList?.contains("fa"));if(nodes.length===0){return;} 8247const el=closestElement(nodes[0],"font");if(!el){return;} 8248return this.dependencies.color.getElementColors(el).backgroundColor;}} 8249return __exports;});; 8250 8251/* /html_editor/static/src/main/media/image_crop.js */ 8252odoo.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");} 8253this.show();});onWillDestroy(this.closeCropper);} 8254closeCropper(){if(!this.isCropperActive&&!this.forceClose){return;} 8255this.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");} 8256this.props?.onClose?.();this.isCropperActive=false;} 8257async reset(){if(this.cropper){this.cropper.reset();if(this.aspectRatio!=="0/0"){this.aspectRatio="0/0";this.cropper.setAspectRatio(cropperAspectRatios[this.aspectRatio].value);} 8258await this.save();}} 8259async show(){if(this.isCropperActive){return;} 8260const 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;} 8261if(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();} 8262await this.scrollToInvisibleImage();await loadImage(this.originalSrc,this.media);if(status(this)!=="mounted"){return;} 8263const 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();
8263offset={top:rect.top,left:rect.left,};} 8264offset.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;} 8265this.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;} 8266this.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});} 8267async save(){const cropperData=this.getCropperData(this.cropper);this.props.onSave?.({aspectRatio:this.aspectRatio,...cropperData,});this.closeCropper();} 8268resetCropBox(){this.cropper.clear();this.cropper.crop();} 8269async 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}),});}} 8270onZoom(scale){this.cropper.zoom(scale);} 8271onReset(){this.cropper.reset();} 8272onRotate(degree){this.cropper.rotate(degree);} 8273onFlip(scaleDirection){const amount=this.cropper.getData()[scaleDirection]*-1;this.cropper[scaleDirection](amount);} 8274setAspectRatio(ratio){this.cropper.reset();this.aspectRatio=ratio;this.cropper.setAspectRatio(cropperAspectRatios[this.aspectRatio].value);} 8275onDocumentMousedown(ev){if(this.props.document.body.contains(ev.target)&&(this.elRef.el===ev.target||!this.elRef.el.contains(ev.target))){return this.closeCropper();}} 8276onDocumentKeydown(ev){if(!this.isCropperActive){return;} 8277if(ev.key==="Enter"){ev.preventDefault();ev.stopImmediatePropagation();if(ev.target===this.discardButtonRef.el){return this.closeCropper();} 8278return this.save();}else if(["Backspace","Escape"].includes(ev.key)){ev.preventDefault();ev.stopImmediatePropagation();return this.closeCropper();}} 8279getCropperData(cropper){return Object.fromEntries(cropperDataFieldsWithAspectRatio.map((field)=>[field,cropper.getData()[field]]).filter(([,value])=>value));} 8280async onCropZoom(){await new Promise((res)=>setTimeout(res,0));this.resetCropBox();}} 8281return __exports;});; 8282 8283/* /html_editor/static/src/main/media/image_crop_plugin.js */ 8284odoo.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");} 8285async openCropImage(targetedImg,imageCropProps={}){targetedImg=targetedImg||this.getTargetedImage();if(!targetedImg){return;} 8286return 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?.();},},});}} 8287return __exports;});; 8288 8289/* /html_editor/static/src/main/media/image_description.js */ 8290odoo.define('@html_editor/main/media/image_description',['@odoo/owl','@web/core/dialog/dialog','@html_editor/main/toolbar/toolbar','@web/core/h
8290otkeys/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";} 8291const 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());} 8292onSave(){this.props.onConfirm(this.state.description||"",this.state.tooltip||"");this.props.close();}} 8293return __exports;});; 8294 8295/* /html_editor/static/src/main/media/image_plugin.js */ 8296odoo.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);} 8297const 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,}
8297,],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",});} 8298destroy(){super.destroy();} 8299get imageSizeName(){const targetedImg=this.getTargetedImage();if(!targetedImg){return"Default";} 8300return targetedImg.style.width||"Default";} 8301setImagePadding({size}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8302for(const classString of targetedImg.classList){if(classString.match(/^p-[0-9]$/)){targetedImg.classList.remove(classString);}} 8303targetedImg.classList.add(`p-${size}`);this.dependencies.history.addStep();} 8304resizeImage({size}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8305targetedImg.style.width=size||"";this.dependencies.history.addStep();} 8306setImageShape(className,{excludeClasses=[]}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8307for(const classString of excludeClasses){if(targetedImg.classList.contains(classString)){targetedImg.classList.remove(classString);}} 8308targetedImg.classList.toggle(className);this.dependencies.history.addStep();} 8309previewImage(){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8310let 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);} 8311deleteImage(){const targetedImg=this.getTargetedImage();if(targetedImg){if(this.delegateTo("delete_image_overrides",targetedImg)){return;} 8312const cursors=this.dependencies.selection.preserveSelection();cursors.update(callbacksForCursorUpdate.remove(targetedImg));const blockEl=closestBlock(targetedImg.parentElement);targetedImg.remove();
8312cursors.restore();fillEmpty(blockEl);this.dependencies.history.addStep();}} 8313getTargetedImage(){const targetedNodes=this.dependencies.selection.getTargetedNodes();return targetedNodes.find((node)=>node.tagName==="IMG");} 8314hasImageSize(size){const targetedImg=this.getTargetedImage();return targetedImg?.style?.width===size;} 8315isSelectionShaped(shape){const targetedNodes=this.dependencies.selection.getTargetedNodes().filter((n)=>n.tagName==="IMG"&&n.classList.contains(shape));return targetedNodes.length>0;} 8316getImageAttribute(attributeName){const targetedNodes=this.dependencies.selection.getTargetedNodes();const targetedImg=targetedNodes.find((node)=>node.tagName==="IMG");return targetedImg.getAttribute(attributeName)||undefined;} 8317getCommandForImageUrlPaste(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();},};}} 8318updateImageDescription({description,tooltip}={}){const targetedImg=this.getTargetedImage();if(!targetedImg){return;} 8319targetedImg.setAttribute("alt",description);targetedImg.setAttribute("title",tooltip);this.dependencies.history.addStep();} 8320resetImageTransformation(image){const stylePropertiesToRemove=["transform","transform-box","transform-origin","transform-style","width","height",];for(const styleProperty of stylePropertiesToRemove){image.style.removeProperty(styleProperty);} 8321this.dependencies.history.addStep();} 8322getImageTransformProps(){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"),};} 8323updateImageParams(){this.imageSize.displayName=this.imageSizeName;} 8324openImageDescriptionPopover(){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});},},});}} 8325setSelectionAroundImage(img){const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesOut(img);this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});this.dependencies.selection.focusEditable();}} 8326return __exports;});; 8327 8328/* /html_editor/static/src/main/media/image_post_process_plugin.js */ 8329odoo.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));} 8330if(onImageInfoLoaded){if(await onImageInfoLoaded(newDataset)){return;}} 8331for(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);} 8332Object.assign(processContext,addedContext);}} 8333const 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};} 8334const 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;
8334j<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);} 8335const 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);} 8336ctx.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};} 8337async processImage(params){const processed=await this._processImage(params);if(!processed){return()=>{};} 8338return()=>this.updateImageAttributes(params.img,processed.url,processed.newDataset);} 8339async getProcessedImageSize(img){const processed=await this._processImage({img});return getDataURLBinarySize(processed.url);} 8340async 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;} 8341return[url,newDataset];} 8342updateImageAttributes(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);} 8343for(const key in newDataset){const value=newDataset[key];if(value){el.dataset[key]=value;}else{delete el.dataset[key];}} 8344this.dispatchTo("on_image_updated_handlers",{imageEl:el});}} 8345__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]);} 8346if(!("quality"in data)){data.quality=DEFAULT_IMAGE_QUALITY;} 8347data.aspectRatio=data.aspectRatio?getAspectRatio(data.aspectRatio):0;return data;} 8348function shouldTransformImage(data){return(data.perspective||data.glFilter||data.width||data.height||data.resizeWidth||data.aspectRatio);} 8349__exports.shouldPreventGifTransformation=shouldPreventGifTransformation;function shouldPreventGifTransformation(data){return isGif(data.mimetypeBeforeConversion)&&!shouldTransformImage(data);} 8350const 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;}
8351return!!(imgEl.dataset.originalSrc||(await loadImageInfo(imgEl)).originalSrc);} 8352const _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]);} 8353delete options.blend;delete options.filterColor;filters.push(...Object.entries(options).map(([filter,amount])=>[filter,parseInt(amount)/100]));applyAll(filter,filters);},};return __exports;});; 8354 8355/* /html_editor/static/src/main/media/image_save_plugin.js */ 8356odoo.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);} 8357return hasChange?oldSrcToNewSrcMap:undefined;} 8358createAttachment({el,imageData,resModel,resId}){return rpc("/html_editor/attachment/add_data",{name:el.dataset.f
8358ileName||"",data:imageData,is_image:true,res_model:resModel,res_id:resId,});} 8359async saveB64Image(el,resModel,resId){const imageData=el.getAttribute("src").split("base64,")[1];if(!imageData){el.classList.remove("o_b64_image_to_save");return;} 8360const attachment=await this.createAttachment({el,imageData,resId,resModel,});if(!attachment){return;} 8361if(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]);} 8362src+=`?access_token=${encodeURIComponent(accessToken)}`;} 8363el.setAttribute("src",src);} 8364el.classList.remove("o_b64_image_to_save");} 8365async 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],};
8365if(size!==originalSize){altData[size]["image/webp"]=canvas.toDataURL("image/webp").split(",")[1];}}} 8366let 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;} 8367el.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();} 8368targetEl.src=newAttachmentSrc;} 8369this.dispatchTo("on_image_saved_handlers",{imageEl:targetEl});} 8370getRecordInfo(editableEl=null){return this.config.getRecordInfo?this.config.getRecordInfo(editableEl):{};}} 8371return __exports;});; 8372 8373/* /html_editor/static/src/main/media/image_toolbar_dropdown.js */ 8374odoo.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());} 8375this.menuRef=useChildRef();useDropdownAutoVisibility(this.env.overlayState,this.menuRef);} 8376onSelected(item){this.props.onSelected(item);}} 8377return __exports;});; 8378 8379/* /html_editor/static/src/main/media/image_transform_button.js */ 8380odoo.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();} 8381pointerDownInsideTransform=false;},{capture:true});useExternalListener(document,"selectionchange",(ev)=>{closeImageTransformation();});function isNodeInsideTransform(node){if(!node){return false;} 8382if(node.nodeType===Node.TEXT_NODE){node=node.parentElement;} 8383if(node.matches(buttonSelector)){return true;} 8384if(isImageTransformationOpen()&&node.matches(".transfo-controls, .transfo-controls *")){return true;} 8385return false;} 8386function isImageTransformationOpen(){return registry.category("main_components").contains("ImageTransformation");} 8387return{isImageTransformationOpen};} 8388const 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"] *',});} 8389onButtonClick(){this.handleImageTransformation(this.props.getTargetedImage());} 8390handleImageTransformation(image){if(this.transform.isImageTransformationOpen()){this.props.resetImageTransformation(image);this.closeImageTransformation();}else{this.openImageTransformation(image);}} 8391openImageTransformation(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(),},});} 8392closeImageTransformation(){this.state.active=false;if(this.transform.isImageTransformationOpen()){registry.category("main_components").remove("ImageTransformation");}}} 8393return __exports;});; 8394 8395/* /html_editor/static/src/main/media/image_transformation.js */ 8396odoo.define('@html_editor/main/media/image_transformation',['@odoo/owl','@web/core/h
8396otkeys/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);} 8397useExternalListener(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();}});} 8398destroy(){this.props.onApply?.();this.props.destroy();} 8399mouseMove(ev){if(!this.transfo.active){return;} 8400ev.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;} 8401if(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;} 8402ang-=dang;if(!ev.ctrlKey){settings.angle=Math.round(ang/this.transfo.settings.rotationStep)*this.transfo.settings.rotationStep;}else{settings.angle=ang;} 8403this.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;} 8404if(this.transfo.active.type.indexOf("b")!=-1){newHeight=height+deltaY;} 8405if(this.transfo.active.type.indexOf("l")!=-1){newWidth=width-deltaX;} 8406if(this.transfo.active.type.indexOf("r")!=-1){newWidth=width+deltaX;} 8407if(newWidth<MIN_IMAGE_SIZE){newWidth=MIN_IMAGE_SIZE;} 8408if(newHeight<MIN_IMAGE_SIZE){newHeight=MIN_IMAGE_SIZE;} 8409if(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;}} 8410this.image.style.width=newWidth+"px";this.image.style.height="auto";settings.width=newWidth;} 8411settings.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();} 8412convertPixelWidthToPercentage(){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- 8413parseFloat(containerStyles.paddingLeft)- 8414parseFloat(containerStyles.paddingRight)- 8415parseFloat(containerStyles.borderLeftWidth)-
8416parseFloat(containerStyles.borderRightWidth)))*100;this.image.style.width=Math.min(100,widthPercent).toFixed(2)+"%";} 8417mouseUp(){if(!this.transfo.active){return;} 8418this.isCurrentlyTransforming=false;if(this.transfo.active.type.length===2){this.convertPixelWidthToPercentage();} 8419this.transfo.active=null;this.props.onApply?.();this.props.onChange?.();} 8420mouseDown(ev){if(this.transfo.active){return;} 8421this.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";} 8422const{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),};} 8423computeImageTransformations(){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;} 8424if(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;} 8425this.transfo.settings.css=window.getComputedStyle(this.image,null);this.transfo.settings.rotationStep=5;} 8426positionTransfoContainer(){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";} 8427setImageTransformation(element){let transform="";if(this.transfo.settings.angle!==0){transform+=" rotate("+this.transfo.settings.angle+"deg) ";} 8428if(this.transfo.settings.translatex){transform+=" translateX("+ 8429(this.transfo.settings.translate==="%"?this.transfo.settings.translatexp+"%":this.transfo.settings.translatex+"px")+") ";} 8430if(this.transfo.settings.translatey){transform+=" translateY("+ 8431(this.transfo.settings.translate==="%"?this.transfo.settings.translateyp+"%":this.transfo.settings.translatey+"px")+") ";} 8432element.style.transform=transform;} 8433normalizeCoordinates(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,};} 8434return{pageX:ev.pageX,pageY:ev.pageY};} 8435getOffset(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;}
8436return{top:rect.top+window.pageYOffset+offset.top,left:rect.left+window.pageXOffset+offset.left,};}} 8437resetHandlers(){this.computeImageTransformations();this.positionTransfoContainer();}} 8438return __exports;});; 8439 8440/* /html_editor/static/src/main/media/media_plugin.js */ 8441odoo.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( 8442 ", " 8443 )}, A, LI) > :is(${ICON_SELECTOR})`,};setup(){this.availableTabs=[...Object.values(TABS),...this.getResource("media_dialog_extra_tabs"),];} 8444getInsertMediaPowerboxItem(){const self=this;return{categoryId:"media",commandId:"insertMedia",get keywords(){return self.availableTabs.map((tab)=>tab.title);},};} 8445getRecordInfo(editableEl=null){return this.config.getRecordInfo?this.config.getRecordInfo(editableEl):{};} 8446isEditableMediaElement(node){if((isMediaElement(node)||node.nodeName==="IMG")&&(node.classList.contains(EDITABLE_MEDIA_CLASS)||isContentEditable(node))){return true;}} 8447replaceImage(){const targetedNodes=this.dependencies.selection.getTargetedNodes();const node=targetedNodes.find((node)=>node.tagName==="IMG");if(node){this.openMediaDialog({node});}} 8448normalizeMedia(node){const mediaElements=[...node.querySelectorAll(MEDIA_SELECTOR)];if(node.matches(MEDIA_SELECTOR)){mediaElements.push(node);} 8449for(const el of mediaElements){if(isProtected(el)||isProtecting(el)){continue;} 8450el.setAttribute("contenteditable",el.hasAttribute("contenteditable")?el.getAttribute("contenteditable"):"false");if(isIconElement(el)&&el.textContent!=="\u200B"){el.textContent="\u200B";}}} 8451clean(root){for(const el of root.querySelectorAll(MEDIA_SELECTOR)){if(isIconElement(el)){el.textContent="";}}} 8452cleanForSave(root){for(const el of root.querySelectorAll(MEDIA_SELECTOR)){if(isIconElement(el)){el.textContent="";} 8453el.removeAttribute("contenteditable");}} 8454async onSaveMediaDialog(element,{node}){if(!element){throw new Error("Element is required: onSaveMediaDialog");} 8455if(node){const changedIcon=isIconElement(node)&&isIconElement(element);if(changedIcon){for(const attribute of element.attributes){node.setAttribute(attribute.no
8455deName,attribute.nodeValue);} 8456element=node;}else{node.replaceWith(element);} 8457this.dispatchTo("on_replaced_media_handlers",{newMediaEl:element});}else{this.dependencies.dom.insert(element);this.dispatchTo("on_added_media_handlers",{newMediaEl:element});} 8458const[anchorNode,anchorOffset]=rightPos(element);this.dependencies.selection.setSelection({anchorNode,anchorOffset});this.dispatchTo("after_save_media_dialog_handlers",element);this.dependencies.history.addStep();} 8459openMediaDialog(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});} 8460return 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;} 8461selectAroundIcon({editableSelection}){if(!editableSelection.isCollapsed){return;} 8462const iconEl=closestElement(editableSelection.anchorNode,isIconElement);if(!iconEl){return;} 8463const[anchorNode,anchorOffset,focusNode,focusOffset]=boundariesOut(iconEl);const iconOuterBoundaries={anchorNode,anchorOffset,focusNode,focusOffset};this.dependencies.selection.setSelection(iconOuterBoundaries);} 8464getActiveDialogTab(searchTerm){if(!searchTerm){return undefined;} 8465const matchedTabs=fuzzyLookup(searchTerm,this.availableTabs,(tab)=>tab.title);if(!matchedTabs.length){return undefined;} 8466return matchedTabs[0].id;}} 8467return __exports;});; 8468 8469/* /html_editor/static/src/main/media/video_plugin.js */ 8470odoo.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;}} 8471return __exports;});; 8472 8473/* /html_editor/static/src/main/movenode_plugin.js */ 8474odoo.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:()=>
8474{if(this.currentMovableElement){this.setMovableElement(this.currentMovableElement);} 8475this.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;} 8476this.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,});} 8477destroy(){super.destroy();this.intersectionObserver.disconnect();this.mutationObserver.disconnect();this.smoothScrollOnDrag&&this.smoothScrollOnDrag.destroy();} 8478intersectionObserverCallback(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`;}}}} 8479updateHooks(){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;
8479this.editableRect.x=this.editableRect.x+paddingLeft-(WIDGET_CONTAINER_WIDTH+5);this.editableRect.width=this.editableRect.width-paddingLeft+(WIDGET_CONTAINER_WIDTH+5);} 8480const 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);} 8481hookElement.style.zIndex=index;} 8482for(const element of elementsToGarbageCollect){this.visibleMovableElements.delete(element);this.elementHookMap.get(element).remove();this.intersectionObserver.unobserve(element);this.elementHookMap.delete(element);} 8483const 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);} 8484hookElement.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`;}} 8485_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);}} 8486getMovableElements(){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);}} 8487return elems;} 8488getDroppableElements(draggableNode){return this.getMovableElements().filter((node)=>!closestElement(node.parentElement,(n)=>n===draggableNode));} 8489setMovableElement(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;} 8490this.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;} 8491this.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` 8492 <div class="o-tooltip tooltip-inner text-start px-3"> 8493 ${escape(dragToMoveTooltip)}<br/> 8494 ${escape(clickToSelectTooltip)} 8495 </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
8495sNode,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);} 8496container.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;},});}} 8497removeMoveWidget(){this.dispatchTo("unset_movable_element_handlers");this.moveWidget?.remove();this.moveWidget=undefined;this.currentMovableElement=undefined;} 8498startDropzones(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;} 8499this._currentDropHintElementPosition=null;};dropzoneBox.addEventListener("mouseleave",removeDropHint);dropzoneBox.addEventListener("pointerleave",removeDropHint);} 8500this.dropzonesContainer.append(dropzoneBox);this.dropzoneHintContainer.append(dropzoneHintBox);}} 8501_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;} 8502if(position==="top"){focusElelement.before(movableElement);}else if(position==="bottom"){focusElelement.after(movableElement);} 8503if(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);}} 8504const isSelectionInsideMovedNode=movableElement.contains(cursors.anchor.node)&&movableElement.contains(cursors.focus.node);
8504if(isSelectionInsideMovedNode){cursors.restore();}else{const selectionPosition=getDeepestPosition(movableElement,0);this.dependencies.selection.setSelection({anchorNode:selectionPosition[0],anchorOffset:selectionPosition[1],});} 8505this.dependencies.selection.focusEditable();this.dependencies.history.addStep();}} 8506onMousemove(e){this._updateAnchorWidgets(e.target);} 8507onDocumentKeydown(){this.removeMoveWidget();} 8508onDocumentMousemove(e){if(this.resetHooksNextMousemove){this.resetHooksNextMousemove=false;this.removeMoveWidget();this.updateHooks();} 8509const 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();}} 8510isNodeMovable(node){const blacklistSelectors=this.getResource("move_node_blacklist_selectors").join(", ");if(blacklistSelectors&&node.matches(blacklistSelectors)){return false;} 8511return(node.parentElement?.getAttribute("contentEditable")==="true"||(node.tagName==="LI"&&node.parentElement.isContentEditable));}} 8512function isPointInside(rect,x,y){return rect.left<=x&&rect.right>=x&&rect.top<=y&&rect.bottom>=y;} 8513const 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="";} 8514return ctx.current;},};return __exports;});; 8515 8516/* /html_editor/static/src/main/placeholder_plugin.js */ 8517odoo.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[];}},}),};} 8518return __exports;});; 8519 8520/* /html_editor/static/src/main/position_plugin.js */ 8521odoo.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);} 8522const 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);}} 8523handlePotentialLayoutGeometryChange(records){for(const record of records){if(record.type==="classList"||(record.type==="attributes"&&record.attributeName==="style")){this.debouncedLayoutGeometryChange();return;}}} 8524destroy(){this.resizeObserver.disconnect();super.destroy();} 8525layoutGeometryChange(){this.dispatchTo("layout_geometry_change_handlers");}} 8526return __exports;});; 8527 8528/* /html_editor/static/src/main/power_buttons_plugin.js */ 8529odoo.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);}} 8530createPowerButtons(){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)=>
8530[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);} 8531btn.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);} 8532triggerDebouncedUpdatePowerButtons(){this.powerButtonsContainer.classList.add("invisible");this.debouncedUpdatePowerButtons();} 8533updatePowerButtons(){this.powerButtonsContainer.classList.add("invisible");const{documentSelection,editableSelection,currentSelectionIsInEditable}=this.dependencies.selection.getSelectionData();if(!currentSelectionIsInEditable){return;} 8534const 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);} 8535this.setPowerButtonsPosition(block,blockRect,direction);this.powerButtonsContainer.classList.remove("invisible");this.powerButtonsContainer.setAttribute("dir",direction);}} 8536getPlaceholderWidth(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;} 8537setPowerButtonsPosition(block,blockRect,direction){const overlayRect=this.powerButtonsOverlay.getBoundingClientRect();let referenceRect={top:0,left:0};let frameElement;try{frameElement=this.document.defaultView.frameElement;}catch{} 8538if(frameElement){referenceRect=frameElement.getBoundingClientRect();} 8539const 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- 8540(overlayRect.left-referenceRect.left)- 8541placeholderWidth- 854230;} 8543this.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"));}} 8544this.powerButtonsContainer.style.left=newButtonContainerLeft+"px";this.powerButtonsContainer.style.top=blockRect.top-(overlayRect.top-referenceRect.top)+"px";} 8545async applyCommand(commandFn){const btns=[...this.powerButtonsContainer.querySelectorAll(".btn")];btns.forEach((btn)=>btn.classList.add("disabled"));await commandFn();btns.forEach((btn)=>btn.classList.remove("disabled"));}} 8546return __exports;});; 8547 8548/* /html_editor/static/src/main/powerbox/powerbox.js */ 8549odoo.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,};
8549setup(){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]);} 8550get commands(){return this.props.state.commands;} 8551get currentIndex(){return this.props.state.currentIndex;} 8552get showCategories(){return this.props.state.showCategories;} 8553onScroll(){this.mouseSelectionActive=false;} 8554onMouseEnter(index){if(this.mouseSelectionActive){this.props.activateCommand(index);}}} 8555return __exports;});; 8556 8557/* /html_editor/static/src/main/powerbox/powerbox_plugin.js */ 8558odoo.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,});} 8559getAvailablePowerboxCommands(){const selection=this.dependencies.selection.getEditableSelection();const blacklistSelector=this.getResource("powerbox_blacklist_selectors").join(", ");if(blacklistSelector&&closestElement(selection.anchorNode).matches(blacklistSelector)){return[];} 8560return this.powerboxCommands.filter((cmd)=>cmd.isAvailable(selection));} 8561makePowerboxCommands(){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)),};});} 8562openPowerbox({commands,categories,onApplyCommand=()=>{},onClose=()=>{}}={}){this.closePowerbox();if(!commands.length){return;} 8563this.onApplyCommand=onApplyCommand;this.onClose=onClose;this.updatePowerbox(commands,categories);} 8564updatePowerbox(commands,categories){if(categories){const orderCommands=[];for(const category of categories){orderCommands.push(...commands.filter((command)=>command.categoryId===category.id));} 8565commands=orderCommands;} 8566Object.assign(this.state,{showCategories:!!categories,commands,currentIndex:0,});this.overlay.open({props:this.overlayProps});} 8567closePowerbox(){if(!this.overlay.isOpen){return;} 8568this.onClose();this.overlay.close();} 8569onKeyDown(ev){if(!this.overlay.isOpen){return;} 8570const 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;} 8571case"ArrowDown":{ev.preventDefault();ev.stopImmediatePropagation();this.state.currentIndex=rotate(this.state.currentIndex,this.state.commands,1);break;} 8572case"ArrowLeft":case"ArrowRight":{this.closePowerbox();break;}}} 8573applyCommand(command){const context={};this.onApplyCommand(command,context);command.run(context);this.closePowerbox();}} 8574return __exports;});; 8575 8576/* /html_editor/static/src/main/powerbox/search_powerbox_plugin.js */ 8577odoo.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}`);} 8578categoryIds.add(category.id);} 8579this.categories=this.getResource("powerbox_categories");this.shouldUpdate=false;this.addDomListener(this.editable,"pointerdown",()=>{if(this.powerButtonAnchorEl){this.powerButtonAnchorEl=false;}});} 8580onBeforeInput(ev){if(ev.data==="/"){this.historySavePointRestore=this.dependencies.history.makeSavePoint();}} 8581onInput(ev){this.searchTerm=undefined;if(ev.data==="/"){this.openSearchPowerbox();}else{this.update();}} 8582update(){if(!this.shouldUpdate){return;} 8583const selection=this.dependencies.selection.getEditableSelection();this.searchNode=selection.startContainer;if(!this.isSearching(selection)){this.dependencies.powerbox.closePowerbox();return;} 8584const searchTerm=this.searchNode.nodeValue?.slice(this.offset+1,selection.endOffset);if(!searchTerm){this.dependencies.powerbox.updatePowerbox(this.enabledCommands,this.categories);return;} 8585if(searchTerm.includes(" ")){this.dependencies.powerbox.closePowerbox();return;} 8586const commands=this.filterCommands(searchTerm);if(!commands.length){this.dependencies.powerbox.closePowerbox();this.shouldUpdate=true;return;} 8587this.searchTerm=searchTerm;this.dependencies.powerbox.updatePowerbox(commands);} 8588filterCommands(searchTerm){return fuzzyLookup(searchTerm,this.enabledCommands,(cmd)=>[cmd.title,cmd.categoryName,cmd.description,...(cmd.keywords||[]),]);} 8589isSearching(selection){return(this.powerButtonAnchorEl===closestElement(this.searchNode)||(selection.endContainer===this.searchNode&&this.searchNode.nodeValue&&this.searchNode.nodeValue[this.offset]==="/"&&selection.endOffset>=this.offset));} 8590openSearchPowerbox(){const selection=this.dependencies.selection.getEditableSelection();if(!(this.checkPredicates("is_powerbox_available_predicates",selection.anchorNode)??true)){return;} 8591this.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;} 8592openPowerbox(){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;}} 8593return __exports;});; 8594 8595/* /html_editor/static/src/main/selection_placeholder_plugin.js */ 8596odoo.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";
8596const 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})=>
8596!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,});} 8597updatePlaceholders(){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);}}} 8598const 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,});}}} 8599for(const{placeholder,siblings}of pendingMarginUpdates){const update=this.prepareMarginUpdate(placeholder,...siblings);if(update){marginUpdates.push(update);}} 8600for(const update of marginUpdates){update();} 8601this.resetBlinkerClasses();} 8602prepareMarginUpdate(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`);}} 8603persistPlaceholder(placeholder){placeholder.removeAttribute(PLACEHOLDER_ATTRIBUTE);this.cleanBlinker(placeholder);placeholder.removeAttribute("style");} 8604cleanBlinker(blinker){if(blinker.className===BLINKER_CLASS){blinker.removeAttribute("class");}else{blinker.classList.remove(BLINKER_CLASS);}} 8605resetBlinkerClasses(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);} 8606for(const blinker of this.editable.querySelectorAll(`.${BLINKER_CLASS}`)){if(blinker!==anchorPlaceholder||!this.document.activeElement.contains(blinker)){this.cleanBlinker(blinker);}}} 8607onSelectionChange(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();}}}}} 8608const 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) 8609[side==="top"?"marginTop":"marginBottom"].replace("px","");return __exports;});; 8610 8611/* /html_editor/static/src/main/separator_plugin.js */ 8612odoo.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
8612ywords:[_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);}} 8613this.dependencies.history.addStep();} 8614deselectHR(root=this.editable){for(const hr of root.querySelectorAll(".o_selected_hr")){removeClass(hr,"o_selected_hr");}} 8615handleSelectionInHr(selectionData){this.deselectHR();if(!selectionData.documentSelectionIsInEditable){return;} 8616const targetedNodes=this.dependencies.selection.getTargetedNodes();for(const node of targetedNodes){if(node.nodeName==="HR"){node.classList.toggle("o_selected_hr",true);}}}} 8617return __exports;});; 8618 8619/* /html_editor/static/src/main/star_plugin.js */ 8620odoo.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);} 8621onMouseDown(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);} 8622for(const star of nextStars){star.classList.toggle("fa-star-o",true);star.classList.toggle("fa-star",false);} 8623this.dependencies.history.addStep();} 8624ev.stopPropagation();ev.preventDefault();}} 8625addStars({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();}} 8626return __exports;});; 8627 8628/* /html_editor/static/src/main/table/table_align_plugin.js */ 8629odoo.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:""});} 8630get currentVerticalAlign(){const targetedCells=this.dependencies.selection.getTargetedNodes().map((node)=>
8630closestElement(node,"td, th")).filter(Boolean);if(!targetedCells.length){return"";} 8631const verticalAlign=targetedCells[0].style.verticalAlign;return verticalAlign&&targetedCells.every((cell)=>cell.style.verticalAlign===verticalAlign)?verticalAlign:"";} 8632setVerticalAlignment(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;}} 8633if(isAlignmentUpdated){this.dependencies.history.addStep();} 8634this.updateVerticalAlignParams();} 8635updateVerticalAlignParams(){this.verticalAlignMode.displayName=this.currentVerticalAlign;}} 8636return __exports;});; 8637 8638/* /html_editor/static/src/main/table/table_align_selector.js */ 8639odoo.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);} 8640onSelected(item){this.props.onSelected(item);}} 8641return __exports;});; 8642 8643/* /html_editor/static/src/main/table/table_menu.js */ 8644odoo.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";} 8645this.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();}});}} 8646get hasCustomTableSize(){const table=closestElement(this.props.target,"table");if(!table){return false;} 8647const rows=[...table.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;} 8648get hasCustomRowHeight(){return!!this.props.target.closest("tr").style.height;} 8649get hasCustomColumnWidth(){return(!!this.props.target.closest("td")?.style?.width||!!this.props.target.closest("th")?.style?.width);} 8650updatePosition(){const{target,type,direction}=this.props;if(!this.overlayEl||!target){return;} 8651let frameRect={top:0,left:0};let frameElement;try{frameElement=this.props.document.defaultView.frameElement;}catch{} 8652if(frameElement){frameRect=frameElement.getBoundingClientRect();} 8653const 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`,});}} 8654onSelected(item){item.action(this.props.target);this.props.close();} 8655colItems(){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
8655ight"),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("table")),},{name:"clear_content",icon:"fa-times-circle",text:_t("Clear content"),action:this.props.clearColumnContent.bind(this),},].filter(Boolean);} 8656rowItems(){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("table")),},{name:"clear_content",icon:"fa-times-circle",text:_t("Clear content"),action:(target)=>this.props.clearRowContent(target.parentElement),}
8656,].filter(Boolean);}} 8657return __exports;});; 8658 8659/* /html_editor/static/src/main/table/table_picker.js */ 8660odoo.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;} 8661break;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;}} 8662break;case"ArrowRight":ev.preventDefault();if(isRTL){if(this.state.cols>1){this.state.cols-=1;}}else{this.state.cols+=1;} 8663break;default:ev.stopImmediatePropagation();this.props.overlay.close();break;}},{capture:true});} 8664updateSize(cols,rows){this.state.cols=cols;this.state.rows=rows;} 8665insertTable(){this.props.insertTable({cols:this.state.cols,rows:this.state.rows});this.props.overlay.close();}} 8666return __exports;});; 8667 8668/* /html_editor/static/src/main/table/table_plugin.js */ 8669odoo.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
8669otkeys/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;} 8670if(!root){return true;} 8671const closestTable=closestElement(node,"table");return!root.contains(closestTable);} 8672const 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);} 8673const 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)=>{if(table.style.width||table.style.marginLeft){return;} 8674const tBody=table.tBodies[0];for(const property of["width","margin-left"]){if(tBody.style[property]){table.style[property]=tBody.style[property];removeStyle(tBody,property);}}});}
8675handleTab(){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();} 8676return true;}} 8677handleShiftTab(){const selection=this.dependencies.selection.getEditableSelection();const inTable=closestElement(selection.anchorNode,"table");if(inTable){this.shiftCursorToTableCell(-1);return true;}} 8678distributeTableColorsToAllCells(root){[...root.querySelectorAll("table")].filter((table)=>table.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"];} 8679table.style["color"]="";table.style["backgroundColor"]="";});} 8680createTable({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);} 8681_insertTable({rows=2,cols=2}={}){const newTable=this.createTable({rows,cols});const[table]=this.dependencies.dom.insert(newTable);return table;} 8682insertTable({rows=2,cols=2}={}){const table=this._insertTable({rows,cols});this.dependencies.selection.setCursorStart(table.querySelector(baseContainerGlobalSelector));this.dependencies.history.addStep();} 8683addColumn(position,reference){const columnIndex=getColumnIndex(reference);const table=closestElement(reference,"table");const tableWidth=table.style.width&&parseFloat(table.style.width);const referenceColumn=table.querySelectorAll(`tr :is(td, th):nth-of-type(${columnIndex + 1})`);const referenceCellWidth=reference.style.width?parseFloat(reference.style.width):reference.clientWidth;const firstRow=table.querySelector("tr");const firstRowCells=[...firstRow.children].filter((child)=>child.nodeName==="TD"||child.nodeName==="TH");let totalWidth=0;if(tableWidth){for(const cell of firstRowCells){const width=parseFloat(cell.style.width);cell.style.width=width+"px";const newWidth=Math.max(Math.round((width*tableWidth)/(tableWidth+referenceCellWidth-1)),13);cell.style.width=newWidth+"px";totalWidth+=newWidth;}} 8684referenceColumn.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");} 8685if(rowIndex===0&&tableWidth){newCell.style.width=cell.style.width;totalWidth+=parseFloat(cell.style.width);}});if(tableWidth){if(totalWidth!==tableWidth-1){firstRowCells[firstRowCells.length-1].style.width=parseFloat(firstRowCells[firstRowCells.length-1].style.width)+ 8686(tableWidth-totalWidth-1)+"px";} 8687table.style.width=tableWidth+"px";}} 8688addRow(position,reference){const referenceRowHeight=reference.style.height&&parseFloat(reference.style.height);const newRow=this.document.createElement("tr");if(referenceRowHeight){newRow.style.height=referenceRowHeight+"px";} 8689const 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";} 8690if(getRowIndex(newRow)===0){let columnIndex=0;for(const column of newRow.children){column.style.width=referenceRowWidths[columnIndex];cells[columnIndex].style.width="";columnIndex++;}}} 8691turnIntoHeader(reference){const preserveSelection=this.dependencies.selection.preserveSelection();
8691[...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;} 8692th.classList.add("o_table_header");th.append(...td.childNodes);td.replaceWith(th);}});preserveSelection.restore();} 8693turnIntoRow(reference){const preserveSelection=this.dependencies.selection.preserveSelection();[...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;} 8694td.append(...th.childNodes);th.replaceWith(td);}});preserveSelection.restore();} 8695removeColumn(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);} 8696removeRow(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);} 8697moveColumn(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;} 8698const 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));} 8699this.dependencies.selection.setSelection(selectionToRestore);} 8700moveRow(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);}} 8701if(!adjustedRow.previousElementSibling){adjustedRow.childNodes.forEach((cell,index)=>{cell.style.width=adjustedRow.nextElementSibling.childNodes[index].style.width;});} 8702this.dependencies.selection.setSelection(selectionToRestore);} 8703normalizeRowHeight(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="";}});} 8704resetRowHeight(row){const table=closestElement(row,"table");row.style.height="";this.normalizeRowHeight(table);} 8705normalizeColumnWidth(table){const rows=[...table.rows];const firstRowCells=[...rows[0].cells];const tableWidth=parseFloat(table.style.width);if(tableWidth){const expectedCellWidth=tableWidth/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=""));}});}} 8706resetColumnWidth(cell){const currentCellWidth=parseFloat(cell.style.width);if(!currentCellWidth){return;} 8707const table=closestElement(cell,"table");const tableWidth=parseFloat(table.style.width);const currentRow=cell.parentElement;const currentRowCells=[...currentRow.cells];const rowCellCount=currentRowCells.length;const expectedCellWidth=tableWidth/rowCellCount;const widthDifference=currentCellWidth-expectedCellWidth;const currentColumnIndex=getColumnIndex(cell);let totalWidthLeftOfCell=0,totalWidthRightOfCell=0;
8707currentRowCells.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;} 8708for(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;} 8709cellsToAdjust=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=`${ 8710 adjCellWidth + (widthDifference > 0 ? adjustmentWidth : -adjustmentWidth) 8711 }px`;});this.normalizeColumnWidth(table);} 8712resetTableSize(table){table.removeAttribute("style");const cells=[...table.querySelectorAll("tr, td, th")];cells.forEach((cell)=>{const cStyle=cell.style;if(cell.tagName==="TR"){cStyle.height="";}else{cStyle.width="";}});} 8713clearColumnContent(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);});} 8714clearRowContent(row){row.querySelectorAll("td, th").forEach((td)=>{const baseContainer=this.dependencies.baseContainer.createBaseContainer();fillEmpty(baseContainer);td.replaceChildren(baseContainer);});} 8715deleteTable(table){table=table||findInSelection(this.dependencies.selection.getEditableSelection(),"table");if(!table){return;} 8716const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));table.before(baseContainer);table.remove();this.dependencies.selection.setCursorStart(baseContainer);} 8717deleteTableCells(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]);} 8718return;} 8719if(areFullRowsSelected){for(let index=firstCellRowIndex;index<=lastCellRowIndex;index++){this.removeRow(rows[index]);} 8720return;} 8721for(const td of selectedTds){const baseContainer=this.dependencies.baseContainer.createBaseContainer();baseContainer.appendChild(this.document.createElement("br"));td.replaceChildren(baseContainer);} 8722this.dependencies.selection.setCursorStart(selectedTds[0].firstChild);} 8723deleteRangeWithFullySelectedTables(range,fullySelectedTables){let{startContainer,startOffset,endContainer,endOffset}=range;const firstTable=fullySelectedTables[0];if(firstTable.contains(startContainer)){[startContainer,startOffset]=leftPos(firstTable);} 8724const lastTable=fullySelectedTables.at(-1);if(lastTable.contains(endContainer)){[endContainer,endOffset]=rightPos(lastTable);} 8725range={startContainer,startOffset,endContainer,endOffset};range=this.dependencies.delete.deleteRange(range);const[anchorNode,anchorOffset]=getDeepestPosition(range.startContainer,range.startOffset);this.dependencies.selection.setSelection({anchorNode,anchorOffset});} 8726handleDeleteRange(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;} 8727const selectedTds=this.editable.querySelectorAll(".o_selected_td");if(selectedTds.length){this.deleteTableCells(selectedTds);return true;} 8728return false;}
8729getTableSelectionRangeRect(){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];} 8730const 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;}} 8731shiftCursorToTableCell(shiftIndex){const sel=this.dependencies.selection.getEditableSelection();const currentTd=closestElement(sel.anchorNode,isTableCell);const closestTable=closestElement(currentTd,"table");if(!currentTd||!closestTable){return false;} 8732const tds=[...closestTable.querySelectorAll("td, th")];const cursorDestination=tds[tds.findIndex((td)=>currentTd===td)+shiftIndex];if(!cursorDestination){return false;} 8733this.dependencies.selection.setCursorEnd(lastLeaf(cursorDestination));return true;} 8734hanldeFirefoxSelection(ev=null){const selection=this.document.getSelection();if(isBrowserFirefox()){if(!this.dependencies.selection.isSelectionInEditable(selection)){return false;} 8735if(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];[anchorOffset,focusOffset]=[focusOffset,anchorOffset];} 8736this.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;}} 8737return false;} 8738updateTableKeyboardSelection(ev){const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;const startTable=closestElement(selection.anchorNode,"table");const endTable=closestElement(selection.focusNode,"table");if(!(startTable||endTable)){return;} 8739const[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;} 8740if(targetNode){ev.preventDefault();this.dependencies.selection.setSelection({anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:targetNode,focusOffset:deselectingBackward?nodeSize(targetNode):0,});}} 8741return;} 8742if(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());} 8743return;} 8744const 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);} 8745break;} 8746case"ArrowDown":{if(endCellPosition.x<tds.length-1){targetTd=tds[endCellPosition.x+1][endCellPosition.y];}else{targetNode=nextLeaf(startTable,this.editable);} 8747break;}
8748case"ArrowRight":{if(endCellPosition.y<tds[0].length-1){targetTd=tds[endCellPosition.x][endCellPosition.y+1];} 8749break;} 8750case"ArrowLeft":{if(endCellPosition.y>0){targetTd=tds[endCellPosition.x][endCellPosition.y-1];} 8751break;}} 8752if(targetTd||targetNode){this.dependencies.selection.setSelection({anchorNode:selection.anchorNode,anchorOffset:selection.anchorOffset,focusNode:targetTd||targetNode,focusOffset:0,});} 8753ev.preventDefault();} 8754updateSelectionTable(selectionData){if(this.hanldeFirefoxSelection()||this._isFirefoxDoubleMousedown||this._isTripleClickInTable){delete this._isFirefoxDoubleMousedown;delete this._isTripleClickInTable;return;} 8755if(!selectionData.documentSelectionIsInEditable){this.deselectTable();return;} 8756const 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();} 8757delete 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,focusNode: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,});}} 8758const 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);}}}}} 8759onMousedown(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;} 8760if(ev.detail===2){this.dependencies.selection.setSelection(this.dependencies.selection.getEditableSelection());} 8761if(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);} 8762this.deselectTable();}}} 8763onMouseup(ev){delete this._mouseMovePositionWhenAllContentsSelected;this._currentMouseState=ev.type;this.editable.removeEventListener("mousemove",this.onMousemove);}
8764isPointerInsideCell(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;}} 8765return false;} 8766onMousemove(ev){if(this._currentMouseState!=="mousedown"){return;} 8767if(this.hanldeFirefoxSelection(ev)){return;} 8768const 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];} 8769const 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- 8770(this._lastMousedownPosition?this._lastMousedownPosition[0]:ev.clientX))>=20){this.selectTableCells(selection);}}} 8771navigateCell(ev){const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;const focusNode=selection.focusNode;const currentCell=closestElement(focusNode,isTableCell);if(!currentCell){return;} 8772const 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;} 8773const actualSelection=this.document.getSelection();actualSelection.modify("move",isArrowUp?"backward":"forward","line");const reachedCell=closestElement(actualSelection.focusNode,"td");ev.preventDefault();if(currentCell===reachedCell){return;}} 8774const 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;} 8775node=domPathNode.next().value;} 8776return 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;} 8777if(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,});}}} 8778selectTableCells(selection){const table=closestElement(selection.commonAncestorContainer,"table");if(!table){return;} 8779table.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)=>
8779[...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);}}} 8780deselectTable(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");} 8781didDeselectTable=true;} 8782return didDeselectTable;} 8783applyTableColor(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"]="";}}}} 8784computeBackgroundColorForTable(){const selectedTds=Array.from(this.editable.querySelectorAll(".o_selected_td"));if(selectedTds.length===0){return null;} 8785const firstStyle=getComputedStyle(selectedTds[0]);const backgroundColor=firstStyle.backgroundColor;const backgroundImage=firstStyle.backgroundImage;if(backgroundImage==="none"&&backgroundColor==="rgba(0, 0, 0, 0)"){return null;} 8786const allSameStyle=selectedTds.slice(1).every((td)=>{const s=getComputedStyle(td);return s.backgroundColor===backgroundColor&&s.backgroundImage===backgroundImage;});if(!allSameStyle){return"#00000000";} 8787return backgroundImage!=="none"?backgroundImage:rgbaToHex(backgroundColor);} 8788adjustTargetedNodes(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;} 8789visitedTables.add(selectedTable);for(const selectedTd of selectedTable.querySelectorAll(".o_selected_td")){modifiedTargetedNodes.push(selectedTd,...descendants(selectedTd));}}else{modifiedTargetedNodes.push(node);}} 8790return modifiedTargetedNodes;} 8791resetTableSelection(){const selection=this.dependencies.selection.getEditableSelection({deep:true});const anchorTD=closestElement(selection.anchorNode,".o_selected_td");if(!anchorTD){return;} 8792this.deselectTable();this.dependencies.selection.setSelection({anchorNode:anchorTD.firstChild,anchorOffset:0,focusNode:anchorTD.lastChild,focusOffset:nodeSize(anchorTD.lastChild),});} 8793normalizeTableStructure(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");}} 8794if(!tbody){tbody=table.ownerDocument.createElement("tbody");tbody.innerHTML=`<tr><td><div class="o-paragraph"><br></div></td></tr>`;table.append(tbody);}});return container;} 8795processContentForClipboard(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();}} 8796const trsWithoutTd=Array.from(tableClone.querySelectorAll("tr")).filter((row)=>!row.querySelector("td, th"));for(const tr of trsWithoutTd){if(closestElement(tr,"table")===tableClone){tr.remove();}}} 8797clonedContents=tableClone;} 8798const startTable=closestElement(selection.startContainer,"table");if(clonedContents.firstChild.nodeName==="TABLE"&&startTable){clonedContents.firstChild.after(startTable.cloneNode(true));clonedContents.firstChild.remove();} 8799const endTable=closestElement(selection.endContainer,"table");if(clonedContents.lastChild.nodeName==="TABLE"&&endTable){clonedContents.lastChild.before(endTable.cloneNode(true));clonedContents.lastChild.remove();} 8800this.deselectTable(clonedContents);return clonedContents;} 8801populateTableSpans(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++;} 8802const 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;}} 8803cell.removeAttribute("rowspan");cell.removeAttribute("colspan");c+=colspan;width=Math.max(width,c);}} 8804for(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);} 8805domIndex++;}}} 8806return root;}} 8807return __exports;});; 8808 8809/* /html_editor/static/src/main/table/table_resize_plugin.js */ 8810odoo.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);} 8811isHoveringTdBorder(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";}
8811else 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";}} 8812return false;} 8813setTableResizeCursor(direction){const classList=this.editable.classList;if(classList.contains("o_col_resize")){classList.remove("o_col_resize");} 8814if(classList.contains("o_row_resize")){classList.remove("o_row_resize");} 8815if(direction==="col"){this.editable.classList.add("o_col_resize");}else if(direction==="row"){this.editable.classList.add("o_row_resize");}} 8816resizeTable(ev,direction,target1,target2){ev.preventDefault();const position=target1?(target2?"middle":"last"):"first";let[item,neighbor]=[target1||target2,target2];const table=closestElement(item,"table");const[sizeProp,positionProp,clientPositionProp]=direction==="col"?["width","x","clientX"]:["height","y","clientY"];const isRTL=this.config.direction==="rtl";if(sizeProp==="width"){const tableRect=table.getBoundingClientRect();table.style[sizeProp]=tableRect[sizeProp]+"px";} 8817const unsizedItemsSelector=`${ 8818 direction === "col" ? "td" : "tr" 8819 }:not([style*=${sizeProp}])`;for(const unsizedItem of table.querySelectorAll(unsizedItemsSelector)){unsizedItem.style[sizeProp]=unsizedItem.getBoundingClientRect()[sizeProp]+"px";} 8820if(direction==="col"){let hostCell=closestElement(table,isTableCell);const hostCells=[];while(hostCell){hostCells.push(hostCell);hostCell=closestElement(hostCell.parentElement,isTableCell);} 8821const nthColumn=getColumnIndex(item);const firstRow=[...table.querySelector("tr").children];[item,neighbor]=[firstRow[nthColumn],firstRow[nthColumn+1]];for(const td of hostCells){if(td!==item&&td!==neighbor&&closestElement(td,"table")===table&&getColumnIndex(td)!==0){td.style.removeProperty(sizeProp);}} 8822if(isRTL&&position=="middle"){[item,neighbor]=[neighbor,item];}} 8823const MIN_SIZE=33;switch(position){case"first":{const marginProp=direction==="col"?(isRTL?"marginRight":"marginLeft"):"marginTop";const itemRect=item.getBoundingClientRect();const tableStyle=getComputedStyle(table);const currentMargin=parseFloat(tableStyle[marginProp]);let sizeDelta=itemRect[positionProp]-ev[clientPositionProp];if(direction==="col"&&isRTL){sizeDelta=ev[clientPositionProp]-itemRect[positionProp]-itemRect[sizeProp];} 8824const newMargin=currentMargin-sizeDelta;const currentSize=itemRect[sizeProp];const newSize=currentSize+sizeDelta;if(newMargin>=0&&newSize>MIN_SIZE){const tableRect=table.getBoundingClientRect();const hostCell=closestElement(table.parentElement,isTableCell);const childTable=item.querySelector("table");const endProp=isRTL?"left":"right";if(direction==="col"&&((hostCell&&tableRect[endProp]+sizeDelta>hostCell.getBoundingClientRect()[endProp]-5)||(childTable&&childTable.getBoundingClientRect()[endProp]>itemRect[endProp]+sizeDelta-5))){break;} 8825table.style[marginProp]=newMargin+"px";item.style[sizeProp]=newSize+"px";if(sizeProp==="width"){table.style[sizeProp]=tableRect[sizeProp]+sizeDelta+"px";}} 8826break;} 8827case"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(table,"td, th");const containerWidth=enclosingCell?.getBoundingClientRect().width||this.editable.clientWidth;const maxWidth=containerWidth- 8828parseFloat(editableStyle.paddingLeft)- 8829parseFloat(editableStyle.paddingRight);const tableRect=table.getBoundingClientRect();if(newSize>MIN_SIZE&&(direction==="row"||newNeighborSize>MIN_SIZE||tableRect[sizeProp]+sizeDelta<maxWidth)){const childTable=item.querySelector("table");if(direction==="col"&&childTable&&childTable.getBoundingClientRect().right>itemRect.right+sizeDelta-5){break;} 8830item.style[sizeProp]=newSize+"px";if(direction==="col"){neighbor.style[sizeProp]=(newNeighborSize>MIN_SIZE?newNeighborSize:currentNeighborSize)+"px";}else if(sizeProp==="width"){table.style[sizeProp]=tableRect[sizeProp]+sizeDelta+"px";}} 8831break;} 8832case"last":{const itemRect=item.getBoundingClientRect();let sizeDelta=ev[clientPositionProp]-(itemRect[positionProp]+itemRect[sizeProp]);if(direction==="col"&&isRTL){sizeDelta=itemRect[positionProp]-ev[clientPositionProp];} 8833const currentSize=itemRect[sizeProp];const newSize=currentSize+sizeDelta;if((newSize>=0||direction==="row")&&newSize>MIN_SIZE){const tableRect=table.getBoundingClientRect();const hostCell=closestElement(table.parentElement,isTableCell);const childTable=item.querySelector("table");const endProp=isRTL?"left":"right";if(direction==="col"&&((hostCell&&tableRect[endProp]+sizeDelta>hostCell.getBoundingClientRect()[endProp]-5)||(childTable&&childTable.getBoundingClientRect()[endProp]>itemRect[endProp]+sizeDelta-5))){break;} 8834if(sizeProp==="width"){table.style[sizeProp]=tableRect[sizeProp]+sizeDelta+"px";} 8835item.style[sizeProp]=newSize+"px";} 8836break;}}} 8837fitToContent(ev){const isHoveringTdBorder=this.isHoveringTdBorder(ev);if(!isHoveringTdBorder){return;} 8838const cell=ev.target;if(["left","right"].includes(isHoveringTdBorder)){const table=closestElement(cell,"table");const currentColumnIndex=getColumnIndex(cell);const currentColumnCells=table.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<table.rows[0].cells.length-1)){const siblingColumnIndex=isLeftSideClick?currentColumnIndex-1:currentColumnIndex+1;const siblingColumnCells=table.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);}}} 8839onMousedown(ev){if(ev.button!==0){return;} 8840const 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;}} 8841this.isResizingTable=true;this.setTableResizeCursor(direction);const resizeTable=(ev)=>{if((target1&&!target1.isConnected)||(target2&&!target2.isConnected)){return stopResizing(ev);} 8842this.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);}} 8843onMousemove(ev){const direction={top:"row",right:"col",bottom:"row",left:"col"}[this.isHoveringTdBorder(ev)]||false;
8843if(direction||!this.isResizingTable){this.setTableResizeCursor(direction);}}} 8844return __exports;});; 8845 8846/* /html_editor/static/src/main/table/table_ui_plugin.js */ 8847odoo.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);} 8848openPicker(){this.picker.open({props:{editable:this.editable,overlay:this.picker,direction:this.config.direction||"ltr",insertTable:(params)=>this.dependencies.table.insertTable(params),},});} 8849openPickerOrInsertTable(){if(this.services.ui.isSmall){this.dependencies.table.insertTable({cols:3,rows:3});}else{this.openPicker();}} 8850onMouseMove(ev){const target=ev.target;if(this.isMenuOpened){return;} 8851const 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;} 8852if(!targetCell){this.setActiveTd(null);}}} 8853createDropdownState(closeMenu){const dropdownState=reactive({isOpen:false,open:()=>{dropdownState.isOpen=true;closeMenu();this.isMenuOpened=true;},close:()=>{dropdownState.isOpen=false;this.isMenuOpened=false;},});return dropdownState;} 8854closeColumnMenu(){registry.category(this.config.localOverlayContainers.key).remove(this.columnMenuOverlayKey);} 8855closeRowMenu(){registry.category(this.config.localOverlayContainers.key).remove(this.rowMenuOverlayKey);} 8856setActiveTd(td){this.activeTd=td;this.closeColumnMenu();this.closeRowMenu();if(!td){return;} 8857const 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,},});} 8858if(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,},});}}} 8859return __exports;});; 8860 8861/* /html_editor/static/src/main/tabulation_plugin.js */ 8862odoo.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));} 8863const 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;} 8864const selection=this.dependencies.selection.getEditableSelection();if(selection.isCollapsed){this.insertTab();}else{const targetedBlocks=this.dependencies.selection.getTargetedBlocks();this.indentBlocks(targetedBlocks);} 8865this.dependencies.history.addStep();} 8866handleShiftTab(){if(this.delegateTo("shift_tab_overrides")){return;} 8867const targetedBlocks=this.dependencies.selection.getTargetedBlocks();this.outdentBlocks(targetedBlocks);this.dependencies.history.addStep();} 8868insertTab(){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);}} 8869indentBlocks(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));} 8870this.dependencies.selection.setSelection(selectionToRestore,{normalize:false});} 8871outdentBlocks(blocks){for(const block of blocks){const firstTab=descendants(block).find(isEditorTab);if(firstTab&&isIndentationTab(firstTab)){this.removeTrailingZWS(firstTab);firstTab.remove();}}} 8872removeTrailingZWS(tab){const selection=this.dependencies.selection.getEditableSelection();
8872const{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++;} 8873if(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,});}} 8874adjustTabWidth(tabSpan){let tabPreviousSibling=tabSpan.previousSibling;while(isZWS(tabPreviousSibling)){tabPreviousSibling=tabPreviousSibling.previousSibling;} 8875if(isEditorTab(tabPreviousSibling)){tabSpan.style.width=`${GRID_COLUMN_WIDTH}px`;return;} 8876const spanRect=tabSpan.getBoundingClientRect();const referenceRect=this.editable.firstElementChild?.getBoundingClientRect();if(!referenceRect?.width||!spanRect.width){return;} 8877const relativePosition=spanRect.left-referenceRect.left;const distToNextGridLine=GRID_COLUMN_WIDTH-(relativePosition%GRID_COLUMN_WIDTH);const width=distToNextGridLine.toFixed(1);tabSpan.style.width=`${width}px`;} 8878alignTabs(root=this.editable){const block=closestBlock(root);if(!block){return;} 8879for(const tab of block.querySelectorAll("span.oe-tabs")){this.adjustTabWidth(tab);}} 8880expandRangeToIncludeZWS(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];}} 8881previous=node;node=node.nextSibling;} 8882return[previous.parentElement,childNodeIndex(previous)+1];} 8883handleDeleteForward(range){let{endContainer,endOffset}=range;if(!(endContainer?.nodeType===Node.ELEMENT_NODE)||!endOffset){return;} 8884const 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;}} 8885normalize(el){this.alignTabs(el);}} 8886return __exports;});; 8887 8888/* /html_editor/static/src/main/text_direction_plugin.js */ 8889odoo.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);} 8890this.direction=this.config.direction||"ltr";} 8891switchDirection(){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;} 8892const shouldApplyStyle=![...blocks].every((block)=>isDirectionSwitched(block,this.editable));for(const block of blocks){for(const node of block.querySelectorAll("ul,ol")){blocks.add(node);}} 8893for(const block of blocks){if(!shouldApplyStyle){block.removeAttribute("dir");}else{block.setAttribute("dir",this.direction==="ltr"?"rtl":"ltr");}} 8894for(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");}} 8895this.dependencies.history.addStep();}} 8896return __exports;});; 8897 8898/* /html_editor/static/src/main/toolbar/mobile_toolbar.js */ 8899odoo.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,};
8899static 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;} 8900useExternalListener(this.targetWindow.visualViewport,"resize",this.fixToolbarPosition);useExternalListener(this.targetWindow.visualViewport,"scroll",this.fixToolbarPosition);onMounted(()=>this.fixToolbarPosition());} 8901fixToolbarPosition(){const visualViewport=this.targetWindow.visualViewport;const keyboardHeight=Math.max(0,this.targetWindow.innerHeight-(visualViewport.height+visualViewport.offsetTop));this.toolbar.el.style.bottom=`${keyboardHeight}px`;}} 8902return __exports;});; 8903 8904/* /html_editor/static/src/main/toolbar/toolbar.js */ 8905odoo.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,});} 8906return true;},},},},},},},},};setup(){this.state=useState(this.props.state);} 8907onButtonClick(button){button.run();this.props.focusEditable();}} 8908const 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,};} 8909return __exports;});; 8910 8911/* /html_editor/static/src/main/toolbar/toolbar_plugin.js */ 8912odoo.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}`);} 8913groupIds.add(group.id);} 8914this.buttonGroups=this.getButtonGroups();this.buttonsByNamespace={DISABLED_NAMESPACE:[]};this.isMobileToolbar=(utils.isSmall()&&hasTouch()&&window.visualVie
8914wport)||isIOS();if(this.isMobileToolbar){this.overlay=new MobileToolbarOverlay(this.editable);}else{this.overlay=this.dependencies.overlay.createOverlay(Toolbar,{positionOptions:{position:"top-start",},closeOnPointerdown:false,});} 8915this.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));}} 8916this.isToolbarExpanded=false;this.toolbarProps={class:"shadow rounded my-2",getSelection:()=>this.dependencies.selection.getSelectionData(),focusEditable:()=>this.dependencies.selection.focusEditable(),state:this.state,};} 8917destroy(){this.debouncedUpdateToolbar.cancel();this.updateToolbar.cancel();this.overlay.close();super.destroy();} 8918triggerDebouncedUpdateToolbar(){this.debouncedUpdateToolbar();} 8919getButtons(){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));} 8920getButtonGroups(){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"],})),}));} 8921getButtonsForNamespace(namespace){if(this.buttonsByNamespace[namespace]){return this.buttonsByNamespace[namespace];} 8922const button=this.buttonGroups.flatMap((group)=>group.buttons.filter((btn)=>btn.namespaces.includes(namespace)));this.buttonsByNamespace[namespace]=button;return button;} 8923getToolbarInfo(){return{buttonGroups:this.buttonGroups,};} 8924getIsToolbarOpen(){return this.overlay.isOpen;} 8925handleSelectionChange(selectionData){if(this.onSelectionChangeActive){this.updateToolbar(selectionData);}} 8926updateToolbar=debounce(this._updateToolbar,0,{trailing:true});_updateToolbar(selectionData=this.dependencies.selection.getSelectionData()){if(this.isDestroyed){return;} 8927if(!selectionData.currentSelectionIsInEditable||selectionData.documentSelectionIsProtected||selectionData.documentSelectionIsProtecting){this.closeToolbar();return;} 8928const targetedNodes=this.dependencies.selection.getTargetedNodes();if(targetedNodes.every((node)=>!this.dependencies.selection.isNodeEditable(node))){this.closeToolbar();return;} 8929let 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;}} 8930if(currentNamespace===DISABLED_NAMESPACE){this.closeToolbar();return;} 8931if(currentNamespace==="compact"&&this.isToolbarExpanded){currentNamespace="expanded";} 8932if(currentNamespace){this.state.namespace=currentNamespace;if(!this.overlay.isOpen){this.overlay.open({props:this.toolbarProps}
8932);} 8933this.updateButtonsStates(selectionData.editableSelection,filteredtargetedNodes);}else{this.closeToolbar();}} 8934getFilteredTargetedNodes(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";});} 8935isToolbarVisible(targetedNodes,editableSelection){if(this.isMobileToolbar){return true;} 8936const isCollapsed=editableSelection.isCollapsed;if(isCollapsed){return false;} 8937const selectionText=editableSelection.textContent();const textCleaned=selectionText.replace(/(\r\n|\n|\r|\u200B|\uFEFF)/gm,"");if(textCleaned.length){return true;} 8938return targetedNodes.some((node)=>node.nodeType===Node.ELEMENT_NODE&&node.tagName==="BR");} 8939closeToolbar(selectionData=null,{force=false}={}){if(!this.overlay.isOpen){return;} 8940const 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;}} 8941updateButtonsStates(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);} 8942getAvailableButtonsSet(selection){if(this.state.namespace==="compact"){return this.getAvailableButtonsCompact(selection);} 8943const isAvailable=(button)=>button.isAvailable(selection);return new Set(this.getButtonsForNamespace(this.state.namespace).filter(isAvailable));} 8944getAvailableButtonsCompact(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);} 8945this.state.namespace="expanded";return new Set(expanded);}} 8946class MobileToolbarOverlay{constructor(editable){this.isOpen=false;this.overlayId=`mobile_toolbar_${Math.random().toString(16).slice(2)}`;this.editable=editable;} 8947open({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";} 8948registry.category("main_components").add(this.overlayId,{Component:ToolbarMobile,props,});this.isOpen=true;}} 8949close(){const modal=this.editable.closest(".o_modal_full");if(modal){modal.style.paddingBottom="";} 8950registry.category("main_components").remove(this.overlayId,"MobileToolbar");this.isOpen=false;}} 8951return __exports;});; 8952 8953/* /html_editor/static/src/main/youtube_plugin.js */ 8954odoo.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"];
8954mediaSpecificClasses=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();},};}} 8955async getYoutubeVideoElement(url){if(!URL.canParse(url)){return;} 8956const 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;} 8957createVideoElement(videoData){return VideoSelector.createElements([{src:videoData.embed_url}])[0];}} 8958return __exports;});; 8959 8960/* /html_editor/static/src/others/collaboration/PeerToPeer.js */ 8961odoo.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"));}} 8962const 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];} 8963this._createPeer(peerId);},rtc_signal_icecandidate:async function(notification){if(debugShowLog){console.log(`%creceive candidate`,"background: darkgreen; color: white;");} 8964const 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;} 8965if(!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);} 8966const 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: "+ 8967notification.fromPeerId);console.trace(pc&&pc.connectionState);console.groupEnd();} 8968return;} 8969if(pc.signalingState==="have-remote-offer"){return;} 8970const isPolite=(""+notification.fromPeerId).localeCompare(""+this._currentPeerId)===1;if(debugShowLog){console.log(`%cisPolite: %c${isPolite}`,"background: deepskyblue;",`background:${isPolite ? "green" : "red"}`);} 8971const 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;");} 8972return;} 8973if(debugShowLog){console.log(`%cisOfferRacing: ${isOfferRacing}`,"background: red;");console.log(`%c SETREMOTEDESCRIPTION`,"background: navy; color:white;");} 8974try{await pc.setRemoteDescription(description);}catch(e){if(e instanceof DOMException&&e.name==="InvalidStateError"){console.error(e);return;}else{throw e;}} 8975if(peerInfos.iceCandidateBuffer.length){for(const candidate of peerInfos.iceCandidateBuffer){await this._addIceCandidate(peerInfos,candidate);} 8976peerInfos.iceCandidateBuffer.splice(0);} 8977if(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;}} 8978this.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;");} 8979this.peersInfos={};this._lastRequestId=-1;this._pendingRequestResolver={};this._stopped=false;} 8980stop(){this.closeAllConnections();this._stopped=true;} 8981getConnectedPeerIds(){return Object.entries(this.peersInfos).filter(([id,infos])=>infos.peerConnection&&infos.peerConnection.iceConnectionState==="connected"&&infos.dataChannel&&infos.dataChannel.readyState==="open").map(([id])=>id);} 8982removePeer(peerId){if(debugShowLog){console.log(`%c REMOVE PEER ${peerId}`,"background: chocolate;");} 8983this.notifySelf("ptp_remove",peerId);const peerInfos=this.peersInfos[peerId];if(!peerInfos){return;} 8984clearTimeout(peerInfos.fallbackTimeout);clearTimeout(peerInfos.zombieTimeout);peerInfos.dataChannel&&peerInfos.dataChannel.close();peerInfos.peerConnection&&peerInfos.peerConnection.close();delete this.peersInfos[peerId];} 8985closeAllConnections(){for(const peerId of Object.keys(this.peersInfos)){this.notifyAllPeers("ptp_disconnect");this.removePeer(peerId);}} 8986async notifyAllPeers(notificationName,notificationPayload,{transport="server"}={}){if(this._stopped){return;} 8987const 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.`);}} 8988notifyPeer(peerId,notificationName,notificationPayload,{transport="server"}={}){if(this._stopped){return;} 8989if(debugShowNotifications){if(notificationName==="ptp_request_result"){console.log(`%c${Date.now()} - REQUEST RESULT SEND: %c${transport}:${ 8990 notificationPayload.requestId 8991 }:${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}:${ 8992 notificationPayload.requestName 8993 }|${notificationPayload.requestId}:${this._currentPeerId.slice( 8994 "-5" 8995 )}:${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( 8996 "-5" 8997 )}:${peerId.slice("-5")}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}} 8998const 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.`);}} 8999notifySelf(notificationName,notificationPayload){if(this._stopped){return;} 9000return this.handleNotification({notificationName,notificationPayload});}
9001handleNotification(notification){if(this._stopped){return;} 9002const 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${ 9003 notification.notificationPayload.requestId 9004 }:${notification.fromPeerId.slice("-5")}:${notification.toPeerId.slice( 9005 "-5" 9006 )}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}else if(notification.notificationName==="ptp_request"){console.log(`%c${Date.now()} - REQUEST RECEIVE: %c${ 9007 notification.notificationPayload.requestName 9008 }|${ 9009 notification.notificationPayload.requestId 9010 }:${notification.fromPeerId.slice("-5")}:${notification.toPeerId.slice( 9011 "-5" 9012 )}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}else{console.log(`%c${Date.now()} - NOTIFICATION RECEIVE: %c${ 9013 notification.notificationName 9014 }:${notification.fromPeerId}:${notification.toPeerId}`,"color: #aaa;font-weight:bold;","color: #aaa;font-weight:normal");}} 9015try{const baseMethod=baseNotificationMethods[notification.notificationName];if(baseMethod){return baseMethod.call(this,notification);} 9016if(this.options.onNotification){return this.options.onNotification(notification);}}catch(error){console.groupCollapsed("=== ERROR: On notification in collaboration ===");console.error(error);console.groupEnd();}}} 9017requestPeer(peerId,requestName,requestPayload,{transport="server"}={}){if(this._stopped){return;} 9018return 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});});} 9019abortCurrentRequests(){for(const{abort}of Object.values(this._pendingRequestResolver)){abort();}} 9020_createPeer(peerId,{makeOffer=true}={}){if(this._stopped){return;} 9021if(debugShowLog){console.log("CREATE CONNECTION with peer id:",peerId);} 9022this.peersInfos[peerId]={makingOffer:false,iceCandidateBuffer:[],backoffFactor:0,};if(!navigator.onLine){return this.peersInfos[peerId];} 9023const pc=new RTCPeerConnection(this.options.peerConnectionConfig);if(makeOffer){pc.onnegotiationneeded=async()=>{if(debugShowLog){console.log(`%c NEGONATION NEEDED: ${pc.connectionState}`,"background: deeppink;");} 9024try{this.peersInfos[peerId].makingOffer=true;if(debugShowLog){console.log(`%ccreating and sending an offer`,"background: darkmagenta; color: white;");} 9025const offer=await pc.createOffer();if(pc.signalingState!=="stable"){return;} 9026await pc.setLocalDescription(offer);this.notifyPeer(peerId,"rtc_signal_description",pc.localDescription);}catch(err){console.error(err);}finally{this.peersInfos[peerId].makingOffer=false;}};} 9027pc.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);} 9028switch(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",});} 9029break;case"connected":this.peersInfos[peerId].backoffFactor=0;break;}};pc.onconnectionstatechange=async()=>{if(debugShowLog){console.log("CONNECTION STATE UPDATE:"+pc.connectionState);} 9030switch(pc.connectionState){case"failed":case"closed":this.removePeer(peerId);break;case"disconnected":if(navigator.onLine){await this._recoverConnection(peerId,{delay:3000,reason:"connection disconnected",});} 9031break;case"connected":case"completed":this.peersInfos[peerId].backoffFactor=0;break;}};pc.onicecandidateerror=async(error)=>{if(debugShowLog){console.groupCollapsed("=== ERROR: onIceCandidate ===");console.log("connectionState: "+ 9032pc.connectionState+" - iceState: "+ 9033pc.iceConnectionState);console.trace(error);console.groupEnd();} 9034this._recoverConnection(peerId,{delay:3000,reason:"ice candidate error"});};
9034const 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];} 9035async _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();}} 9036_channelNotify(peerId,transportPayload){if(this._stopped){return;} 9037const 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}
9037. The connection will be killed in 10 seconds if the datachannel state has not changed.`);} 9038this._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;} 9039dataChannel.send("-");}} 9040_getRequestId(){this._lastRequestId++;return this._lastRequestId;} 9041async _onRequest(fromPeerId,requestId,requestName,requestPayload,requestTransport){if(this._stopped){return;} 9042const 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});} 9043_recoverConnection(peerId,{delay=0,reason=""}={}){if(this._stopped){this.removePeer(peerId);return;} 9044const peerInfos=this.peersInfos[peerId];if(!peerInfos||peerInfos.fallbackTimeout){return;} 9045const 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;");} 9046return;} 9047peerInfos.fallbackTimeout=setTimeout(async()=>{peerInfos.fallbackTimeout=undefined;const pc=peerInfos.peerConnection;if(!pc||pc.iceConnectionState==="connected"){return;} 9048if(["connected","closed"].includes(pc.connectionState)){return;} 9049if(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;");} 9050this.removePeer(peerId);const newPeerInfos=this._createPeer(peerId);newPeerInfos.backoffFactor=backoffFactor+1;},backoffDelay);} 9051_killPotentialZombie(peerId){if(this._stopped){this.removePeer(peerId);return;} 9052const peerInfos=this.peersInfos[peerId];if(!peerInfos||peerInfos.zombieTimeout){return;} 9053peerInfos.zombieTimeout=setTimeout(()=>{if(peerInfos&&peerInfos.dataChannel&&peerInfos.dataChannel.readyState!=="open"){if(debugShowLog){console.log(`%c KILL ZOMBIE ${peerId}`,"background: red;");} 9054this.removePeer(peerId);}else{if(debugShowLog){console.log(`%c NOT A ZOMBIE ${peerId}`,"background: green;");}}},10000);}} 9055const RequestError=__exports.RequestError=class RequestError extends Error{constructor(message){super(message);this.name="RequestError";}} 9056return __exports;});; 9057 9058/* /html_editor/static/src/others/collaboration/collaboration_odoo_plugin.js */ 9059odoo.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);} 9060stripHistoryIds(this.editable);} 9061destroy(){this.collaborationStopBus&&this.collaborationStopBus();if(this.peerToPeerLoading){this.peerToPeerLoading.then(()=>{this.stopPeerToPeer();});} 9062super.destroy();} 9063stopPeerToPeer(){this.joiningPtp=false;this.ptpJoined=false;this.resetCollabRequests();this.ptp&&this.ptp.stop();} 9064getCurrentCollaborativeSelection(){const selection=this.dependencies.selection.getEditableSelection();return{selection:this.dependencies.history.serializeSelection(selection),peerId:this.config.collaboration.peerId,};} 9065setupCollaboration(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;} 9066this.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()=>
9066{if(!ICE_SERVERS){ICE_SERVERS=await rpc("/html_editor/get_ice_servers");} 9067let iceServers=ICE_SERVERS;if(!iceServers.length){iceServers=[{urls:["stun:stun1.l.google.com:19302","stun:stun2.l.google.com:19302"],},];} 9068this.iceServers=iceServers;this.ptp=this.getNewPtp();};this.peerToPeerLoading=loadPeerToPeer();} 9069getNewPtp(){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;} 9070return{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;} 9071this.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,};
9071if(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);} 9072break;} 9073case"oe_history_step":if(this.historySyncFinished){this.dependencies.collaboration.onExternalHistorySteps([notificationPayload,]);}else{this.historyStepsBuffer.push(notificationPayload);} 9074break;case"oe_history_set_selection":{const peer=this.ptp.peersInfos[fromPeerId];if(!peer){return;} 9075const selection=notificationPayload;this.onExternalMultiselectionUpdate(selection);break;}}},});} 9076getPeerMetadata(peerId){return this.ptp.peersInfos[peerId]?.metadata;} 9077onExternalMultiselectionUpdate(selection){this.dispatchTo("collaborative_selection_update_handlers",selection);} 9078async 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;}});} 9079getMetadata(){const metadatas={startTime:this.startCollaborationTime,peerName:user.name,};for(const cb of this.getResource("collaboration_peer_metadata_providers")){Object.assign(metadatas,cb());} 9080return metadatas;} 9081onServerLastIdUpdate(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();}} 9082joinPeerToPeer(){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;}} 9083this.ptp.notifyAllPeers("ptp_join");this.joiningPtp=false;this.ptpJoined=true;});}} 9084isLastDocumentStale(){if(!this.serverLastStepId){return false;} 9085return!this.dependencies.collaboration.getBranchIds().includes(this.serverLastStepId);} 9086async 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();}} 9087let 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();} 9088return;} 9089this.processMissingSteps(response.missingSteps);this.isDocumentStale=this.isLastDocumentStale();snapshots.push(response.snapshot);if(nbPendingResponses<1){processSnapshots();}});} 9090const processSnapshots=async()=>{this.isDocumentStale=this.isLastDocumentStale();if(!this.isDocumentStale){return success();} 9091if(snapshots[0]){this.showConflictDialog();} 9092for(const snapshot of snapshots){this.applySnapshot(snapshot);this.isDocumentStale=this.isLastDocumentStale();if(!this.isDocumentStale){return success();}} 9093if(this.isDocumentStale){this.showConflictDialog();await this.resetFromServerAndResyncWithPeers();} 9094success();};const timeout=setTimeout(()=>{if(resetCollabCount!==this.lastCollaborationResetId){return;} 9095hasRetrievalBudgetTimeout=true;this.onRecoveryPeerTimeout(processSnapshots);},PTP_MAX_RECOVERY_TIME);});} 9096getPtpPeers(){const peers=Object.entries(this.ptp.peersInfos).map(([peerId,peerInfo])=>({id:peerId,...peerInfo,}));return peers.sort((a,b)=>(isPeerFirst(a,b)?-1:1));} 9097getLastHistoryStepId(value){const matchId=value.match(/data-last-history-steps="[0-9,]*?([0-9]+)"/);
9097return matchId&&matchId[1];} 9098resetCollabRequests(){this.lastCollaborationResetId++;this.ptp&&this.ptp.abortCurrentRequests();} 9099async resetFromServerAndResyncWithPeers(){let collaborationResetId=this.lastCollaborationResetId;const record=await this.getCurrentRecord();if(collaborationResetId!==this.lastCollaborationResetId){return;} 9100const 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());} 9101stripHistoryIds(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;} 9102onReset(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);}} 9103async processMissingSteps(missingSteps){if(missingSteps===-1||!missingSteps.length){return false;} 9104this.dependencies.collaboration.onExternalHistorySteps(missingSteps);return true;} 9105applySnapshot(snapshot){const{steps,historyIds,historyShareId}=snapshot;const isStaleDocument=this.serverLastStepId&&!historyIds.includes(this.serverLastStepId);if(isStaleDocument){return;} 9106this.historyShareId=historyShareId;this.historySyncAtLeastOnce=true;this.dependencies.collaboration.resetFromSteps(steps,historyIds);return true;} 9107async onRecoveryPeerTimeout(processSnapshots){processSnapshots();} 9108showConflictDialog(){} 9109getHistorySnapshot(){return Object.assign({},this.dependencies.collaboration.getSnapshotSteps(),{historyShareId:this.historyShareId,});} 9110async 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;} 9111if(resetCollabCount!==this.lastCollaborationResetId){return;} 9112if(this.historySyncAtLeastOnce){return;} 9113const 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;} 9114const applied=this.applySnapshot(snapshot);if(!applied){return;} 9115const anchorNode=this._getNodeFromIndexPath(anchorNodeIndexPath);if(this.dependencies.selection.isSelectionInEditable({anchorNode,focusNode:anchorNode})){this.dependencies.selection.setSelection({anchorNode,anchorOffset,});} 9116this.historySyncFinished=true;if(this.historyStepsBuffer.length){this.dependencies.collaboration.onExternalHistorySteps(this.historyStepsBuffer);this.historyStepsBuffer=[];} 9117this.editable.dispatchEvent(new CustomEvent("onHistoryResetFromPeer"));this.resetCollaborativeSelection(fromPeerId);} 9118async resetCollaborativeSelection(fromPeerId){const remoteSelection=await this.requestPeer(fromPeerId,"get_collaborative_selection",undefined,{transport:"rtc"});if(remoteSelection===REQUEST_ERROR){return;} 9119if(remoteSelection){this.onExternalMultiselectionUpdate(remoteSelection);}} 9120async onHistoryMissingParentStep({step,fromStepId}){if(!this.ptp){return;} 9121const missingSteps=await this.requestPeer(step.peerId,"get_missing_steps",{fromStepId:fromStepId,toStepId:step.id,},{transport:"rtc"});if(missingSteps===REQUEST_ERROR){return;} 9122this.processMissingSteps(Array.isArray(missingSteps)?missingSteps.concat(step):missingSteps);} 9123async 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;} 9124attachHistoryIds(editable){const historyIds=this.dependencies.collaboration.getBranchIds().join(",");const firstChild=editable.children[0];if(firstChild){firstChild.setAttribute("data-last-history-steps",historyIds);}} 9125_getNodeIndexPath(node){return[node,...ancestors(node,this.editable)].map((ancestor)=>childNodeIndex(ancestor));} 9126_getNodeFromIndexPath(indexPath){return indexPath.reduceRight((node,index)=>node?.childNodes?.[index],this.editable.parentElement);}} 9127function isPeerFirst(peerA,peerB){if(peerA.startTime===peerB.startTime){return peerA.id.localeCompare(peerB.id)===-1;} 9128if(peerA.startTime===undefined||peerB.startTime===undefined){return Boolean(peerA.startTime);}else{return peerA.startTime<peerB.startTime;}} 9129__exports.stripHistoryIds=stripHistoryIds;function stripHistoryIds(element){element.querySelectorAll("[data-last-history-steps]").forEach((el)=>el.removeAttribute("data-last-history-steps"));} 9130return __exports;});; 9131 9132/* /html_editor/static/src/others/collaboration/collaboration_plugin.js */ 9133odoo.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");} 9134this._snapshotInterval=setInterval(()=>{this.makeSnapshot();},HISTORY_SNAPSHOT_INTERVAL);} 9135destroy(){super.destroy();clearInterval(this._snapshotInterval);this._snapshotInterval=false;} 9136onHistoryClean(){this.branchStepIds=[];} 9137onHistoryReset(){const firstStep=this.dependencies.history.getHistorySteps()[0];this.snapshots=[{step:firstStep}];} 9138isUnreversibleStep(step){return step.peerId!==this.peerId;} 9139setAttribute(node,attributeName,attributeValue){if(attributeValue){this.safeSetAttribute(node,attributeName,attributeValue);return true;}} 9140getBranchIds(){const steps=this.dependencies.history.getHistorySteps();return(this.initialBranchStepId||"").split(",").concat(this.branchStepIds).c
9140oncat(steps.map((s)=>s.id));} 9141safeSetAttribute(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);}} 9142onExternalHistorySteps(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;} 9143this.dependencies.history.addExternalStep(newStep,insertIndex);stepIndex++;} 9144if(selectionData.documentSelectionIsInEditable){this.dependencies.selection.rectifySelection(selectionData.editableSelection);} 9145this.dispatchTo("external_history_step_handlers");if(stepIndex){this.config.onChange?.();}} 9146getInsertStepIndex(steps,newStep){let index=steps.length-1;while(index>=0&&steps[index].id!==newStep.previousStepId){if(steps[index].id===newStep.id){return;} 9147index--;} 9148if(index<0){const historySteps=steps;let index=historySteps.length-1;while(index!==0){if(historySteps[index].peerId===newStep.peerId){break;} 9149index--;} 9150const fromStepId=historySteps[index].id;this.dispatchTo("history_missing_parent_step_handlers",{step:newStep,fromStepId:fromStepId,});return;} 9151let 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;}} 9152index++;} 9153return index;} 9154historyGetMissingSteps({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;} 9155return steps.slice(fromIndex+1,toIndex);} 9156getSnapshotSteps(){const historySteps=this.dependencies.history.getHistorySteps();if(!this.snapshots[0].time){return{steps:historySteps,historyIds:this.getBranchIds()};} 9157const snapshotSteps=[];let snapshot;if(this.snapshots[0].time+HISTORY_SNAPSHOT_BUFFER_TIME<Date.now()){snapshot=this.snapshots[0];}else{snapshot=this.snapshots[1];} 9158let index=historySteps.length-1;while(historySteps[index].id!==snapshot.step.id){snapshotSteps.push(historySteps[index]);index--;} 9159snapshotSteps.push(snapshot.step);snapshotSteps.reverse();return{steps:snapshotSteps,historyIds:this.getBranchIds()};} 9160setInitialBranchStepId(stepId){this.initialBranchStepId=stepId;} 9161resetFromSteps(steps,branchStepIds){this.dependencies.selection.resetSelection();this.dependencies.history.resetFromSteps(steps);this.snapshots=[{step:steps[0]}];this.branchStepIds=branchStepIds;} 9162makeSnapshot(){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]];}} 9163onStepAdded(step){step.peerId=this.peerId;this.dispatchTo("collaboration_step_added_handlers",step);} 9164processHistoryStep(step){step.peerId=this.peerId;return step;}} 9165return __exports;});; 9166 9167/* /html_editor/static/src/others/collaboration/collaboration_selection_avatar_plugin.js */ 9168odoo.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=`${ 9169 browser.location.origin 9170 }/web/image?model=res.users&field=avatar_128&id=${encodeURIComponent(user.userId)}`;} 9171handleCollaborationNotification({notificationName,notificationPayload}){switch(notificationName){case"ptp_remove":this.selectionInfos.delete(notificationPayload);this.refreshSelection();}} 9172updateSelection(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();} 9173drawPeerAvatar(selectionInfo){const{selection,peerId}=selectionInfo;const peerMetadata=this.dependencies.collaborationOdoo.getPeerMetadata(peerId);if(!peerMetadata){return;} 9174const{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;} 9175let anchorBlock=closestBlock(anchorNode);
9175if(!anchorBlock){return;} 9176if(isProtecting(anchorBlock)){const rootAnchorBlock=closestElement(anchorNode,(el)=>isBlock(el)&&el.parentElement===this.editable);if(rootAnchorBlock){anchorBlock=rootAnchorBlock;}} 9177const 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");} 9178if(!avatarElement.parentElement){this.avatarOverlay.append(avatarElement);} 9179selectionInfo.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}`;} 9180updateAvatarCounters(){const avatarsOverlaps={};for(const info of this.selectionInfos.values()){const key=info.avatarPositionKey;avatarsOverlaps[key]=avatarsOverlaps[key]||new Set();avatarsOverlaps[key].add(info);} 9181this.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);}}} 9182refreshSelection(){if(!this.selectionInfos.size){this.avatarOverlay.replaceChildren();} 9183this.avatarsCountersOverlay.replaceChildren();for(const selection of this.selectionInfos.values()){this.drawPeerAvatar(selection);} 9184this.updateAvatarCounters();} 9185disableAvatarForElement(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");}}}} 9186enableAvatars(){for(const element of this.avatarOverlay.querySelectorAll(".oe-collaboration-caret-avatar.invisible")){element.classList.remove("invisible");}}} 9187return __exports;});; 9188 9189/* /html_editor/static/src/others/collaboration/collaboration_selection_plugin.js */ 9190odoo.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%)`;} 9191handleCollaborationNotification({notificationName,notificationPayload}){switch(notificationName){case"ptp_remove":this.multiselectionRemove(notificationPayload);this.selectionInfos.delete(notificationPayload);break;}} 9192updateSelection(selection){this.selectionInfos.set(selection.peerId,selection);this.drawPeerSelection(selection);} 9193drawPeerSelection({selection,peerId}){const peerMetadata=this.dependencies.collaborationOdoo.getPeerMetadata(peerId);if(!peerMetadata){return;} 9194const{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;} 9195const 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;} 9196if(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;}
9197const 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);} 9198clientRects=Array.from(range.getClientRects());}catch{clientRects=[];} 9199if(!clientRects.length){return;} 9200const containerRect=this.selectionOverlay.getBoundingClientRect();const indicators=clientRects.map(({x,y,width,height})=>{const rectElement=this.document.createElement("div");rectElement.style=` 9201 position: absolute; 9202 top: ${y - containerRect.y}px; 9203 left: ${x - containerRect.x}px; 9204 width: ${width}px; 9205 height: ${height}px; 9206 background-color: ${selectionColor}; 9207 opacity: 0.25; 9208 pointer-events: none; 9209 `;rectElement.setAttribute("data-selection-peer-id",peerId);return rectElement;});const caretElement=this.document.createElement("div");caretElement.style=`border-left: 2px solid ${selectionColor}; position: absolute;`;
9209caretElement.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`;} 9210this.selectionOverlay.append(caretElement,...indicators);} 9211multiselectionRemove(peerId){const elements=this.selectionOverlay.querySelectorAll(`[data-selection-peer-id="${peerId}"]`);for(const element of elements){element.remove();}} 9212refreshSelection(){this.selectionOverlay.replaceChildren();for(const selection of this.selectionInfos.values()){this.drawPeerSelection(selection);}}} 9213return __exports;});; 9214 9215/* /html_editor/static/src/others/embedded_components/backend/caption/caption.js */ 9216odoo.define('@html_editor/others/embedded_components/backend/caption/caption',[],function(require){'use strict';let __exports={};return __exports;});; 9217 9218/* /html_editor/static/src/others/embedded_components/backend/file/file.js */ 9219odoo.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]);} 9220onBlurNameInput(ev){this.localState.editFileName=false;this.renameFile();} 9221onFocusFileName(ev){this.localState.editFileName=true;} 9222onKeydownNameInput(ev){if(ev.key!=="Enter"){return;}else{ev.preventDefault();} 9223if(this.renameFile()){this.localState.editFileName=false;this.env.editorShared?.setSelectionAfter(this.props.host);}} 9224renameFile(){let newName=this.nameInput.el.value;if(!newName.length){return false;} 9225if(newName===this.fileModel.filename){return true;} 9226this.fileModel.filename=newName;if(this.fileModel.extension){const pattern=new RegExp(`\\.${this.fileModel.extension}$`,"i");if(!newName.match(pattern)){newName+=`.${this.fileModel.extension}`;}} 9227this.fileModel.name=newName;return true;}} 9228const 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;});; 9229 9230/* /html_editor/static/src/others/embedded_components/backend/syntax_highlighting/code_toolbar.js */ 9231odoo.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;}} 9232return __exports;});; 9233 9234/* /html_editor/static/src/others/embedded_components/backend/syntax_highlighting/syntax_highlighting.js */ 9235odoo.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,]);} 9236loadPrism(){return loadBundle(`html_editor.assets_prism${cookie.get("
9236color_scheme") === "dark" ? "_dark" : ""}`,{targetDoc:this.props.host.ownerDocument});} 9237highlight(){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;} 9238if(focus){this.textarea.focus({preventScroll:true});this.props.onTextareaFocus();} 9239this.embeddedState.value=this.textarea.value;} 9240onInput(){this.textarea.focus();this.props.onTextareaFocus();this.embeddedState.value=this.textarea.value;} 9241onKeydown(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)+ 9242tab+ 9243this.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);}} 9244const 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;} 9245const isArrowUp=ev.key==="ArrowUp";const isCursorAtBoundary=isArrowUp?value.slice(0,selectionStart).lastIndexOf("\n")===-1:value.indexOf("\n",selectionEnd)===-1;if(!isCursorAtBoundary){return;} 9246ev.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,});}} 9247onScroll(){this.pre.scrollTop=this.textarea.scrollTop;this.pre.scrollLeft=this.textarea.scrollLeft;} 9248onLanguageChange(languageId){if(languageId&&this.embeddedState.languageId!==languageId){this.textarea.focus();this.props.onTextareaFocus();this.embeddedState.languageId=languageId;}}} 9249const syntaxHighlightingEmbedding=__exports.syntaxHighlightingEmbedding={name:"syntaxHighlighting",Component:EmbeddedSyntaxHighlightingComponent,getProps:(host)=>({host,...getEmbeddedProps(host)}),getStateChangeManager:(config)=>new StateChangeManager(config),};return __exports;});; 9250 9251/* /html_editor/static/src/others/embedded_components/backend/video/video.js */ 9252odoo.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;} 9253this.videoSettingsOverlay.close();});onWillDestroy(()=>{this.videoSettingsOverlay?.close();});} 9254get url(){return getVideoUrl(this.state.platform,this.state.videoId,this.state.params).toString();} 9255replaceVideo(media){this.state.videoId=media.videoId;this.state.platform=media.platform;this.state.params=media.params;this.props.focusEditable();}} 9256const 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;} 9257this.props.overlay.close();});onWillUnmount(()=>{if(!this.props.videoBlock.isConnected){this.props.focusEditable();}});}} 9258return __exports;});; 9259 9260/* /html_editor/static/src/others/embedded_components/embedding_sets.js */ 9261odoo.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;});; 9262 9263/* /html_editor/static/src/others/embedded_components/plugins/caption_plugin/caption_plugin.js */ 9264odoo.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];} 9265return[];},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
9265)=>{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);} 9266figures.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);} 9267if(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();}} 9268onPaste(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;}} 9269getCaptionId(){return""+Math.floor(Math.random()*Date.now());} 9270hasImageCaption(image){if(!image){return;} 9271const block=closestBlock(image.parentElement);return block.nodeName==="FIGURE"&&!!block.querySelector(CAPTION_SPAN_SELECTOR);} 9272toggleImageCaption(image=this.dependencies.image.getTargetedImage()){if(!image){return;} 9273if(this.hasImageCaption(image)){this.removeImageCaption(image);}else{this.addImageCaption(image,image.getAttribute("data-caption")||"");this.dependencies.history.addStep();}} 9274addImageCaption(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();} 9275if(isBlock(block.nextSibling)&&!isVisible(block.nextSibling)){block.nextSibling.remove();}} 9276image.before(figure);figure.append(image);if(!link&&isParagraphRelatedElement(figure.parentElement)){unwrapContents(figure.parentElement);} 9277const 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);} 9278setupCaption(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);} 9279this.dependencies.selection.setCursorEnd(span);}} 9280removeImageCaption(image){const figure=closestElement(image,"figure");
9280if(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);}} 9281unwrapContents(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();}} 9282cleanForSave({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);}} 9283getImageName(image){if(closestElement(image,"figure")){return image.getAttribute("data-caption");}} 9284isLinkAllowedOnSelection(){const figure=findInSelection(this.dependencies.selection.getSelectionData().deepEditableSelection,"figure");
9284if(figure&&this.dependencies.selection.getTargetedNodes().every((node)=>closestElement(node,"figure")===figure)){return true;}} 9285onImageReplaced(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);} 9286this.dependencies.selection.setSelection({anchorNode,anchorOffset});}} 9287afterDelete(){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,});}}} 9288handleDeleteImage(image){const figure=closestElement(image,"figure");
9288if(figure){const sibling=figure.nextSibling||figure.previousSibling;figure.remove();this.dependencies.selection.setSelection({anchorNode:sibling,anchorOffset:0,});this.dependencies.history.addStep();return true;}} 9289expandSelectionToCaption(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});}} 9290processContentForClipboard(clonedContents,selection){if(clonedContents.firstChild.nodeName==="IMG"){clonedContents=selection.commonAncestorContainer.cloneNode(true);} 9291return clonedContents;}} 9292return __exports;});; 9293 9294/* /html_editor/static/src/others/embedded_components/plugins/embedded_file_plugin/embedded_file_documents_selector.js */ 9295odoo.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);}} 9296__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}),});} 9297return __exports;});; 9298 9299/* /html_editor/static/src/others/embedded_components/plugins/embedded_file_plugin/embedded_file_plugin.js */ 9300odoo.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);} 9301isUploadCommandAvailable({anchorNode}){return(super.isUploadCommandAvailable()&&!closestElement(anchorNode,"[data-embedded='clipboard']"));} 9302get componentForMediaDialog(){return EmbeddedFileDocumentsSelector;} 9303setupNewFile({name,env}){if(name==="file"){Object.assign(env.editorShared,{setSelectionAfter:(host)=>{try{const leaf=nextLeaf(host,this.editable);if(!leaf){return;} 9304const leafEl=isBlock(leaf)?leaf:leaf.parentElement;if(isBlock(leafEl)&&leafEl.isContentEditable){this.dependencies.selection.setSelection({anchorNode:leafEl,anchorOffset:0,});}}catch{return;}},});}}} 9305return __exports;});; 9306 9307/* /html_editor/static/src/others/embedded_components/plugins/syntax_highlighting_plugin/syntax_highlighting_plugin.js */ 9308odoo.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
9308otkeys/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);}});} 9309navigateAroundCodeBlock(ev){const isArrowUp=ev.key==="ArrowUp";const selection=this.dependencies.selection.getSelectionData().deepEditableSelection;if(!selection.isCollapsed){return;} 9310const anchorNode=selection.anchorNode;const currentBlock=closestBlock(anchorNode);const adjacentBlock=isArrowUp?currentBlock.previousElementSibling:currentBlock.nextElementSibling;if(!adjacentBlock?.matches(CODE_BLOCK_SELECTOR)){return;} 9311const 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);}} 9312cleanForSave(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);}} 9313addCodeBlocks(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();} 9314pre.remove();}} 9315setupNewCodeBlock({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");}}} 9316return __exports;});; 9317 9318/* /html_editor/static/src/others/embedded_components/plugins/table_of_content_plugin/table_of_content_plugin.js */ 9319odoo.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
9319)=>{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;} 9320insertTableOfContent(){const tableOfContentBlueprint=renderToElement("html_editor.TableOfContentBlueprint");this.dependencies.dom.insert(tableOfContentBlueprint);this.dependencies.history.addStep();} 9321cleanForSave({root}){for(const el of root.querySelectorAll(".o_embedded_toc_header_highlight")){el.classList.remove("o_embedded_toc_header_highlight");}} 9322destroy(){super.destroy();this.alive=false;} 9323delayedUpdateTableOfContents(element){const selector=HEADINGS.join(",");if(!(!element||this.manager.structure.headings.length||element.querySelector(selector)||element.closest(selector))){return;} 9324if(this.updateTimeout){window.clearTimeout(this.updateTimeout);} 9325this.updateTimeout=window.setTimeout(()=>{if(!this.alive){return;} 9326this.manager.updateStructure();},500);} 9327setupNewToc({name,props}){if(name==="tableOfContent"){Object.assign(props,{manager:this.manager,});}}} 9328return __exports;});; 9329 9330/* /html_editor/static/src/others/embedded_components/plugins/toggle_block_plugin/toggle_block_plugin.js */ 9331odoo.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();} 9332explodeToggle(toggle){const title=toggle.querySelector(titleSelector);const content=toggle.querySelector(contentSelector);let contentChildren=children(content);if(contentChildren.length===1&&isEmptyBlock(contentChildren[0])){contentChildren=[];} 9333toggle.replaceWith(...children(title),...contentChildren);} 9334forceToggle(toggle,{showContent,restoreSelection}={}){toggle.dispatchEvent(new CustomEvent("forceToggle",{detail:{showContent,restoreSelection}}));} 9335generateUniqueIds(toggles){for(const toggle of toggles){const props=getEmbeddedProps(toggle);props.toggleBlockId=this.getUniqueIdentifier();toggle.dataset.embeddedProps=JSON.stringify(props);}} 9336getClosestToggleContentInfo(node){const toggle=closestElement(node,toggleSelector);const title=toggle?.querySelector(titleSelector);const content=toggle?.querySelector(contentSelector);return content?.contains(node)?{content,title,toggle}:{};} 9337getClosestToggleTitleInfo(node){const toggle=closestElement(node,toggleSelector);const title=toggle?.querySelector(titleSelector);const content=toggle?.querySelector(contentSelector);return title?.contains(node)?{content,title,toggle}:{};} 9338getToggleFromTitleSelection(){const selection=this.dependencies.selection.getEditableSelection();if(!selection.anchorNode){return;} 9339const{toggle}=this.getClosestToggleTitleInfo(selection.anchorNode);return toggle;} 9340getUniqueIdentifier(){return uuid();} 9341getAdjacentToggleBlock(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`];} 9342return sibling?.matches(toggleSelector)?sibling:null;} 9343handleDeleteBackward(range){for(const handler of[this.handleDeleteBackwardTitleStart,this.handleDeleteBackwardContentEnd,this.handleDeleteBackwardContentStart,this.handleDeleteBackwardAfterToggle,]){if(handler.call(this,range)){return true;}}} 9344handleDeleteBackwardContentEnd({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;} 9345toggle.after(block);this.dependencies.selection.setCursorStart(block);return true;} 9346handleDeleteBackwardContentStart({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;} 9347title.append(block);this.dependencies.selection.setCursorStart(block);this.dependencies.delete.deleteBackward(this.dependencies.selection.getEditableSelection(),"character");return true;} 9348handleDeleteBackwardTitleStart({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;} 9349const cursors=this.dependencies.selection.preserveSelection();this.explodeToggle(toggle);
9349cursors.restore();return true;} 9350handleDeleteBackwardAfterToggle({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;} 9351let target=toggle.querySelector(contentSelector);if(target.parentElement.matches(".d-none")){if(!isParagraphRelatedElement(block)){return;} 9352const title=toggle.querySelector(titleSelector);target=title;} 9353target.append(block);this.dependencies.selection.setCursorStart(block);this.preventDeleteBackwardContentEnd=true;this.dependencies.delete.deleteBackward(this.dependencies.selection.getEditableSelection(),"character");this.preventDeleteBackwardContentEnd=false;return true;} 9354handleDeleteForward(range){for(const handler of[this.handleDeleteForwardTitleEnd,this.handleDeleteForwardContentEnd,this.handleDeleteForwardBeforeToggle,]){if(handler.call(this,range)){return true;}}} 9355handleDeleteForwardContentEnd({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;} 9356let nextEl=this.getAdjacentToggleBlock(toggle,"next");if(nextEl){this.explodeToggle(nextEl);nextEl=toggle.nextSibling;} 9357if(!isParagraphRelatedElement(nextEl)){return;} 9358content.append(nextEl);this.dependencies.selection.setCursorEnd(block);this.dependencies.delete.deleteForward(this.dependencies.selection.getEditableSelection(),"character");return true;} 9359handleDeleteForwardTitleEnd({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;} 9360let 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;} 9361if(nextEl?.matches?.(toggleSelector)){this.explodeToggle(nextEl);nextEl=content.firstChild;}} 9362if(nextEl&&(isTextNode(nextEl)||isParagraphRelatedElement(nextEl))){title.append(nextEl);this.dependencies.selection.setCursorEnd(block);this.dependencies.delete.deleteForward(this.dependencies.selection.getEditableSelection(),"character");return true;}} 9363handleDeleteForwardBeforeToggle({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;} 9364if(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");} 9365return true;} 9366handleInsert(insertContainer){const insertedToggles=insertContainer.querySelectorAll(toggleSelector);this.generateUniqueIds(insertedToggles);return insertContainer;} 9367handleShiftTab(){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();} 9368containerContent.append(...siblings);closestToggleAncestor.after(toggle);this.forceToggle(toggle,{showContent:true,restoreSelection:cursors.restore});this.dependencies.history.addStep();} 9369return true;}} 9370handleSplitElementBlock({targetNode,targetOffset,blockToSplit}){const{toggle,title,content}=this.getClosestToggleTitleInfo(targetNode);
9370if(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));} 9371const 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);} 9372this.dependencies.selection.setCursorStart(baseContainer);return true;} 9373const 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);} 9374if(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);}} 9375this.dependencies.selection.setCursorStart(afterSplit);} 9376return true;}} 9377handleTab(){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);} 9378const content=toggle.querySelector(contentSelector);if(!content.parentElement.matches(".d-none")){toggle.after(...children(content));} 9379this.forceToggle(previousToggleBlock,{showContent:true,restoreSelection:cursors.restore,});this.dependencies.history.addStep();} 9380return true;}} 9381insertToggleBlock(){const block=this.renderToggleBlock();const target=block.querySelector(`${titleSelector} > ${baseContainerGlobalSelector}`);this.dependencies.dom.insert(block);this.dependencies.selection.setCursorStart(target);this.dependencies.history.addStep();} 9382manageToggleFromTitle(){const toggle=this.getToggleFromTitleSelection();if(!toggle){return;} 9383this.forceToggle(toggle);} 9384normalize(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;} 9385if(!isParagraphRelatedElement(titleChild)){toggle.after(titleChild);shouldRestoreCursor=true;}} 9386if(shouldRestoreCursor){cursors.restore();} 9387for(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);}} 9388renderToggleBlock(){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()}),}));} 9389showPowerButtons(selection){return(selection.isCollapsed&&!closestElement(selection.anchorNode,`${toggleSelector} ${titleSelector}`));}} 9390return __exports;});; 9391 9392/* /html_editor/static/src/others/embedded_components/plugins/video_plugin/embedded_video_plugin.js */ 9393odoo.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"];
9393resources={...this.resources,mount_component_handlers:this.extendEmbeddedVideoProps.bind(this),};get componentForMediaDialog(){return EmbeddedVideoSelector;} 9394extendEmbeddedVideoProps({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);},});}} 9395openVideoSelectorDialog(save,iframe){this.dependencies.media.openMediaDialog({node:iframe,save:(elements,[media])=>{if(media.src){save(media);}},visibleTabs:["VIDEOS"],});}} 9396return __exports;});; 9397 9398/* /html_editor/static/src/others/embedded_components/plugins/video_plugin/embedded_youtube_plugin.js */ 9399odoo.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];}} 9400return __exports;});; 9401 9402/* /html_editor/static/src/others/embedded_components/plugins/video_plugin/video_selector_dialog/embedded_video_selector.js */ 9403odoo.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||{},}),}));}} 9404return __exports;});; 9405 9406/* /html_editor/static/src/others/embedded_component_plugin.js */ 9407odoo.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;} 9408return result;});} 9409isMutationRecordSavable(record){const info=this.nodeMap.get(record.target);if(info&&record.type==="attributes"&&record.attributeName==="data-embedded-props"){return false;} 9410return true;} 9411processDescendantsToSerialize(elem,serializableDescendants){const embedding=this.getEmbedding(elem);if(!embedding){return serializableDescendants;} 9412return Object.values(embedding.getEditableDescendants?.(elem)||{}).map(nodeToTree);} 9413handleComponents(elem){this.destroyRemovedComponents([...this.components]);this.forEachEmbeddedComponentHost(elem,(host,embedding)=>{const info=this.nodeMap.get(host);if(!info){this.mountComponent(host,embedding);}});} 9414forEachEmbeddedComponentHost(elem,callback){const selector=`[data-embedded]`;const targets=[...elem.querySelectorAll(selector)];if(elem.matches(selector)){targets.unshift(elem);} 9415for(const host of targets){const embedding=this.getEmbedding(host);if(!embedding){continue;} 9416callback(host,embedding);}} 9417getEmbedding(host){return this.embeddedComponents(this.getResource("embedded_components"))[host.dataset.embedded];} 9418onChangeAttribute(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,});}} 9419return newAttributeValue||attributeValue;} 9420getStateChangeManager(host){const embedding=this.getEmbedding(host);if(!("getStateChangeManager"in embedding)){return null;} 9421if(!this.hostToStateChangeManagerMap.has(host)){const config={host,commitStateChanges:()=>this.dependencies.history.addStep(),};const stateChangeManager=embedding.getStateChangeManager(config);stateChangeManager.setup();this.hostToStateChangeManagerMap.set(host,stateChangeManager);} 9422return this.hostToStateChangeManagerMap.get(host);} 9423mountComponent(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);} 9424if(getEditableDescendants){env.getEditableDescendants=getEditableDescendants;Object.assign(env.editorShared,{selection:{...this.dependencies.selection},});} 9425this.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);} 9426const info={root,host,};this.components.add(info);this.nodeMap.set(host,info);} 9427destroyRemovedComponents(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);
9427if(parentNode){parentNode.replaceChild(clone,host);} 9428host.style.display="none";this.editable.after(host);this.destroyComponent(info);if(parentNode){parentNode.replaceChild(host,clone);}else{host.remove();} 9429host.style.display=display;if(!host.getAttribute("style")){host.removeAttribute("style");}}}});} 9430deepDestroyComponent({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);} 9431destroyComponent({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));} 9432destroy(){super.destroy();for(const info of[...this.components]){if(this.components.has(info)){this.deepDestroyComponent(info);}}} 9433renderBlueprintToElement(template,context={},onComponentInserted=undefined){const host=renderToElement(template,context);if(onComponentInserted){this.hostToOnComponentInsertedMap.set(host,onComponentInserted);} 9434return host;} 9435extractOnComponentInserted(host){const onComponentInserted=this.hostToOnComponentInsertedMap.get(host);this.hostToOnComponentInsertedMap.delete(host);return onComponentInserted;} 9436normalize(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);}});} 9437cleanForSave(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);} 9438delete host.dataset.oeProtected;delete host.dataset.embeddedState;});} 9439preProcessSanitizedElem(elem){if(elem?.nodeType!==Node.ELEMENT_NODE){return elem;} 9440for(const host of selectElements(elem,"[data-embedded-props], [data-embedded-state]")){if(host.dataset.embeddedProps){host.dataset.embeddedProps=encodeURIComponent(host.dataset.embeddedProps);} 9441if(host.dataset.embeddedState){host.dataset.embeddedState=encodeURIComponent(host.dataset.embeddedState);}} 9442return elem;}
9443postProcessSanitizedElem(elem){if(elem?.nodeType!==Node.ELEMENT_NODE){return elem;} 9444for(const host of selectElements(elem,"[data-embedded-props], [data-embedded-state]")){if(host.dataset.embeddedProps){host.dataset.embeddedProps=decodeURIComponent(host.dataset.embeddedProps);} 9445if(host.dataset.embeddedState){host.dataset.embeddedState=decodeURIComponent(host.dataset.embeddedState);}} 9446return elem;}} 9447return __exports;});; 9448 9449/* /html_editor/static/src/others/qweb_picker.js */ 9450odoo.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});} 9451onChange(ev){const[groupIndex,elementIndex]=ev.target.value.split(",");this.props.select(this.state.groups[groupIndex][elementIndex].node);}} 9452return __exports;});; 9453 9454/* /html_editor/static/src/others/qweb_plugin.js */ 9455odoo.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;} 9456isValidTargetForDomListener(ev){if(ev.type==="click"&&ev.target&&closestElement(ev.target,PROTECTED_QWEB_SELECTOR)){return true;} 9457return super.isValidTargetForDomListener(ev);} 9458onSelectionChange(){if(this.picker.isOpen){this.picker.close();}} 9459normalize(root){this.normalizeInline(root);for(const element of selectElements(root,PROTECTED_QWEB_SELECTOR)){this.dependencies.protectedNode.setProtectingNode(element,true);} 9460this.applyGroupQwebBranching(root);} 9461checkAllInline(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");}});} 9462normalizeInline(root){const targets=[...root.querySelectorAll("t")];if(root.matches("t")){targets.unshift(root);} 9463for(const el of targets.filter((el)=>this.checkAllInline(el))){el.setAttribute("data-oe-t-inline","true");}} 9464getNodeGroups(node){const branchNode=node.closest("[data-oe-t-group]");if(!branchNode){return[];} 9465const 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";} 9466group.push({groupId,node,label,isActive:node.getAttribute("data-oe-t-group-active")==="true",});} 9467return this.getNodeGroups(branchNode.parentElement).concat([group]);} 9468onClick(ev){if(this.picker.isOpen){this.picker.close();} 9469if(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
9469sNode,focusOffset,});}} 9470const targetNode=ev.target;if(targetNode.closest("[data-oe-t-group]")){this.selectNode(targetNode);}} 9471selectNode(node){const editableSelection=this.dependencies.selection.getSelectionData().editableSelection;if(!editableSelection.isCollapsed){return;} 9472this.selectedNode=node;this.picker.open({target:node,props:{groups:this.getNodeGroups(node),select:this.select.bind(this),},});} 9473applyGroupQwebBranching(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++;} 9474groupsEncounter.add(groupId);node.setAttribute("data-oe-t-group",groupId);} 9475for(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");}}} 9476select(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;} 9477activeElement.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();} 9478clearDataAttributes(root){for(const node of root.querySelectorAll(dataAttributesSelector)){QWEB_DATA_ATTRIBUTES.forEach((attr)=>node.removeAttribute(attr));}}} 9479return __exports;});; 9480 9481/* /html_editor/static/src/services/upload_local_files_service.js */ 9482odoo.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;} 9483async function filesToAttachments(files,{resModel,resId},setAbortCallback){const attachments=[];await uploadService.uploadFiles(files,{resModel,resId},(attachment)=>{attachments.push(attachment);},setAbortCallback);return attachments;} 9484async 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);} 9485return attachments;}catch{return[];}} 9486async 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;} 9487function getURL(attachment,{unique,download,accessToken}={}){let url=`/web/content/${attachment.id}`;const queryParams=[];if(unique){queryParams.push(`unique=${encodeURIComponent(attachment.checksum)}`);} 9488if(download){queryParams.push("download=true");} 9489if(accessToken&&attachment.access_token){queryParams.push(`access_token=${attachment.access_token}`);} 9490if(queryParams.length){url+=`?${queryParams.join("&")}`;} 9491return url;} 9492return{upload,addAccessToken,getURL};},};registry.category("services").add("uploadLocalFiles",uploadLocalFileService);return __exports;});; 9493 9494/* /mail/static/src/model/export.js */ 9495odoo.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;});; 9496 9497/* /mail/static/src/model/make_store.js */ 9498odoo.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}
9498=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()})`);} 9499const 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);} 9500return res;} 9501if(Model._.fieldsCompute.get(name)&&!Model._.fieldsEager.get(name)){record._.fieldsComputeInNeed.set(name,true);if(record._.fieldsComputeOnNeed.get(name)){record._.compute(record,name);}} 9502if(Model._.fieldsSort.get(name)&&!Model._.fieldsEager.get(name)){record._.fieldsSortInNeed.set(name,true);if(record._.fieldsSortOnNeed.get(name)){record._.sort(record,name);}} 9503record._.gettingField=true;const val=recordFullProxy[name];record._.gettingField=false;if(isRelation(Model,name)){const recordListFullProxy=val._proxy;if(isMany(Model,name)){return recordListFullProxy;} 9504return recordListFullProxy[0];} 9505return 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;} 9506return Reflect.deleteProperty(record,name);});},set(record,name,val,receiver){if(record._.updatingAttrs.has(name)){record[name]=val;return true;} 9507return store.MAKE_UPDATE(function recordSet(){const reactiveSet=receiver!==record._proxyInternal;if(reactiveSet){record._.proxyUsed.set(name,true);} 9508store._.updateFields(record,{[name]:val});if(reactiveSet){record._.proxyUsed.delete(name);} 9509return 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;} 9510for(const name of Model._.fields.keys()){record._.prepareField(record,name,recordProxy);} 9511return 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);}}} 9512for(const Model of Object.values(Models)){for(const name of Model._.fields.keys()){if(!isRelation(Model,name)){continue;} 9513const targetModel=Model._.fieldsTargetModel.get(name);const inverse=Model._.fieldsInverse.get(name);if(targetModel&&!Models[targetModel]){throw new Error(`No target model ${targetModel} exists`);} 9514if(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[ 9515 targetModel 9516 ].getName()}.${inverse} has wrong targetModel. Expected: "${Model.getName()}" Actual: "${rel2TargetModel}"`);} 9517if(rel2Inverse&&rel2Inverse!==name){throw new Error(`Fields ${Models[ 9518 targetModel 9519 ].getName()}.${inverse} has wrong inverse. Expected: "${name}" Actual: "${rel2Inverse}"`);} 9520OtherModel._.fieldsTargetModel.set(inverse,Model.getName());OtherModel._.fieldsInverse.set(inverse,name);Model._.fieldsEager.set(name,true);OtherModel._.fieldsEager.set(inverse,true);}}} 9521Object.assign(store.Store,{store,_rawStore:store});
9521store=toRaw(store.Store.insert())._raw;for(const Model of Object.values(Models)){Model._rawStore=store;Model.store=store._proxy;store._proxy[Model.getName()]=Model;} 9522Object.assign(store,{Models,storeReady:true});return store._proxy;} 9523return __exports;});; 9524 9525/* /mail/static/src/model/misc.js */ 9526odoo.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];} 9527__exports.OR=OR;function OR(...args){return[OR_SYM,...args];} 9528__exports.isCommand=isCommand;function isCommand(data){return["ADD","DELETE","ADD.noinv","DELETE.noinv"].includes(data?.[0]?.[0]);} 9529__exports.isOne=isOne;function isOne(Model,fieldName){return Model._.fieldsOne.get(fieldName);} 9530__exports.isMany=isMany;function isMany(Model,fieldName){return Model._.fieldsMany.get(fieldName);} 9531__exports.isRecord=isRecord;function isRecord(record){return Boolean(record?._?.[IS_RECORD_SYM]);} 9532__exports.isRelation=isRelation;function isRelation(Model,fieldName){return isMany(Model,fieldName)||isOne(Model,fieldName);} 9533__exports.isFieldDefinition=isFieldDefinition;function isFieldDefinition(val){return val?.[FIELD_DEFINITION_SYM];} 9534const 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;});; 9535 9536/* /mail/static/src/model/model_internal.js */ 9537odoo.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);} 9538if(data[ONE_SYM]){this.fieldsOne.set(fieldName,true);} 9539if(data[MANY_SYM]){this.fieldsMany.set(fieldName,true);} 9540for(const key in data){const value=data[key];switch(key){case"html":{if(!value){break;} 9541this.fieldsHtml.set(fieldName,value);break;} 9542case"targetModel":{this.fieldsTargetModel.set(fieldName,value);break;} 9543case"compute":{this.fieldsCompute.set(fieldName,value);break;} 9544case"eager":{if(!value){break;} 9545this.fieldsEager.set(fieldName,value);break;} 9546case"sort":{this.fieldsSort.set(fieldName,value);break;} 9547case"inverse":{this.fieldsInverse.set(fieldName,value);break;} 9548case"onAdd":{this.fieldsOnAdd.set(fieldName,value);break;} 9549case"onDelete":{this.fieldsOnDelete.set(fieldName,value);break;} 9550case"onUpdate":{this.fieldsOnUpdate.set(fieldName,value);break;} 9551case"type":{this.fieldsType.set(fieldName,value);break;}}}}} 9552return __exports;});; 9553 9554/* /mail/static/src/model/record.js */ 9555odoo.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);} 9556static onChange(record,name,cb){return this.store.onChange(...arguments);} 9557static get(data){const Model=toRaw(this);return this.records[Model.localId(data)];} 9558static getName(){return this._name||this.name;} 9559static register(localRegistry){if(localRegistry){localRegistry.add(this.getName(),this);}else{modelRegistry.add(this.getName(),this);}} 9560static localId(data){const Model=toRaw(this);let idStr;if(typeof data==="object"&&data!==null){idStr=Model._localId(Model.id,data);}else{idStr=data;} 9561return`${Model.getName()},${idStr}`;} 9562get localId(){return toRaw(this)._.localId;} 9563static _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");} 9564if(!isRelation(Model,expr)){return data[expr];} 9565if(isCommand(data[expr])){const[cmd,data2]=data[expr].at(-1);if(cmd==="DELETE"){return undefined;}else{return`(${data2?.localId})`;}} 9566if(isRecord(data[expr])){return`(${data[expr]?.localId})`;} 9567const TargetModelName=Model._.fieldsTargetModel.get(expr);return`(${Model.store[TargetModelName].get(data[expr])?.localId})`;} 9568return data[expr];} 9569const vals=[];for(let i=1;i<expr.length;i++){vals.push(Model._localId(expr[i],data,{brackets:true}));} 9570let res=vals.join(expr[0]===OR_SYM?" OR ":" AND ");if(brackets){res=`(${res})`;} 9571return res;} 9572static _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,});} 9573return Object.assign(res,{[expr2]:data[expr2]});} 9574if(expr2 instanceof Array){for(const expr of this.id){if(typeof expr==="symbol"){continue;} 9575_deepRetrieve(expr);}}}
9576if(Model.id===undefined){return res;} 9577if(typeof Model.id==="string"){if(typeof data!=="object"||data===null){return{[Model.id]:data};} 9578if(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,});} 9579return{[Model.id]:data[Model.id]};} 9580for(const expr of Model.id){if(typeof expr==="symbol"){continue;} 9581_deepRetrieve(expr);} 9582return res;} 9583static 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,});} 9584Model._rawStore.recordByLocalId.set(record.localId,recordProxy);for(const fieldName of record.Model._.fields.keys()){record._.requestCompute?.(record,fieldName);record._.requestSort?.(record,fieldName);} 9585return recordProxy;});} 9586static 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];} 9587const res=data.map(function RecordInsertMap(d){return Model._insert.call(ModelFullProxy,d,options);});if(!isMulti){return res[0];} 9588return res;});} 9589static _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;} 9590static 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]);}} 9591return Model.get.call(ModelFullProxy,data)??Model.new(data,ids);} 9592get store(){return toRaw(this)._raw.Model._rawStore._proxy;} 9593get _rawStore(){return toRaw(this)._raw.Model._rawStore;} 9594Model;_raw;_proxyInternal;_proxy;setup(){} 9595update(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!`);} 9596store._.updateFields(record,{[record.Model.id]:data});}});} 9597delete(){const record=toRaw(this)._raw;const store=record._rawStore;return store.MAKE_UPDATE(function recordDelete(){store._.ADD_QUEUE("delete",record);});} 9598exists(){return!this[IS_DELETED_SYM];} 9599eq(record){return toRaw(this)._raw===toRaw(record)?._raw;} 9600notEq(record){return!this.eq(record);} 9601in(collection){if(!collection){return false;} 9602return collection.some((record)=>toRaw(record)._raw.eq(this));} 9603notIn(collection){return!this.in(collection);} 9604toData(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}`);} 9605this._toData(ongoing,prefix);return ongoing.storeData;} 9606_cleanupData(data){const fieldsToDelete=["_","_fieldsValue","_proxy","_proxyInternal","_raw","env","Model",];fieldsToDelete.forEach((field)=>delete data[field]);} 9607_getActualModelName(){return this.Model.getName();} 9608_toData(ongoing,prefix=undefined){if(ongoing.depth&&ongoing.seenRecords.has(this.localId)){return;} 9609ongoing.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;} 9610const 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;}}} 9611this._cleanupData(data);const pyModelName=record._getActualModelName();ongoing.storeData[pyModelName]||=[];ongoing.storeData[pyModelName].push(data);} 9612_toDataRelationalRecord(ongoing,prefix=undefined){const data=this.Model._retrieveIdFromData(this);if(ongoing.depth||ongoing.fields?.some((field)=>field.startsWith(prefix))){this._toData(ongoing,prefix);}
9613for(const[name,val]of Object.entries(data)){if(isRecord(val)){data[name]=val._toDataRelationalRecord(ongoing,prefix);}} 9614return data;}} 9615Record.register();return __exports;});; 9616 9617/* /mail/static/src/model/record_internal.js */ 9618odoo.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;} 9619if(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);} 9620const cb=function computeObserver(){self.requestCompute(record,fieldName);};const computeProxy2=reactive(recordProxy,cb);this.fieldsComputeProxy2.set(fieldName,computeProxy2);} 9621if(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);} 9622const sortProxy2=reactive(recordProxy,function sortObserver(){self.requestSort(record,fieldName);});this.fieldsSortProxy2.set(fieldName,sortProxy2);} 9623if(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);}});}} 9624requestCompute(record,fieldName,{force=false}={}){if(record[IS_DELETED_SYM]){return;} 9625const Model=record.Model;if(!Model._.fieldsCompute.get(fieldName)){return;} 9626const 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);}}} 9627requestSort(record,fieldName,{force}={}){if(record[IS_DELETED_SYM]){return;} 9628const Model=record.Model;if(!Model._.fieldsSort.get(fieldName)){return;} 9629const 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);}}} 9630compute(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);} 9631store._.updateFields(record,{[fieldName]:computedValue,});this.fieldsComputing.delete(fieldName);} 9632sort(record,fieldName){const Model=record.Model;if(!Model._.fieldsSort.get(fieldName)){return;} 9633const 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);
9633if(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;}} 9634this.fieldsSorting.delete(fieldName);} 9635onUpdate(record,fieldName){const store=record._rawStore;const Model=record.Model;if(!Model._.fieldsOnUpdate.get(fieldName)){return;} 9636try{Model._.fieldsOnUpdate.get(fieldName).call(record._proxyInternal);}catch(err){store.handleError(err);} 9637this.fieldsOnUpdateObserves.get(fieldName)?.();} 9638downgradeProxy(record,fullProxy){return record._proxy===fullProxy?record._proxyInternal:fullProxy;}} 9639return __exports;});; 9640 9641/* /mail/static/src/model/record_list.js */ 9642odoo.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);} 9643function getTargetModel(reclist){return reclist._.owner.Model._.fieldsTargetModel.get(reclist._.name);} 9644function isComputeField(reclist){return reclist._.owner.Model._.fieldsCompute.get(reclist._.name);} 9645function isSortField(reclist){return reclist._.owner.Model._.fieldsSort.get(reclist._.name);} 9646function isEager(reclist){return reclist._.owner.Model._.fieldsEager.get(reclist._.name);} 9647function setComputeInNeed(reclist){reclist._.owner._.fieldsComputeInNeed.set(reclist._.name,true);} 9648function setSortInNeed(reclist){reclist._.owner._.fieldsSortInNeed.set(reclist._.name,true);} 9649function isComputeOnNeed(reclist){return reclist._.owner._.fieldsComputeOnNeed.get(reclist._.name);} 9650function isSortOnNeed(reclist){return reclist._.owner._.fieldsSortOnNeed.get(reclist._.name);} 9651function computeField(reclist){reclist._.owner._.compute(reclist._.owner,reclist._.name);} 9652function sortField(reclist){reclist._.owner._.sort(reclist._.owner,reclist._.name);} 9653function isOne(reclist){return reclist._.owner.Model._.fieldsOne.get(reclist._.name);} 9654const 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;} 9655const 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;} 9656for(const val of records){if(isRecord(val)&&val.in(recordList)){continue;} 9657const 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);}} 9658assign(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);}}} 9659recordList._proxy.data=newRecords.map((newRecord)=>newRecord.localId);recordList._.syncLength(recordList);});} 9660deleteNoinv(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);}} 9661downgradeProxy(recordList,fullProxy){return recordList._proxy===fullProxy?recordList._proxyInternal:fullProxy;} 9662insert(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()}/${ 9663 recordList._.name 9664 }": target model "${targetModel}" doesn't support single-id data!`);} 9665val={[recordList._store[targetModel].id]:val};} 9666if(inverse&&inv){const target=isRecord(val)&&val._raw===val?val._proxy:val;target[inverse]=[[mode==="ADD"?"ADD.noinv":"DELETE.noinv",recordList._.owner]];} 9667let newRecordProxy;if(!isRecord(val)){newRecordProxy=recordList._store[targetModel].preinsert(val);}else{newRecordProxy=val;} 9668const newRecord=toRaw(newRecordProxy)._raw;fn?.(newRecord);if(!isRecord(val)){recordList._store[targetModel].insert(val);} 9669return newRecord;} 9670syncLength(reclist){reclist.length=reclist.data.length;}} 9671const 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);} 9672return res;} 9673if(isComputeField(recordList)&&!isEager(recordList)){setComputeInNeed(recordList);if(isComputeOnNeed(recordList)){computeField(recordList);}} 9674if(name==="length"){return recordListFullProxy.data.length;} 9675if(isSortField(recordList)&&!isEager(recordList)){setSortInNeed(recordList);if(isSortOnNeed(recordList)){sortField(recordList);}} 9676if(typeof name!=="symbol"&&!window.isNaN(parseInt(name))){const index=
9676parseInt(name);return recordListFullProxy._store.recordByLocalId.get(recordListFullProxy.data[index]);} 9677const 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);} 9678store._.ADD_QUEUE("onDelete",recordList._.owner,recordList._.name,oldRecord);const inverse=getInverse(recordList);if(inverse){oldRecord[inverse].delete(recordList._.owner);} 9679if(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);} 9680recordListProxy.data.length=newLength;recordList._.syncLength(recordList);}}else{return Reflect.set(recordList,name,val,recordListProxy);} 9681return true;});},});recordList._proxyInternal=recordListProxyInternal;recordList._proxy=reactive(recordListProxyInternal);return recordList;} 9682push(...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);}} 9683return recordListFullProxy.data.length;});} 9684pop(){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);} 9685return oldRecordProxy;});} 9686shift(){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;} 9687const 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);} 9688return recordProxy;});} 9689unshift(...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);}} 9690return recordListFullProxy.data.length;});} 9691indexOf(recordProxy){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);return recordListFullProxy.data.indexOf(toRaw(recordProxy)?._raw.localId);} 9692splice(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
9692ordList.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;} 9693recordList._.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);}} 9694for(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);}}});} 9695sort(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;});} 9696concat(...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]));} 9697add(...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;} 9698return recordList._.insert(recordList,last,function recordListAddInsertOne(record){if(record.localId!==recordList.data[0]){recordList.splice.call(recordList._proxy,0,1,record);}});} 9699const res=[];for(const val of records){if(isRecord(val)&&recordList.data.includes(val.localId)){continue;} 9700const rec=recordList._.insert(recordList,val,function recordListAddInsertMany(record){if(recordList.data.indexOf(record.localId)===-1){recordList.push.call(recordList._proxy,record);}});res.push(rec);} 9701return res.length===1?res[0]:res;});} 9702delete(...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"});}});} 9703clear(){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);}}
9703 9704at(index){const recordList=toRaw(this)._raw;const recordListFullProxy=recordList._.downgradeProxy(recordList,this);return recordListFullProxy._store.recordByLocalId.get(recordListFullProxy.data.at(index));}} 9705return __exports;});; 9706 9707/* /mail/static/src/model/record_uses.js */ 9708odoo.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());} 9709const use=this.data.get(record.localId);if(!use.get(list._.name)){use.set(list._.name,0);} 9710use.set(list._.name,use.get(list._.name)+1);} 9711delete(list){const record=list._.owner;if(!this.data.has(record.localId)){return;} 9712const use=this.data.get(record.localId);if(!use.get(list._.name)){return;} 9713use.set(list._.name,use.get(list._.name)-1);if(use.get(list._.name)===0){use.delete(list._.name);}}} 9714return __exports;});; 9715 9716/* /mail/static/src/model/store.js */ 9717odoo.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);} 9718handleError(err){this._.ERRORS.push(err);} 9719warnErrors=true;MAKE_UPDATE(fn){this._.UPDATE++;let res;try{res=fn();}catch(err){this.handleError(err);} 9720this._.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});}} 9721while(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});}} 9722while(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);}}}} 9723while(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);}}}} 9724while(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);}} 9725while(RO_QUEUE.size>0){const cb=RO_QUEUE.keys().next().value;RO_QUEUE.delete(cb);try{cb();}catch(err){this.handleError(err);}} 9726while(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;} 9727for(let c=0;c<count;c++){usingRecord[name2].delete(record);}}} 9728deletingRecordsByLocalId.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];}} 9729this._.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);}} 9730const[error1]=this._.ERRORS;
9730this._.ERRORS=[];throw error1;}} 9731return res;} 9732insert(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;} 9733const insertData=[];for(const vals of Array.isArray(data)?data:[data]){const extraFields=storeInsertFns.getExtraFieldsFromModel(store,pyOrJsModelName);if(extraFields){Object.assign(vals,extraFields);} 9734if(vals._DELETE){delete vals._DELETE;recordsDataToDelete.push([modelName,vals]);}else{insertData.push(vals);}} 9735store[modelName].insert(insertData,options);} 9736for(const[modelName,vals]of recordsDataToDelete){store[modelName].get(vals)?.delete();}});} 9737onChange(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();}});} 9738_onChange(record,key,callback){let proxy;function _observe(){const val=proxy[key];if(typeof val==="object"&&val!==null){void Object.keys(val);} 9739if(Array.isArray(val)){void val.length;void toRaw(val).forEach.call(val,(i)=>i);}} 9740if(Array.isArray(key)){for(const k of key){this._onChange(record,k,callback);} 9741return;} 9742let ready=true;proxy=reactive(record,()=>{if(ready){callback(_observe);}});_observe();return()=>{ready=false;};} 9743_cleanupData(data){super._cleanupData(data);if(this._getActualModelName()==="Store"){delete data.Models;for(const[name]of modelRegistry.getEntries()){delete data[name];}}}} 9744return __exports;});; 9745 9746/* /mail/static/src/model/store_internal.js */ 9747odoo.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);} 9748break;} 9749case"compute":{const[record,fieldName]=params;let recMap=this.FC_QUEUE.get(record);if(!recMap){recMap=new Map();this.FC_QUEUE.set(record,recMap);} 9750recMap.set(fieldName,true);break;} 9751case"sort":{const[record,fieldName]=params;let recMap=this.FS_QUEUE.get(record);if(!recMap){recMap=new Map();this.FS_QUEUE.set(record,recMap);} 9752recMap.set(fieldName,true);break;} 9753case"onAdd":{const[record,fieldName,addedRec]=params;const Model=record.Model;if(Model._.fieldsSort.get(fieldName)){this.ADD_QUEUE("sort",record,fieldName);} 9754if(!Model._.fieldsOnAdd.get(fieldName)){return;} 9755let recMap=this.FA_QUEUE.get(record);if(!recMap){recMap=new Map();this.FA_QUEUE.set(record,recMap);} 9756let fieldMap=recMap.get(fieldName);if(!fieldMap){fieldMap=new Map();recMap.set(fieldName,fieldMap);} 9757fieldMap.set(addedRec,true);break;} 9758case"onDelete":{const[record,fieldName,removedRec]=params;const Model=record.Model;if(!Model._.fieldsOnDelete.get(fieldName)){return;} 9759let recMap=this.FD_QUEUE.get(record);if(!recMap){recMap=new Map();this.FD_QUEUE.set(record,recMap);} 9760let fieldMap=recMap.get(fieldName);if(!fieldMap){fieldMap=new Map();recMap.set(fieldName,fieldMap);} 9761fieldMap.set(removedRec,true);break;} 9762case"onUpdate":{const[record,fieldName]=params;let recMap=this.FU_QUEUE.get(record);if(!recMap){recMap=new Map();this.FU_QUEUE.set(record,recMap);} 9763recMap.set(fieldName,true);break;}}} 9764sortRecordList(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);
9764const hasChanged=recordList.data.some((localId,i)=>localId!==data[i]);if(hasChanged){recordListFullProxy.data=data;}} 9765updateAttr(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);} 9766shouldChange=!record[fieldName]||!value.equals(record[fieldName]);} 9767if(fieldType==="date"&&value){if(!(value instanceof luxon.DateTime)){value=deserializeDate(value);} 9768shouldChange=!record[fieldName]||!value.equals(record[fieldName]);} 9769let 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;} 9770if(shouldChange){record._.updatingAttrs.set(fieldName,true);targetRecord[fieldName]=newValue;record._.updatingAttrs.delete(fieldName);}} 9771updateFields(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);}}} 9772updateRelation(record,fieldName,value){const recordList=record[fieldName];if(isMany(record.Model,fieldName)){this.updateRelationMany(recordList,value);}else{this.updateRelationOne(recordList,value);}} 9773updateRelationMany(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);}} 9774updateRelationOne(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);}}} 9775return __exports;});; 9776 9777/* /mail/static/src/core/common/action.js */ 9778odoo.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"));} 9779get params(){return{action:this,store:this.store,owner:this.owner};} 9780_badge(action){} 9781get badge(){return(this._badge(this.params)??(typeof this.definition.badge==="function"?this.definition.badge.call(this,this.params):this.definition.badge));} 9782_badgeIcon(action){} 9783get badgeIcon(){return(this._badgeIcon(this.params)??(typeof this.definition.badgeIcon==="function"?this.definition.badgeIcon.call(this,this.params):this.definition.badgeIcon));} 9784_badgeText(action){} 9785get badgeText(){return(this._badgeText(this.params)??(typeof this.definition.badgeText==="function"?this.definition.badgeText.call(this,this.params):this.definition.badgeText));} 9786_btnAttrs(action){} 9787get btnAttrs(){return(this._btnAttrs(this.params)??(typeof this.definition.btnAttrs==="function"?this.definition.btnAttrs.call(this,this.params):this.definition.btnAttrs));} 9788_btnClass(action){} 9789get btnClass(){return(this._btnClass(this.params)??(typeof this.definition.btnClass==="function"?this.definition.btnClass.call(this,this.params):this.definition.btnClass));} 9790_component(action){} 9791get component(){return this._component(this.params)??this.definition.component;} 9792_componentCondition(action){} 9793get componentCondition(){return(this._componentCondition(this.params)??(typeof this.definition.componentCondition==="function"?this.definition.componentCondition.call(this,this.params):this.definition.componentCondition??true));} 9794_componentProps(action){} 9795get componentProps(){return(this._componentProps(this.params)??this.definition.componentProps?.call(this,this.params));} 9796_condition(action){} 9797get condition(){return(this._condition(this.params)??(typeof this.definition.condition==="function"?this.definition.condition.call(this,this.params):this.definition.condition??true));} 9798_disabledCondition(action){} 9799get disabledCondition(){return Boolean(this._disabledCondition(this.params)??this.definition.disabledCondition?.call(this,this.params));} 9800_dropdown(action){} 9801get dropdown(){return this._dropdown(this.params)??this.definition.dropdown;} 9802_dropdownComponent(action){} 9803get 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));} 9804_dropdownComponentProps(action){} 9805get dropdownComponentProps(){return(this._dropdownComponentProps(this.params)??(typeof this.definition.dropdownComponentProps==="function"?this.definition.dropdownComponentProps.call(this,this.params):this.definition.dropdownComponentProps));} 9806_dropdownMenuClass(action){} 9807get dropdownMenuClass(){return(this._dropdownMenuClass(this.params)??(typeof this.definition.dropdownMenuClass==="function"?this.definition.dropdownMenuClass.call(this,this.params):this.definition.dropdownMenuClass));} 9808_dropdownPosition(action){} 9809get dropdownPosition(){return(this._dropdownPosition(this.params)??(typeof this.definition.dropdownPosition==="function"?this.definition.dropdownPosition.call(this,this.params):this.definition.dropdownPosition));} 9810_dropdownState(action){} 9811get dropdownState(){return(this._dropdownState(this.params)??(typeof this.definition.dropdownState==="function"?this.definition.dropdownState.call(this,this.params):this.definition.dropdownState));} 9812_dropdownTemplate(action){} 9813get dropdownTemplate(){return(this._dropdownTemplate(this.params)??(typeof this.definition.dropdownTemplate==="function"?this.definition.dropdownTemplate.call(this,this.params):this.definition.dropdownTemplate));} 9814_dropdownTemplateParams(action){} 9815get dropdownTemplateParams(){return(this._dropdownTemplateParams(this.params)??(typeof this.definition.dropdownTemplateParams==="function"?this.definition.dropdownTemplateParams.call(this,this.params):this.definition.dropdownTemplateParams));} 9816_hasBtnBg(action){} 9817get hasBtnBg(){return(this._hasBtnBg(this.params)??(typeof this.definition.hasBtnBg==="function"?this.definition.hasBtnBg.call(this,this.params):this.definition.hasBtnBg));} 9818_hotkey(action){} 9819get hotkey(){return(this._hotkey(this.params)??(typeof this.definition.hotkey==="function"?this.definition.hotkey.call(this,this.params):this.definition.hotkey));} 9820_icon(action){} 9821get icon(){return(this._icon(this.params)??(typeof this.definition.icon==="function"?this.definition.icon.call(this,this.params):this.definition.icon));} 9822_inlineName(action){} 9823get inlineName(){return(this._inlineName(this.params)??(typeof this.definition.inlineName==="function"?this.definition.inlineName.call(this,this.params):this.definition.inlineName)??false);} 9824_isActive(action){} 9825get isActive(){return(this._isActive(this.params)??(typeof this.definition.isActive==="function"?this.definition.isActive.call(this,this.params):this.definition.isActive));} 9826_name(action){} 9827get name(){return(this._name(this.params)??(typeof this.definition.name==="function"?this.definition.name.call(this,this.params):this.definition.name));} 9828_onSelected(action,ev){} 9829onSelected(ev){return(this._onSelected(this.params,ev)??this.definition.onSelected?.call(this,this.params,ev));} 9830_sequence(action){} 9831get sequence(){return(this._sequence(this.params)??(typeof this.definition.sequence==="function"?this.definition.sequence.call(this,this.params):this.definition.sequence));} 9832_sequenceGroup(action){} 9833get sequenceGroup(){return(this._sequenceGroup(this.params)??(typeof this.definition.sequenceGroup==="function"?this.definition.sequenceGroup.call(this,this.params):this.definition.sequenceGroup));} 9834_sequenceQuick(action){} 9835get sequenceQuick(){return(this._sequenceQuick(this.params)??(typeof this.definition.sequenceQuick==="function"?this.definition.sequenceQuick.call(this,this.params):this.definition.sequenceQuick));} 9836_setup(action){} 9837setup(){return this._setup(this.params)??this.definition.setup?.call(this,this.params);} 9838_tags(action){} 9839get 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];} 9840get tagClassNames(){return this.tags.map((tag)=>`o-tag-${tag}`).join(" ");}} 9841const 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;} 9842more(data={}
9842,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);} 9843return moreAction;} 9844get actions(){const actions=this.transformedActions.filter((action)=>action.condition).sort((a1,a2)=>a1.sequence-a2.sequence);return actions;} 9845get 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]=[];} 9846groups[a.sequenceGroup].push(a);} 9847const sortedGroups=Object.entries(groups).sort(([groupId1],[groupId2])=>groupId1-groupId2);for(const[,actions]of sortedGroups){actions.sort((a1,a2)=>a1.sequence-a2.sequence);} 9848const 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};}} 9849return __exports;});; 9850 9851/* /mail/static/src/core/common/action_list.js */ 9852odoo.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;} 9853get Dropdown(){if(this.env.inDiscussCallView?.isPip){return CallDropdown;} 9854return Dropdown;} 9855setup(){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();});}} 9856get action(){return this.props.action;} 9857get hasBtnBg(){return(this.props.odooControlPanelSwitchStyle||this.props.hasBtnBg||this.props.action.hasBtnBg);} 9858onSelected(action,ev){action.onSelected?.(ev);this.env.inCallDropdown?.close();}} 9859const 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}`,};} 9860setup(){super.setup();this.store=useService("mail.store");this.ui=useService("ui");this.actionListProps=actionListProps;} 9861get groups(){let groups;if(this.props.actions.find((i)=>Array.isArray(i))){groups=this.props.actions;}else{groups=[this.props.actions];} 9862return groups.filter((group)=>group.length);} 9863get hasBtnBg(){return this.props.odooControlPanelSwitchStyle||this.props.hasBtnBg;}} 9864return __exports;});; 9865 9866/* /mail/static/src/core/common/activity_model.js */ 9867odoo.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(),});} 9868return activity;} 9869id;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"])));}} 9870Activity.register();return __exports;});; 9871 9872/* /mail/static/src/core/common/attachment_list.js */ 9873odoo.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();}} 9874const 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();} 9875getImageUrl(attachment){if(attachment.uploading&&attachment.tmpUrl){return attachment.tmpUrl;} 9876return url(attachment.urlRoute,{...attachment.urlQueryParams,});} 9877canDownload(attachment){return!attachment.uploading&&!this.env.inComposer;} 9878onClickDownload(attachment){downloadFile(attachment.downloadUrl);} 9879onClickUnlink(attachment){if(this.env.inComposer){return this.props.unlinkAttachment(attachment);} 9880this.dialog.add(ConfirmationDialog,{body:_t('Do you really want to delete "%s"?',attachment.name),cancel:()=>{},confirm:()=>this.onConfirmUnlink(attachment),});} 9881onClickAttachment(attachment){this.fileViewer.open(attachment,this.props.attachments);} 9882onConfirmUnlink(attachment){this.props.unlinkAttachment(attachment);} 9883onImageLoaded(){this.env.onImageLoaded?.();} 9884get isInChatWindowAndIsAlignedRight(){return this.env.inChatWindow&&this.env.alignedRight;} 9885get isInChatWindowAndIsAlignedLeft(){return this.env.inChatWindow&&!this.env.alignedRight;} 9886getActions(attachment){const res=[];if(this.showDelete){res.push({label:_t("Remove"),icon:"fa fa-tras
9886h",onSelect:()=>this.onClickUnlink(attachment),});} 9887if(this.canDownload(attachment)){res.push({label:_t("Download"),icon:"fa fa-download",onSelect:()=>this.onClickDownload(attachment),});} 9888return res;} 9889get showDelete(){if(this.env.inComposer){return true;} 9890if(!this.attachment.isDeletable){return false;} 9891return(!this.env.message||this.env.message.hasTextContent||(this.env.message&&this.props.attachments.length>1));} 9892showUploaded(attachment){return!attachment.isImage&&!attachment.uploading&&this.env.inComposer;}} 9893return __exports;});; 9894 9895/* /mail/static/src/core/common/attachment_model.js */ 9896odoo.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;} 9897composer=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,}));} 9898get gifPaused(){return this.thread?!this.thread.isFocused:!this.composer?.isFocused;} 9899get isDeletable(){if(this.message&&this.store.self.main_user_id?.share!==false){return this.message.editable;} 9900return true;} 9901get monthYear(){if(!this.create_date){return undefined;} 9902return`${this.create_date.monthLong}, ${this.create_date.year}`;} 9903get uploading(){return this.id<0;} 9904delete(){if(this.tmpUrl){URL.revokeObjectURL(this.tmpUrl);} 9905super.delete();} 9906async remove(){if(this.id>0){await rpc("/mail/attachment/delete",assignDefined({attachment_id:this.id},{access_token:this.ownership_token}));} 9907this.delete();} 9908get previewName(){return this.voice?_t("Voice Message"):this.name||"";} 9909async 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}));}}} 9910Attachment.register();return __exports;});; 9911 9912/* /mail/static/src/core/common/attachment_upload_service.js */ 9913odoo.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);} 9914setup(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
9914:{upload}})=>{const tmpId=parseInt(upload.data.get("temporary_id"));if(!this.uploadingAttachmentIds.has(tmpId)){return;} 9915const{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;} 9916const 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;} 9917if(upload.xhr.status!==200){this.notificationService.add(_t("Server error"),{type:"danger"});def.resolve();this._cleanupUploading(tmpId);return;} 9918const response=JSON.parse(upload.xhr.response);if(response.error){this.notificationService.add(response.error,{type:"danger"});def.resolve();this._cleanupUploading(tmpId);return;} 9919const{thread,composer}=this.targetsByTmpId.get(tmpId);this._processLoaded(thread,composer,response,tmpId,def);});this.fileUploadService.bus.addEventListener("FILE_UPLOAD_ERROR",({detail
9919:{upload}})=>{const tmpId=parseInt(upload.data.get("temporary_id"));if(!this.uploadingAttachmentIds.has(tmpId)){return;} 9920this.deferredByAttachmentId.get(tmpId).resolve();this._cleanupUploading(tmpId);});} 9921_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);}} 9922def.resolve(attachment);this._fileUploadBus.trigger("UPLOAD",thread);this._cleanupUploading(tmpId);} 9923_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();} 9924getUploadURL(thread){return"/mail/attachment/upload";} 9925async 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;} 9926if(this.deletingAttachmentIds.has(attachment.id)){return;} 9927this.deletingAttachmentIds.add(attachment.id);try{await attachment.remove();}finally{this.deletingAttachmentIds.delete(attachment.id);}} 9928async upload(thread,composer,file,options){const tmpId=this.nextId--;const tmpURL=URL.createObjectURL(file);return this._upload(thread,composer,file,options,tmpId,tmpURL);} 9929async _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;} 9930onFileUploaded(thread,onFileUploaded){this._fileUploadBus.addEventListener("UPLOAD",({detail})=>{if(thread.eq(detail)){onFileUploaded();}});} 9931_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);} 9932return formData;} 9933_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;}} 9934const 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;});; 9935 9936/* /mail/static/src/core/common/attachment_uploader_hook.js */ 9937odoo.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});} 9938const AttachmentUploader=__exports.AttachmentUploader=class AttachmentUploader{constructor(thread,{composer}={}){this.attachmentUploadService=useService("mail.attachment_upload");Object.assign(this,{thread,composer});} 9939uploadData({data,name,type},options){const file=new File([dataUrlToBlob(data,type)],name,{type});return this.uploadFile(file,options);} 9940async uploadFile(file,options){const thread=options?.thread||this.thread;return this.attachmentUploadService.upload(thread,this.composer,file,options);} 9941async unlink(attachment){await this.attachmentUploadService.unlink(attachment);}} 9942__exports.useAttachmentUploader=useAttachmentUploader;function useAttachmentUploader(thread,{composer,onFileUploaded}={}){return useState(new AttachmentUploader(...arguments));} 9943return __exports;});; 9944 9945/* /mail/static/src/core/common/attachment_view.js */ 9946odoo.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));} 9947onClickNext(){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);} 9948onClickPrevious(){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);} 9949updateFromProps(props){this.state.thread=this.store.Thread.insert({id:props.threadId,model:props.threadModel,});} 9950get displayName(){return this.state.thread.message_main_attachment_id.name;} 9951onClickPopout(){}} 9952const PopoutAttachmentView=__exports.PopoutAttachmentView=class PopoutAttachmentView extends AbstractAttachmentView{static template="mail.PopoutAttachmentView";} 9953__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;} 9954return null;} 9955function showAttachmentView(){const parentElementClassList=attachmentViewParentElementClassList();const hiddenClass="d-none";if(parentElementClassList?.contains(hiddenClass)){parentElementClassList.remove(hiddenClass);}} 9956function hideAttachmentView(){const parentElementClassList=attachmentViewParentElementClassList();const hiddenClass="d-none";if(!parentElementClassList?.contains(hiddenClass)){parentElementClassList?.add(hiddenClass);}} 9957function extractPopoutProps(props){return{threadId:props.threadId,threadModel:props.threadModel,};} 9958function popout(){mailPopoutService.addHooks(()=>{hideAttachmentView();uiService.bus.trigger("resize");},()=>{showAttachmentView();uiService.bus.trigger("resize");});mailPopoutService.popout(PopoutAttachmentView,extractPopoutProps(component.props));} 9959function updatePopout(newProps=component.props){if(mailPopoutService.externalWindow){hideAttachmentView();mailPopoutService.popout(PopoutAttachmentView,extractPopoutProps(newProps));}} 9960function resetPopout(){mailPopoutService.reset();} 9961onMounted(updatePopout);onWillUpdateProps((props)=>{const oldProps=extractPopoutProps(component.props);const newProps=extractPopoutProps(props);if(!deepEqual(oldProps,newProps)){updatePopout(newProps);}});onWillUnmount(resetPopout);return{popout,updatePopout,resetPopout,};} 9962const AttachmentView=__exports.AttachmentView=class AttachmentView extends AbstractAttachmentView{setup(){super.setup();this.attachmentPopout=usePopoutAttachment();} 9963onClickPopout(){this.attachmentPopout.popout();}} 9964return __exports;});; 9965 9966/* /mail/static/src/core/common/autoresize_input.js */ 9967odoo.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)=>
9967{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);}});} 9968onKeydownInput(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;}} 9969onBlurInput(){this.state.isFocused=false;this.props.onValidate(this.state.value);}} 9970return __exports;});; 9971 9972/* /mail/static/src/core/common/canned_response_model.js */ 9973odoo.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;} 9974CannedResponse.register();return __exports;});; 9975 9976/* /mail/static/src/core/common/chat_bubble.js */ 9977odoo.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;} 9978get previewText(){const lastMessage=this.thread?.newestPersistentOfAllMessage;if(!lastMessage){return false;} 9979return lastMessage.previewText;}} 9980const 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;} 9981this.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});} 9982get thread(){return this.props.chatWindow.thread;} 9983get showImStatus(){return(this.thread?.correspondent?.im_status&&this.thread.correspondent.im_status!=="offline");}} 9984return __exports;});; 9985 9986/* /mail/static/src/core/common/chat_hub.js */ 9987odoo.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;} 9988setup(){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();});} 9989get 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,}));} 9990if(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,}));} 9991return actions;} 9992get isMobileOS(){return isMobileOS();} 9993onDrop({top,left}){this.position.bottom="unset";this.position.right="unset";this.position.top=`${top}px`;
9993this.position.left=`${left}px`;} 9994onResize(){this.chatHub.onRecompute();} 9995resetPosition(){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();} 9996get 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;} 9997return counter;} 9998get hiddenCounter(){let counter=0;for(const chatWindow of this.chatHub.folded.slice(this.chatHub.maxFolded)){counter+=chatWindow.thread.importantCounter>0?1:0;} 9999return counter;} 10000get displayConversations(){return this.chatHub.showConversations&&!this.chatHub.compact;} 10001get isShown(){return true;} 10002shouldDisplayChatWindow(cw){return cw.canShow;} 10003expand(){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();}}} 10004const 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;});; 10005 10006/* /mail/static/src/core/common/chat_hub_model.js */ 10007odoo.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();} 10008if(ev.key===CHAT_HUB_COMPACT_LS){chatHub._recomputeCompact++;}});chatHub.load(browser.localStorage.getItem(CHAT_HUB_KEY)??undefined).then(()=>chatHub.initPromise.resolve());return chatHub;} 10009_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}));} 10010await Promise.all(promises);this.save();} 10011hideAll(){for(const cw of this.opened){cw.bypassCompact=false;} 10012browser.localStorage.setItem(CHAT_HUB_COMPACT_LS,true);this._recomputeCompact++;} 10013onRecompute(){while(this.opened.length>this.maxOpened){const cw=this.opened.pop();this.folded.unshift(cw);}} 10014async load(str="{}"){await this.loadMutex.exec(()=>this._load(str));} 10015async _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);} 10016const 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});}} 10017this.folded=toFold;this.opened=toOpen;} 10018get 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;} 10019get maxFolded(){const chatBubbleSpace=this.BUBBLE_START+this.BUBBLE+this.BUBBLE_OUTER*2;
10019return Math.min(this.BUBBLE_LIMIT,Math.floor(browser.innerHeight/chatBubbleSpace));} 10020save(){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})),}));} 10021showConversations=fields.Attr(false,{compute(){return this.canShowOpened.length+this.canShowFolded.length>0;},});} 10022ChatHub.register();return __exports;});; 10023 10024/* /mail/static/src/core/common/chat_window.js */ 10025odoo.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,});} 10026get autofocusComposer(){if(this.isMobileOS||this.thread.composerDisabled){return undefined;} 10027return this.props.chatWindow.autofocus;} 10028get autofocusThread(){if(this.isMobileOS||this.thread.composerDisabled){return this.props.chatWindow.autofocus;} 10029return undefined;}
10030get composerType(){if(this.thread.model!=="discuss.channel"){return"note";} 10031return undefined;} 10032get 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));} 10033get thread(){return this.props.chatWindow.thread;} 10034get showImStatus(){return this.thread?.channel_type==="chat"&&this.thread.correspondent;} 10035get attClass(){return{"w-100 h-100 o-mobile":this.ui.isSmall,"o-rounded-bubble border border-dark mb-2":!this.ui.isSmall,};} 10036get 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;`;} 10037onKeydown(ev){const chatWindow=toRaw(this.props.chatWindow);if(ev.key==="Escape"&&this.threadActions.activeAction){this.threadActions.activeAction.close();ev.stopPropagation();return;} 10038if(ev.target.closest(".o-dropdown")||ev.target.closest(".o-dropdown--menu")){return;} 10039ev.stopPropagation();switch(getActiveHotkey(ev)){case"escape":if(isEventHandled(ev,"NavigableList.close")||isEventHandled(ev,"Composer.discard")){return;} 10040if(this.state.editingName){this.state.editingName=false;return;} 10041this.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});} 10042break;} 10043case"control+k":this.store.env.services.command.openMainPalette({searchValue:"@"});ev.preventDefault();break;}} 10044onClickHeader(ev){if(this.ui.isSmall||this.state.editingName||this.props.chatWindow.actionsDisabled||isEventHandled(ev,"ThreadAction.onSelected")){return;} 10045this.toggleFold();} 10046toggleFold(){const chatWindow=toRaw(this.props.chatWindow);if(this.state.actionsMenuOpened){return;} 10047chatWindow.fold();} 10048close(options){const chatWindow=toRaw(this.props.chatWindow);chatWindow.close(options);} 10049get actionsMenuTitleText(){return _t("Open Actions Menu");} 10050async renameThread(name){const thread=toRaw(this.thread);await thread.rename(name);this.state.editingName=false;} 10051async renameGuest(name){const newName=name.trim();if(this.store.self.name!==newName){await this.store.self.updateGuestName(newName);} 10052this.state.editingGuestName=false;} 10053async onActionsMenuStateChanged(isOpen){this.state.actionsMenuOpened=isOpen;}} 10054return __exports;});; 10055 10056/* /mail/static/src/core/common/chat_window_model.js */ 10057odoo.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;} 10058get isOpen(){return Boolean(this.hubAsOpened);} 10059canShow=fields.Attr(true,{compute(){return this.computeCanShow();},});computeCanShow(){if(this.store.env.services.ui.isSmall){return!this.hubAsFolded||!this.store.discuss?.isActive;} 10060return!this.store.discuss?.isActive;} 10061async 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();} 10062if(escape&&indexAsOpened!==-1&&chatHub.opened.length>0){chatHub.opened[indexAsOpened===0?0:indexAsOpened-1].focus();} 10063this._onClose(options);this.delete();} 10064focus({jumpToNewMessage=false}={}){this.autofocus++;if(jumpToNewMessage){this.jumpToNewMessage++;}} 10065async 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;} 10066async 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);} 10067if(notifyState){this.store.chatHub.save();} 10068if(focus){this.focus({jumpToNewMessage});}} 10069_onClose(){}}
10070ChatWindow.register();return __exports;});; 10071 10072/* /mail/static/src/core/common/composer.js */ 10073odoo.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");
10073const{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();} 10074onClickTextRecover(){this.props.onClickTextRecover();this.props.close();}} 10075const 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));} 10076useChildSubEnv({inComposer:true});useEffect((focus)=>
10076{if(focus&&this.ref.el){this.selection.restore();this.ref.el.focus();} 10077if(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";} 10078this.ref.el.style.height=this.fakeTextarea.el.scrollHeight+"px";if(wasEmpty){this.fakeTextarea.el.value="";}} 10079this.saveContentDebounced();},()=>[this.props.composer.composerText,this.ref.el]);useEffect(()=>{if(!this.props.composer.forceCursorMove){return;} 10080this.selection.restore();this.props.composer.forceCursorMove=false;},()=>[this.props.composer.forceCursorMove]);useEffect((isFullComposerOpen,restoredFromFullComposer,fullComposerButtonEl)=>{if(isFullComposerOpen||!restoredFromFullComposer||!fullComposerButtonEl){this.fullComposerRecoveryPopover.close();return;} 10081if(this.fullComposerRecoveryPopover.isOpen){return;} 10082this.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;} 10083const composerHtml=composerProxy.composerHtml;if(this.updateFromEditor){return;} 10084if(!this.editor?.editable){return;} 10085setElementContent(this.editor.editable,composerHtml);this.setEditorCursorEnd();this.editor.shared.history.addStep();});void composerProxy.composerHtml;} 10086setEditorCursorEnd(){const lastNode=lastLeaf(this.editor?.editable);if(!lastNode){return;} 10087const 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);} 10088this.editor.shared.selection.selectAroundNonEditable();} 10089get areAllActionsDisabled(){return false;} 10090get isMultiUpload(){return true;} 10091get placeholder(){if(this.props.placeholder){return this.props.placeholder;} 10092if(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,});} 10093return _t("Message #%(threadName)sâ¦",{threadName});} 10094return _t("Message %(thread name)sâ¦",{"thread name":this.thread.displayName});} 10095return"";} 10096get wysiwygConfig(){return{content:this.props.composer.composerHtml,placeholder:this.placeholder,Plugins:this.ui.isSmall?MAIL_SMALL_UI_P
10096LUGINS: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();},};} 10097onClickCancelOrSaveEditText(ev){const composer=toRaw(this.props.composer);if(composer.message&&ev.target.dataset?.type===EDIT_CLICK_TYPE.CANCEL){this.props.onDiscardCallback(ev);} 10098if(composer.message&&ev.target.dataset?.type===EDIT_CLICK_TYPE.SAVE){this.editMessage(ev);}} 10099get 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);} 10100get SEND_TEXT(){if(this.props.composer.message){return _t("Save editing");} 10101return this.props.type==="note"?_t("Log"):_t("Send");} 10102get sendKeybinds(){return this.env.inChatter?[_t("CTRL"),_t("Enter")]:[_t("Enter")];} 10103get showComposerAvatar(){return!this.compact&&this.props.sidebar;} 10104get thread(){return this.props.composer.targetThread;} 10105get allowUpload(){return this.props.allowUpload;} 10106get message(){return this.props.composer.message??null;} 10107get extraData(){return this.thread.rpcParams;} 10108get isSendButtonDisabled(){const attachments=this.props.composer.attachments;return(!this.state.active||(isHtmlEmpty(this.props.composer.composerHtml)&&attachments.length===0)||attachments.some(({uploading})=>Boolean(uploading)));} 10109get hasSuggestions(){return Boolean(this.suggestion?.state.items);} 10110get navigableListProps(){const props={anchorRef:this.inputContainerRef.el,position:this.env.inChatter?"bottom-fit":"top-fit",onClose:()=>this.suggestion.dismiss(),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;} 10111return{...props,...mapSuggestionsToOptions(this.suggestion.state.items.type,this.suggestion.state.items.suggestions,{thread:this.thread}),};} 10112onDropFile(ev){if(isDragSourceExternalFile(ev.dataTransfer)){for(const file of ev.dataTransfer.files){this.attachmentUploader.uploadFile(file);}}} 10113onCloseFullComposerCallback(isDiscard){if(this.props.onCloseFullComposerCallback){this.props.onCloseFullComposerCallback(isDiscard);}else{this.thread?.fetchNewMessages();}} 10114onInput(ev){if(!this.props.composer.isDirty){this.props.composer.isDirty=true;}} 10115onPaste(ev){if(!this.allowUpload){return;} 10116if(!ev.clipboardData?.items){return;} 10117if(ev.clipboardData.files.length===0){return;} 10118ev.preventDefault();for(const file of ev.clipboardData.files){this.attachmentUploader.uploadFile(file);}} 10119onKeydown(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);}} 10120break;case"Enter":{if(isEventHandled(ev,"NavigableList.select")||!this.state.active){ev.preventDefault();return;} 10121if(this.isMobileOS||ev.isComposing){return;} 10122const shouldPost=this.env.inChatter?ev.ctrlKey:!ev.shiftKey;if(!shouldPost){return;} 10123ev.preventDefault();if(composer.message){this.editMessage();}else{this.sendMessage();} 10124break;} 10125case"Escape":if(isEventHandled(ev,"NavigableList.close")){return;} 10126if(this.props.onDiscardCallback){this.props.onDiscardCallback();markEventHandled(ev,"Composer.discard");} 10127break;}} 10128get fullComposerAdditionalContext(){return{};} 10129async 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=[];
10129newPartners.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;}}} 10130const 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;} 10131const 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();} 10132this.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;} 10133formatDefaultBodyForFullComposer(defaultBody,signature=""){if(signature){defaultBody=markup`${defaultBody}<br>${signature}`;} 10134return markup`<div>${defaultBody}</div>`;} 10135clear(){this.props.composer.clear();browser.localStorage.removeItem(this.props.composer.localId);} 10136notifySendFromMailbox(){this.store.notifySendFromMailbox(this.thread.displayName);} 10137isEventTrusted(ev){return ev.isTrusted;} 10138async 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;} 10139this.state.active=false;await cb(trimEmptyBlocksAround(this.props.composer.composerHtml));if(this.props.onPostCallback){this.props.onPostCallback();} 10140this.clear();this.state.active=true;this.ref.el?.focus();}} 10141get canProcessMessage(){return(!isHtmlEmpty(this.props.composer.composerHtml)||this.props.composer.attachments.length>0||(this.message&&this.message.attachment_ids.length>0));} 10142async sendMessage(){const composer=toRaw(this.props.composer);this.composerActions.activePicker?.close?.();if(composer.message){this.editMessage();return;} 10143if(this.props.type!=="note"){const allRecipients=[...composer.thread.suggestedRecipients,...composer.thread.additionalRecipients,];if(allRecipients.some((recipient)=>!recipient.email||!isEmail(recipient.email))){return;}} 10144await this.processMessage(async(value)=>{await this._sendMessage(value,this.postData,this.extraData);});} 10145get 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,};} 10146async _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();} 10147if(thread.model==="mail.box"){this.notifySendFromMailbox();} 10148this.suggestion?.clearRawMentions();this.suggestion?.clearCannedResponses();this.props.composer.replyToMessage=undefined;this.props.composer.emailAddSignature=true;this.props.composer.thread.additionalRecipients=[];return message;} 10149async editMessage(){const composer=toRaw(this.props.composer);
10149if(!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});} 10150this.suggestion?.clearRawMentions();} 10151get askDeleteFromEdit(){const composer=toRaw(this.props.composer);return!composer.composerText&&composer.message.attachment_ids.length===0;} 10152onClickInsertCannedResponse(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(" ");} 10153this.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);} 10154if(!this.ui.isSmall||!this.env.inChatter){composer.autofocus++;}} 10155onChangeWysiwygContent(){this.updateFromEditor=true;this.props.composer.composerHtml=markup(this.editor.getContent());if(!this.props.composer.isDirty){this.props.composer.isDirty=true;} 10156this.updateFromEditor=false;} 10157onLoadWysiwyg(editor){this.editor=editor;} 10158addEmoji(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);} 10159if(this.ui.isSmall&&!this.env.inChatter){return false;}else{composer.autofocus++;}} 10160onFocusin(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();}} 10161onFocusout(ev){if([EDIT_CLICK_TYPE.CANCEL,EDIT_CLICK_TYPE.SAVE].includes(ev.relatedTarget?.dataset?.type)){return;} 10162this.props.composer.isFocused=false;} 10163saveContent(){const composer=toRaw(this.props.composer);if(composer.restoredFromFullComposer&&!this.state.isFullComposerOpen){return;} 10164const 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,});}} 10165restoreContent(){const composer=toRaw(this.props.composer);let config;try{config=JSON.parse(browser.localStorage.getItem(composer.localId));}catch{browser.localStorage.removeItem(composer.localId);} 10166if(!config){return;} 10167if(!isHtmlEmpty(config.composerHtml)){if(composer.thread&&composer.thread?.model!=="discuss.channel"){composer.restoredFromFullComposer=config.fromFullComposer;} 10168composer.emailAddSignature=config.emailAddSignature;composer.composerHtml=config.composerHtml;} 10169if(Number.isInteger(config.replyToMessageId)){composer.replyToMessage=this.store["mail.message"].insert(config.replyToMessageId);}} 10170get shouldHideFromMessageListOnDelete(){return false;}} 10171return __exports;});; 10172 10173/* /mail/static/src/core/common/composer_actions.js */ 10174odoo.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);} 10175__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;}} 10176const previousPicker=component.getActivePicker();previousPicker?.close();if(toRaw(previousPicker)===toRaw(action.picker)){component.setActivePicker(null);}else{component.setActivePicker(action.picker);component.getActivePicker().open({el:anchorEl});}} 10177__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();} 10178registerComposerAction("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;} 10179_disabledCondition({composer}){if(composer.restoredFromFullComposer&&this.id!=="open-full-composer"){return true;} 10180return super._disabledCondition(...arguments);} 10181get params(){return Object.assign(super.params,{composer:this.composerFn()});} 10182get isPicker(){return this.definition.isPicker;} 10183get pickerName(){return typeof this.definition.pickerName==="function"?this.definition.pickerName(this._component):this.definition.pickerName;}} 10184class 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)=>
10184a1.sequenceQuick-a2.sequenceQuick);groupedPickers.other?.sort((a1,a2)=>a1.sequence-a2.sequence);const pickers=(groupedPickers.other??[]).concat(groupedPickers.quick??[]);return Object.assign(res,{pickers});}} 10185__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();} 10186const state=useState(new UseComposerActions(component,transformedActions,useService("mail.store")));component.getActivePicker=()=>state.activePicker;component.setActivePicker=(newActivePicker)=>(state.activePicker=newActivePicker);return state;} 10187return __exports;});; 10188 10189/* /mail/static/src/core/common/composer_model.js */ 10190odoo.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",});} 10191insertText(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;} 10192this.selection.end=this.selection.start;this.forceCursorMove=true;} 10193attachments=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;} 10194const 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>"));} 10195return this.composerHtml;},onUpdate(){if(this.updateFrom==="text"){this.updateFrom=undefined;return;} 10196const 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;} 10197get targetThread(){return this.replyToMessage?.thread??this.thread??this.message?.thread??null;} 10198insertReplyFromNote(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});} 10199return;} 10200const composerBody=createDocumentFragmentFromContent(this.composerHtml).body;if(composerBody.querySelector(`a.o_mail_redirect[data-oe-model="res.partner"][data-oe-id="${message.author.id}"]`)){return;} 10201composerBody.firstElementChild.prepend(generatePartnerMentionElement(message.author,this.thread),nbsp);this.composerHtml=markup(composerBody.innerHTML);}} 10202Composer.register();return __exports;});; 10203 10204/* /mail/static/src/core/common/composer_service.js */ 10205odoo.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
10205se),setHtmlComposer(){if(state.htmlEnabled){return;} 10206state.htmlEnabled=true;legacy_multi_tab.setSharedValue("mail.html_composer.enabled",true);},setTextComposer(){if(!state.htmlEnabled){return;} 10207state.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;});; 10208 10209/* /mail/static/src/core/common/country_flag.js */ 10210odoo.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";} 10211return __exports;});; 10212 10213/* /mail/static/src/core/common/country_model.js */ 10214odoo.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;} 10215return`/base/static/img/country_flags/${encodeURIComponent(this.code.toLowerCase())}.png`;}} 10216Country.register();return __exports;});; 10217 10218/* /mail/static/src/core/common/data_response_model.js */ 10219odoo.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});} 10220id;_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");} 10221DataResponse.register();return __exports;});; 10222 10223/* /mail/static/src/core/common/date_section.js */ 10224odoo.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();}} 10225return __exports;});; 10226 10227/* /mail/static/src/core/common/discuss_call_history_model.js */ 10228odoo.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;} 10229DiscussCallHistory.register();return __exports;});; 10230 10231/* /mail/static/src/core/common/discuss_component_registry.js */ 10232odoo.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;});; 10233 10234/* /mail/static/src/core/common/failure_model.js */ 10235odoo.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;} 10236get resModel(){return this.notifications?.[0]?.mail_message_id?.thread?.model;} 10237get resIds(){return new Set([...this.notifications.map((notif)=>notif.mail_message_id?.thread?.id).filter((id)=>!!id),]);} 10238lastMessage=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;}} 10239return lastMsg;},});get type(){return this.notifications?.[0]?.notification_type;} 10240get status(){return this.notifications?.[0]?.notification_status;} 10241get iconSrc(){return"/mail/static/src/img/smiley/mailfailure.svg";} 10242get 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,});} 10243return _t("An error occurred when sending an email");} 10244get datetime(){return this.lastMessage?.datetime;}} 10245Failure.register();return __exports;});; 10246 10247/* /mail/static/src/core/common/follower_model.js */ 10248odoo.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");} 10249get isEditable(){const hasWriteAccess=this.thread?this.thread.hasWriteAccess:false;return this.partner_id.eq(this.store.self_partner)?this.thread.hasReadAccess:hasWriteAccess;} 10250async 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);} 10251removeRecipient(){this.thread.recipients.delete(this);}} 10252Follower.register();return __exports;});; 10253 10254/* /mail/static/src/core/common/gif.js */ 10255odoo.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");
10255if(new URL(src).origin!==location.origin){image.crossOrigin="anonymous";} 10256image.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();} 10257onLoad(){this.props.onLoad?.(...arguments);this.keepLast.add(this.generateGifSnapshot(this.props.src)).then((snapshot)=>(this.state.snapshot=snapshot));}} 10258return __exports;});; 10259 10260/* /mail/static/src/core/common/im_status.js */ 10261odoo.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;}} 10262return __exports;});; 10263 10264/* /mail/static/src/core/common/im_status_dropdown.js */ 10265odoo.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"),};} 10266setManualImStatus(status){rpc("/mail/set_manual_im_status",{status});} 10267get readableImStatus(){const imStatus=this.store.self.im_status||"offline";for(const status in this.readableImStatusByCode){if(imStatus.includes(status)){return this.readableImStatusByCode[status];}} 10268return _t("Unknown Status");}} 10269__exports.imStatusItem=imStatusItem;function imStatusItem(env){return{type:"component",contentComponent:ImStatusDropdown,sequence:45,};} 10270registry.category("user_menuitems").add("im_status",imStatusItem);return __exports;});; 10271 10272/* /mail/static/src/core/common/im_status_service.js */ 10273odoo.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;} 10274if(debounce){partner?.debouncedSetImStatus(im_status);guest?.debouncedSetImStatus(im_status);}else{partner?.updateImStatus(im_status);guest?.updateImStatus(im_status);} 10275if(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();} 10276startAwayTimeout();});return{updateBusPresence};},};registry.category("services").add("im_status",imStatusService);return __exports;});; 10277 10278/* /mail/static/src/core/common/link_preview.js */ 10279odoo.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]);} 10280onClick(){this.dialogService.add(LinkPreviewConfirmDelete,{linkPreview:this.props.linkPreview,delete:this.props.delete,deleteAll:this.props.deleteAll,LinkPreview,});} 10281onImageLoaded(){this.env.onImageLoaded?.();}} 10282return __exports;});; 10283 10284/* /mail/static/src/core/common/link_preview_confirm_delete.js */ 10285odoo.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");} 10286get message(){return this.props.linkPreview.message_id;} 10287onClickOk(){this.props.delete();this.props.close();} 10288onClickDeleteAll(){this.props.deleteAll?.();this.props.close();} 10289onClickCancel(){this.props.close();}} 10290return __exports;});; 10291 10292/* /mail/static/src/core/common/link_preview_model.js */ 10293odoo.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");} 10294get imageUrl(){return this.og_image?this.og_image:this.source_url;} 10295get isImage(){return Boolean(this.image_mimetype||this.og_mimetype==="image/gif");} 10296get isVideo(){let fileExt;if(this.og_title){fileExt=this.og_title.split(".").pop();} 10297return(VIDEO_EXTENSIONS.has(fileExt)||Boolean(!this.isImage&&this.og_type&&this.og_type.startsWith("video")));} 10298get isCard(){return!this.isImage&&!this.isVideo;} 10299get videoURL(){const{url}=convertToEmbedURL(this.source_url);return url;} 10300get videoProvider(){const{provider}=convertToEmbedURL(this.source_url);return provider;}} 10301LinkPreview.register();return __exports;});; 10302 10303/* /mail/static/src/core/common/mail_activity_type_model.js */ 10304odoo.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;} 10305MailActivityType.register();return __exports;});; 10306 10307/* /mail/static/src/core/common/mail_attachment_dropzone.js */ 10308odoo.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;} 10309return __exports;});; 10310 10311/* /mail/static/src/core/common/mail_core_common_service.js */ 10312odoo.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"];} 10313setup(){this.busService.subscribe("ir.attachment/delete",(payload)=>{const{id:attachmentId,message:messageData}=payload;if(messageData){this.store["mail.message"].insert(messageData);} 10314const 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;} 10315this.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);});} 10316_handleNotificationToggleStar(payload,metadata){const{message_ids:messageIds,starred}=payload;this.store["mail.message"].insert(messageIds.map((id)=>({id,starred})));}} 10317const 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;});; 10318 10319/* /mail/static/src/core/common/mail_fullscreen.js */ 10320odoo.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");}} 10321const 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;} 10322state.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();}}} 10323async 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;} 10324try{if(el.requestFullscreen){await el.requestFullscreen();}else if(el.mozRequestFullScreen){await el.mozRequestFullScreen();}else if(el.webkitRequestFullscreen){await el.webkitRequestFullscreen();}}catch{}} 10325window.addEventListener("fullscreenchange",()=>{const isFullscreen=Boolean(document.webkitFullscreenElement||document.fullscreenElement);if(!isFullscreen){state.exit();}});return state;},};registry.category("services").add("mail.fullscreen",fullscreenService);return __exports;});; 10326 10327/* /mail/static/src/core/common/mail_guest_model.js */ 10328odoo.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;} 10329avatar_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);} 10330if(this._triggerPresenceSubscription){this.store.env.services.bus_service.addChannel(this.presenceChannel);} 10331this.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}`;} 10332return 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;} 10333if(this.id===-1){return TRANSPARENT_AVATAR;} 10334return imageUrl("mail.guest",this.id,"avatar_128",{...accessTokenParam,unique:this.write_date,});} 10335async updateGuestName(name){await rpc("/mail/guest/update_name",{guest_id:this.id,name,});} 10336updateImStatus(newStatus){if(newStatus==="offline"){this.offline_since=DateTime.now();} 10337this.im_status=newStatus;}} 10338MailGuest.register();return __exports;});; 10339 10340/* /mail/static/src/core/common/mail_message_subtype_model.js */ 10341odoo.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
10341ord{static id="id";static _name="mail.message.subtype";description;id;name;} 10342MailMessageSubtype.register();return __exports;});; 10343 10344/* /mail/static/src/core/common/mail_popout_service.js */ 10345odoo.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;} 10346const doc=popout.externalWindow?.document;if(doc){doc.head.textContent="";if(useAlternativeAssets){await mailPopoutService.addAssets(popout.externalWindow);}else{doc.write(window.document.head.outerHTML);} 10347doc.body=doc.createElement("body");} 10348if(popout.app){popout.app.destroy();popout.app=null;}} 10349async 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;}}} 10350async 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}`);} 10351popout.externalWindow=externalWindow;pollClosedWindow(id);} 10352await 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;} 10353function 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);} 10354reset(id);popout.app=new App(component,{name:"Popout",env,props,getTemplate,translatableAttributes:["data-tooltip"],translateFn:appTranslateFn,});popout.app.mount(externalWindow.document.body);return externalWindow;} 10355function getExternalWindow(id){const externalWindow=popouts.get(id)?.externalWindow;return externalWindow&&!externalWindow.closed?externalWindow:null;} 10356function addHooks(id,hooks){const popout=popouts.get(id);popout.hooks=hooks;}
10357function 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;},};} 10358return Object.assign(createManager(),{createManager});},};registry.category("services").add("mail.popout",mailPopoutService);return __exports;});; 10359 10360/* /mail/static/src/core/common/mail_template_model.js */ 10361odoo.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;} 10362MailTemplate.register();return __exports;});; 10363 10364/* /mail/static/src/core/common/message.js */ 10365odoo.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;}} 10366const 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");
10366if(isMobileOS()){useLongPress("root",{action:()=>this.openMobileActions(),predicate:()=>!this.isEditing,});} 10367onWillUpdateProps((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=` 10368 * { 10369 background-color: transparent !important; 10370 color: ${color} !important; 10371 } 10372 a, a * { 10373 color: ${this.constructor.SHADOW_LINK_COLOR} !important; 10374 } 10375 a:hover, a *:hover { 10376 color: ${this.constructor.SHADOW_LINK_HOVER_COLOR} !important; 10377 } 10378 .o-mail-Message-searchHighlight { 10379 background: ${this.constructor.SHADOW_HIGHLIGHT_COLOR} !important; 10380 } 10381 `;if(!this.store.isOdooWhiteTheme){this.shadowRoot.appendChild(shadowStyle);} 10382const ellipsisStyle=document.createElement("style");ellipsisStyle.textContent=` 10383 .o-mail-ellipsis { 10384 min-width: 2.7ch; 10385 background-color: ButtonFace; 10386 border-radius: 50rem; 10387 border: 0; 10388 display: block 10389 font: -moz-button; 10390 font-size: .75rem; 10391 font-weight: 500; 10392 line-height: 1.1; 10393 cursor: pointer; 10394 padding: 0 4px; 10395 vertical-align: top; 10396 color #ffffff; 10397 text-decoration: none; 10398 text-align: center; 10399 &:hover { 10400 background-color: -moz-buttonhoverface; 10401 } 10402 } 10403 `;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]);} 10404computeActions(){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();} 10405this.state.moreAction=moreAction;this.quickActions=quickActions;this.actions=actions;} 10406get 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,};} 10407get authorAvatarAttClass(){return{"object-fit-contain":this.props.message.author_id?.is_company,"object-fit-cover":!this.props.message.author_id?.is_company,};} 10408get 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");} 10409if(this.message.author){return this.message.author.avatarUrl;} 10410return this.store.DEFAULT_AVATAR;} 10411get expandText(){return _t("Expand");} 10412get isEditing(){return!this.props.isReadOnly&&this.props.message.composer;} 10413get message(){return this.props.message;} 10414get quickActionCount(){if(isMobileOS()){return 1;} 10415return this.env.inChatWindow||this.env.inMeetingChat?2:4;} 10416get showSubtypeDescription(){return(this.message.subtype_id?.description&&this.message.subtype_id.description.toLowerCase()!==htmlToTextContentInline(this.message.body||"").toLowerCase());} 10417get messageTypeText(){if(this.props.message.message_type==="notification"){return _t("System notification");} 10418if(this.props.message.message_type==="auto_comment"){return _t("Automated message");} 10419if(this.props.message.message_type==="out_of_office"){return _t("Out-of-office message");} 10420if(!this.props.message.isDiscussion&&this.props.message.message_type!=="user_notification"){return _t("Note");} 10421return _t("Message");} 10422get isActive(){return(this.state.isHovered||this.state.isClicked||this.emojiPicker?.isOpen||Boolean(this.state.moreAction?.isActive));} 10423get isAlignedRight(){return Boolean(this.env.inChatWindow&&this.props.message.isSelfAuthored);} 10424get isMobileOS(){return isMobileOS();} 10425get isPersistentMessageFromAnotherThread(){return(!this.message.is_transient&&!this.message.isPending&&this.message.thread&&this.message.thread.notEq(this.props.thread));} 10426get translatedFromText(){return _t("(Translated from: %(language)s)",{language:this.message.translationSource});} 10427get translationFailureText(){return _t("(Translation Failure: %(error)s)",{error:this.message.translationErrors});} 10428onMouseenter(){this.state.isHovered=true;} 10429onMouseleave(){this.state.isHovered=false;this.state.isClicked=null;} 10430get shouldDisplayAuthorName(){if(!this.env.inChatWindow){return true;} 10431if(this.message.isSelfAuthored){return false;} 10432if(this.props.thread.channel_type==="chat"){return false;} 10433return true;} 10434async onClickAttachmentUnlink(attachment){await toRaw(attachment).remove();} 10435async onClick(ev){if(this.store.handleClickOnLink(ev,this.props.thread)){return;} 10436if(!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});}}} 10437prepareMessageBody(bodyEl){if(!bodyEl){return;} 10438const 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}));}}}} 10439getAuthorAttClass(){return{"opacity-50":this.message.isPending};} 10440getAvatarContainerAttClass(){return{"opacity-50":this.message.isPending,"o-inChatWindow":this.env.inChatWindow,};} 10441exitEditMode(){this.message.exitEditMode(this.props.thread);} 10442onClickNotification(ev){const message=toRaw(this.message);if(message.failureNotifications.length>0){markEventHandled(ev,"Message.ClickFailure");} 10443this.popover.open(ev.target,{message});} 10444openMobileActions(ev){if(!isMobileOS()){return;} 10445ev?.stopPropagation();this.optionsDropdown.open();} 10446openReactionMenu(reaction){const message=toRaw(this.props.message);this.dialog.add(MessageReactionMenu,{message,initialReaction:reaction},{context:this});} 10447async onClickToggleTranslation(){toRaw(this.props.message).onClickToggleTranslation();} 10448get shouldHideFromMessageListOnDelete(){return false;}}
10449discussComponentRegistry.add("Message",Message);return __exports;});; 10450 10451/* /mail/static/src/core/common/message_actions.js */ 10452odoo.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);} 10453registerMessageAction("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;} 10454if(["discuss.channel","mail.box"].includes(thread.model)){composer.replyToMessage=message;} 10455if(thread.model==="discuss.channel"){return;} 10456if(!message.isSelfAuthored&&message.model!=="discuss.channel"&&message.author){composer.insertReplyFromNote(message);} 10457owner.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})=>
10457message.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;} 10458get params(){return Object.assign(super.params,{message:this.messageFn(),thread:this.threadFn()});}} 10459class UseMessageActions extends UseActions{ActionClass=MessageAction;} 10460__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();} 10461const state=useState(new UseMessageActions(component,transformedActions,useService("mail.store")));return state;} 10462return __exports;});; 10463 10464/* /mail/static/src/core/common/message_card_list.js */ 10465odoo.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?.();}});} 10466async 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();} 10467await new Promise((resolve)=>setTimeout(()=>requestAnimationFrame(resolve)));await this.env.messageHighlight?.highlightMessage(message,this.props.thread);} 10468get emptyText(){return this.props.emptyText??_t("No messages found");}} 10469return __exports;});; 10470 10471/* /mail/static/src/core/common/message_confirm_dialog.js */ 10472odoo.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
10472itle?","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");} 10473onClickConfirm(){this.props.onConfirm();this.props.close();}} 10474discussComponentRegistry.add("MessageConfirmDialog",MessageConfirmDialog);return __exports;});; 10475 10476/* /mail/static/src/core/common/message_in_reply.js */ 10477odoo.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");} 10478get 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");} 10479if(this.props.message.parent_id.author){return this.props.message.parent_id.author.avatarUrl;} 10480return this.store.DEFAULT_AVATAR;}} 10481return __exports;});; 10482 10483/* /mail/static/src/core/common/message_link_preview_list.js */ 10484odoo.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};} 10485return __exports;});; 10486 10487/* /mail/static/src/core/common/message_link_preview_model.js */ 10488odoo.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;} 10489hide(){rpc("/mail/link_preview/hide",{message_link_preview_ids:[this.id]});}} 10490MessageLinkPreview.register();return __exports;});; 10491 10492/* /mail/static/src/core/common/message_model.js */ 10493odoo.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;}} 10494attachment_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;} 10495body=fields.Html("");call_history_ids=fields.Many("discuss.call.history");
10495richBody=fields.Html("",{compute(){if(!this.store.emojiLoader.loaded){loadEmoji();} 10496return decorateEmojis(this.body)??"";},});richTranslationValue=fields.Html("",{compute(){if(!this.store.emojiLoader.loaded){loadEmoji();} 10497return 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;} 10498const 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);} 10499get isNote(){return this.store.mt_note?.eq(this.subtype_id);} 10500is_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;} 10501get bubbleColor(){if(this.message_type==="notification"){return undefined;} 10502if(!this.isSelfAuthored&&!this.isNote&&!this.isHighlightedFromMention){return"blue";} 10503if(this.isSelfAuthored&&!this.isNote&&!this.isHighlightedFromMention){return"green";} 10504if(this.isHighlightedFromMention){return"orange";} 10505return undefined;} 10506get editable(){if(this.isEmpty||!this.allowsEdition){return false;} 10507return this.message_type==="comment";} 10508get dateDay(){let dateDay=this.datetime.toLocaleString(DateTime.DATE_MED);if(dateDay===DateTime.now().toLocaleString(DateTime.DATE_MED)){dateDay=_t("Today");} 10509return dateDay;} 10510get dateSimple(){return this.datetime.toLocaleString(DateTime.TIME_SIMPLE,{locale:user.lang,}).replace("â¯"," ");} 10511get dateSimpleWithDay(){const userLocale={locale:user.lang};if(this.datetime.hasSame(DateTime.now(),"day")){return this.datetime.toLocaleString(DateTime.TIME_SIMPLE,userLocale);} 10512if(this.datetime.hasSame(DateTime.now().minus({day:1}),"day")){return _t("Yesterday at %(time)s",{time:this.datetime.toLocaleString(DateTime.TIME_SIMPLE,userLocale),});} 10513if(this.datetime?.year===DateTime.now().year){return this.datetime.toLocaleString({...DateTime.DATETIME_MED,year:undefined},userLocale);} 10514return this.datetime.toLocaleString({...DateTime.DATETIME_MED},userLocale);} 10515get datetime(){return this.date||DateTime.now();} 10516get effectiveSelf(){return this.thread?.effectiveSelf??this.store.self;}
10517get datetimeShort(){return this.datetime.toLocaleString(DateTime.DATETIME_SHORT_WITH_SECONDS);} 10518get isSelfMentioned(){return this.effectiveSelf.in(this.partner_ids);} 10519get isHighlightedFromMention(){return this.isSelfMentioned&&this.thread?.model==="discuss.channel";} 10520isSelfAuthored=fields.Attr(false,{compute(){return Boolean(this.author?.eq(this.effectiveSelf));},});isPending=false;get hasActions(){return!this.is_transient;} 10521get isNotification(){return this.message_type==="notification"&&this.thread?.model==="discuss.channel";} 10522get isSubjectSimilarToThreadName(){if(!this.subject||!this.thread||!this.thread.display_name){return false;} 10523const regexPrefix=/^((re|fw|fwd)\s*:\s*)*/i;const cleanedThreadName=this.thread.display_name.replace(regexPrefix,"");const cleanedSubject=this.subject.replace(regexPrefix,"");return cleanedSubject===cleanedThreadName;} 10524get 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());} 10525get persistent(){return Number.isInteger(this.id);} 10526get resUrl(){return url(router.stateToUrl({model:this.thread.model,resId:this.thread.id}));} 10527isTranslatable(thread){return(!this.isEmpty&&!this.isBodyEmpty&&!this.hasMailNotificationSummary&&this.store.hasMessageTranslationFeature&&!["discuss.channel","mail.box"].includes(thread?.model));} 10528get hasTextContent(){return!this.isBodyEmpty||this.subject||this.edited;} 10529isEmpty=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);} 10530get 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);} 10531get authorName(){if(this.author){return this.getPersonaName(this.author);} 10532return this.email_from||_t("Unnamed");} 10533get notificationHidden(){return false;} 10534inlineBody=fields.Html("",{compute(){if(this.notificationType==="call"){return _t("%(caller)s started a call",{caller:this.authorName});} 10535if(this.notificationType==="thread_deletion"){return _t('%(user)s deleted the thread "%(thread_name)s"',{user:this.authorName,thread_name:decorateEmojis(htmlToTextContentInline(this.body)),});} 10536if(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);} 10537if(this.isEmpty){return _t("This message has been removed");} 10538if(!this.body){return"";} 10539return decorateEmojis(htmlToTextContentInline(this.body));},});get notificationIcon(){switch(this.notificationType){case"pin":return"fa fa-thumb-tack";case"call":return"fa fa-phone";} 10540return null;} 10541get failureNotifications(){return this.notification_ids.filter((notification)=>notification.isFailure);} 10542get scheduledDateSimple(){return this.scheduledDatetime.toLocaleString(DateTime.TIME_SIMPLE,{locale:user.lang,});} 10543get canToggleStar(){return Boolean(!this.is_transient&&!this.isPending&&this.store.self_partner?.main_user_id?.share===false&&this.persistent);} 10544get hasOnlyAttachments(){return this.isBodyEmpty&&this.attachment_ids.length>0;} 10545previewText=fields.Html("",{compute(){if(!this.hasOnlyAttachments){return this.inlineBody||this.subtype_id?.description;} 10546const{attachment_ids:attachments}=this;if(!attachments||attachments.length===0){return"";} 10547switch(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"";} 10548const 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";}} 10549canAddReaction(thread){return Boolean(!this.is_transient&&!this.isPending&&this.thread?.can_react&&!this.thread.isTransient&&this.thread.has_mail_thread);} 10550canReplyTo(thread){return(["discuss.channel","mail.box"].includes(thread?.model)&&this.message_type!=="user_notification");} 10551canUnfollow(thread){return Boolean(this.thread?.selfFollower&&thread?.model==="mail.box");} 10552async 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";} 10553this.store.env.services.notification.add(notification,{type});} 10554async 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"});} 10555this.store.env.services.notification.add(_t("Message Copied!"),{type:"info"});} 10556async 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;} 10557const 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});} 10558return data;} 10559async 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;} 10560this.composer={composerHtml:getNonEditableMentions(this.body),mentionedChannels:validChannels,mentionedPartners:this.partner_ids,mentionedRoles:validRoles,selection:{start:text.length,end:text.length,direction:"none",},};} 10561exitEditMode(thread){const threadAsInEdition=this.threadAsInEdition;this.composer=undefined;if(threadAsInEdition&&threadAsInEdition.eq(thread)){threadAsInEdition.composer.autofocus++;}} 10562getPersonaName(persona){return(this.thread?.getPersonaName(persona)||persona?.displayName||persona?.n
10562ame||_t("Unnamed"));} 10563async 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;} 10564this.showTranslation=!this.showTranslation&&Boolean(this.translationValue);} 10565async react(content){this.store.insert(await rpc("/mail/message/reaction",{action:"add",content,message_id:this.id,...this.thread.rpcParams,},{silent:true}));} 10566async 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));} 10567this.composer=undefined;return data;} 10568get removeParams(){return{attachment_ids:[],attachment_tokens:[],body:"",subject:"",partner_ids:[],};} 10569async setDone(){await this.store.env.services.orm.silent.call("mail.message","set_message_done",[[this.id],]);} 10570async toggleStar(){this.store.insert(await this.store.env.services.orm.silent.call("mail.message","toggle_message_starred",[[this.id]]));} 10571async unfollow(){if(this.needaction){await this.setDone();} 10572const 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"});} 10573hideAllLinkPreviews(){rpc("/mail/link_preview/hide",{message_link_preview_ids:this.message_link_preview_ids.map((lpm)=>lpm.id),});}} 10574Message.register();return __exports;});; 10575 10576/* /mail/static/src/core/common/message_notification_popover.js */ 10577odoo.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?"];} 10578return __exports;});; 10579 10580/* /mail/static/src/core/common/message_reaction_list.js */ 10581odoo.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],});} 10582previewText(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],});}} 10583hasSelfReacted(reaction){return this.props.message.effectiveSelf.in(reaction.personas);} 10584onClickReaction(reaction){if(!this.props.message.canAddReaction()){return;} 10585if(this.hasSelfReacted(reaction)){reaction.remove();}else{this.props.message.react(reaction.content);}} 10586onContextMenu(ev){if(this.ui.isSmall){ev.preventDefault();this.props.openReactionMenu();}} 10587onClickReactionList(reaction){this.preview.isOpen=false;this.props.openReactionMenu(reaction);}} 10588return __exports;});; 10589 10590/* /mail/static/src/core/common/message_reaction_menu.js */ 10591odoo.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];}}
10591,()=>[this.props.message.reactions.length]);onMounted(()=>{if(!this.store.emojiLoader.loaded){loadEmoji();}});} 10592onKeydown(ev){switch(ev.key){case"Escape":this.props.close();break;case"q":this.props.close();break;default:return;}} 10593getEmojiShortcode(reaction){return this.store.emojiLoader.loaded?.emojiValueToShortcodes?.[reaction.content]?.[0]??"?";} 10594get 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(" ");}} 10595return __exports;});; 10596 10597/* /mail/static/src/core/common/message_reactions.js */ 10598odoo.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);}},});}} 10599return __exports;});; 10600 10601/* /mail/static/src/core/common/message_reactions_model.js */ 10602odoo.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}));}} 10603MessageReactions.register();return __exports;});; 10604 10605/* /mail/static/src/core/common/message_search_hook.js */ 10606odoo.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;} 10607const 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})`;} 10608const 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;} 10609const end=htmlDoc.createTextNode(node.textContent.slice(curIndex));newNode.push(end);}else{newNode.push(node);}} 10610element.replaceChildren(...newNode);}} 10611return markup(htmlDoc.body.innerHTML);} 10612__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
10612defined){this.searching=true;const data=await sequential(()=>store.searchMessagesInThread(this.searchTerm,this.thread,before,this.is_notification));if(!data){return;} 10613const{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;} 10614return __exports;});; 10615 10616/* /mail/static/src/core/common/navigable_list.js */ 10617odoo.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");} 10618const NavigableList=__exports.NavigableList=class NavigableList extends Component{static components={ImStatus};static template="mail.NavigableList";static props={anchorRef:{optional:true},class:{type:String,optional:true},onClose:{type:Function,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;} 10619this.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]);} 10620get show(){return Boolean(this.state.open&&(this.props.isLoading||this.props.options.length));} 10621get sortedOptions(){return this.props.options.sort((o1,o2)=>(o1.group??0)-(o2.group??0));} 10622open(){this.state.open=true;this.state.activeIndex=null;this.navigate("first");} 10623close(){if(this.props.closeOnSelect){this.state.open=false;this.state.activeIndex=null;this.props.onClose?.();}} 10624selectOption(ev,index,params={}){const{option=this.props.options[index],...onSelectParams}=params;if(!option){return;} 10625if(option.unselectable){this.close();return;} 10626this.props.onSelect(ev,option,{...onSelectParams,});this.close();} 10627navigate(direction){if(this.props.options.length===0){return;} 10628const 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;} 10629break;case"next":targetId=activeOptionId+1;if(targetId>this.props.options.length-1){this.navigate("first");return;} 10630break;default:return;} 10631this.state.activeIndex=targetId;} 10632onKeydown(ev){if(!this.show){return;} 10633const hotkey=getActiveHotkey(ev);switch(hotkey){case"enter":markEventHandled(ev,"NavigableList.select");if(this.state.activeIndex===null){this.close();return;} 10634this.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;} 10635if(this.props.options.length!==0){ev.stopPropagation();} 10636ev.preventDefault();} 10637onOptionMouseEnter(index){}} 10638return __exports;});; 10639 10640/* /mail/static/src/core/common/notification_message.js */ 10641odoo.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");} 10642async 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);}} 10643get message(){return this.props.message;} 10644get 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});} 10645let 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});} 10646const 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"}),});}} 10647return __exports;});; 10648 10649/* /mail/static/src/core/common/notification_model.js */ 10650odoo.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
10650otification";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;} 10651const 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");}} 10652res_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");} 10653return"";} 10654get isFailure(){return["exception","bounce"].includes(this.notification_status);} 10655get icon(){if(this.isFailure){return"fa fa-envelope";} 10656return"fa fa-envelope-o";} 10657get label(){return"";} 10658get isFollowerNotification(){return this.res_partner_id&&this.mail_message_id.thread.followers.some((follower)=>follower.partner_id.id===this.res_partner_id.id);} 10659get 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";}
10660return"fa fa-trash-o";} 10661return"";} 10662get 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");} 10663return"";}} 10664Notification.register();return __exports;});; 10665 10666/* /mail/static/src/core/common/notification_permission_service.js */ 10667odoo.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";} 10668const registration=await browser.navigator.serviceWorker?.getRegistration();return(await registration?.pushManager.permissionState())??"prompt";} 10669const 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{} 10670const 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));} 10671return state;},};registry.category("services").add("mail.notification.permission",notificationPermissionService);return __exports;});; 10672 10673/* /mail/static/src/core/common/out_of_focus_service.js */ 10674odoo.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);} 10675setup(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=[];} 10676async notify(message,thread){const messageTypesHandledByPush=["comment","email","notification","user_notification","whatsapp_message",];if(messageTypesHandledByPush.includes(message.message_type)&&!message.isSelfAuthored&&(await this.hasServiceWorkInstalledAndPushSubscriptionActive())){return;} 10677const 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;}} 10678const 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,});} 10679async hasServiceWorkInstalledAndPushSubscriptionActive(){const registration=await browser.navigator.serviceWorker?.getRegistration();if(registration){const pushManager=await registration.pushManager;if(pushManager){const subscription=await pushManager.getSubscription();return!!subscription;}} 10680return false;} 10681async sendNotification({message,sound=true,title,type,icon}){if(!this.canSendNativeNotification||!(await this.multiTab.isOnMainTab())){if(sound){this._playSound();} 10682return;} 10683try{this.sendNativeNotification(title,message,icon,{sound});}catch(error){if(error.message.includes("ServiceWorkerRegistration")){this.sendOdooNotification(message,{sound,title,type});}else{throw error;}}} 10684async 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()();} 10685if(sound){this._playSound();}} 10686sendNativeNotification(title,message,icon,{sound=true}={}){const notification=new Notification(title,{body:message,icon,});notification.addEventListener("click",({target:notification})=>{window.focus();
10686notification.close();});if(sound){this._playSound();}} 10687async _playSound(){if(isAndroid()&&browser.Notification?.permission==="granted"){return;} 10688if(this.canPlayAudio&&this.store.settings.messageSound&&(await this.multiTab.isOnMainTab())){this.soundEffectService.play("new-message");}} 10689get canPlayAudio(){return typeof Audio!=="undefined";} 10690get canSendNativeNotification(){return Boolean(window.Notification&&window.Notification.permission==="granted");}} 10691const 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;});; 10692 10693/* /mail/static/src/core/common/partner_compare.js */ 10694odoo.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;} 10695if(!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;} 10696if(!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);} 10697const isFollower1=followerList.some((follower)=>p1.eq(follower.partner_id));const isFollower2=followerList.some((follower)=>p2.eq(follower.partner_id));if(isFollower1&&!isFollower2){return-1;} 10698if(!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;} 10699if(!cleanedName1.startsWith(searchTerm)&&cleanedName2.startsWith(searchTerm)){return 1;} 10700if(cleanedName1<cleanedName2){return-1;} 10701if(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;} 10702if(!cleanedEmail1.startsWith(searchTerm)&&cleanedEmail2.startsWith(searchTerm)){return 1;} 10703if(cleanedEmail1<cleanedEmail2){return-1;} 10704if(cleanedEmail1>cleanedEmail2){return 1;}},{sequence:55});partnerCompareRegistry.add("mail.id",(p1,p2)=>p1.id-p2.id,{sequence:75});return __exports;});; 10705 10706/* /mail/static/src/core/common/plugin/mail_composer_plugin.js */ 10707odoo.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)=>
10707(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);} 10708handlePasteHtmlOverride(sanitizedFragment){if(sanitizedFragment.childNodes.length===0){return false;} 10709const removeStyle=(node)=>{if(node.nodeType===Node.ELEMENT_NODE){const tagName=node.nodeName.toUpperCase();if(tagName==="BR"){return;} 10710if(!ALLOWED_TAGS.includes(tagName)){node.replaceWith(document.createTextNode(node.textContent));return;} 10711node.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");}} 10712[...node.childNodes].forEach(removeStyle);}};[...sanitizedFragment.childNodes].forEach(removeStyle);this.dependencies.dom.insert(sanitizedFragment);this.dependencies.history.addStep();return true;}} 10713return __exports;});; 10714 10715/* /mail/static/src/core/common/plugin/mention_plugin.js */ 10716odoo.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"];} 10717selectAll({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);} 10718if(closestElement(focusNode,SELECTOR)){const endMention=closestElement(focusNode,SELECTOR);focusNode=endMention.parentNode;focusOffset=Array.prototype.indexOf.call(focusNode.childNodes,endMention)+1;} 10719this.dependencies.selection.setSelection({anchorNode,anchorOffset,focusNode,focusOffset,});} 10720get 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,},];} 10721async 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);}} 10722prepareValidMentionLinks(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();}}} 10723async isValidChannelMentionElement(el){if(el.dataset.oeModel!=="discuss.channel"){return false;} 10724const channel=await this.store.Thread.getOrFetch({model:"discuss.channel",id:Number(el.dataset.oeId),});if(!channel){return false;} 10725const validChannelMention=generateThreadMentionElement(channel);return(validChannelMention.getAttribute("href")===el.getAttribute("href")&&[...validChannelMention.classList].every((cls)=>el.classList.contains(cls)));}} 10726return __exports;});; 10727 10728/* /mail/static/src/core/common/plugin/plugin_sets.js */ 10729odoo.define('@mail/core/common/plugin/plugin_sets',['@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{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,ColorPlugin,FeffPlugin,HintPlugin,InlineCodePlugin,LinkPastePlugin,LinkPlugin,MailComposerPlugin,MentionPlugin,ProtectedNodePlugin,ShortCutPlugin,TabulationPlugin,];const MAIL_PLUGINS=__exports.MAIL_PLUGINS=[...MAIL_CORE_PLUGINS,ToolbarPlugin];
10729const MAIL_SMALL_UI_PLUGINS=__exports.MAIL_SMALL_UI_PLUGINS=MAIL_CORE_PLUGINS;return __exports;});; 10730 10731/* /mail/static/src/core/common/quick_reaction_menu.js */ 10732odoo.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;} 10733if(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;} 10734this.togglePicker(ev.key);});} 10735togglePicker(initialSearchTerm){if(this.picker.isOpen){this.picker.close();}else{this.picker.open(this.toggle,{initialSearchTerm});}} 10736getEmojiShortcode(emoji){return this.store.emojiLoader.loaded?.emojiValueToShortcodes?.[emoji]?.[0]??"?";} 10737onClick(){if(!this.store.emojiLoader.isLoaded){loadEmoji();} 10738if(this.ui.isSmall){this.props.action.onSelected();}else{this.picker.close();if(this.dropdown.isOpen){this.dropdown.close();}else{this.dropdown.open();}}} 10739toggleReaction(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);} 10740if(resetOnSelect){this.dropdown.close();this.picker.close();}} 10741get 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,};} 10742reactedBySelf(emoji){return this.props.message.reactions.some((r)=>r.content===emoji&&this.props.message.effectiveSelf.in(r.personas));} 10743get 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)));} 10744get navigationOptions(){return{onUpdated:(navigator)=>{if(!navigator.activeItem){navigator.items[0]?.setActive();}},hotkeys:{arrowright:(navigator)=>navigator.next(),arrowleft:(navigator)=>navigator.previous(),arrowdown:null,arrowup:null,},};}} 10745return __exports;});; 10746 10747/* /mail/static/src/core/common/record.js */ 10748odoo.define('@mail/core/common/record',['@mail/model/export'],function(require){'use strict';let __exports={};Object.assign(__exports,require("@mail/model/export"));return __exports;});; 10749 10750/* /mail/static/src/core/common/relative_time.js */ 10751odoo.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);});} 10752computeRelativeTime(datetime){if(!datetime){this.relativeTime="";return;} 10753const 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();} 10754const updateDelay=absDelta<MINUTE?absDelta:absDelta<HOUR?MINUTE:HOUR;this.timeout=setTimeout(()=>{this.computeRelativeTime(this.props.datetime);this.render();},updateDelay);}} 10755return __exports;});; 10756 10757/* /mail/static/src/core/common/res_company_model.js */ 10758odoo.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;} 10759ResCompany.register();return __exports;});; 10760 10761/* /mail/static/src/core/common/res_groups_model.js */ 10762odoo.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");} 10763ResGroups.register();return __exports;});; 10764 10765/* /mail/static/src/core/common/res_groups_privilege_model.js */ 10766odoo.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";} 10767ResGroupsPrivilege.register();return __exports;});; 10768 10769/* /mail/static/src/core/common/res_lang_model.js */ 10770odoo.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;
10770name;} 10771ResLang.register();return __exports;});; 10772 10773/* /mail/static/src/core/common/res_partner_model.js */ 10774odoo.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;} 10775_triggerPresenceSubscription=fields.Attr(null,{compute(){return this.monitorPresence&&this.presenceChannel;},onUpdate(){if(this.previousPresencechannel){this.store.env.services.bus_service.deleteChannel(this.previousPresencechannel);} 10776if(this._triggerPresenceSubscription){this.store.env.services.bus_service.addChannel(this.presenceChannel);} 10777this.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;} 10778return 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}`;} 10779return channel;},});previousPresencechannel;write_date=fields.Datetime();_computeDisplayName(){return this.name||this.display_name;} 10780get avatarUrl(){const accessTokenParam={};if(this.store.self.main_user_id?.share!==false){accessTokenParam.access_token=this.avatar_128_access_token;} 10781return imageUrl("res.partner",this.id,"avatar_128",{...accessTokenParam,unique:this.write_date,});} 10782get displayName(){return this._computeDisplayName();} 10783searchChat(){return Object.values(this.store.Thread.records).find((thread)=>thread.channel_type==="chat"&&thread.correspondent?.persona.eq(this));} 10784updateImStatus(newStatus){if(newStatus==="offline"){this.offline_since=DateTime.now();} 10785this.im_status=newStatus;}} 10786ResPartner.register();return __exports;});; 10787 10788/* /mail/static/src/core/common/res_role_model.js */ 10789odoo.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;} 10790ResRole.register();return __exports;});; 10791 10792/* /mail/static/src/core/common/res_users_model.js */ 10793odoo.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;} 10794im_status;is_admin;get name(){return this.partner_id?.name;} 10795notification_type;partner_id=fields.One("res.partner");get phone(){return this.partner_id?.phone;} 10796share;signature=fields.Html(undefined);getSignatureBlock(){if(!this.signature){return"";} 10797const 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);}} 10798ResUsers.register();return __exports;});; 10799 10800/* /mail/static/src/core/common/search_message_input.js */ 10801odoo.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});} 10802search(){this.props.messageSearch.searchTerm=this.state.searchTerm;this.props.messageSearch.search();this.state.searchedTerm=this.state.searchTerm;} 10803clear(){this.state.searchTerm="";this.state.searchedTerm=this.state.searchTerm;this.props.messageSearch.clear();this.props.closeSearch?.();} 10804onKeydownSearch(ev){if(ev.key!=="Enter"){return;} 10805if(!this.state.searchTerm){this.clear();}else{this.search();}} 10806onChangeSearchFilter(searchFilter){if(searchFilter.is_notification!==this.props.messageSearch.is_notification){this.props.messageSearch.is_notification=searchFilter.is_notification;this.search();}} 10807get 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,},];}} 10808return __exports;});; 10809 10810/* /mail/static/src/core/common/search_message_result.js */ 10811odoo.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;} 10812return _t("%s messages found",this.props.messageSearch.count);} 10813onLoadMoreVisible(){const before=this.props.messageSearch?.messages?Math.min(...this.props.messageSearch.messages.map((message)=>message.id)):false;this.props.messageSearch.search(before);}} 10814return __exports;});; 10815 10816/* /mail/static/src/core/common/search_messages_panel.js */ 10817odoo.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)=>
10817{if(this.props.thread.notEq(nextProps.thread)){this.env.searchMenu?.close();}});} 10818get title(){return _t("Search Message");}} 10819return __exports;});; 10820 10821/* /mail/static/src/core/common/settings_model.js */ 10822odoo.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;} 10823setup(){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();} 10824delete(){browser.removeEventListener("storage",this.onStorage);super.delete(...arguments);} 10825channel_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;} 10826browser.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;} 10827return 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;} 10828return constraints;} 10829get cameraConstraints(){const constraints={width:1280,};if(this.cameraFacingMode){constraints.facingMode=this.cameraFacingMode;}else if(this.cameraInputDeviceId){constraints.deviceId=this.cameraInputDeviceId;} 10830return constraints;} 10831get NOTIFICATIONS(){return[{label:"all",name:_t("All Messages"),},{label:"mentions",name:_t("Mentions Only"),},{label:"no_notif",name:_t("Nothing"),},];} 10832get 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"),},];} 10833setUseBlur(newValue){if(newValue){browser.localStorage.setItem(USE_BLUR_LS,true);}else{browser.localStorage.removeItem(USE_BLUR_LS);} 10834this._recomputeUseBlur++;} 10835getMuteUntilText(dt){if(dt){return dt.year<=luxon.DateTime.now().year+2?_t(`Until %s`,dt.toLocaleStr
10835ing(luxon.DateTime.DATETIME_MED)):_t("Until I turn it back on");} 10836return undefined;} 10837async setCustomNotifications(custom_notifications,thread=undefined){return rpc("/discuss/settings/custom_notifications",{custom_notifications:!thread&&custom_notifications==="mentions"?false:custom_notifications,channel_id:thread?.id,});} 10838async setMuteDuration(minutes,thread=undefined){return rpc("/discuss/settings/mute",{minutes,channel_id:thread?.id,});} 10839async setAudioInputDevice(audioInputDeviceId){this.audioInputDeviceId=audioInputDeviceId;browser.localStorage.setItem("mail_user_setting_audio_input_device_id",audioInputDeviceId);} 10840async setAudioOutputDevice(audioOutputDeviceId){this.audioOutputDeviceId=audioOutputDeviceId;browser.localStorage.setItem("mail_user_setting_audio_output_device_id",audioOutputDeviceId);} 10841async setCameraInputDevice(cameraInputDeviceId){this.cameraFacingMode=undefined;this.cameraInputDeviceId=cameraInputDeviceId;browser.localStorage.setItem("mail_user_setting_camera_input_device_id",cameraInputDeviceId);} 10842setDelayValue(value){this.voice_active_duration=parseInt(value,10);this._saveSettings();} 10843async setPushToTalkKey(ev){const nonElligibleKeys=new Set(["Shift","Control","Alt","Meta"]);let pushToTalkKey=`${ev.shiftKey || ""}.${ev.ctrlKey || ev.metaKey || ""}.${ 10844 ev.altKey || "" 10845 }`;if(!nonElligibleKeys.has(ev.key)){pushToTalkKey+=`.${ev.key === " " ? "Space" : ev.key}`;} 10846this.push_to_talk_key=pushToTalkKey;this._saveSettings();} 10847async saveVolumeSetting({partnerId,guestId,volume}){if(!this.store.self_partner){return;} 10848const key=`${partnerId}_${guestId}`;if(this.volumeSettingsTimeouts.get(key)){browser.clearTimeout(this.volumeSettingsTimeouts.get(key));} 10849this.volumeSettingsTimeouts.set(key,browser.setTimeout(this._onSaveVolumeSettingTimeout.bind(this,{key,partnerId,guestId,volume}),5000));} 10850setThresholdValue(voiceActivationThreshold){this.voiceActivationThreshold=voiceActivationThreshold;this.saveVoiceThresholdDebounce();} 10851buildKeySet({shiftKey,ctrlKey,altKey,key}){const keys=new Set();if(key){keys.add(key==="Meta"?"Alt":key);} 10852if(shiftKey){keys.add("Shift");} 10853if(ctrlKey){keys.add("Control");} 10854if(altKey){keys.add("Alt");} 10855return keys;} 10856isPushToTalkKey(ev){if(!this.use_push_to_talk||!this.push_to_talk_key){return false;} 10857const[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));} 10858return settingsKeySet.has(ev.key==="Meta"?"Alt":ev.key);} 10859pushToTalkKeyFormat(){if(!this.push_to_talk_key){return;} 10860const[shiftKey,ctrlKey,altKey,key]=this.push_to_talk_key.split(".");return{shiftKey:!!shiftKey,ctrlKey:!!ctrlKey,altKey:!!altKey,key:key||false,};} 10861setPushToTalk(value){this.use_push_to_talk=value;this._saveSettings();} 10862_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");} 10863async _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,},});} 10864async _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});} 10865onStorage(ev){if(ev.key===MESSAGE_SOUND){this._recomputeMessageSound++;} 10866if(ev.key===USE_BLUR_LS){this._recomputeUseBlur++;} 10867if(ev.key==="mail_user_setting_audio_input_device_id"){this.audioInputDeviceId=ev.newValue;} 10868if(ev.key==="mail_user_setting_audio_output_device_id"){this.audioOutputDeviceId=ev.newValue;} 10869if(ev.key==="mail_user_setting_camera_input_device_id"){this.cameraInputDeviceId=ev.newValue;}} 10870async _saveSettings(){if(!this.store.self_partner){return;} 10871browser.clearTimeout(this.globalSettingsTimeout);this.globalSettingsTimeout=browser.setTimeout(()=>this._onSaveGlobalSettingsTimeout(),2000);}} 10872Settings.register();return __exports;});; 10873 10874/* /mail/static/src/core/common/sound_effects_service.js */ 10875odoo.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
10875hannel_01_out"},};} 10876play(soundEffectName,{loop=false,volume}={}){if(typeof browser.Audio==="undefined"){return;} 10877const soundEffect=this.soundEffects[soundEffectName];if(!soundEffect){return;} 10878if(!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;} 10879if(!soundEffect.audio.paused){soundEffect.audio.pause();} 10880soundEffect.audio.currentTime=0;soundEffect.audio.loop=loop;soundEffect.audio.volume=volume??soundEffect.defaultVolume??1;Promise.resolve(soundEffect.audio.play()).catch(()=>{});} 10881stop(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;}}}}} 10882const soundEffects=__exports.soundEffects={start(env){return new SoundEffects(env);},};registry.category("services").add("mail.sound_effects",soundEffects);return __exports;});; 10883 10884/* /mail/static/src/core/common/store_service.js */ 10885odoo.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);} 10886return{pyModels:Object.values(pyToJsModels)};},getActualModelName(store,ctx,pyOrJsModelName){if(!(store instanceof Store)){return super.getActualModelName(...arguments);} 10887if(ctx.pyModels.includes(pyOrJsModelName)){console.warn(`store.insert() should receive the python model name instead of â${pyOrJsModelName}â.`);} 10888return pyToJsModels[pyOrJsModelName]||pyOrJsModelName;},getExtraFieldsFromModel(store,pyOrJsModelName){if(!(store instanceof Store)){return super.getExtraFieldsFromModel(...arguments);} 10889return 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;} 10890allChannels=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)=>
10890f2.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));} 10891return threads;},sort(thread1,thread2){const compareFunctions=threadCompareRegistry.getAll();for(const fn of compareFunctions){const result=fn(thread1,thread2);if(result!==undefined){return result;}} 10892return 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);} 10893discussDropdownMenuClass(ctx){const simulateDarkTheme=this.shouldSimulateDarkTheme(ctx);return attClassObjectToString({"o-discuss-dropdownMenu d-flex flex-column border-secondary":true,"o-simulateDarkTheme":simulateDarkTheme,"bg-view":!simulateDarkTheme,});} 10894standaloneInboxMessages=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;} 10895tmpMessage.postFailRedo=()=>{tmpMessage.postFailRedo=undefined;tmpMessage.thread.messages.delete(tmpMessage);tmpMessage.thread.messages.add(tmpMessage);this.doMessagePost(params,tmpMessage);};} 10896return res;});} 10897async 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;} 10898async initialize(){await this.fetchStoreData("init_messaging");this.isReady.resolve();} 10899makeCachedFetchData(name,params){let def=null;const r=reactive({status:"not_fetched",fetch:()=>{if(["fetching","fetched"].includes(r.status)){return def;} 10900r.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;} 10901_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;} 10902_fetchStoreDataRpc(fetchParams){return rpc(this.fetchReadonly?"/mail/data":"/mail/action",{fetch_params:fetchParams,context:user.context},{silent:this.fetchSilent});} 10903async 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"});}} 10904tabToThreadType(tab){return tab==="chat"?["chat","group"]:[tab];} 10905handleClickOnLink(ev,thread){const link=ev.target.closest("a");if(!link){return;} 10906const 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)=>
10906{if(hasAccess){targetThread.highlightMessage=message;let isOpen=targetThread.eq(thread);if(!isOpen){isOpen=targetThread.open({focus:true,swapOpened:false});} 10907if(!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;} 10908if(browser.location.host===url.host&&browser.location.pathname.startsWith("/odoo")){this.ChatWindow.get({thread})?.fold();}} 10909return false;} 10910setup(){super.setup();this._fetchStoreDataDebounced=debounce(this._fetchStoreDataDebounced,Store.FETCH_DATA_DEBOUNCE_DELAY);} 10911onStarted(){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{} 10912if(this.self_partner?.im_status?.includes("busy")||(isTabFocused&&thread?.isDisplayed)){navigator.serviceWorker.controller?.postMessage({type:"notification-display-response",payload:{correlationId},});}} 10913if(type==="notification-displayed"){this.onPushNotificationDisplayed(payload);}});} 10914onPushNotificationDisplayed(payload){if(["mail.thread","discuss.channel"].includes(payload.model)){this.env.services["mail.out_of_focus"]._playSound();}} 10915async getChat({userId,partnerId}){const partner=await this.getPartner({userId,partnerId});if(!partner){return;} 10916let chat=partner.searchChat();if(!chat?.self_member_id?.is_pinned){chat=await this.joinChat(partner.id);} 10917if(!chat){this.env.services.notification.add(_t("An unexpected error occurred during the creation of the chat."),{type:"warning"});return;} 10918return chat;} 10919fillPartnersMentionToken(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;}}} 10920getLastMessageId(){return Object.values(this["mail.message"].records).reduce((lastMessageId,message)=>Math.max(lastMessageId,message.id),0);} 10921handleValidChannelMention(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}`);}} 10922getMentionsFromText(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;} 10923remaining[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;}
10924async 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);} 10925postData={body:await generateEmojisOnHtml(body),email_add_signature:emailAddSignature,message_type:"comment",subtype_xmlid:subtype,};if(attachments.length){postData.attachment_ids=attachments.map(({id})=>id);} 10926if(partner_ids.length){Object.assign(postData,{partner_ids});this.fillPartnersMentionToken(postData);} 10927if(role_ids.length){Object.assign(postData,{role_ids});} 10928if(thread.model==="discuss.channel"&&validMentions?.specialMentions.length){postData.special_mentions=validMentions.specialMentions;} 10929if(attachments.length){postData.attachment_tokens=attachments.map((attachment)=>attachment.ownership_token);} 10930if(recipientEmails.length){postData.partner_emails=recipientEmails;} 10931const params={post_data:postData,thread_id:thread.id,thread_model:thread.model,};if(cannedResponseIds?.length){params.canned_response_ids=cannedResponseIds;} 10932return params;} 10933notifySendFromMailbox(recordName){this.env.services.notification.add(_t('Message posted on "%s"',recordName),{type:"info",});} 10934getNextTemporaryId(){const lastMessageId=this.getLastMessageId();if(prevLastMessageId===lastMessageId){temporaryIdOffset+=0.01;}else{prevLastMessageId=lastMessageId;temporaryIdOffset=0.01;} 10935return lastMessageId+temporaryIdOffset;} 10936async getPartner({userId,partnerId}
10936){if(userId){let user=this.users[userId];if(!user){this.users[userId]={id:userId};user=this.users[userId];} 10937if(!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];}} 10938if(!user.partner_id){this.env.services.notification.add(_t("You can only chat with existing users."),{type:"warning",});return;} 10939partnerId=user.partner_id;} 10940if(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;} 10941if(!partner.main_user_id){partner.main_user_id=userId;}} 10942return partner;}} 10943async 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});} 10944return channel;} 10945async openChat(person){const chat=await this.getChat(person);chat?.open({focus:true});} 10946openDocument({id,model}){this.env.services.action.doAction({type:"ir.actions.act_window",res_model:model,views:[[false,"form"]],res_id:id,});} 10947onClickPartnerMention(ev,id){this.openChat({partnerId:id});} 10948async 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),};}} 10949Store.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;});; 10950 10951/* /mail/static/src/core/common/suggestion_hook.js */ 10952odoo.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.isDismissed=false;this.update();if(this.search.position===undefined||!this.search.delimiter){return;} 10953if(!this.composer.store.self_partner){return;} 10954if(this.lastFetchedSearch?.count===0&&(!this.search.delimiter||this.isSearchMoreSpecificThanLastFetch)){return;} 10955this.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,]);} 10956comp;get composer(){return this.comp.props.composer;} 10957suggestionService=useService("mail.suggestion");state=useState({count:0,items:undefined,isFetching:false,});search={delimiter:undefined,position:undefined,term:"",};lastFetchedSearch;isDismissed=false;get isSearchMoreSpecificThanLastFetch(){return(this.lastFetchedSearch.delimiter===this.search.delimiter&&this.search.term.startsWith(this.lastFetchedSearch.term)&&this.lastFetchedSearch.position>=this.search.position);} 10958clearRawMentions(){this.composer.mentionedChannels.length=0;this.composer.mentionedPartners.length=0;this.composer.mentionedRoles.length=0;} 10959clearCannedResponses(){this.composer.cannedResponses=[];} 10960clearSearch(){Object.assign(this.search,{delimiter:undefined,position:undefined,term:"",});this.state.items=undefined;} 10961dismiss(){this.isDismissed=true;} 10962detect(){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;} 10963start=selection.startOffset;end=selection.endOffset;text=selection.anchorNode.textContent;}else{start=this.composer.selection.start;end=this.composer.selection.end;text=this.composer.composerText;} 10964if(start!==end){this.clearSearch();return;} 10965const candidatePositions=[];let numberOfSpaces=0;for(let index=start-1;index>=0;
10965--index){if(/\s/.test(text[index])){numberOfSpaces++;if(numberOfSpaces===2){break;}} 10966candidatePositions.push(index);} 10967if(this.search.position!==undefined&&this.search.position<start){candidatePositions.push(this.search.position);} 10968const supportedDelimiters=this.suggestionService.getSupportedDelimiters(this.thread,this.comp.env);for(const candidatePosition of candidatePositions){if(candidatePosition<0||candidatePosition>=text.length){continue;} 10969const 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;}} 10970return goodCandidate;};const candidateDelimiter=findAppropriateDelimiter();if(!candidateDelimiter){continue;} 10971const charBeforeCandidate=text[candidatePosition-1];if(charBeforeCandidate&&!/\s/.test(charBeforeCandidate)){continue;} 10972Object.assign(this.search,{delimiter:candidateDelimiter,position:candidatePosition,term:text.substring(candidatePosition+candidateDelimiter.length,start),});this.state.count++;return;} 10973this.clearSearch();} 10974get thread(){return this.composer.thread||this.composer.message?.thread;} 10975insert(option){let position=this.search.position+1;if([":","::"].includes(this.search.delimiter)||(this.comp.composerService.htmlEnabled&&this.search.delimiter!=="/")){position=this.search.position;} 10976if(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,});} 10977if(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);} 10978if(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)+ 10979this.composer.composerText.substring(this.composer.selection.end);this.clearSearch();this.composer.insertText(`${option.label} `,position);}} 10980update(){if(!this.search.delimiter){return;} 10981const{type,suggestions}=this.suggestionService.searchSuggestions(this.search,{thread:this.thread,});if(!suggestions.length){this.state.items=undefined;return;} 10982const limit=8;suggestions.length=Math.min(suggestions.length,limit);this.state.items={type,suggestions};} 10983async fetchSuggestions(){if(!this.thread||status(this.comp)==="destroyed"){return;} 10984let 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;} 10985throw e;}finally{if(resetFetchingState){this.state.isFetching=false;}} 10986if(!this.thread||status(this.comp)==="destroyed"||this.isDismissed){return;} 10987this.update();this.lastFetchedSearch={...this.search,count:this.state.items?.suggestions.length??0,};if(!this.state.items?.suggestions.length){this.clearSearch();}}} 10988__exports.useSuggestion=useSuggestion;function useSuggestion(){return new UseSuggestion(useComponent());} 10989__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)=>
10989{if(suggestion.isSpecial){return{...suggestion,group:1,optionTemplate:"mail.Composer.suggestionSpecial",classList,};} 10990if(suggestion?.Model?.getName?.()==="res.role"){return{label:suggestion.name,role:suggestion,thread,optionTemplate:"mail.Composer.suggestionRole",classList,};} 10991return{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:[]};}} 10992__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);} 10993return inlineElement;} 10994return __exports;});; 10995 10996/* /mail/static/src/core/common/suggestion_service.js */ 10997odoo.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;} 10998getSupportedDelimiters(thread,env){return[["@"],["#"],["::"],[":",undefined,2]];} 10999async 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;}}} 11000makeOrmCall(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));});} 11001async fetchPartnersRoles(term,thread,{abortSignal}={}){const kwargs={search:term};if(thread?.model==="discuss.channel"){kwargs.channel_id=thread.id;} 11002const data=await this.makeOrmCall("res.partner",thread?.model==="discuss.channel"?"get_mention_suggestions_from_channel":"get_mention_suggestions",[],kwargs,{abortSignal});this.store.insert(data);} 11003async fetchThreads(term,{abortSignal}={}){const data=await this.makeOrmCall("discuss.channel","get_mention_suggestions",[],{search:term},{abortSignal});this.store.insert(data);} 11004searchCannedResponseSuggestions(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;} 11005if(!cleanedName1.startsWith(cleanedSearchTerm)&&cleanedName2.startsWith(cleanedSearchTerm)){return 1;} 11006if(cleanedName1<cleanedName2){return-1;} 11007if(cleanedName1>cleanedName2){return 1;} 11008return c1.id-c2.id;};return{type:"mail.canned.response",suggestions:cannedResponses.sort(sortFunc),};} 11009searchEmojisSuggestions(cleanedSearchTerm){let emojis=[];if(this.emojis&&cleanedSearchTerm){emojis=fuzzyLookup(cleanedSearchTerm,this.emojis,(emoji)=>emoji.shortcodes);} 11010return{type:"emoji",suggestions:emojis,};} 11011searchSuggestions({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],};} 11012case"#":return this.searchChannelSuggestions(cleanedSearchTerm);case"::":return this.searchCannedResponseSuggestions(cleanedSearchTerm);case":":return this.searchEmojisSuggestions(cleanedSearchTerm);} 11013return{type:undefined,suggestions:[],};} 11014searchRoleSuggestions(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;} 11015if(!cleanedName1.startsWith(cleanedSearchTerm)&&cleanedName2.startsWith(cleanedSearchTerm)){return 1;} 11016if(cleanedName1<cleanedName2){return-1;} 11017if(cleanedName1>cleanedName2){return 1;} 11018return r1.id-r2.id;};return{suggestions:roles.sort(sortFunc),};} 11019isSuggestionValid(partner,thread){return((this.store.self_partner?.main_user_id?.share===false||partner.mention_token)&&partner.notEq(this.store.odoobot));} 11020getPartnerSuggestions(thread){return Object.values(this.store["res.partner"].records).filter((partner)=>this.isSuggestionValid(partner,thread));} 11021searchPartnerSuggestions(cleanedSearchTerm,thread){const partners=this.getPartnerSuggestions(thread);const suggestions=[];for(const partner of partners){if(!partner.name){continue;} 11022if(cleanTerm(partner.name).includes(cleanedSearchTerm)||(partner.email&&cleanTerm(partner.email).includes(cleanedSearchTerm))){suggestions.push(partner);}} 11023suggestions.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)],};} 11024sortPartnerSuggestions(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;} 11025for(const fn of compareFunctions){const result=fn(p1,p2,{env:this.env,searchTerm:cleanedSearchTerm,thread,context,});if(result!==undefined){return result;}}});} 11026sortPartnerSuggestionsContext(){return{};} 11027searchChannelSuggestions(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;} 11028if(!isPublicChannel1&&isPublicChannel2){return 1;} 11029if(c1.hasSelfAsMember&&!c2.hasSelfAsMember){return-1;} 11030if(!c1.hasSelfAsMember&&c2.hasSelfAsMember){return 1;} 11031const cleanedDisplayName1=cleanTerm(c1.displayName);const cleanedDisplayName2=cleanTerm(c2.displayName);if(cleanedDisplayName1.startsWith(cleanedSearchTerm)&&!cleanedDisplayName2.startsWith(cleanedSearchTerm)){return-1;} 11032if(!cleanedDisplayName1.startsWith(cleanedSearchTerm)&&cleanedDisplayName2.startsWith(cleanedSearchTerm)){return 1;} 11033if(cleanedDisplayName1<cleanedDisplayName2){return-1;} 11034if(cleanedDisplayName1>cleanedDisplayName2){return 1;} 11035return c1.id-c2.id;};return{type:"Thread",suggestions:suggestionList.sort(sortFunc),};}} 11036const 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;});; 11037 11038/* /mail/static/src/core/common/thread.js */ 11039odoo.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;} 11040this.updateShowJumpPresent();},()=>[this.state.mountedAndLoaded]);onMounted(()=>
11040{if(!this.env.chatter||this.env.chatter?.fetchMessages){if(this.env.chatter){this.env.chatter.fetchMessages=false;} 11041this.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;} 11042const 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;} 11043if(!this.env.chatter||this.env.chatter?.fetchMessages){if(this.env.chatter){this.env.chatter.fetchMessages=false;} 11044toRaw(nextProps.thread).fetchNewMessages();}});} 11045computeJumpPresentPosition(){if(!this.viewportEl||!this.jumpPresentRef.el){return;} 11046const 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(${ 11047 this.env.inChatter ? 22 : width - ps - pe - 22 11048 }px, ${ 11049 this.env.inChatter && !this.env.inChatter.aside 11050 ? -22 11051 : height - pt - pb - (this.env.inChatter?.aside ? 75 : 0) 11052 }px)`;} 11053setupScroll(){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;} 11054this.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]);} 11055applyScroll(){if(!this.props.thread.isLoaded||!this.state.mountedAndLoaded){this.reset();return;} 11056const 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;}} 11057applyScrollContextually(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+ 11058this.scrollableRef.el.scrollHeight- 11059this.snapshot.scrollHeight);}else if(this.snapshot&&messagesAtBottom){this.setScroll(this.snapshot.scrollTop);}else if(!this.env.messageHighlight?.highlightedMessageId&&thread.scrollTop!==undefined){let value;
11059if(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- 11060thread.scrollTop- 11061this.scrollableRef.el.clientHeight;} 11062if((this.lastSetValue===undefined||Math.abs(this.lastSetValue-value)>1)&&!this.isSmoothScrolling){this.setScroll(value,{smooth:typeof thread.scrollTop==="string"&&thread.scrollTop?.includes("smooth"),});}}} 11063fetchMessages(){toRaw(this.props.thread).fetchNewMessages();} 11064get viewportEl(){let viewportEl=this.scrollableRef.el;if(viewportEl&&viewportEl.clientHeight>browser.innerHeight){while(viewportEl&&viewportEl.clientHeight>browser.innerHeight){viewportEl=viewportEl.parentElement;}} 11065return viewportEl;} 11066get PRESENT_THRESHOLD(){const threshold=(this.viewportEl?.clientHeight??0)*PRESENT_VIEWPORT_THRESHOLD;return this.state.showJumpPresent?threshold-200:threshold;} 11067updateShowJumpPresent(){this.state.showJumpPresent=this.visibleState.isVisible&&(this.props.thread.loadNewer||this.presentThresholdState.isVisible===false);} 11068onClickLoadOlder(){this.props.thread.fetchMoreMessages();} 11069onClickRetry(){if(!this.props.thread.oldestPersistentMessage){this.fetchMessages();return;} 11070this.onClickLoadOlder();} 11071async 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);} 11072onFocusin(){this.props.thread.isFocusedByThread=true;const thread=toRaw(this.props.thread);if(thread?.scrollTop==="bottom"&&!thread.scrollUnread&&!thread.markedAsUnread){thread?.markAsRead();}} 11073onFocusout(){this.props.thread.isFocusedByThread=false;} 11074async onParentMessageClick(parentMessage){if(!parentMessage){return;} 11075const targetThread=parentMessage.thread;if(!targetThread){return;} 11076if(targetThread.eq(this.props.thread)){this.env.messageHighlight?.highlightMessage(parentMessage,targetThread);}else{targetThread.highlightMessage=parentMessage;await targetThread.open({focus:true});}} 11077getMessageClassName(message){return!message.isNotification&&this.messageHighlight?.highlightedMessageId===message.id?"o-highlighted bg-view shadow-lg pb-1":"";} 11078async 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;} 11079this.props.thread.scrollTop=immediate?"bottom":"bottom-smooth";if(!this.ui.isSmall){this.props.thread.composer.autofocus++;}} 11080registerMessageRef(message,ref){if(!ref){this.refByMessageId.delete(message.id);return;} 11081this.refByMessageId.set(message.id,markRaw(ref));} 11082reset(){this.state.mountedAndLoaded=false;if(this.props.thread.isLoaded){this.state.resetCount++;} 11083this.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;} 11084isSquashed(msg,prevMsg){if(this.props.thread.model==="mail.box"){return false;} 11085if(!prevMsg||prevMsg.message_type==="notification"||this.env.inChatter){return false;} 11086if(!msg.author?.eq(prevMsg.author)){return false;} 11087if(!msg.thread?.eq(prevMsg.thread)){return false;} 11088if(msg.isNote){return false;} 11089return msg.datetime.ts-prevMsg.datetime.ts<5*60*1000;} 11090get isAtBottom(){if(this.loadNewer){return false;} 11091return this.props.order==="asc"?this.scrollableRef.el.scrollHeight- 11092this.scrollableRef.el.scrollTop- 11093this.scrollableRef.el.clientHeight<30:this.scrollableRef.el.scrollTop<30;} 11094onScroll(){const thread=toRaw(this.props.thread);if(this.isAtBottom&&!thread.markedAsUnread&&thread.isFocused&&!thread.markingAsRead){thread.markAsRead();} 11095this.saveScroll();} 11096saveScroll(){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- 11097this.scrollableRef.el.scrollTop- 11098this.scrollableRef.el.clientHeight;}} 11099async scrollToHighlighted(){if(!this.messageHighlight?.highlightedMessageId||this.scrollingToHighlight){return;} 11100const 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));}} 11101get orderedMessages(){const messages=this.state.mountedAndLoaded?this.props.thread.messages:this.props.thread.phantomMessages;return this.props.order==="asc"?[...messages]:[...messages].reverse();} 11102get showLoadOlder(){return(this.props.thread.loadOlder&&this.props.thread.isLoaded&&!this.props.thread.isTransient&&!this.props.thread.hasLoadingFailed&&!this.messageHighlight?.initiated&&!this.messageHighlight?.highlightedMessageId);} 11103setScroll(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);}} 11104this.scrollableRef.el.scrollTo({behavior:smooth?"smooth":undefined,top:value});this.lastSetValue=value;this.messageHighlight?.startupDeferred?.resolve();this.saveScroll();} 11105get showStartMessage(){return(this.state.mountedAndLoaded&&["channel","group","chat"].includes(this.props.thread.channel_type));} 11106get startMessageTitle(){const channelName=this.props.thread.name;if(this.props.thread.parent_channel_id){return channelName;} 11107if(this.props.thread.channel_type==="channel"){return _t("Welcome to #%(channelName)s!",{channelName});} 11108return this.props.thread.displayName;} 11109get 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});}} 11110if(this.props.thread.channel_type==="channel"){return _t("This is the start of the #%(channelName)s channel",{channelName:this.props.thread.name,});} 11111if(this.props.thread.channel_type==="group"){return _t("This is the start of %(conversationName)s group",{conversationName:this.props.thread.displayName,});} 11112return _t("This is the start of your direct chat with %(userName)s",{userName:this.props.thread.displayName,});}} 11113return __exports;});; 11114 11115/* /mail/static/src/core/common/thread_actions.js */ 11116odoo.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);} 11117registerThreadAction("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,});
11117registerThreadAction("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);} 11118return tags;},});const ThreadAction=__exports.ThreadAction=class ThreadAction extends Action{popover=null;threadFn;constructor({thread}){super(...arguments);this.threadFn=typeof thread==="function"?thread:()=>thread;} 11119get params(){return Object.assign(super.params,{thread:this.threadFn()});} 11120get actionPanelComponent(){return this.definition.actionPanelComponent;} 11121get actionPanelComponentCondition(){return this.isActive&&this.actionPanelComponent&&this.condition&&!this.popover;} 11122get actionPanelComponentProps(){return this.definition.actionPanelComponentProps?.call(this,this.params);} 11123close({nextActiveAction}={}){if(this.toggle){this.owner.threadActions.activeAction=this.owner.threadActions.actionStack.pop();} 11124this.definition.close?.call(this,Object.assign(this.params,{nextActiveAction}));} 11125get isActive(){return this.id===this.owner.threadActions.activeAction?.id;} 11126get nameClass(){return typeof this.definition.nameClass==="function"?this.definition.nameClass.call(this,this.params):this.definition.nameClass;} 11127onSelected(ev,{keepPrevious}={}){if(ev){markEventHandled(ev,"ThreadAction.onSelected");} 11128if(this.toggle&&this.isActive){this.close();}else{this.open({keepPrevious});}} 11129open({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});}} 11130this.owner.threadActions.activeAction=this;} 11131this.definition.open?.call(this,this.params);} 11132get panelOuterClass(){return typeof this.definition.panelOuterClass==="function"?this.definition.panelOuterClass.call(this,this.params):this.definition.panelOuterClass;} 11133get toggle(){return this.definition.toggle;}} 11134class UseThreadActions extends UseActions{ActionClass=ThreadAction;actionStack=[];activeAction=null;} 11135__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();} 11136return useState(new UseThreadActions(component,transformedActions,useService("mail.store")));} 11137return __exports;});; 11138 11139/* /mail/static/src/core/common/thread_compare.js */ 11140odoo.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>
111400&&bNeedaction===0){return-1;} 11141if(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;} 11142if(!bMessageDateTime&&aMessageDatetime){return-1;} 11143if(aMessageDatetime&&bMessageDateTime&&aMessageDatetime!==bMessageDateTime){return bMessageDateTime-aMessageDatetime;}},{sequence:40});return __exports;});; 11144 11145/* /mail/static/src/core/common/thread_icon.js */ 11146odoo.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");} 11147get correspondent(){return this.props.thread.correspondent;} 11148get defaultChatIcon(){return{class:"fa fa-question-circle opacity-75",title:_t("No IM status available"),};}} 11149return __exports;});; 11150 11151/* /mail/static/src/core/common/thread_model.js */ 11152odoo.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;} 11153return localId.split(",").slice(1).join("_").replace(" AND ","_");} 11154static 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;}} 11155return thread;} 11156autofocus=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"];} 11157get canLeave(){return(this.allowedToLeaveChannelTypes.includes(this.channel_type)&&this.group_ids.length===0&&this.store.self_partner);} 11158get allowedToUnpinChannelTypes(){return["chat"];} 11159get canUnpin(){return(this.parent_channel_id||this.allowedToUnpinChannelTypes.includes(this.channel_type));} 11160can_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;} 11161return this.message_needaction_counter;} 11162isDisplayed=fields.Attr(false,{compute(){return this.computeIsDisplayed();},onUpdate(){this.isDisplayedOnUpdate();},});isDisplayedOnUpdate(){} 11163get composerDisabled(){return false;} 11164get isFocused(){return this.isFocusedCounter!==0;} 11165isFocusedByThread=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();},});
11165fetchMembersState="not_fetched";highlightMessage=fields.One("mail.message");access_token;hash;pid;get accessRestrictedToGroupText(){if(!this.group_public_id?.full_name){return false;} 11166return _t('Access restricted to group "%(groupFullName)s"',{groupFullName:this.group_public_id.full_name,});} 11167get busChannel(){return`${this.model}_${this.id}`;} 11168get followersFullyLoaded(){return(this.followersCount===(this.selfFollower?this.followers.length+1:this.followers.length));} 11169get attachmentsInWebClientView(){const attachments=this.attachments.filter((attachment)=>(attachment.isPdf||attachment.isImage)&&!attachment.uploading);attachments.sort((a1,a2)=>a2.id-a1.id);return attachments;} 11170get isUnread(){return this.needactionMessages.length>0;} 11171get typesAllowingCalls(){return["chat","channel","group"];} 11172get allowCalls(){return(!this.isTransient&&this.typesAllowingCalls.includes(this.channel_type)&&!this.correspondent?.persona.eq(this.store.odoobot));} 11173get canPostMessage(){return this.hasWriteAccess||(this.hasReadAccess&&this.canPostOnReadonly);} 11174getPersonaName(persona){return persona?.displayName||persona?.name;} 11175get hasAttachmentPanel(){return this.model==="discuss.channel";} 11176get isChatChannel(){return["chat","group"].includes(this.channel_type);} 11177get supportsCustomChannelName(){return this.isChatChannel&&this.channel_type!=="group";} 11178get displayName(){return this.display_name;} 11179computeIsDisplayed(){return this.store.ChatWindow.get({thread:this})?.isOpen;} 11180get avatarUrl(){return this.module_icon??this.store.DEFAULT_AVATAR;} 11181get allowDescription(){return["channel","group"].includes(this.channel_type);} 11182get fullNameWithParent(){const text=this.parent_channel_id?`${this.parent_channel_id.displayName} > ${this.displayName}`:this.displayName;return text;} 11183get isTransient(){return!this.id||this.id<0;} 11184get lastEditableMessageOfSelf(){const editableMessagesBySelf=this.nonEmptyMessages.filter((message)=>message.isSelfAuthored&&message.editable);if(editableMessagesBySelf.length>0){return editableMessagesBySelf.at(-1);} 11185return null;} 11186get needactionCounter(){return this.message_needaction_counter;} 11187newestMessage=fields.One("mail.message",{inverse:"threadAsNewest",compute(){return this.messages.at(-1);},});get newestPersistentMessage(){return this.messages.findLast((msg)=>Number.isInteger(msg.id));} 11188newestPersistentAllMessages=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));} 11189onPinStateUpdated(){} 11190get invitationLink(){if(!this.uuid||this.channel_type==="chat"){return undefined;} 11191return`${window.location.origin}/chat/${this.id}/${this.uuid}`;} 11192get isEmpty(){return this.messages.length===0;} 11193get nonEmptyMessages(){return this.messages.filter((message)=>!message.isEmpty);} 11194get persistentMessages(){return this.messages.filter((message)=>!message.is_transient&&!message.isPending);} 11195get prefix(){return this.isChatChannel?"@":"#";} 11196get rpcParams(){return{};} 11197async checkReadAccess(){await this.store.Thread.getOrFetch(this,["hasReadAccess"]);return this.hasReadAccess;} 11198executeCommand(command,body=""){return this.store.env.services.orm.call("discuss.channel",command.methodName,[[this.id]],{body});} 11199async fetchMessages({after,around,before}={}){this.status="loading";if(!["mail.box","discuss.channel"].includes(this.model)&&!this.id){this.isLoaded=true;return[];} 11200let 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;} 11201this.store.insert(res.data);const msgs=this.store["mail.message"].insert(res.messages.reverse());this.isLoaded=true;this.status="ready";return msgs;} 11202async 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,},});} 11203async fetchMoreMessages(epoch="older"){if(this.status==="loading"||(epoch==="older"&&!this.loadOlder)||(epoch==="newer"&&!this.loadNewer)){return;} 11204const 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;} 11205if((after!==undefined&&!this.messages.some((message)=>message.id===after))||(before!==undefined&&!this.messages.some((message)=>message.id===before))){return;} 11206const 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);} 11207if(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);}}} 11208this._enrichMessagesWithTransient();this.pendingNewMessages=[];} 11209get effectiveSelf(){return this.store.self_partner||this.store.self_guest;} 11210async fetchNewMessages(){if(this.status==="loading"||(!this.hasLoadingFailed&&this.isLoaded&&["discuss.channel","mail.box"].includes(this.model))){return;} 11211const after=this.isLoaded?this.newestPersistentMessage?.id:undefined;let fetched=[];try{fetched=await this.fetchMessages({after});}catch{return;} 11212let startIndex;if(after===undefined){startIndex=0;}else{const afterIndex=this.messages.findIndex((message)=>message.id===after);if(afterIndex===-1){return;}else{startIndex=afterIndex+1;}} 11213const 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,});}
11214getFetchParams(){if(this.model==="discuss.channel"){return{channel_id:this.id};} 11215if(this.model==="mail.box"){return{};} 11216return{thread_id:this.id,thread_model:this.model,...this.rpcParams,};} 11217getFetchRoute(){if(this.model==="discuss.channel"){return"/discuss/channel/messages";} 11218if(this.model==="mail.box"&&this.id==="inbox"){return`/mail/inbox/messages`;} 11219if(this.model==="mail.box"&&this.id==="starred"){return`/mail/starred/messages`;} 11220if(this.model==="mail.box"&&this.id==="history"){return`/mail/history/messages`;} 11221return this.fetchRouteChatter;} 11222get fetchRouteChatter(){return"/mail/thread/messages";} 11223async loadAround(messageId){if(this.status==="loading"||(this.isLoaded&&this.messages.some(({id})=>id===messageId))){return;} 11224this.isLoaded=false;this.scrollTop=undefined;let receivedMessages;try{this.phantomMessages=this.messages;const knownMessages=[...this.messages];const fetched=await this.fetchMessages({around:messageId});receivedMessages=this.messages.filter((message)=>message.notIn(knownMessages));this.messages=fetched;this.phantomMessages=[];}catch{this.isLoaded=true;return;} 11225this.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;} 11226if(newerMessagesCount<limit/2){this.loadNewer=false;}} 11227this._enrichMessagesWithTransient();if(!this.loadNewer){const missingMessages=receivedMessages.filter((message)=>message.notIn(this.messages));this.messages.push(...missingMessages);this.messages.sort((m1,m2)=>m1.id-m2.id);}} 11228async 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;} 11229async markAsFetched(){await this.store.env.services.orm.silent.call("discuss.channel","channel_fetched",[[this.id],]);} 11230markAsRead(options){const newestPersistentMessage=this.newestPersistentOfAllMessage;if(!newestPersistentMessage&&!this.isLoaded){this.isLoadedDeferred.then(()=>new Promise(setTimeout)).then(()=>this.markAsRead(options));return;} 11231if(this.message_needaction_counter>0){this.markAllMessagesAsRead();}} 11232async notifyAvatarToServer(data){await rpc("/discuss/channel/update_avatar",{channel_id:this.id,data,});} 11233async notifyDescriptionToServer(description){this.description=description;return this.store.env.services.orm.call("discuss.channel","channel_change_description",[[this.id]],{description});} 11234onNewSelfMessage(message){} 11235open(options){return false;} 11236async openChatWindow({focus=false,fromMessagingMenu,bypassCompact,swapOpened}={}){const thread=await this.store.Thread.getOrFetch(this);if(!thread){return;} 11237await this.store.chatHub.initPromise;const cw=this.store.ChatWindow.insert(assignDefined({thread:this},{fromMessagingMenu,bypassCompact}));cw.open({focus,swapOpened});return cw;} 11238async closeChatWindow(options={}){await this.store.chatHub.initPromise;const chatWindow=this.store.ChatWindow.get({thread:this});await chatWindow?.close({notifyState:false,...options});} 11239async 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;} 11240await this.store.env.services.orm.call("discuss.channel","channel_set_custom_name",[[this.id]],{name:newName});}}} 11241addOrReplaceMessage(message,tmpMsg){if(tmpMsg&&tmpMsg.in(this.messages)&&this.effectiveSelf.eq(message.author)){this.messages.splice(this.messages.indexOf(tmpMsg),1,message);return;} 11242this.messages.add(message);} 11243async post(body,postData={},extraData={}){let tmpMsg;postData.attachments=postData.attachments?[...postData.attachments]:[];const{attachments,parentId}=postData;
11243const 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;} 11244if(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;} 11245if(parentId){tmpData.parent_id=this.store["mail.message"].get(parentId);} 11246tmpMsg=this.store["mail.message"].insert({...tmpData,body:await generateEmojisOnHtml(body),isPending:true,thread:this,});this.messages.push(tmpMsg);this.onNewSelfMessage(tmpMsg);} 11247const data=await this.store.doMessagePost(params,tmpMsg);if(!data){return;} 11248this.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});} 11249return message;} 11250async 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,]);} 11251_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;} 11252this.messages.splice(afterIndex-1,0,message);}}} 11253async 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?"));} 11254if(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?"));} 11255await 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,});}} 11256_getActualModelName(){return this.model==="discuss.channel"?"discuss.channel":"mail.thread";}} 11257Thread.register();return __exports;});; 11258 11259/* /mail/static/src/core/common/volume_model.js */ 11260odoo.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;} 11261volume=1;} 11262Volume.register();return __exports;});; 11263 11264/* /mail/static/src/discuss/core/common/action_panel.js */ 11265odoo.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});} 11266get 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,});} 11267get minWidth(){return this.props.minWidth;} 11268get initialWidth(){return this.props.initialWidth;}} 11269return __exports;});; 11270 11271/* /mail/static/src/discuss/core/common/attachment_model_patch.js */ 11272odoo.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;} 11273return super.isDeletable;},};patch(Attachment.prototype,attachmentPatch);return __exports;});; 11274 11275/* /mail/static/src/discuss/core/common/attachment_panel.js */ 11276odoo.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)=>
11276{if(nextProps.thread.notEq(this.props.thread)){nextProps.thread.fetchMoreAttachments();}});useVisible("load-older",(isVisible)=>{if(isVisible){this.props.thread.fetchMoreAttachments();}});} 11277get attachmentsByDate(){const attachmentsByDate={};for(const attachment of this.props.thread.attachments){const attachments=attachmentsByDate[attachment.monthYear]??[];attachments.push(attachment);attachmentsByDate[attachment.monthYear]=attachments;} 11278return attachmentsByDate;}} 11279return __exports;});; 11280 11281/* /mail/static/src/discuss/core/common/avatar_stack.js */ 11282odoo.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`);} 11283return styles.join(";");}} 11284return __exports;});; 11285 11286/* /mail/static/src/discuss/core/common/channel_commands.js */ 11287odoo.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;});; 11288 11289/* /mail/static/src/discuss/core/common/channel_invitation.js */ 11290odoo.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();}});} 11291get selectablePartners(){return this.props.state?.selectablePartners??this.state.selectablePartners;} 11292set selectablePartners(partners){if(this.props.state?.selectablePartners){this.props.state.selectablePartners=partners;}else{this.state.selectablePartners=partners;}} 11293get selectedPartners(){return this.props.state?.selectedPartners??this.state.selectedPartners;} 11294set selectedPartners(partners){if(this.props.state?.selectedPartners){this.props.state.selectedPartners=partners;}else{this.state.selectedPartners=partners;}} 11295get searchStr(){return this.props.state?.searchStr??this.state.searchStr;} 11296set searchStr(newSearchStr){if(this.props.state?.searchStr!==undefined){this.props.state.searchStr=newSearchStr;}else{this.state.searchStr=newSearchStr;}} 11297get 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,});} 11298get searchPlaceholder(){if(this.props.thread?.allow_invite_by_email){return _t("Invite people or email");} 11299return _t("Search people to invite");} 11300async 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;} 11301this.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);} 11302if(results.email_already_sent){this.state.sentEmails.add(results.selectable_email);} 11303this.state.selectableEmails=[...new Set(selectableEmails)];} 11304onInput(){this.searchStr=this.inputRef.el.value;this.debouncedFetchPartnersToInvite();} 11305onClickSelectablePartner(partner){if(partner.in(this.selectedPartners)){const index=this.selectedPartners.indexOf(partner);if(index!==-1){this.selectedPartners.splice(index,1);} 11306return;} 11307this.selectedPartners.push(partner);} 11308onClickSelectableEmail(email){const index=this.state.selectedEmails.indexOf(email);if(index!==-1){this.state.selectedEmails.splice(index,1);return;} 11309this.state.selectedEmails.push(email);} 11310onClickSelectedPartner(partner){const index=this.selectedPartners.indexOf(partner);this.selectedPartners.splice(index,1);} 11311onClickSelectedEmail(email){const index=this.state.selectedEmails.indexOf(email);this.state.selectedEmails.splice(index,1);} 11312onFocusInvitationLinkInput(ev){ev.target.select();} 11313async 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";} 11314this.notification.add(notification,{type});} 11315async 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);} 11316await this.store.startChat(partnerIds);this.props.close?.();return;} 11317const 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),}));} 11318if(this.state.selectedEmails.length){invitePromises.push(this.orm.call("discuss.channel","invite_by_email",[this.props.thread.id],{emails:this.state.selectedEmails,}));} 11319await Promise.all(invitePromises);this.state.selectedEmails=[];this.state.selectedPartners=[];this.props.close?.();} 11320get invitationButtonText(){if(!this.props.thread){return"";} 11321if(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");} 11322if(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");} 11323return _t("Start a Conversation");}} 11324return _t("Create Group Chat");} 11325return _t("Invite");}} 11326return __exports;});; 11327 11328/* /mail/static/src/discuss/core/common/channel_member_list.js */ 11329odoo.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)=>
11329{if(nextProps.thread.fetchMembersState==="not_fetched"){nextProps.thread.fetchChannelMembers();}});} 11330get onlineSectionText(){return _t("Online - %(online_count)s",{online_count:this.props.thread.onlineMembers.length,});} 11331get offlineSectionText(){return _t("Offline - %(offline_count)s",{offline_count:this.props.thread.offlineMembers.length,});} 11332canOpenChatWith(member){return!this.store.inPublicPage&&!member.guest_id&&member.persona.main_user_id;} 11333onClickAvatar(ev,member){if(!this.canOpenChatWith(member)){return;} 11334this.store.openChat({partnerId:member.partner_id.id});}} 11335return __exports;});; 11336 11337/* /mail/static/src/discuss/core/common/channel_member_model.js */ 11338odoo.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;} 11339channel_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;} 11340if(this.isTyping){this.registerTypingTimeout();}},});registerTypingTimeout(){this.typingTimeoutId=browser.setTimeout(()=>(this.isTyping=false),Store.OTHER_LONG_TYPING);} 11341threadAsTyping=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;} 11342return this.channel_id.getPersonaName(this.partner_id);} 11343get avatarUrl(){return this.partner_id?.avatarUrl||this.guest_id?.avatarUrl;} 11344get im_status(){return this.partner_id?.im_status||this.guest_id?.im_status;} 11345getLangName(){return this.persona.lang_name;} 11346get memberSince(){return this.create_date?deserializeDateTime(this.create_date):undefined;} 11347hasSeen(message){return this.persona.eq(message.author)||this.seen_message_id?.id>=message.id;} 11348get lastSeenDt(){return this.last_seen_dt?this.last_seen_dt.toLocaleString(DateTime.TIME_24_SIMPLE,{locale:user.lang,}):undefined;}} 11349ChannelMember.register();return __exports;});; 11350 11351/* /mail/static/src/discuss/core/common/delete_thread_dialog.js */ 11352odoo.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");} 11353async 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;} 11354await rpc("/discuss/channel/sub_channel/delete",{sub_channel_id:this.props.thread.id,});if(toOpenThread?.exists()){toOpenThread.open();} 11355this.props.close();this.env.services.notification.add(_t('Thread "%(thread_name)s" has been deleted',{thread_name:threadName}),{type:"info"});}} 11356return __exports;});; 11357 11358/* /mail/static/src/discuss/core/common/discuss_core_common_service.js */ 11359odoo.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"];} 11360setup(){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
11360annel_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--;}}});} 11361async _handleNotificationChannelDelete(thread,metadata){await thread.closeChatWindow({force:true});thread.messages.splice(0,thread.messages.length);thread.delete();} 11362async _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;} 11363const message=this.store["mail.message"].get(data["mail.message"][0]);if(!message){return;} 11364if(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);} 11365if(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;} 11366if(!channel.isDisplayed&&channel.self_member_id){channel.scrollUnread=true;} 11367if(notifId>channel.self_member_id?.message_unread_counter_bus_id&&!message.isNotification){channel.self_member_id.message_unread_counter++;}}} 11368if(channel.channel_type!=="channel"&&this.store.self_partner&&channel.self_member_id){channel.markAsFetched();} 11369if(!channel.loadNewer&&!message.isSelfAuthored&&channel.scrollTop==="bottom"&&channel.composer.isFocused&&this.store.self_partner&&channel.newestPersistentMessage?.eq(channel.newestMessage)&&!channel.markedAsUnread){channel.markAsRead();} 11370this.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;}}} 11371const discussCoreCommon=__exports.discussCoreCommon={dependencies:["bus_service","mail.out_of_focus","mail.store","notification","orm","presence",],start(env,services){const discussCoreCommon=reactive(new Discu
11371ssCoreCommon(env,services));discussCoreCommon.setup(env,services);return discussCoreCommon;},};registry.category("services").add("discuss.core.common",discussCoreCommon);return __exports;});; 11372 11373/* /mail/static/src/discuss/core/common/discuss_notification_settings.js */ 11374odoo.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,});} 11375onChangeMessageSound(){if(this.store.settings.messageSound){this.disableMessageSound();}else{this.enableMessageSound();}} 11376enableMessageSound(){browser.localStorage.removeItem(MESSAGE_SOUND);this.store.settings._recomputeMessageSound++;} 11377disableMessageSound(){browser.localStorage.setItem(MESSAGE_SOUND,false);this.store.settings._recomputeMessageSound++;}} 11378return __exports;});; 11379 11380/* /mail/static/src/discuss/core/common/discuss_notification_settings_client_action.js */ 11381odoo.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` 11382 <div class="o-mail-DiscussNotificationSettingsClientAction mx-3 my-2"> 11383 <DiscussNotificationSettings/> 11384 </div> 11385 `;} 11386registry.category("actions").add("mail.discuss_notification_settings_action",DiscussNotificationSettingsClientAction);return __exports;});; 11387 11388/* /mail/static/src/discuss/core/common/mail_guest_model_patch.js */ 11389odoo.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;});; 11390 11391/* /mail/static/src/discuss/core/common/message_actions.js */ 11392odoo.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;} 11393message.thread.markedAsUnread=true;rpc("/discuss/channel/set_new_message_separator",{channel_id:message.thread.id,message_id:message.id,});},sequence:70,});return __exports;});; 11394 11395/* /mail/static/src/discuss/core/common/message_model_patch.js */ 11396odoo.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;} 11397return 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;});; 11398 11399/* /mail/static/src/discuss/core/common/message_patch.js */ 11400odoo.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;});; 11401 11402/* /mail/static/src/discuss/core/common/message_seen_indicator.js */ 11403odoo.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);}} 11404const MessageSeenIndicator=__exports.MessageSeenIndicator=class MessageSeenIndicator extends Component{static template="mail.MessageSeenIndicator";static props=["message","thread","className?"];setup(){super.setup();this.dialog=useService("dialog");}
11405get 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});} 11406return _t("Seen by everyone");} 11407const 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,});}} 11408openDialog(){if(this.props.message.channelMemberHaveSeen.length===0){return;} 11409this.dialog.add(MessageSeenIndicatorDialog,{message:this.props.message});}} 11410return __exports;});; 11411 11412/* /mail/static/src/discuss/core/common/notification_settings.js */ 11413odoo.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` 11414 <Dialog size="'md'" footer="false"> 11415 <DiscussNotificationSettingsClientAction/> 11416 </Dialog> 11417 `;} 11418const 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");} 11419setMute(minutes){this.store.settings.setMuteDuration(minutes,this.props.thread);this.props.close?.();} 11420onClickAllConversationsMuted(){this.dialog.add(NotificationDialog);}} 11421return __exports;});; 11422 11423/* /mail/static/src/discuss/core/common/partner_compare.js */ 11424odoo.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;} 11425if(!isMember1&&isMember2){return 1;}}},{sequence:40});return __exports;});; 11426 11427/* /mail/static/src/discuss/core/common/res_partner_model_patch.js */ 11428odoo.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;});; 11429 11430/* /mail/static/src/discuss/core/common/store_service_patch.js */ 11431odoo.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");
11431if(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;});; 11432 11433/* /mail/static/src/discuss/core/common/suggestion_service_patch.js */ 11434odoo.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[];} 11435return 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;} 11436return 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));} 11437return Array.from(partnersById.values());}else{return super.getPartnerSuggestions(...arguments);}},searchSuggestions({delimiter,term},{thread}={}){if(delimiter==="/"){return this.searchChannelCommand(cleanTerm(term),thread);} 11438return super.searchSuggestions(...arguments);},searchChannelCommand(cleanedSearchTerm,thread){if(!thread.model==="discuss.channel"){return;} 11439const commands=this.getChannelCommands(thread).filter(({name})=>cleanTerm(name).includes(cleanedSearchTerm));const sortFunc=(c1,c2)=>{if(c1.channel_types&&!c2.channel_types){return-1;} 11440if(!c1.channel_types&&c2.channel_types){return 1;} 11441const cleanedName1=cleanTerm(c1.name);const cleanedName2=cleanTerm(c2.name);if(cleanedName1.startsWith(cleanedSearchTerm)&&!cleanedName2.startsWith(cleanedSearchTerm)){return-1;} 11442if(!cleanedName1.startsWith(cleanedSearchTerm)&&cleanedName2.startsWith(cleanedSearchTerm)){return 1;} 11443if(cleanedName1<cleanedName2){return-1;} 11444if(cleanedName1>cleanedName2){return 1;} 11445return 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;});; 11446 11447/* /mail/static/src/discuss/core/common/thread_actions.js */ 11448odoo.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` 11449 <Dialog size="'md'" title="props.title" footer="false" contentClass="'o-bg-body'" bodyClass="'p-1'"> 11450 <t t-component="props.contentComponent" t-props="props.contentProps"/> 11451 </Dialog> 11452 `;} 11453registerThreadAction("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 ${ 11454 owner.props.chatWindow ? "bg-inherit" : "" 11455 } 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);}
11455,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;});; 11456 11457/* /mail/static/src/discuss/core/common/thread_compare_patch.js */ 11458odoo.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;} 11459if(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;});; 11460 11461/* /mail/static/src/discuss/core/common/thread_model_patch.js */ 11462odoo.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);} 11463const thread=this.store.Thread.get({id:data.id,model:data.model});if(thread?.fetchChannelInfoState==="fetched"){return Promise.resolve(thread);} 11464const fetchChannelInfoDeferred=this.store.channelIdsFetchingDeferred.get(data.id);if(fetchChannelInfoDeferred){return fetchChannelInfoDeferred;} 11465const 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;} 11466const 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];} 11467if(!separator||messages.length===0||messages.at(-1).id<separator){return null;} 11468let message=this.store["mail.message"].get({id:separator});if(!message||this.notEq(message.thread)){message=nearestGreaterThanOrEqual(messages,separator,(msg)=>msg.id);} 11469return 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;} 11470return 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;} 11471let 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;} 11472res=message;break;} 11473return 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";} 11474return 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,});} 11475if(this.channel_type==="chat"&&this.correspondent){return this.correspondent.avatarUrl;} 11476return super.avatarUrl;},get showCorrespondentCountry(){return false;},async checkReadAccess(){const res=await super.checkReadAccess();if(!res&&this.model==="discuss.channel"){return this.channel_type;} 11477return res;},computeCorrespondent(){if(["channel","group"].includes(this.channel_type)){return undefined;} 11478const correspondents=this.correspondents;if(correspondents.length===1){return correspondents[0];} 11479if(correspondents.length===0&&this.channel_member_ids.length===1){return this.channel_member_ids[0];} 11480return 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;} 11481if(this.channel_type==="chat"&&this.correspondent){return this.correspondent.name;} 11482if(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));} 11483return formatList(nameParts);} 11484if(this.model==="discuss.channel"&&this.name){return this.name;} 11485return super.displayName;},async fetchChannelMembers(){if(this.fetchMembersState==="pending"){return;} 11486const 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;} 11487this.fetchMembersState="fetched";this.store.insert(data);},async fetchMoreAttachments(limit=30){if(this.isLoadingAttachments||this.areAttachmentsLoaded){return;} 11488this.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;} 11489if(this.discussAppCategory?.id==="channels"){if(this.store.settings.channel_notifications==="no_notif"){return 0;} 11490if(this.store.settings.channel_notifications==="all"&&!this.self_member_id?.mute_until_dt){return this.self_member_id?.message_unread_counter_ui;}} 11491return super.importantCounter;},isDisplayedOnUpdate(){super.isDisplayedOnUpdate(...arguments);if(!this.self_member_id){return;} 11492if(!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;} 11493const newestPersistentMessage=this.newestPersistentOfAllMessage;if(!newestPersistentMessage){return;} 11494const alreadyReadBySelf=this.self_member_id.seen_message_id?.id>=newestPersistentMessage.id&&this.self_member_id.new_message_separator>newestPersistentMessage.id;if(alreadyReadBySelf){return;} 11495this.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;} 11496this.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;} 11497this.openChatWindow(options);return true;} 11498return 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);
11498if(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;}} 11499return 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;});; 11500 11501/* /mail/static/src/discuss/core/common/thread_patch.js */ 11502odoo.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;} 11503const 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;} 11504const messageCenter=messageEl.offsetTop- 11505this.scrollableRef.el.offsetHeight/2+ 11506messageEl.offsetHeight/2;this.setScroll(messageCenter);}else{const scrollTop=this.props.order==="asc"?this.scrollableRef.el.scrollHeight-this.scrollableRef.el.clientHeight:0;this.setScroll(scrollTop);} 11507thread.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);} 11508return _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;});; 11509 11510/* /mail/static/src/discuss/call/common/blur_manager.js */ 11511odoo.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;} 11512canvas.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();} 11513const 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");
11513this.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;} 11514this.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(()=>{});} 11515close(){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"));}} 11516async _handleWorkerMessage(e){if(e.data.command==="tick"){await this._onFrame();this.worker.postMessage({command:"tock"});}} 11517_terminateWorker(){if(this.worker){this.worker.postMessage({command:"stop"});this.worker.terminate();} 11518this.worker=null;} 11519_drawWithCompositing(image,compositeOperation){this.canvas.getContext("2d").globalCompositeOperation=compositeOperation;
11519this.canvas.getContext("2d").drawImage(image,0,0);} 11520_onVideoPlay(){this.isVideoDataLoaded=true;if(this.worker){this.worker.postMessage({command:"start",fps:FPS});}else{this._requestFrame();}} 11521async _onFrame(){if(!this.selfieSegmentation){return;} 11522if(!this.video){return;} 11523if(!this.isVideoDataLoaded){return;} 11524await this.selfieSegmentation.send({image:this.video});} 11525_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;}} 11526_requestFrame(){if(!this.isVideoDataLoaded){return;} 11527browser.requestAnimationFrame(async()=>{await this._onFrame();if(!this.worker){browser.setTimeout(()=>this._requestFrame(),Math.floor(1000/FPS));}});}} 11528return __exports;});; 11529 11530/* /mail/static/src/discuss/call/common/blur_performance_warning.js */ 11531odoo.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");} 11532onClickClose(){this.store.settings.blurPerformanceWarning=false;}} 11533return __exports;});; 11534 11535/* /mail/static/src/discuss/call/common/call.js */ 11536odoo.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
11536otkeys/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();} 11537get layoutActions(){if(!this.isActiveCall){return[];} 11538return this.callActions.actions.filter((action)=>action.tags.includes(ACTION_TAGS.CALL_LAYOUT));} 11539get isFullSize(){return this.props.isPip||this.rtc.state.isFullscreen;} 11540get isActiveCall(){return Boolean(this.channel.eq(this.rtc.channel));} 11541get minimized(){if(this.rtc.state.isFullscreen||!this.channel||this.channel.activeRtcSession){return false;} 11542if(!this.isActiveCall||this.channel.videoCount===0||this.props.compact){return true;} 11543return false;} 11544get channel(){return this.props.thread||this.rtc.channel;} 11545get visibleMainCards(){const activeSession=this.channel.activeRtcSession;if(!activeSession){this.state.insetCard=undefined;return this.channel.visibleCards;} 11546const type=activeSession.mainVideoStreamType;if(type==="screen"||activeSession.is_screen_sharing_on){this.setInset(activeSession,type==="camera"?"screen":"camera");}else{this.state.insetCard=undefined;} 11547return[{key:"session_"+activeSession.id,session:activeSession,type,videoStream:activeSession.getStream(type),},];} 11548setInset(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),};}} 11549get hasCallNotifications(){return Boolean((!this.props.compact||this.rtc.state.isFullscreen)&&this.isActiveCall&&this.rtc.notifications.size);} 11550get hasSidebarButton(){return Boolean(this.channel.activeRtcSession&&this.state.overlay&&(!this.props.compact||this.rtc.state.isFullscreen));} 11551get isControllerFloating(){return this.rtc.state.isFullscreen||(this.channel.activeRtcSession&&!this.ui.isSmall);} 11552onMouseleaveMain(ev){if(ev.relatedTarget&&ev.relatedTarget.closest(".o-dropdown--menu")){return;} 11553this.state.overlay=false;} 11554onMousemoveMain(ev){if(isEventHandled(ev,"CallMain.MousemoveOverlay")){return;} 11555this.showOverlay();} 11556onMousemoveOverlay(ev){markEventHandled(ev,"CallMain.MousemoveOverlay");this.state.overlay=true;browser.clearTimeout(this.overlayTimeout);} 11557showOverlay(){this.state.overlay=true;browser.clearTimeout(this.overlayTimeout);this.overlayTimeout=browser.setTimeout(()=>{this.state.overlay=false;},3000);} 11558arrangeTiles(){if(!this.grid.el){return;} 11559this.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);
11559const 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);} 11560const area=tileHeight*tileWidth;if(area<=optimal.area){continue;} 11561optimal={area,columnCount,tileHeight,tileWidth,};} 11562Object.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`);}} 11563return __exports;});; 11564 11565/* /mail/static/src/discuss/call/common/call_action_list.js */ 11566odoo.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);} 11567this.actions=[...group2,other];});} 11568get isPromotingFullscreen(){return Boolean(!this.env.pipWindow&&this.props.thread.promoteFullscreen===CALL_PROMOTE_FULLSCREEN.ACTIVE);} 11569get MORE(){return _t("More");} 11570get isOfActiveCall(){return Boolean(this.props.thread.eq(this.rtc.channel));} 11571get isSmall(){return Boolean(this.props.compact&&this.rtc.state.isFullscreen);} 11572get isMobileOS(){return isMobileOS();} 11573onMouseenterMore(){if(this.isPromotingFullscreen){this.popover.open(this.more.el,{tooltip:_t("Enter full screen!")});this.props.thread.promoteFullscreen=CALL_PROMOTE_FULLSCREEN.DISCARDED;}} 11574onMouseleaveMore(){if(this.popover.isOpen){this.popover.close();}} 11575onClickMore(){if(this.popover.isOpen){this.popover.close();}}} 11576return __exports;});; 11577 11578/* /mail/static/src/discuss/call/common/call_actions.js */ 11579odoo.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);} 11580const 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);} 11581if(store.rtc.microphonePermission!=="granted"){tags.push(ACTION_TAGS.DANGER,ACTION_TAGS.WARNING_BADGE);} 11582return 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})=>
11582(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);} 11583if(thread?.default_display_mode==="video_full_screen"&&store.rtc.cameraPermission!=="granted"){tags.push(ACTION_TAGS.DANGER,ACTION_TAGS.WARNING_BADGE);} 11584return 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})=>
11584store.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;} 11585store.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;} 11586get params(){return Object.assign(super.params,{thread:this.threadFn()});} 11587get isTracked(){return this.definition.isTracked;}} 11588class UseCallActions extends UseActions{ActionClass=CallAction;} 11589__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")));} 11590return __exports;});; 11591 11592/* /mail/static/src/discuss/call/common/call_components.js */ 11593odoo.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;});; 11594 11595/* /mail/static/src/discuss/call/common/call_context_menu.js */ 11596odoo.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(()=>
11596{if(!this.env.debug){return;} 11597this.updateStats();this.updateStatsTimeout=browser.setInterval(()=>this.updateStats(),3000);});onWillUnmount(()=>browser.clearInterval(this.updateStatsTimeout));} 11598get isSelf(){return this.rtc.selfSession?.eq(this.props.rtcSession);} 11599get inboundConnectionTypeText(){const candidateType=this.rtc.state.connectionType===CONNECTION_TYPES.SERVER?this.state.downloadStats.remoteCandidateType:this.state.peerStats.remoteCandidateType;return this.formatProtocol(candidateType);} 11600get outboundConnectionTypeText(){const candidateType=this.rtc.state.connectionType===CONNECTION_TYPES.SERVER?this.state.uploadStats.localCandidateType:this.state.peerStats.localCandidateType;return this.formatProtocol(candidateType);} 11601get volume(){return this.store.settings.getVolume(this.props.rtcSession);} 11602formatProtocol(candidateType){if(!candidateType){return _t("no connection");} 11603return _t("%(candidateType)s (%(protocol)s)",{candidateType,protocol:PROTOCOLS_TEXT[candidateType],});} 11604async 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;} 11605const 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;} 11606break;case"transport":formattedUploadStats.dtlsState=value.dtlsState;formattedUploadStats.iceState=value.iceState;formattedUploadStats.packetsSent=value.packetsSent;break;}} 11607const 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||"";} 11608break;case"transport":formattedDownloadStats.dtlsState=value.dtlsState;formattedDownloadStats.iceState=value.iceState;formattedDownloadStats.packetsReceived=value.packetsReceived;break;}} 11609const 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;}} 11610formattedProducerStats[type]=currentTypeStats;} 11611this.state.uploadStats=formattedUploadStats;this.state.downloadStats=formattedDownloadStats;this.state.producerStats=formattedProducerStats;} 11612return;} 11613this.state.peerStats=await this.rtc.p2pService.getFormattedStats(this.props.rtcSession.id);} 11614onChangeVolume(ev){const volume=Number(ev.target.value);this.rtc.setVolume(this.props.rtcSession,volume);}} 11615return __exports;});; 11616 11617/* /mail/static/src/discuss/call/common/call_dropdown.js */ 11618odoo.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:()=>
11618{if(this.state.isOpen&&this.menuRef.el){return this.menuRef.el.querySelectorAll(":scope .o-navigable, :scope .o-dropdown");} 11619return[];},});this.handleClick=this.handleClick.bind(this);useEffect((triggerEl)=>{if(triggerEl){triggerEl.addEventListener("click",this.handleClick);return()=>triggerEl.removeEventListener("click",this.handleClick);}},()=>[this.triggerRef.el]);} 11620get triggerRef(){return{el:getFirstElementOfNode(this.__owl__.bdom)};} 11621get window(){return this.env.pipWindow||window;} 11622get isOpen(){return this.state.isOpen;} 11623toggle(){this.isOpen?this.close():this.open();} 11624open(){this.state.isOpen=true;} 11625close(){this.state.isOpen=false;} 11626handleClick(ev){ev.preventDefault();ev.stopPropagation();this.toggle();} 11627onClickAway(ev){if(!this.isOpen){return;} 11628const isOutsideClick=!this.triggerRef.el?.contains(ev.target)&&!this.menuRef.el?.contains(ev.target);if(isOutsideClick){this.close();}} 11629onClickMenu(ev){ev.stopPropagation();} 11630onKeydown(ev){if(ev.key==="Escape"&&this.isOpen){ev.preventDefault();this.close();}}} 11631return __exports;});; 11632 11633/* /mail/static/src/discuss/call/common/call_infinite_mirroring_warning.js */ 11634odoo.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},};} 11635return __exports;});; 11636 11637/* /mail/static/src/discuss/call/common/call_invitation.js */ 11638odoo.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});} 11639joinCall(){this.props.thread.open({focus:true});this.rtc.toggleCall(this.props.thread,{audio:this.state.hasMicrophone,camera:this.state.hasCamera,});} 11640get 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,}),];} 11641get 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++;} 11642if(this.state.hasMicrophone){this.state.activateMicrophone++;}},tags:()=>[ACTION_TAGS.CALL_LAYOUT],},store:this.store,}),];} 11643get 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});} 11644return _t("View the %(channel_name)s channel",{channel_name:channelName});} 11645get inviter(){return this.props.thread.self_member_id?.rtc_inviting_session_id?.channel_member_id;} 11646get incomingCallText(){if(this.props.thread.channel_type==="chat"||!this.inviter){return _t("Incoming call");} 11647return _t("Incoming call from %(inviter)s",{inviter:this.inviter.name});} 11648onCallSettingsChanged(settings){if(settings.microphone!==undefined){this.state.hasMicrophone=settings.microphone;}
11649if(settings.camera!==undefined){this.state.hasCamera=settings.camera;}}} 11650return __exports;});; 11651 11652/* /mail/static/src/discuss/call/common/call_invitations.js */ 11653odoo.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");}} 11654const 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();
11654onChange(store.ringingThreads,"length",onChangeRingingThreadsLength);},};registry.category("services").add("discuss.call_invitations",callInvitationsService);return __exports;});; 11655 11656/* /mail/static/src/discuss/call/common/call_menu.js */ 11657odoo.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});} 11658get icon(){const res=this.rtc.callActions.find((action)=>action.id===this.rtc.lastSelfCallAction)?.icon;return(typeof res==="function"?res():res)??"fa fa-microphone";}} 11659registry.category("systray").add("discuss.CallMenu",{Component:CallMenu},{sequence:100});return __exports;});; 11660 11661/* /mail/static/src/discuss/call/common/call_participant_card.js */ 11662odoo.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;} 11663this.rtc.updateVideoDownload(this.rtcSession,{viewCountIncrement:1,});});onWillUnmount(()=>{if(!this.rtcSession){return;} 11664this.rtc.updateVideoDownload(this.rtcSession,{viewCountIncrement:-1,});});useExternalListener(browser,"fullscreenchange",this.onFullScreenChange);} 11665get isContextMenuAvailable(){return(this.isOfActiveCall&&(this.rtcSession.notEq(this.rtc.selfSession)||(this.env.debug&&this.rtc.state.connectionType===CONNECTION_TYPES.SERVER)));} 11666get isRemoteVideo(){if(!this.rtcSession){return false;} 11667return(this.rtc.isRemote&&(this.rtcSession.is_screen_sharing_on||this.rtcSession.is_camera_on));} 11668get isSmall(){return Boolean(this.props.isSidebarItem||this.ui.isSmall||this.props.minimized||this.props.inset);} 11669get window(){return this.env.pipWindow||window;} 11670get showLiveLabel(){if(this.props.isSidebarItem){return false;} 11671if(this.props.cardData.type==="screen"){if(this.props.inset){return true;}else{return(!this.rtcSession.eq(this.rtcSession.channel.activeRtcSession)&&!this.props.minimized);}} 11672return false;} 11673get showRemoteWarning(){return!this.props.minimized&&!this.props.inset&&this.isRemoteVideo;} 11674get rtcSession(){return this.props.cardData.session;} 11675get channelMember(){return this.rtcSession?this.rtcSession.channel_member_id:this.props.cardData.member;} 11676get isOfActiveCall(){return Boolean(this.rtcSession&&this.rtcSession.channel?.eq(this.rtc.channel));} 11677get showConnectionState(){if(!this.rtcSession||!this.rtc.isHost||!this.isOfActiveCall||HIDDEN_CONNECTION_STATES.has(this.rtcSession.connectionState)){return false;} 11678if(this.rtc.state.connectionType===CONNECTION_TYPES.SERVER){return this.rtcSession.eq(this.rtc?.selfSession);}else{return this.rtcSession.notEq(this.rtc?.selfSession);}} 11679get showServerState(){return false;} 11680get name(){return this.channelMember?.name;} 11681get hasMediaError(){return(this.isOfActiveCall&&Boolean(this.rtcSession?.videoError||this.rtcSession?.audioError));} 11682get hasVideo(){return Boolean(this.props.cardData.videoStream);} 11683get isTalking(){return Boolean(this.rtcSession&&this.rtcSession.isActuallyTalking&&!this.rtc.selfSession?.is_deaf);} 11684get hasRaisingHand(){const screenStream=this.rtcSession.videoStreams.get("screen");return Boolean(this.rtcSession.raisingHand&&(!screenStream||screenStream!==this.props.cardData.videoStream));} 11685get isActiveRtcSession(){return this.rtcSession&&this.rtcSession.eq(this.rtcSession.channel?.activeRtcSession);} 11686async onClick(ev){if(isEventHandled(ev,"CallParticipantCard.clickVolumeAnchor")){return;} 11687if(this.isDrag){this.isDrag=false;return;} 11688if(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);}} 11689return;} 11690await rpc("/mail/rtc/channel/cancel_call_invitation",{channel_id:this.props.thread.id,member_ids:[this.channelMember.id],});} 11691async onClickReplay(){this.env.bus.trigger("RTC-SERVICE:PLAY_MEDIA");} 11692onMouseDown(){if(!this.props.inset){return;} 11693const 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";} 11694if(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";} 11695this.dragPos=undefined;this.parentBoundingRect=undefined;document.removeEventListener("mouseup",onMouseup);document.removeEventListener("mousemove",onMousemove);};document.addEventListener("mouseup",onMouseup);document.addEventListener("mousemove",onMousemove);} 11696onTouchMove(ev){if(!this.props.inset){return;} 11697this.drag(ev);} 11698drag(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};} 11699const dX=this.dragPos.posX-clientX;const dY=this.dragPos.posY-clientY;
11699const 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";} 11700onFullScreenChange(){this.root.el.style="left:''; top:''";}} 11701return __exports;});; 11702 11703/* /mail/static/src/discuss/call/common/call_participant_video.js */ 11704odoo.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();});} 11705_update(){if(!this.root.el){return;} 11706if(!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);} 11707this.root.el.load();} 11708async play(){try{await this.root.el?.play?.();this.props.session.videoError=undefined;}catch(error){if(status(this)==="destroyed"){return;} 11709this.props.session.videoError=error.name;}} 11710async onVideoLoadedMetaData(){await this.play();}} 11711return __exports;});; 11712 11713/* /mail/static/src/discuss/call/common/call_permission_dialog.js */ 11714odoo.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");} 11715async onClickUseMicrophone(){if(await this.rtc.askForBrowserPermission({audio:true})){await this.props.useMicrophone();} 11716this.props.close();} 11717async onClickUseCamera(){if(await this.rtc.askForBrowserPermission({video:true})){await this.props.useCamera();} 11718this.props.close();} 11719async onClickUseMicAndCamera(){if(await this.rtc.askForBrowserPermission({audio:true,video:true})){await Promise.all([this.props.useMicrophone(),this.props.useCamera()]);} 11720this.props.close();} 11721get primaryActionText(){return this.props.media==="camera"?_t("Use Camera"):_t("Use Microphone");} 11722get permissionPrompt(){if(this.props.media==="microphone"){return _t("Do you want people to hear you in the meeting?");} 11723return _t("Do you want people to see you in the meeting?");} 11724get permissionNote(){return _t("You can still turn off your %s anytime.",this.props.media);}} 11725return __exports;});; 11726 11727/* /mail/static/src/discuss/call/common/call_preview.js */ 11728odoo.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;} 11729if(videoEl&&!videoEl.srcObject&&videoStream){videoEl.srcObject=blurStream??videoStream;}},()=>[this.videoRef.el,this.audioRef.el,this.state.audioStream,this.state.videoStream,this.state.blurManager?.stream,]);
11729if(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]);}} 11730get hasRtcSupport(){return Boolean(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&window.MediaStream);} 11731get 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);} 11732return 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,}),],];} 11733async enableMicrophone(){if(this.rtc.microphonePermission!=="granted"&&!(await this.rtc.askForBrowserPermission({audio:true}))){return;} 11734this.state.audioStream=await navigator.mediaDevices.getUserMedia({audio:this.store.settings.audioConstraints,});if(status(this)==="destroyed"){closeStream(this.state.audioStream);return;} 11735if(this.audioRef.el){this.audioRef.el.srcObject=this.state.audioStream;} 11736this.props.onSettingsChanged?.({microphone:true});} 11737disableMicrophone(){closeStream(this.state.audioStream);this.state.audioStream=null;if(this.audioRef.el){this.audioRef.el.srcObject=null;} 11738this.props.onSettingsChanged?.({microphone:false});} 11739async toggleMic(){if(this.state.audioStream){this.disableMicrophone();return;} 11740if(this.rtc.microphonePermission==="prompt"){this.dialog.add(CallPermissionDialog,{media:"microphone",useMicrophone:()=>this.enableMicrophone(),useCamera:()=>this.enableCamera(),});return;} 11741await this.enableMicrophone();} 11742async enableCamera(){if(this.rtc.cameraPermission!=="granted"&&!(await this.rtc.askForBrowserPermission({video:true}))){return;} 11743this.state.videoStream=await navigator.mediaDevices.getUserMedia({video:this.store.settings.cameraConstraints,});if(!this.videoRef.el){return;} 11744if(status(this)==="destroyed"){closeStream(this.state.videoStream);return;} 11745if(this.videoRef.el){this.videoRef.el.srcObject=this.state.videoStream;} 11746this.props.onSettingsChanged?.({camera:true});if(this.store.settings.useBlur){await this.enableBlur();}} 11747disableCamera(){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;} 11748this.props.onSettingsChanged?.({camera:false});} 11749async toggleCamera(){if(this.state.videoStream){this.disableCamera();return;} 11750if(this.rtc.cameraPermission==="prompt"){this.dialog.add(CallPermissionDialog,{media:"camera",useMicrophone:()=>this.enableMicrophone(),useCamera:()=>this.enableCamera(),});return;} 11751await this.enableCamera();} 11752async enableBlur(){this.store.settings.setUseBlur(true);if(!this.videoRef.el){return;} 11753try{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();}} 11754disableBlur(){this.store.settings.setUseBlur(false);
11754if(this.videoRef.el){this.videoRef.el.srcObject=this.state.videoStream;} 11755this.state.blurManager?.close();this.state.blurManager=undefined;} 11756toggleBlur(){if(this.state.blurManager){this.disableBlur();return;} 11757this.enableBlur();}} 11758return __exports;});; 11759 11760/* /mail/static/src/discuss/call/common/call_settings.js */ 11761odoo.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;} 11762this.state.userDevices=await browser.navigator.mediaDevices.enumerateDevices();});} 11763get stopText(){return _t("Stop");} 11764get testText(){return _t("Test");} 11765get 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(" + ");} 11766get isMobileOS(){return isMobileOS();} 11767_onKeyDown(ev){if(!this.store.settings.isRegisteringKey){return;} 11768ev.stopPropagation();ev.preventDefault();this.store.settings.setPushToTalkKey(ev);} 11769_onKeyUp(ev){if(!this.store.settings.isRegisteringKey){return;} 11770ev.stopPropagation();ev.preventDefault();this.store.settings.isRegisteringKey=false;} 11771onChangeLogRtc(ev){this.store.settings.logRtc=ev.target.checked;} 11772onChangeSelectAudioInput(ev){this.store.settings.setAudioInputDevice(ev.target.value);} 11773onClickDownloadLogs(){this.rtc.dumpLogs({download:true});} 11774onClickRegisterKeyButton(){this.store.settings.isRegisteringKey=!this.store.settings.isRegisteringKey;} 11775onChangeDelay(ev){this.store.settings.setDelayValue(ev.target.value);} 11776onChangeBlur(ev){this.store.settings.setUseBlur(ev.target.checked);} 11777onChangeShowOnlyVideo(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;});}}
11778onChangeBackgroundBlurAmount(ev){this.store.settings.backgroundBlurAmount=Number(ev.target.value);this.saveBackgroundBlurAmount();} 11779onChangeEdgeBlurAmount(ev){this.store.settings.edgeBlurAmount=Number(ev.target.value);this.saveEdgeBlurAmount();}} 11780const CallSettingsDialog=__exports.CallSettingsDialog=class CallSettingsDialog extends Component{static template=xml` 11781 <Dialog size="medium" footer="false" title.translate="Voice & Video Settings"> 11782 <CallSettings withActionPanel="false"/> 11783 </Dialog> 11784 `;static props=["*"];static components={CallSettings,Dialog};} 11785return __exports;});; 11786 11787/* /mail/static/src/discuss/call/common/channel_member_patch.js */ 11788odoo.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;} 11789this.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;} 11790browser.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;});; 11791 11792/* /mail/static/src/discuss/call/common/chat_window_patch.js */ 11793odoo.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;});; 11794 11795/* /mail/static/src/discuss/call/common/device_select.js */ 11796odoo.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;} 11797await this.updateDevicesList();this.setupEventListeners();});onWillDestroy(()=>{this.abortController.abort();});} 11798async updateDevicesList(){this.state.userDevices=await browser.navigator.mediaDevices.enumerateDevices();} 11799async 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});}} 11800async 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;}}}
11801isSelected(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;}} 11802onChangeSelectAudioInput(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;}} 11803isPermissionGranted(kind){if(kind==="videoinput"){return this.store.rtc.cameraPermission==="granted";} 11804return this.store.rtc.microphonePermission==="granted";}} 11805return __exports;});; 11806 11807/* /mail/static/src/discuss/call/common/discuss_call_settings_client_action.js */ 11808odoo.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";} 11809registry.category("actions").add("mail.discuss_call_settings_action",DiscussCallSettingsClientAction);return __exports;});; 11810 11811/* /mail/static/src/discuss/call/common/discuss_p2p_service.js */ 11812odoo.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;});; 11813 11814/* /mail/static/src/discuss/call/common/mail_guest_model_patch.js */ 11815odoo.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;});; 11816 11817/* /mail/static/src/discuss/call/common/meeting.js */ 11818odoo.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(()=>
11818{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));} 11819get thread(){return this.store.rtc.channel;}} 11820return __exports;});; 11821 11822/* /mail/static/src/discuss/call/common/meeting_chat.js */ 11823odoo.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});} 11824get thread(){return this.store.rtc.channel;}} 11825return __exports;});; 11826 11827/* /mail/static/src/discuss/call/common/meeting_side_actions.js */ 11828odoo.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});} 11829computeActions(){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;}} 11830return __exports;});; 11831 11832/* /mail/static/src/discuss/call/common/peer_to_peer.js */ 11833odoo.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
11833NDIDATE:"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();} 11834disconnect(){if(this.connection){const RTCRtpSenders=this.connection.getSenders();for(const sender of RTCRtpSenders){try{this.connection.removeTrack(sender);}catch{}} 11835for(const transceiver of this.connection.getTransceivers()){try{transceiver.stop();}catch{}}} 11836this.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();}} 11837getRecommendedTransceiverDirection(streamType,canUpload=false){if(this.medias[streamType].accepted){return canUpload?"sendrecv":"recvonly";}else{return canUpload?"sendonly":"inactive";}} 11838getTransceiver(streamType){if(!this.connection){return;} 11839const transceivers=this.connection.getTransceivers();return transceivers[ORDERED_TRANSCEIVER_TYPES.indexOf(streamType)];} 11840getTransceiverStreamType(transceiver){const transceivers=this.connection.getTransceivers();return ORDERED_TRANSCEIVER_TYPES[transceivers.indexOf(transceiver)];}} 11841const 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);} 11842constructor({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);} 11843connect(selfId,channelId,{info={},iceServers=DEFAULT_ICE_SERVERS}={}){if(!IS_CLIENT_RTC_COMPATIBLE){throw new Error("RTCPeerConnection is not supported");} 11844this.selfId=selfId;this.channelId=channelId;this._iceServers=iceServers;this._localInfo=Object.assign(this._localInfo,info);} 11845removeALlPeers(){for(const peer of this.peers.values()){this.removePeer(peer.id);} 11846this.peers.clear();} 11847disconnect(){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,});} 11848async addPeer(id,options={}){const peer=this.peers.get(id);if(peer){return peer;} 11849const newPeer=this._createPeer(id,options);await newPeer.ready;return newPeer;} 11850removePeer(id){const recoverTimeoutId=this._recoverTimeouts.get(id);browser.clearTimeout(recoverTimeoutId);this._recoverTimeouts.delete(id);const peer=this.peers.get(id);if(!peer){return;} 11851this.peers.delete(id);peer.disconnect();} 11852broadcast(message){this._dataChannelBroadcast(INTERNAL_EVENT.BROADCAST,message);} 11853async getFormattedStats(id){const peer=this.peers.get(id);const formattedStats={};if(!peer){return formattedStats;} 11854formattedStats.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||"";} 11855break;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;}} 11856return formattedStats;} 11857updateDownload(id,states){const peer=this.peers.get(id);if(!peer){return;} 11858for(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;} 11859transceiver.direction=peer.getRecommendedTransceiverDirection(streamType,Boolean(this._tracks[streamType]));}} 11860async 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)));} 11861await Promise.all(proms);} 11862updateInfo(info){this._localInfo=Object.assign(this._localInfo,info);this._dataChannelBroadcast(INTERNAL_EVENT.INFO,this._localInfo);} 11863async handleNotification(id,content){const{event,channelId,payload}=JSON.parse(content);this._emitLog(id,`received notification: ${event}`,LOG_LEVEL.DEBUG);
11863if(channelId!==this.channelId){return;} 11864let 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;} 11865switch(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;} 11866const description=new window.RTCSessionDescription(payload.sdp);try{await peer.connection.setRemoteDescription(description);}catch{this._recover(id,"answer handling: Failed at setting remoteDescription");} 11867break;} 11868case INTERNAL_EVENT.BROADCAST:{this._emitUpdate({name:UPDATE_EVENT.BROADCAST,payload:{senderId:id,message:payload},});peer.ready.resolve(true);break;} 11869case INTERNAL_EVENT.DISCONNECT:{this.removePeer(id);this._emitUpdate({name:UPDATE_EVENT.DISCONNECT,payload:{sessionId:id}});break;} 11870case INTERNAL_EVENT.ICE_CANDIDATE:{if(INVALID_ICE_CONNECTION_STATES.has(peer.connection.iceConnectionState)){return;} 11871const rtcIceCandidate=new window.RTCIceCandidate(payload.candidate);try{await peer.connection.addIceCandidate(rtcIceCandidate);}catch{this._recover(id,"failed at adding ice candidate");} 11872break;} 11873case 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;} 11874case 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);} 11875if(!peer){peer=this._createPeer(id,{sequence:payload.sequence});} 11876if(!peer.connection||INVALID_ICE_CONNECTION_STATES.has(peer.connection.iceConnectionState)||peer.connection.signalingState==="have-remote-offer"){return;} 11877const 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`);}} 11878const description=new window.RTCSessionDescription(payload.sdp);try{await peer.connection.setRemoteDescription(description);}catch{this._recover(id,"failed at setting remoteDescription");return;} 11879if(!peer.connection){this._emitLog(id,"the peer connection was closed during offer negotiation",LOG_LEVEL.WARN);return;} 11880if(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);}} 11881for(const transceiverName of ORDERED_TRANSCEIVER_TYPES){await this._updateRemote(peer,transceiverName);}} 11882peer.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;} 11883peer.isBuildingAnswer=false;if(!this.isActive||!this.peers.has(id)){return;} 11884this._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;}}} 11885setLoggingLevel(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);}} 11886_dataChannelBroadcast(internalEvent,message){for(const peer of this.peers.values()){if(!peer?.dataChannel||peer?.dataChannel.readyState!=="open"){continue;} 11887peer.dataChannel.send(JSON.stringify({event:internalEvent,channelId:this.channelId,payload:message,}));}} 11888_emitUpdate(detail){this.dispatchEvent(new CustomEvent("update",{detail}));} 11889_emitLog(id,message,level=LOG_LEVEL.DEBUG){this._loggingFunctions[level](id,message);} 11890_recover(id,reason=""){this._emitLog(id,`connection recovery candidate: ${reason}`,LOG_LEVEL.WARN);if(this._recoverTimeouts.get(id)){return;} 11891const peer=this.peers.get(id);if(!peer){return;} 11892const 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;} 11893this._emitUpdate({name:UPDATE_EVENT.RECOVERY,payload:{id}});
11893this._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));} 11894async _sendNotifications(){if(this._isPendingNotify){return;} 11895this._isPendingNotify=true;await new Promise((resolve)=>setTimeout(resolve,this._batchDelay));if(!this.isActive){this._isPendingNotify=false;return;} 11896const 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();}}} 11897async _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;} 11898this._notificationsToSend.set(id,{channelId:this.channelId,event,payload,sender:this.selfId,targets,});await this._sendNotifications();} 11899async _updateRemote(peer,streamType){const track=this._tracks[streamType];const transceiver=peer.getTransceiver(streamType);if(!transceiver){return;} 11900try{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}`);}} 11901_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;} 11902if(!this.isActive||!this.peers.has(id)){return;} 11903await 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;} 11904this._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;} 11905peer.isBuildingOffer=false;if(!this.isActive||!this.peers.has(id)){return;} 11906await 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;} 11907const streamType=peer.getTransceiverStreamType(transceiver);if(!streamType){this._recover(id,"received track for unknown transceiver");return;} 11908peer.medias[streamType].track=track;if(!(await peer.ready)){return;} 11909this._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;} 11910dataChannel.send(JSON.stringify({event:INTERNAL_EVENT.INFO,channelId:this.channelId,payload:this._localInfo,}));this.broadcast({sequence:peer.sequence});});return peer;}} 11911return __exports;});; 11912 11913/* /mail/static/src/discuss/call/common/pip_banner.js */ 11914odoo.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});} 11915onClickClose(){this.rtc.closePip();}} 11916return __exports;});; 11917 11918/* /mail/static/src/discuss/call/common/pip_service.js */ 11919odoo.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();} 11920async function openPip({context}){const rtc=env.services["discuss.rtc"];if(!rtc?.channel){return;} 11921state.active=true;const isShadowRoot=context?.root?.el?.getRootNode()instanceof ShadowRoot;pipWindow=await popout.pip(Meeting,{props:{isPip:true}
11921,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";} 11922return reactive({get isNativePipAvailable(){return Boolean(window.documentPictureInPicture);},get pipWindow(){return pipWindow;},state,closePip,openPip,});},};registry.category("services").add("discuss.pip_service",callPipService);return __exports;});; 11923 11924/* /mail/static/src/discuss/call/common/ptt_ad_banner.js */ 11925odoo.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),});} 11926onClickClose(){browser.localStorage.setItem(PttAdBanner.LOCAL_STORAGE_KEY,true);this.state.wasDiscarded=true;} 11927get isVisible(){return(!this.pttExtService.isEnabled&&this.store.settings.use_push_to_talk&&!isMobileOS()&&!this.state.wasDiscarded);}} 11928return __exports;});; 11929 11930/* /mail/static/src/discuss/call/common/ptt_extension_service.js */ 11931odoo.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;} 11932switch(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);}} 11933break;case"toggle-voice":{if(self.voiceActivated){rtc.setPttReleaseTimeout(0);}else{rtc.onPushToTalk();} 11934self.voiceActivated=!self.voiceActivated;} 11935break;case"answer-is-enabled":pttExtensionServiceInternal.onAnswerIsEnabled(self);break;}});async function sendMessage(type,value){if(!self.isEnabled&&type!=="ask-is-enabled"){return;} 11936const version=parseVersion(await versionPromise);if(location.origin==="null"){return;} 11937if(version.isLowerThan("1.0.0.2")){window.postMessage({from:"discuss",type,value},location.origin);return;} 11938window.chrome?.runtime?.sendMessage(EXT_ID,{type,value});} 11939sendMessage("ask-is-enabled");return self;},};registry.category("services").add("discuss.ptt_extension",pttExtensionHookService);return __exports;});; 11940 11941/* /mail/static/src/discuss/call/common/quick_video_settings.js */ 11942odoo.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;} 11943onClickVideoSettings(){this.dialogService.add(CallSettingsDialog,{});}} 11944return __exports;});; 11945 11946/* /mail/static/src/discuss/call/common/quick_voice_settings.js */ 11947odoo.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");} 11948onClickVoiceSettings(){this.dialogService.add(CallSettingsDialog,{});}} 11949return __exports;});; 11950 11951/* /mail/static/src/discuss/call/common/res_partner_model_patch.js */ 11952odoo.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;});; 11953 11954/* /mail/static/src/discuss/call/common/rtc_service.js */ 11955odoo.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}
11955=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);} 11956const 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"]}];} 11957const 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:");} 11958if(server.urls){if(Array.isArray(server.urls)){hasTurn=server.urls.some((url)=>url.startsWith("turn:"))||hasTurn;}else{hasTurn=server.urls.startsWith("turn:")||hasTurn;}} 11959return hasTurn;});} 11960const Network=__exports.Network=class Network{p2p;sfu;_listeners=[];constructor(p2p,sfu){this.p2p=p2p;this.sfu=sfu;} 11961getSfuConsumerStats(sessionId){const consumers=this.sfu?._consumers.get(sessionId);if(!consumers){return[];} 11962return 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";} 11963return{type,state};});} 11964addSfu(sfu){if(this.sfu){this.sfu.disconnect();} 11965this.sfu=sfu;} 11966removeSfu(){if(!this.sfu){return;} 11967for(const{name,f}of this._listeners){this.sfu.removeEventListener(name,f);} 11968this.sfu.disconnect();} 11969addEventListener(name,f){this._listeners.push({name,f});this.p2p.addEventListener(name,f);this.sfu?.addEventListener(name,f);} 11970async updateUpload(type,track){const proms=[this.p2p.updateUpload(type,track)];if(this.sfu?.state==="connected"){proms.push(this.sfu.updateUpload(type,track));} 11971await Promise.all(proms);} 11972updateDownload(sessionId,states){this.p2p.updateDownload(sessionId,states);this.sfu?.updateDownload(sessionId,states);} 11973updateInfo(info,options={}){this.p2p.updateInfo(info,options);this.sfu?.updateInfo(info,options);} 11974disconnect(){for(const{name,f}of this._listeners.splice(0)){this.p2p.removeEventListener(name,f);this.sfu?.removeEventListener(name,f);} 11975this.p2p.disconnect();this.sfu?.disconnect();}} 11976const 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;} 11977if(this._remotelyHostedChannelId){return this.store.Thread.insert({model:"discuss.channel",id:this._remotelyHostedChannelId,});}},onUpdate(){if(!this.channel){return;} 11978this.store.Thread.getOrFetch({model:"discuss.channel",id:this.channel.i
11978d,});},});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);} 11979get isHost(){return Boolean(this.localSession);} 11980callActions=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();} 11981return transformedActions;},onUpdate(){for(const action of this.callActions){if(action.isActive===this.lastActions[action.id]){continue;} 11982if(!action.isTracked){continue;} 11983if(action.isActive){if(!this.actionsStack.includes(action.id)){this.actionsStack.unshift(action.id);}}else{this.actionsStack.splice(this.actionsStack.indexOf(action.id),1);}} 11984this.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;} 11985start(){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});} 11986this.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;} 11987for(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;} 11988this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.PING,hostedSessionId:this.localSession.id,});await this.ping();if(!this.localSession||!this.state.channel){return;} 11989this.call();},PING_INTERVAL);} 11990get displaySurface(){return this.state.sourceScreenStream?.getVideoTracks()[0]?.getSettings().displaySurface;} 11991isPushToTalkRelease(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;} 11992return true;} 11993onKeyDown(ev){if(!this.store.settings.isPushToTalkKey(ev)){return;} 11994this.onPushToTalk();} 11995onKeyUp(ev){if(!this.isPushToTalkRelease(ev)){return;} 11996this.setPttReleaseTimeout();} 11997onBlur(){if(!this.isPushToTalkRelease()){return;} 11998this.setPttReleaseTimeout();} 11999showMirroringWarning(){this.state.screenTrack.enabled=false;const trackEndedFn=()=>this.removeMirroringWarning?.();this.removeMirroringWarning=this.overlay.add(CallInfiniteMirroringWarning,{onClose:({stopScreensharing}={})=>{this.removeMirroringWarning({stopScreensharing});},},{onRemove:({stopScreensharing}={})=>
11999{if(stopScreensharing){this.toggleVideo("screen",false);} 12000this.state.screenTrack?.removeEventListener("ended",trackEndedFn);this.removeMirroringWarning=null;},});this.state.screenTrack.addEventListener("ended",trackEndedFn,{once:true});} 12001setPttReleaseTimeout(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));} 12002onPushToTalk(){if(!this.state.channel||this.store.settings.isRegisteringKey||!this.store.settings.use_push_to_talk){return;} 12003browser.clearTimeout(this.state.pttReleaseTimeout);if(!this.localSession.isTalking&&!this.localSession.isMute){this.soundEffectsService.play("ptt-press");} 12004this.setTalking(true);} 12005async openPip(options){if(this.isHost){this.exitFullscreen();await this.pipService.openPip(options);return;} 12006this.notification.add(UNAVAILABLE_AS_REMOTE,{type:"warning",});} 12007closePip(){if(this.isHost){this.pipService.closePip();}else{this._remoteAction({pip:false});}} 12008addCallNotification({id,text,delay=3000}){if(this.notifications.has(id)){return;} 12009this.notifications.set(id,{id,text});this.timeouts.set(id,browser.setTimeout(()=>{this.notifications.delete(id);this.timeouts.delete(id);},delay));} 12010removeCallNotification(id){browser.clearTimeout(this.timeouts.get(id));this.notifications.delete(id);this.timeouts.delete(id);} 12011async leaveCall(channel=this.state.channel){this.store.fullscreenChannel=null;this.state.hasPendingRequest=true;await this.rpcLeaveCall(channel);this.endCall(channel);this.state.hasPendingRequest=false;} 12012endCall(channel=this.state.channel){this._endHost();if(channel.self_member_id){channel.self_member_id.rtc_inviting_session_id=undefined;} 12013channel.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");}} 12014async deafen(){if(this.isRemote){this._remoteAction({is_deaf:true});return;} 12015await this.setDeaf(true);this.soundEffectsService.play("earphone-off");} 12016setRemoteRaiseHand(session,active){if(Boolean(session.raisingHand)===active){return;} 12017Object.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);}} 12018setVolume(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},});} 12019async mute(){if(this.isRemote){this._remoteAction({is_muted:true});return;} 12020await this.setMute(true);this.soundEffectsService.play("mic-off");} 12021async 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,});} 12022async exitFullscreen(){this.store.fullscreenChannel=null;await this.fullscreen.exit(CALL_FULLSCREEN_ID);} 12023async toggleCall(channel,{audio=true,camera}={}){if(channel.id===this._remotelyHostedChannelId){this._postToTabs({type:CROSS_TAB_CLIENT_MESSAGE.LEAVE});this.clear();return;} 12024await Promise.resolve(()=>loadJS(url("/mail/static/lib/selfie_segmentation/selfie_segmentation.js")).catch(()=>{}));if(this.state.hasPendingRequest){return;} 12025const isActiveCall=channel.eq(this.state.channel);if(this.state.channel){await this.leaveCall(this.state.channel);} 12026if(!isActiveCall){const joinCallOpts={audio,camera};if(this.microphonePermission!=="granted"){joinCallOpts.audio=false;} 12027await this.joinCall(channel,joinCallOpts);}} 12028async toggleCameraFacingMode(){this.store.settings.cameraFacingMode=this.store.settings.cameraFacingMode==="user"?"environment":"user";await this.toggleVideo("camera",{force:true,refreshStream:true});} 12029async toggleDeafen(){if(this.selfSession.is_deaf){await this.undeafen();if(this.selfSession.is_muted){await this.unmute();}}else{await this.deafen();}} 12030async toggleMicrophone(){if(this.selfSession.isMute){if(this.selfSession.is_muted){await this.unmute();} 12031if(this.selfSession.is_deaf){await this.undeafen();}}else{await this.mute();}} 12032async undeafen(){if(this.isRemote){this._remoteAction({is_deaf:false});return;} 12033await this.setDeaf(false);this.soundEffectsService.play("earphone-on");} 12034showMediaPermissionDialog(media){this.closeCallPermissionDialog=this.dialog.add(CallPermissionDialog,{media,useMicrophone:()=>this.unmute(),useCamera:()=>this.toggleVideo("camera",{force:true,refreshStream:true}),},{context:{root:{el:this.rootEl}}});} 12035showMediaUnavailableWarning({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.");} 12036this.notification.add(errorMessage,{type:"warning"});} 12037async 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";} 12038if(video){this.cameraPermission="granted";}} 12039closeStream(stream);}catch{this.showMediaUnavailableWarning({microphone:audio,camera:video}
12039);return false;} 12040if(audio&&video){return this.microphonePermission==="granted"&&this.cameraPermission==="granted";} 12041return audio?this.microphonePermission==="granted":this.cameraPermission==="granted";} 12042async unmute(){if(this.isRemote){this._remoteAction({is_muted:false});return;} 12043if(this.microphonePermission==="prompt"){this.showMediaPermissionDialog("microphone");return;} 12044if(this.state.micAudioTrack){await this.setMute(false);}else{await this.resetMicAudioTrack({force:true});} 12045this.soundEffectsService.play("mic-on");} 12046async _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);} 12047resolve();},1000);});}} 12048updateUpload(){this.network?.updateUpload("audio",this.state.audioTrack);this.network?.updateUpload("camera",this.state.cameraTrack);this.network?.updateUpload("screen",this.state.screenTrack);} 12049async _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,});} 12050this.selfSession.connectionState="initializing";}else{this.log(this.localSession,"no sfu server info, using peer-to-peer");} 12051this.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();}} 12052_remoteAction(changes){this._postToTabs({type:CROSS_TAB_CLIENT_MESSAGE.REQUEST_ACTION,changes,});} 12053_updateInfo(){if(!this.isHost){return;} 12054const info=toRaw(this.formatInfo());this.network?.updateInfo(info);this._updateRemoteTabs({[this.localSession.id]:info});} 12055_host(){this._remotelyHostedChannelId=undefined;this._remotelyHostedSessionId=this.localSession.id;this._updateRemoteTabs({[this.localSession.id]:toRaw(this.formatInfo())});} 12056_endHost(){this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.CLOSE,hostedSessionId:this._remotelyHostedSessionId,});} 12057_updateRemoteTabs(changes){this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.UPDATE_REMOTE,hostedChannelId:this.state.channel.id,hostedSessionId:this.localSession.id,changes,});} 12058_postToTabs(message){if(!this._broadcastChannel){this.log(this.selfSession,"broadcast channel not available");return;} 12059try{this._broadcastChannel.postMessage(message);}catch(error){this.log(this.selfSession,"failed to post message to broadcast channel",{error});}} 12060_refreshCrossTabTimeout(){browser.clearTimeout(this._crossTabTimeoutId);this._crossTabTimeoutId=browser.setTimeout(()=>{this.clear();},PING_INTERVAL+10_000);} 12061async _onBroadcastChannelMessage({data:{type,hostedChannelId,hostedSessionId,changes},}){switch(type){case CROSS_TAB_HOST_MESSAGE.UPDATE_REMOTE:if(this.isHost){return;} 12062this._remotelyHostedSessionId=hostedSessionId;this._remotelyHostedChannelId=hostedChannelId;this._refreshCrossTabTimeout();this.updateSessionInfo(changes);return;case CROSS_TAB_HOST_MESSAGE.CLOSE:{if(this._remotelyHostedSessionId!==hostedSessionId){return;} 12063this.clear();return;} 12064case CROSS_TAB_HOST_MESSAGE.PIP_CHANGE:{if(this.isHost){return;}
12065this.state.isPipMode=changes.isPipMode;return;} 12066case CROSS_TAB_HOST_MESSAGE.PING:{this._refreshCrossTabTimeout();return;} 12067case CROSS_TAB_CLIENT_MESSAGE.INIT:{if(!this.isHost){return;} 12068this._updateRemoteTabs({[this.localSession.id]:toRaw(this.formatInfo())});this._postToTabs({type:CROSS_TAB_HOST_MESSAGE.PIP_CHANGE,changes:{isPipMode:this.state.isPipMode},});return;} 12069case CROSS_TAB_CLIENT_MESSAGE.REQUEST_ACTION:{if(!this.isHost){return;} 12070await this._localAction(changes);this._updateRemoteTabs({[this.localSession.id]:toRaw(this.formatInfo())});return;} 12071case CROSS_TAB_CLIENT_MESSAGE.LEAVE:{if(!this.isHost){return;} 12072await this.leaveCall(this.channel);return;} 12073case CROSS_TAB_CLIENT_MESSAGE.UPDATE_VOLUME:{const session=this.store["discuss.channel.rtc.session"].get(changes.sessionId);if(!session){return;} 12074session.volume=changes.volume;return;}}} 12075async _localAction(actions={}){const promises=[];for(const[key,value]of Object.entries(actions)){switch(key){case"is_muted":if(value===this.localSession.is_muted){break;} 12076promises.push(value?this.mute():this.unmute());break;case"is_deaf":if(value===this.localSession.is_deaf){break;} 12077value?promises.push(this.deafen()):promises.push(this.undeafen());break;case"raisingHand":if(value===Boolean(this.localSession.raisingHand)){break;} 12078promises.push(this.raiseHand(value));break;
12078case"pip":if(value===this.state.isPipMode){break;} 12079if(value){promises.push(this.openPip());}else{this.closePip();} 12080break;}} 12081await Promise.all(promises);} 12082log(session,entry,param2={}){if(!session){return;} 12083const{error,step,state,important,...data}=param2;session.logStep=entry;if(!this.store.settings.logRtc&&!important){return;} 12084console.debug(`%c${new Date().toLocaleString()} - [${entry}]`,"color: #e36f17; font-weight: bold;",toRaw(session)._raw,param2);if(!this.state.logs){return;} 12085let sessionEntry=this.state.logs.entriesBySessionId[session.id];if(!sessionEntry){this.state.logs.entriesBySessionId[session.id]=sessionEntry={step:"",state:"",logs:[],};} 12086if(step){sessionEntry.step=step;} 12087if(state){sessionEntry.state=state;} 12088sessionEntry.logs.push({event:`${new Date().toISOString()}: ${entry}`,error:error&&{name:error.name,message:error.message,stack:error.stack&&error.stack.split("\n"),},...data,});} 12089async _handleNetworkUpdates({detail:{name,payload}}){if(!this.state.channel){return;} 12090switch(name){case"broadcast":{const{senderId,message:{sequence},}=payload;if(!sequence){return;} 12091const session=await this.store["discuss.channel.rtc.session"].getWhenReady(senderId);if(!session){return;} 12092if(!session.sequence||session.sequence<sequence){session.sequence=sequence;}} 12093return;case"connection_change":{const{id,state}=payload;const session=this.store["discuss.channel.rtc.session"].get(id);if(!session){return;} 12094session.connectionState=state;} 12095return;case"disconnect":{const{sessionId}=payload;const session=this.store["discuss.channel.rtc.session"].get(sessionId);if(!session){return;} 12096this.disconnect(session);} 12097return;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;} 12098if(sequence&&sequence<session.sequence){this.log(session,`track received for old sequence ${sequence} (${this.state.connectionType})`);return;} 12099this.log(session,`${type} track received (${this.state.connectionType})`);try{await this.handleRemoteTrack({session,track,type,active});}catch{} 12100setTimeout(()=>{this.updateVideoDownload(session);},2000);} 12101return;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;} 12102this._p2pRecoveryCount++;if(this._p2pRecoveryCount>1||!hasTurn(this.iceServers)){this.upgradeConnectionDebounce();}}}} 12103async _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;} 12104let 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();} 12105this.notification.add(text,{type:"warning",});} 12106return;}} 12107async _upgradeConnection(){const channelId=this.state.channel?.id;if(this.serverInfo||this.state.fallbackMode||!channelId){return;} 12108await rpc("/mail/rtc/channel/upgrade_connection",{channel_id:channelId},{silent:true});} 12109updateSessionInfo(payload){if(!payload){return;} 12110if(this.isHost){this._updateRemoteTabs(payload);} 12111for(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;} 12112this.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,});})();}} 12113async _downgradeConnection(){this.serverInfo=undefined;this.state.fallbackMode=true;this.state.connectionType=CONNECTION_TYPES.P2P;this.network.removeSfu();await this.call();this.updateUpload();} 12114async call({asFallback=false}={}){if(asFallback&&!this.state.fallbackMode){return;} 12115if(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,});} 12116return;} 12117if(this.state.channel.rtc_session_ids.length===0){return;} 12118const sequence=getSequence();for(const session of this.state.channel.rtc_session_ids){if(session.eq(this.localSession)){continue;} 12119this.p2pService.addPeer(session.id,{sequence});}} 12120async 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});} 12121async joinCall(channel,{audio=true,camera=false}={}){if(!IS_CLIENT_RTC_COMPATIBLE){this.notification.add(_t("Your browser does not support webRTC."),{type:"warning"});return;} 12122this.pttExtService.subscribe();this.state.hasPendingRequest=true;const data=await rpc("/mail/rtc/channel/join_call",{camera,channel_id:channel.i
12122d,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;} 12123await 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;} 12124if(camera){await this.toggleVideo("camera");} 12125if(!this.selfSession){return;} 12126await this._initConnection();await this.resetMicAudioTrack({force:audio});if(!this.state.channel?.id){return;} 12127this.soundEffectsService.play("call-join");this._host();this.cleanups.push(subscribe(browser,"beforeunload",(event)=>{event.preventDefault();}));this.channel?.focusAvailableVideo();} 12128newLogs(){this.state.logs={channelId:this.state.channel.id,selfSessionId:this.localSession.id,start:new Date().toISOString(),hasTurn:hasTurn(this.iceServers),entriesBySessionId:{},};} 12129dumpLogs({download=false}={}){const logs=[];if(this.state.logs){logs.push({type:"timeline",entry:this.state.logs.start,value:toRaw(this.state.logs),});} 12130if(this.state.channel){logs.push(this.buildSnapshot());} 12131if(logs.length||download){browser.navigator.serviceWorker?.controller?.postMessage({name:SW_MESSAGE_TYPE.POST_RTC_LOGS,logs,download,});}} 12132buildSnapshot(){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);} 12133const 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;} 12134const audioEl=session.audioElement;if(audioEl){sessionInfo.audio={state:audioEl.readyState,muted:audioEl.muted,paused:audioEl.paused,networkState:audioEl.networkState,};} 12135const peer=this.p2pService?.peers.get(session.id);if(peer){sessionInfo.peer={id:peer.id,state:peer.connection.connectionState,iceState:peer.connection.iceConnectionState,};} 12136return sessionInfo;});return{type:"snapshot",entry:new Date().toISOString(),value:{server,sessions,connectionType:this.state.connectionType,fallback:this.state.fallbackMode,},};} 12137logSnapshot(){if(!this.state.channel){return;} 12138browser.navigator.serviceWorker?.controller?.postMessage({name:SW_MESSAGE_TYPE.POST_RTC_LOGS,logs:[this.buildSnapshot()],});} 12139async rpcLeaveCall(channel){await rpc("/mail/rtc/channel/leave_call",{channel_id:channel.id,},{silent:true});} 12140async 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);} 12141disconnect(session){const downloadTimeout=this.downloadTimeouts.get(session.id);if(downloadTimeout){clearTimeout(downloadTimeout);this.downloadTimeouts.delete(session.id);} 12142this.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"});} 12143clear(){if(this.state.channel){for(const session of this.state.channel.rtc_session_ids){this.removeAudioFromSession(session);this.removeVideoFromSession(session);session.isTalking=false;}} 12144this.exitFullscreen();this._remotelyHostedSessionId=undefined;this._remotelyHostedChannelId=undefined;browser.clearTimeout(this._crossTabTimeoutId);
12144this.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;} 12145this.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();} 12146async setDeaf(is_deaf){this.updateAndBroadcast({is_deaf});for(const session of this.state.channel.rtc_session_ids){if(!session.audioElement){continue;} 12147session.audioElement.muted=is_deaf;} 12148await this.refreshMicAudioStatus();} 12149async setOutputDevice(deviceId){const promises=[];for(const session of this.state.channel.rtc_session_ids){if(!session.audioElement){continue;} 12150promises.push(session.audioElement.setSinkId(deviceId));} 12151await Promise.all(promises);} 12152async setMute(is_muted){this.updateAndBroadcast({is_muted});await this.refreshMicAudioStatus();} 12153async raiseHand(raise){if(this.isRemote){this._remoteAction({raisingHand:raise});return;} 12154if(!this.localSession||!this.state.channel){return;} 12155this.localSession.raisingHand=raise?new Date():undefined;await this._updateInfo();} 12156async setTalking(isTalking){if(!this.localSession||isTalking===this.localSession.isTalking){return;} 12157this.localSession.isTalking=isTalking;
12157if(!this.localSession.isMute){this.pttExtService.notifyIsTalking(isTalking);await this.refreshMicAudioStatus();}} 12158async applyBlurEffect(videoStream){return new BlurManager(videoStream,{backgroundBlur:this.store.settings.backgroundBlurAmount,edgeBlur:this.store.settings.edgeBlurAmount,});} 12159async 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;} 12160if(this.isRemote){this.notification.add(UNAVAILABLE_AS_REMOTE,{type:"warning",});return;} 12161if(!this.state.channel?.id){return;} 12162switch(type){case"camera":{if(this.cameraPermission==="prompt"&&!this.state.cameraTrack){this.showMediaPermissionDialog("camera");return;} 12163const track=this.state.cameraTrack;const sendCamera=force??!this.state.sendCamera;this.state.sendCamera=false;await this.setVideo(track,type,{activateVideo:sendCamera,env,refreshStream});break;} 12164case"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;}} 12165if(!this.localSession){return;} 12166switch(type){case"camera":{this.removeVideoFromSession(this.localSession,{type:"camera",cleanup:false,});if(this.state.cameraTrack){this.updateStream(this.localSession,this.state.cameraTrack);} 12167this.updateAndBroadcast({is_camera_on:!!this.state.sendCamera,});break;} 12168case"screen":{if(!this.state.screenTrack){this.removeVideoFromSession(this.localSession,{type:"screen",cleanup:false,});}else{this.updateStream(this.localSession,this.state.screenTrack);} 12169this.updateAndBroadcast({is_screen_sharing_on:!!this.state.sendScreen,});break;}} 12170const updatedTrack=type==="camera"?this.state.cameraTrack:this.state.screenTrack;await this.network?.updateUpload(type,updatedTrack);} 12171updateAndBroadcast(data){this._updateRemoteTabs({[this.localSession.id]:data});assignDefined(this.localSession,data);this.state.updateAndBroadcastDebounce?.();} 12172async refreshMicAudioStatus(){if(!this.state.micAudioTrack){return;} 12173this.state.micAudioTrack.enabled=!this.localSession.isMute&&this.localSession.isTalking;this._updateInfo();} 12174async setVideo(track,type,options){let activateVideo;let env;if(typeof options==="boolean"){activateVideo=options??false;}else{activateVideo=options?.activateVideo??false;env=options?.env;} 12175const stopVideo=()=>{if(track){track.stop();} 12176switch(type){case"camera":{this.state.cameraTrack=undefined;closeStream(this.state.sourceCameraStream);this.state.sourceCameraStream=null;break;} 12177case"screen":{this.state.screenTrack=undefined;closeStream(this.state.sourceScreenStream);this.state.sourceScreenStream=null;break;}}};if(!activateVideo){if(type==="screen"){this.soundEffectsService.play("screen-sharing");} 12178if(type==="camera"&&this.blurManager){this.blurManager.close();this.blurManager=undefined;} 12179stopVideo();return;} 12180let 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,});}} 12181if(type==="screen"){if(this.state.sourceScreenStream){sourceStream=this.state.sourceScreenStream;}else{sourceStream=await sourceWindow.navigator.mediaDevices.getDisplayMedia({video:SCREEN_CONFIG,audio:true,});} 12182this.soundEffectsService.play("screen-sharing");}}catch{this.showMediaUnavailableWarning({camera:type==="camera",screen:type==="screen",});stopVideo();return;} 12183if(!this.selfSession){closeStream(sourceStream);return;} 12184let 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";}}} 12185if(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;} 12186switch(type){case"camera":{Object.assign(this.state,{sourceCameraStream:sourceStream,cameraTrack:outputTrack,sendCamera:Boolean(outputTrack),isCameraSourceExternal:Boolean(sourceStream)&&env?.pipWindow,});break;} 12187case"screen":{Object.assign(this.state,{sourceScreenStream:sourceStream,screenTrack:outputTrack,screenAudioTrack:screenAudioTrack,sendScreen:Boolean(outputTrack),isScreenSourceExternal:Boolean(sourceStream)&&env?.pipWindow,});break;}} 12188if(this.state.screenAudioTrack){this.updateAudioTrack();}} 12189async updateAudioTrack(){const{micAudioTrack,screenAudioTrack}=this.state;if(!micAudioTrack&&!screenAudioTrack){return;} 12190if(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;} 12191await this.network?.updateUpload("audio",this.state.audioTrack);} 12192async resetMicAudioTrack({force=false}){this.state.micAudioTrack?.stop();this.state.micAudioTrack=undefined;this.state.audioTrack?.stop();this.state.audioTrack=undefined;if(!this.state.channel){return;} 12193if(this.localSession){this.setMute(true);} 12194if(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;} 12195if(!this.localSession){micAudioTrack.stop();return;} 12196micAudioTrack.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();}} 12197async linkVoiceActivation(){this.state.disconnectAudioMonitor?.();if(!this.localSession){return;} 12198if(this.store.settings.use_push_to_talk||!this.state.channel||!this.state.micAudioTrack){this.localSession.isTalking=false;await this.refreshMicAudioStatus();return;} 12199try{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;} 12200await this.refreshMicAudioStatus();} 12201deleteSession(id){const session=this.store["discuss.channel.rtc.session"].get(id);if(session){if(this.localSession&&session.eq(this.localSession)){this.notifyServerDisconnect();this.endCall();} 12202this.disconnect(session);session.delete();}} 12203notifyServerDisconnect(){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",});} 12204formatInfo(){this.localSession.is_camera_on=Boolean(this.state.cameraTrack);this.localSession.is_screen_sharing_on=Boolean(this.state.screenTrack);return this.localSession.info;} 12205async 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();} 12206if(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});}} 12207removeVideoFromSession(session,{type,cleanup=true}={}){if(type){this.updateActiveSession(session,type);if(cleanup){closeStream(session.videoStreams.get(type));} 12208session.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);}} 12209session.videoStreams.clear();}} 12210removeAudioFromSession(session){closeStream(session.audioStream);if(session.audioElement){session.audioElement.pause();try{session.audioElement.srcObject=undefined;}catch{}} 12211session.audioStream=undefined;} 12212updateActiveSession(session,videoType,{addVideo=false}={}){const activeRtcSession=this.state.channel.activeRtcSession;if(addVideo){if(videoType==="screen"){this.state.channel.activeRtcSession=session;session.mainVideoStreamType=videoType;return;} 12213if(activeRtcSession&&session.hasVideo&&!session.isMainVideoStreamA
12213ctive){session.mainVideoStreamType=videoType;} 12214return;} 12215if(!activeRtcSession||activeRtcSession.notEq(session)){return;} 12216if(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";}}}} 12217updateVideoDownload(rtcSession,{viewCountIncrement=0}={}){rtcSession.videoComponentCount+=viewCountIncrement;const downloadTimeout=this.downloadTimeouts.get(rtcSession.id);if(downloadTimeout){this.downloadTimeouts.delete(rtcSession.id);browser.clearTimeout(downloadTimeout);} 12218if(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));}}} 12219Rtc.register();const rtcService=__exports.rtcService={dependencies:["bus_service","discuss.p2p","discu
12219ss.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();} 12220rtc.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;} 12221if(rtc.serverInfo?.channelUUID===serverInfo.channelUUID){rtc.p2pService.removeALlPeers();return;} 12222rtc.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;});; 12223 12224/* /mail/static/src/discuss/call/common/rtc_session_model.js */ 12225odoo.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;} 12226static 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);} 12227return deferred;} 12228return session;} 12229static new(){const record=super.new(...arguments);this.awaitedRecords.get(record.id)?.resolve(record);this.awaitedRecords.delete(record.id);return record;} 12230channel_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;} 12231is_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++;} 12232this.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";} 12233if(this.is_deaf){return"deafen";} 12234if(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;} 12235get isMute(){return this.is_muted||this.is_deaf;}
12236get mainVideoStream(){return this.isMainVideoStreamActive&&this.videoStreams.get(this.mainVideoStreamType);} 12237get isMainVideoStreamActive(){if(!this.mainVideoStreamType){return false;} 12238return this.mainVideoStreamType==="camera"?this.is_camera_on:this.is_screen_sharing_on;} 12239get hasVideo(){return this.is_screen_sharing_on||this.is_camera_on;} 12240getStream(type){const isActive=type==="camera"?this.is_camera_on:this.is_screen_sharing_on;return isActive&&this.videoStreams.get(type);} 12241get 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,};} 12242get name(){return this.channel_member_id?.name;} 12243get volume(){return this.audioElement?.volume||this.localVolume;} 12244set volume(value){if(this.audioElement){this.audioElement.volume=value;} 12245this.localVolume=value;} 12246async playAudio(){if(!this.audioElement){return;} 12247if(this.store.settings.audioOutputDeviceId){await this.audioElement.setSinkId(this.store.settings.audioOutputDeviceId).catch();} 12248try{await this.audioElement.play();this.audioError=undefined;}catch(error){this.audioError=error.name;}} 12249updateStreamState(type,state){if(type==="camera"){this.is_camera_on=state;}else if(type==="screen"){this.is_screen_sharing_on=state;}}} 12250RtcSession.register();return __exports;});; 12251 12252/* /mail/static/src/discuss/call/common/settings_model_patch.js */ 12253odoo.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;});; 12254 12255/* /mail/static/src/discuss/call/common/store_service_patch.js */ 12256odoo.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;} 12257this._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;});; 12258 12259/* /mail/static/src/discuss/call/common/thread_actions.js */ 12260odoo.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})=>
12260thread?.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;});; 12261 12262/* /mail/static/src/discuss/call/common/thread_model_patch.js */ 12263odoo.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;} 12264if(shouldPlayJoinSound){this.store.env.services["mail.sound_effects"].play("call-join");this.store.rtc.call({asFallback:true});} 12265if(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;} 12266this.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;
12266const 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,});} 12267const 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,});}} 12268if(!filterVideos){for(const member of this.invited_member_ids){invitationCards.push({key:"member_"+member.id,member});}} 12269raisingHandCards.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;} 12270return 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
12270de||this.isCallDisplayedInChatWindow)){return;} 12271const otherStreamingSession=this.rtc_session_ids.find((session)=>session.notEq(this.store.rtc.selfSession)&&session.hasVideo);if(!otherStreamingSession){return;} 12272this.activeRtcSession=otherStreamingSession;otherStreamingSession.mainVideoStreamType=otherStreamingSession.is_screen_sharing_on?"screen":"camera";},open(options){if(this.store.fullscreenChannel?.notEq(this)){this.store.rtc.exitFullscreen();} 12273return 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;} 12274this.focusStack.delete(session);if(session.isTalking&&!session.isMute){this.focusStack.push(session);} 12275const activeSession=this.focusStack.at(-1);if(!activeSession){return;} 12276this.activeRtcSession=activeSession;activeSession.mainVideoStreamType="camera";},};patch(Thread.prototype,ThreadPatch);return __exports;});; 12277 12278/* /mail/static/src/discuss/call/common/tick_worker.js */ 12279odoo.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;} 12280awaitingTock=false;isRunning=false;} 12281function startProcessing(fps){if(isRunning){return;} 12282isRunning=true;intervalId=setInterval(()=>{if(awaitingTock){return;} 12283awaitingTock=true;self.postMessage({command:"tick"});},Math.floor(1000/(fps||30)));} 12284self.onmessage=(e)=>{if(!e.data?.command){return;} 12285const{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;});; 12286 12287/* /mail/static/src/discuss/typing/common/composer_patch.js */ 12288odoo.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;} 12289const 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;}} 12290if(!this.typingNotified&&value){this.typingNotified=true;this.notifyIsTyping();browser.setTimeout(()=>(this.typingNotified=false),LONG_TYPING);} 12291this.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;});; 12292 12293/* /mail/static/src/discuss/typing/common/thread_icon_patch.js */ 12294odoo.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;});; 12295 12296/* /mail/static/src/discuss/typing/common/typing.js */ 12297odoo.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]);} 12298if(typingMemberNames.length===2){return _t("%(user1)s and %(user2)s are typing...",{user1:typingMemberNames[0],user2:typingMemberNames[1],});} 12299return _t("%(user1)s, %(user2)s and more are typing...",{user1:typingMemberNames[0],user2:typingMemberNames[1],});}} 12300return __exports;});; 12301 12302/* /mail/static/src/utils/common/dates.js */ 12303odoo.define('@mail/utils/common/dates',[],function(require){'use strict';let __exports={};const{DateTime}=luxon;__exports.computeDelay=computeDelay;function computeDelay(datetime){if(!datetime){return 0;} 12304const today=DateTime.now().startOf("day");return datetime.diff(today,"days").days;} 12305__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();} 12306__exports.isToday=isToday;function isToday(datetime){if(!datetime){return false;}
12307return(datetime.toLocaleString(DateTime.DATE_FULL)===DateTime.now().toLocaleString(DateTime.DATE_FULL));} 12308return __exports;});; 12309 12310/* /mail/static/src/utils/common/format.js */ 12311odoo.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;} 12312let 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;} 12313__exports.generateEmojisOnHtml=generateEmojisOnHtml;async function generateEmojisOnHtml(htmlBody,{allowEmojiLoading=true}={}){let body=htmlBody;
12313if(allowEmojiLoading||odoo.loader.modules.get("@web/core/emoji_picker/emoji_data")){body=await _generateEmojisOnHtml(body);} 12314return body;} 12315__exports.prettifyMessageContent=prettifyMessageContent;async function prettifyMessageContent(rawBody,{validMentions=[],allowEmojiLoading=true}={}){let body=prettifyMessageText(rawBody,{validMentions});body=await generateEmojisOnHtml(body,{allowEmojiLoading});return body;} 12316__exports.parseAndTransform=parseAndTransform;function parseAndTransform(htmlString,transformFunction){const div=document.createElement("div");try{setElementContent(div,htmlString);}catch{div.appendChild(createElementWithContent("pre",htmlString));} 12317return _parseAndTransform(Array.from(div.childNodes),transformFunction);} 12318function _parseAndTransform(nodes,transformFunction){if(!nodes){return;} 12319return htmlJoin(Object.values(nodes).map((node)=>transformFunction(node,function(){return _parseAndTransform(node.childNodes,transformFunction);})));} 12320function 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;} 12321result=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");} 12322result=htmlJoin([result,markup(link.outerHTML)]);curIndex=match.index+match[0].length;} 12323return htmlJoin([result,text.slice(curIndex)]);} 12324__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);} 12325node.parentNode.removeChild(node);return linkified;} 12326return node.textContent;} 12327if(node.tagName==="A"){return markup(node.outerHTML);} 12328transformChildren();return markup(node.outerHTML);} 12329function 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;} 12330__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}`,});} 12331__exports.generateRoleMentionElement=generateRoleMentionElement;function generateRoleMentionElement(role){return generateMentionElement({className:"o-discuss-mention",id:role.id,model:"res.role",text:`@${role.name}`,});} 12332__exports.generateSpecialMentionElement=generateSpecialMentionElement;function generateSpecialMentionElement(label){const link=document.createElement("a");setAttributes(link,{class:"o-discuss-mention",contenteditable:"false",});link.textContent=`@${label}`;return link;} 12333__exports.generateThreadMentionElement=generateThreadMentionElement;function generateThreadMentionElement(thread){return generateMentionElement({className:`o_channel_redirect${ 12334 thread.parent_channel_id ? " o_channel_redirect_asThread" : "" 12335 }`,id:thread.id,model:"discuss.channel",text:`#${thread.fullNameWithParent}`,});} 12336function 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,});} 12337for(const thread of threads){const placeholder=`#-mention-channel-${thread.id}!`;const text=`#${thread.fullNameWithParent}`;mentions.push({link:generateThreadMentionElement(thread),placeholder,text,});} 12338for(const mention of mentions.sort((m1,m2)=>m2.text.length-m1.text.length)){body=htmlReplace(body,mention.text,mention.placeholder);} 12339for(const special of specialMentions){const text=`@${special}`;const placeholder=`@-mention-special-${special}`;mentions.push({link:generateSpecialMentionElement(special),placeholder,});body=htmlReplace(body,text,placeholder);} 12340for(const role of roles){const placeholder=`@-mention-role-${role.i
12340d}`;const text=`@${role.name}`;mentions.push({link:generateRoleMentionElement(role),placeholder,});body=htmlReplace(body,text,placeholder);} 12341for(const mention of mentions){const link=mention.link;body=htmlReplace(body,mention.placeholder,markup(link.outerHTML));} 12342return htmlEscape(body);} 12343async 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);}} 12344return htmlEscape(htmlString);} 12345__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");} 12346for(const mention of doc.body.querySelectorAll(".o_mail_redirect")){mention.setAttribute("contenteditable",false);} 12347for(const mention of doc.body.querySelectorAll(".o_channel_redirect")){mention.setAttribute("contenteditable",false);} 12348for(const mention of doc.body.querySelectorAll(".o-discuss-mention")){mention.setAttribute("contenteditable",false);} 12349return markup(doc.body.innerHTML);} 12350__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));} 12351return div.textContent.trim().replace(/[\n\r]/g,"").replace(/\s\s+/g," ");} 12352__exports.convertBrToLineBreak=convertBrToLineBreak;function convertBrToLineBreak(str){str=htmlReplace(str,/<br\s*\/?>/gi,()=>"\n");return createDocumentFragmentFromContent(str).body.textContent;} 12353__exports.trimEmptyBlocksAround=trimEmptyBlocksAround;function trimEmptyBlocksAround(content){if(isHtmlEmpty(content)){return content;} 12354const body=createDocumentFragmentFromContent(content).body;let changed=false;const removeNode=(node)=>{node.remove();changed=true;};const getBoundaryChild=(element,side)=>{if(!element){return null;} 12355return side==="start"?element.firstChild:element.lastChild;};const getBoundaryElement=(element,side)=>{if(!element){return null;} 12356return 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;} 12357trimTextNodes(paragraph,side);let node=getBoundaryChild(paragraph,side);while(node?.nodeName==="BR"){removeNode(node);trimTextNodes(paragraph,side);node=getBoundaryChild(paragraph,side);} 12358trimEmptyParagraphs(side);if(getBoundaryElement(body,side)!==paragraph){trimBoundaryParagraph(side);}};trimBoundaryParagraph("start");trimBoundaryParagraph("end");return changed?markup(body.innerHTML):content;} 12359__exports.cleanTerm=cleanTerm;function cleanTerm(term){return typeof term==="string"?normalize(term):"";} 12360__exports.parseEmail=parseEmail;function parseEmail(text){if(!text){return;} 12361let result=text.match(/"?(.*?)"? <(.*@.*)>/);if(result){const name=(result[1]||"").trim().replace(/(^"|"$)/g,"");return[name,(result[2]||"").trim()];} 12362result=text.match(/(.*@.*)/);if(result){return[String(result[1]||"").trim(),String(result[1]||"").trim()];} 12363return[text,false];} 12364const 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}|`+ 12365r`${EMOJI}(?:\u200D${EMOJI})*`,"gu");__exports.decorateEmojis=decorateEmojis;function decorateEmojis(content){if(!loader.loaded||!content){return content;} 12366const 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( 12367 loader.loaded.emojiValueToShortcodes[codepoints], 12368 { style: "unit-narrow" } 12369 )}">${htmlEscape(codepoints)}</span>`)));node.replaceWith(...span.childNodes);} 12370return markup(doc.body.innerHTML);} 12371__exports.attClassObjectToString=attClassObjectToString;function attClassObjectToString(obj){return Object.entries(obj).filter(([_,val])=>val).map(([key,_])=>key).join(" ");} 12372return __exports;});; 12373 12374/* /mail/static/src/utils/common/hooks.js */ 12375odoo.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
12375s){const boundHandler=handler.bind(useComponent());let t;onMounted(()=>{t=target();if(!t){return;} 12376t.addEventListener(eventName,boundHandler,eventParams);});onPatched(()=>{const t2=target();if(t!==t2){if(t){t.removeEventListener(eventName,boundHandler,eventParams);} 12377if(t2){t2.addEventListener(eventName,boundHandler,eventParams);} 12378t=t2;}});onWillUnmount(()=>{if(!t){return;} 12379t.removeEventListener(eventName,boundHandler,eventParams);});} 12380__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;}} 12381function onMousedown(ev){downTarget=ev.target;} 12382function onMouseup(ev){upTarget=ev.target;} 12383onMounted(()=>{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);});} 12384__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;} 12385targets.push({ref:useRef(refName)});} 12386const 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();} 12387if(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);}} 12388wasHovering=hovering;} 12389function onmouseenter(ev){if(state.isHover){return;} 12390for(const target of toRaw(state)._targets){if(!target.ref.el){continue;} 12391if(target.ref.el.contains(ev.target)){setHover(true);lastHoveredTarget=target;return;}} 12392for(const contains of state._contains){if(contains(ev.target)){setHover(true);return;}}} 12393function onmouseleave(ev){if(!state.isHover){return;} 12394for(const target of toRaw(state._targets)){if(!target.ref.el){continue;} 12395if(target.ref.el.contains(ev.relatedTarget)){return;}} 12396for(const contains of state._contains){if(contains(ev.relatedTarget)){return;}} 12397setHover(false);lastHoveredTarget=null;} 12398for(const target of targets){useLazyExternalListener(()=>target.ref.el,"mouseenter",(ev)=>onmouseenter(ev),true);useLazyExternalListener(()=>target.ref.el,"mouseleave",(ev)=>onmouseleave(ev),true);} 12399if(stateObserver){useEffect((open)=>{if((lastHoveredTarget&&!lastHoveredTarget.ref.el)||!open){setHover(false);lastHoveredTarget=null;}},stateObserver);} 12400return state;} 12401const 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);} 12402removeTarget?.();});}} 12403__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();}} 12404onMounted(()=>{ref.el?.addEventListener("scroll",onScroll);});onWillUnmount(()=>{ref.el?.removeEventListener("scroll",onScroll);});} 12405__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);} 12406const observer=new IntersectionObserver((entries)=>{setValue(entries.at(-1).isIntersecting);});useEffect((el,ready)=>
12406{if(el&&ready){observer.observe(el);return()=>{setValue(undefined);observer.unobserve(el);};}},()=>[ref.el,state.ready]);return state;} 12407__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);} 12408const lastHighlightedMessageId=state.highlightedMessageId;this.clear();if(lastHighlightedMessageId===message.id){await new Promise(setTimeout);} 12409thread.scrollTop=messageScrollDirection==="top"?"bottom":undefined;if(thread.scrollTop==="bottom"){state.startupDeferred=new Deferred();await state.startupDeferred;state.startupDeferred=null;} 12410state.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);} 12411el.scrollIntoView({behavior:"smooth",block:"center"});return scrollPromise;},highlightedMessageId:null,});return state;} 12412__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;} 12413state.isReady=false;disconnectAudioMonitor?.();disconnectAudioMonitor=undefined;if(audioTrack){audioTrack.stop();audioTrack=null;state.isReady=true;state.isActive=false;state.value=0;return;} 12414let 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;} 12415if(isClosed){track.stop();return;} 12416audioMonitorPromise=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;} 12417__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,});}} 12418onExternalClick(refName,async(ev)=>{if(await preserveOnClickAwayPredicate(ev)){return;} 12419if(!ref.el){return;} 12420Object.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;}},};} 12421__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);} 12422inProgress=false;if(nextFunction&&nextResolve){call();}} 12423return(func)=>{nextResolve?.();const prom=new Promise((resolve,reject)=>{nextResolve=resolve;nextReject=reject;});nextFunction=func;if(!inProgress){call();} 12424return prom;};}
12425__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]);} 12426return{class:"o-mail-DiscussSystray-class",get contentClass(){return`d-flex flex-column flex-grow-1 ${ 12427 ui.isSmall ? "overflow-auto o-scrollbar-thin w-100 mh-100" : "" 12428 }`;},get menuClass(){return`p-0 o-mail-DiscussSystray ${ 12429 ui.isSmall 12430 ? "o-mail-systrayFullscreenDropdownMenu start-0 w-100 mh-100 d-flex flex-column mt-0 border-0 shadow-lg" 12431 : "" 12432 }`;},};} 12433const 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;} 12434useLazyExternalListener(()=>ref.el,"touchstart",(ev)=>{if(!predicate()){return;} 12435const 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;} 12436const 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);} 12437const inDiscussCallViewProps=__exports.inDiscussCallViewProps=["isPip?"];__exports.useInDiscussCallView=useInDiscussCallView;function useInDiscussCallView(){const component=useComponent();useSubEnv({inDiscussCallView:{get isPip(){return component.props.isPip;},},});} 12438return __exports;});; 12439 12440/* /mail/static/src/utils/common/media_monitoring.js */ 12441odoo.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";} 12442const audioContext=new AudioContext();const source=audioContext.createMediaStreamSource(stream);let processor;try{processor=await _loadAudioWorkletProcessor(source,audioContext,processorOptions);}catch{processor=_loadScriptProcessor(source,audioContext,processorOptions);} 12443return async()=>{processor.disconnect();source.disconnect();monitoredTrack.stop();try{await audioContext.close();}catch(e){if(e.name==="InvalidStateError"){return;} 12444throw e;}};} 12445function _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;} 12446nextUpdateFrame+=intervalInFrames;const normalizedVolume=getFrequencyAverage(analyser,frequencyRange[0],frequencyRange[1]);if(normalizedVolume>=volumeThreshold){activityBuffer=minimumActiveCycles;}else if(normalizedVolume<volumeThreshold&&activityBuffer>0){activityBuffer--;} 12447isAboveThreshold=activityBuffer>0;onTic?.(normalizedVolume);if(wasAboveThreshold!==isAboveThreshold){wasAboveThreshold=isAboveThreshold;onThreshold?.(isAboveThreshold);}};return{disconnect:()=>{analyser.disconnect();scriptProcessorNode.disconnect();scriptProcessorNode.onaudioprocess=null;},};} 12448async 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);} 12449if(volume!==undefined){onTic?.(volume);}};return{disconnect:()=>{thresholdProcessor.port.onmessage=null;thresholdProcessor.disconnect();},};} 12450function 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;} 12451if(!count){return 0;} 12452return sum/count;} 12453function _getFrequencyIndex(targetFrequency,sampleRate,binCount){const index=Math.round((targetFrequency/(sampleRate/2))*binCount);return Math.min(Math.max(0,index),binCount);} 12454return __exports;});; 12455 12456/* /mail/static/src/utils/common/misc.js */ 12457odoo.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];}} 12458return obj;} 12459__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);} 12460__exports.assignIn=assignIn;function assignIn(obj,data,keys=Object.keys(data)){for(const key of keys){if(key in data){obj[key]=data[key];}} 12461return obj;} 12462__exports.nearestGreaterThanOrEqual=nearestGreaterThanOrEqual;function nearestGreaterThanOrEqual(list,target,itemToCompareVal){const findNext=(left,right,next)=>{if(left>right){return next;} 12463const 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);} 12464const mailGlobal=__exports.mailGlobal={isInTest:false,};__exports.rpcWithEnv=rpcWithEnv;function rpcWithEnv(){return rpc;} 12465__exports.isDragSourceExternalFile=isDragSourceExternalFile;function isDragSourceExternalFile(dataTransfer){const dragDataType=dataTransfer.types;if(dragDataType.constructor===window.DOMStringList){return dragDataType.contains("Files");} 12466if(dragDataType.constructor===Array){return dragDataType.includes("Files");} 12467return false;} 12468__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);} 12469if(Array.isArray(val)){void val.length;void val.forEach((i)=>i);}} 12470if(Array.isArray(key)){for(const k of key){onChange(target,k,callback);} 12471return;} 12472proxy=reactive(target,()=>{_observe();callback();});_observe();return proxy;} 12473__exports.closeStream=closeStream;
12473function closeStream(stream){stream?.getTracks?.().forEach((track)=>track.stop());} 12474__exports.compareDatetime=compareDatetime;function compareDatetime(date1,date2){if(date1?.ts===date2?.ts){return 0;} 12475if(!date1){return-1;} 12476if(!date2){return 1;} 12477return date1.ts-date2.ts;} 12478function 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;} 12479if(num1>num2){return 1;}} 12480return 0;} 12481__exports.parseVersion=parseVersion;function parseVersion(v){return{isLowerThan(other){return compareVersion(v,other)<0;},};} 12482__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"};} 12483const 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"};} 12484return{url:null,provider:null};} 12485const 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;} 12486const 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;}} 12487return 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);} 12488__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;} 12489clearTimeout(timeout);if(!active){cleanup=effectFn(deps);active=true;} 12490return()=>{timeout=setTimeout(()=>{cleanup();active=false;},delay);};},dependencies:(...targets)=>({predicate:predicate(...targets),...dependencies(...targets),}),reactiveTargets,});} 12491__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;}}} 12492return __exports;});; 12493 12494/* /mail/static/src/utils/common/pdf_thumbnail.js */ 12495odoo.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};} 12496try{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;}}
12496catch(_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;} 12497if(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,","");} 12498return{isPdfValid,thumbnail,pdfEnabled:true};} 12499return __exports;});; 12500 12501/* /rating/static/src/core/common/message_model_patch.js */ 12502odoo.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;});; 12503 12504/* /rating/static/src/core/common/rating_model.js */ 12505odoo.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;} 12506Rating.register();return __exports;});; 12507 12508/* /im_livechat/static/src/core/common/chat_bubble_patch.js */ 12509odoo.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;} 12510return super.showImStatus;},});return __exports;});; 12511 12512/* /im_livechat/static/src/core/common/chat_window_model_patch.js */ 12513odoo.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);} 12514if(options.force){this.livechatStep=CW_LIVECHAT_STEP.NONE;return super.close(...arguments);} 12515const 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;} 12516if(!this.thread.hasSelfAsMember){super.close(...arguments);break;} 12517if(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);} 12518break;} 12519this.actionsDisabled=true;this.livechatStep=CW_LIVECHAT_STEP.CONFIRM_CLOSE;if(!isSelfVisitor&&this.thread.channel_member_ids.length>2){super.close(...arguments);break;} 12520if(!this.hubAsOpened){this.open({focus:true});} 12521break;} 12522case 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);} 12523break;} 12524case CW_LIVECHAT_STEP.FEEDBACK:{this.livechatStep=CW_LIVECHAT_STEP.NONE;super.close(...arguments);break;}}},};patch(ChatWindow.prototype,chatWindowPatch);return __exports;});; 12525 12526/* /im_livechat/static/src/core/common/chat_window_patch.js */ 12527odoo.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;});; 12528 12529/* /im_livechat/static/src/core/common/chatbot_model.js */ 12530odoo.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);},});
12530async start(){if(this.completed){return;} 12531if(this.thread.isLastMessageFromCustomer){await this.processAnswer(this.thread.newestPersistentOfAllMessage);} 12532if(!this.currentStep?.expectAnswer||this.currentStep?.completed){this._runUntilUserInputStep();}} 12533stop(){clearTimeout(this.nextStepTimeout);} 12534async restart(){if(!this.completed){return;} 12535const{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;}} 12536async processAnswer(message){if(this.forwarded||this.thread.notEq(message.thread)||!this.currentStep?.expectAnswer){return;} 12537if(this.currentStep.step_type==="free_input_multi"){await this._processAnswerDebounced(message);}else{await this._processAnswer(message);} 12538this.isProcessingAnswer=false;} 12539async _triggerNextStep(){if(this.currentStep){await this._simulateTyping();} 12540await this._goToNextStep();if(!this.currentStep||this.currentStep.completed||!this.thread){return;} 12541if(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,});} 12542if(this.currentStep.message){this.thread.messages.add(this.currentStep.message);}} 12543get completed(){return(this.currentStep?.isLast||this.currentStep?.operatorFound||this.thread.livechat_end_dt);} 12544get canRestart(){return this.currentStep?.isLast&&!this.currentStep.operatorFound;} 12545async _goToNextStep(){if(!this.thread){return;} 12546if(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;} 12547this.steps.push(dataRequest.chatbot_step);}else{const nextStepIndex=this.steps.lastIndexOf(this.currentStep)+1;this.currentStep=this.steps[nextStepIndex];this.currentStep.selectedAnswer=null;this.currentStep.completed=false;}} 12548async _runUntilUserInputStep(){await this._triggerNextStep();if(!this.currentStep||this.completed||(this.currentStep.expectAnswer&&!this.currentStep.completed)){return;} 12549this.nextStepTimeout=browser.setTimeout(async()=>this._runUntilUserInputStep(),Chatbot.TYPING_DELAY);} 12550async _simulateTyping(duration=Chatbot.MESSAGE_DELAY){this.isTyping=true;await new Promise((res)=>setTimeout(()=>{this.isTyping=false;res();},duration));} 12551async _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);} 12552this.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);} 12553this.currentStep.completed=stepCompleted;if(this.currentStep.completed){await this._runUntilUserInputStep();}} 12554async _delayThenProcessAnswerAgain(message){this.tmpAnswer=this.thread.composer.composerText;await Promise.resolve();return this._processAnswerDebounced(message);} 12555async _processAnswerQuestionSelection(message){const answer=this.currentStep.selectedAnswer;if(!answer?.redirect_link){return true;} 12556let 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;} 12557const 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();} 12558return redirectionAlreadyDone||!isRedirecting;} 12559async _processAnswerQuestionEmail(){const{success,data}=await rpc("/chatbot/step/validate_email",{channel_id:this.thread.id,});this.store.insert(data);return success;}} 12560Chatbot.register();return __exports;});; 12561 12562/* /im_livechat/static/src/core/common/chatbot_script_model.js */ 12563odoo.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");} 12564ChatbotScript.register();return __exports;});; 12565 12566/* /im_livechat/static/src/core/common/chatbot_script_step_answer_model.js */ 12567odoo.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;} 12568ChatbotScriptStepAnswer.register();return __exports;});; 12569 12570/* /im_livechat/static/src/core/common/chatbot_script_step_model.js */ 12571odoo.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");} 12572ChatbotScriptStep.register();return __exports;});; 12573 12574/* /im_livechat/static/src/core/common/chatbot_step_model.js */ 12575odoo.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);} 12576get 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"";}}} 12577ChatbotStep.register();return __exports;});; 12578 12579/* /im_livechat/static/src/core/common/close_confirmation.js */ 12580odoo.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"});} 12581onKeydown(ev){if(ev.key==="Escape"){this.props.onCloseConfirmationDialog();}else if(ev.key==="Enter"){this.props.onClickLeaveConversation();}}} 12582return __exports;});; 12583 12584/* /im_livechat/static/src/core/common/data_response_model_patch.js */ 12585odoo.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;});; 12586 12587/* /im_livechat/static/src/core/common/expirable_storage.js */ 12588odoo.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);}}}} 12589const 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;} 12590return null;},setItem(key,value,ttl){let expires;if(ttl){expires=Date.now()+ttl*1000;} 12591browser.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;});; 12592 12593/* /im_livechat/static/src/core/common/livechat_channel_model.js */ 12594odoo.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;
12594name;} 12595LivechatChannel.register();return __exports;});; 12596 12597/* /im_livechat/static/src/core/common/livechat_channel_rule_model.js */ 12598odoo.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;} 12599LivechatChannelRule.register();return __exports;});; 12600 12601/* /im_livechat/static/src/core/common/livechat_command_dialog.js */ 12602odoo.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();} 12603onKeydown(ev){if(ev.key==="Enter"&&this.state.inputText.trim().length>0){this.executeCommand();}} 12604executeCommand(){const command=commandRegistry.get(this.props.commandName,false);if(command){this.props.thread.executeCommand(command,`/${this.props.commandName} ${this.state.inputText}`);this.props.close();}}} 12605return __exports;});; 12606 12607/* /im_livechat/static/src/core/common/livechat_conversation_tag_model.js */ 12608odoo.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;} 12609LivechatConversationTag.register();return __exports;});; 12610 12611/* /im_livechat/static/src/core/common/livechat_expertise_model.js */ 12612odoo.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;} 12613LivechatExpertise.register();return __exports;});; 12614 12615/* /im_livechat/static/src/core/common/message_model_patch.js */ 12616odoo.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;});; 12617 12618/* /im_livechat/static/src/core/common/misc.js */ 12619odoo.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);} 12620return __exports;});; 12621 12622/* /im_livechat/static/src/core/common/res_partner_model_patch.js */ 12623odoo.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;});; 12624 12625/* /im_livechat/static/src/core/common/res_users_model_patch.js */ 12626odoo.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;});; 12627 12628/* /im_livechat/static/src/core/common/suggestion_service_patch.js */ 12629odoo.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
12629ortedDelimiters(...arguments);return thread?.channel_type==="livechat"&&!this.store.self_partner?res.filter((delimiter)=>delimiter.at(0)!=="@"):res;},});return __exports;});; 12630 12631/* /im_livechat/static/src/core/common/thread_actions_patch.js */ 12632odoo.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;} 12633return super._condition(...arguments);},});patch(threadActionsRegistry.get("invite-people"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12634return super.condition(...arguments);},});patch(threadActionsRegistry.get("notification-settings"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12635return super.condition(...arguments);},});patch(threadActionsRegistry.get("camera-call"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12636return super.condition(...arguments);},});patch(threadActionsRegistry.get("call"),{condition({thread}){if(thread?.channel_type==="livechat"){return super.condition(...arguments)&&!thread.livechat_end_dt;} 12637return super.condition(...arguments);},});return __exports;});; 12638 12639/* /im_livechat/static/src/core/common/thread_model_patch.js */ 12640odoo.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;} 12641const 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));} 12642return super.showCorrespondentCountry;}
12642,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;} 12643return super.getPersonaName(persona);},});return __exports;});; 12644 12645/* /im_livechat/static/src/core/common/thread_patch.js */ 12646odoo.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;} 12647clearTimeout(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;} 12648return()=>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");} 12649const 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),});} 12650if(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),});} 12651return _t("Visitor is disconnected");},});return __exports;});; 12652 12653/* /im_livechat/static/src/core/common/transcript_sender.js */ 12654odoo.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]);} 12655get isButtonDisabled(){return([this.STATUS.SENDING,this.STATUS.SENT].includes(this.state.status)||!this.isValidEmail(this.state.email));} 12656get 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));} 12657onKeydown(ev){if(ev.key=="Enter"&&!this.isButtonDisabled){this.onClickSend();}} 12658clear(){this.state.status=this.STATUS.IDLE;this.state.email="";} 12659async onClickSend(){this.state.status=this.STATUS.SENDING;
12659try{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;}}} 12660return __exports;});; 12661 12662/* /im_livechat/static/src/embed/common/attachment_model_patch.js */ 12663odoo.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;} 12664return super.isViewable;}});return __exports;});; 12665 12666/* /im_livechat/static/src/embed/common/attachment_upload_service_patch.js */ 12667odoo.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;} 12668thread.readyToSwapDeferred.resolve();composer=thread.composer;} 12669return super.upload(thread,composer,file,options);},});return __exports;});; 12670 12671/* /im_livechat/static/src/embed/common/autopopup_service.js */ 12672odoo.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);});} 12673get 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);}} 12674const 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;});; 12675 12676/* /im_livechat/static/src/embed/common/boot_helpers.js */ 12677odoo.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;} 12678const link=document.createElement("link");link.rel="preload";link.as="font";link.href=url;link.crossOrigin="";const style=document.createElement("style");style.appendChild(document.createTextNode(` 12679 @font-face { 12680 font-family: ${name}; 12681 src: url('${url}') format('woff2'); 12682 font-weight: normal; 12683 font-style: normal; 12684 font-display: block; 12685 } 12686 `));const loadPromise=new Promise((res,rej)=>{link.addEventListener("load",res);link.addEventListener("error",rej);});targetDocument.head.appendChild(link);targetDocument.head.appendChild(style);return loadPromise;} 12687function loadStyle(target){const link=document.createElement("link");link.rel="stylesheet";link.href=url("/im_livechat/assets_embed.css");
12687const stylesLoadedPromise=new Promise((res,rej)=>{link.addEventListener("load",res);link.addEventListener("error",rej);});target.appendChild(link);return stylesLoadedPromise;} 12688__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;} 12689__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),]);} 12690__exports.makeShadow=makeShadow;async function makeShadow(root){const shadow=root.attachShadow({mode:"open"});await loadAssets(shadow);return shadow;} 12691return __exports;});; 12692 12693/* /im_livechat/static/src/embed/common/chat_hub_patch.js */ 12694odoo.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;} 12695const 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;});; 12696 12697/* /im_livechat/static/src/embed/common/chat_window_model_patch.js */ 12698odoo.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;});; 12699 12700/* /im_livechat/static/src/embed/common/chat_window_patch.js */ 12701odoo.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;} 12702return thread.chatbot?.completed||thread.livechat_end_dt;},});return __exports;});; 12703 12704/* /im_livechat/static/src/embed/common/composer_patch.js */ 12705odoo.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;} 12706return _t("Say something...");},});return __exports;});; 12707 12708/* /im_livechat/static/src/embed/common/disabled_features.js */ 12709odoo.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;});; 12710 12711/* /im_livechat/static/src/embed/common/feedback_panel/feedback_panel.js */ 12712odoo.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;} 12713select(rating){this.state.rating=rating;} 12714get allowNewSession(){return(this.store.livechat_rule?.action!=="hide_button"&&this.livechatService.options.channel_id);} 12715get transcriptUrl(){return this.props.thread.transcriptUrl;} 12716onClickSendFeedback(){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");}}} 12717return __exports;});; 12718 12719/* /im_livechat/static/src/embed/common/history_service.js */ 12720odoo.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"];} 12721setup(){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;} 12722const 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,});});} 12723updateHistory(){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();} 12724expirableStorage.setItem(HistoryService.HISTORY_STORAGE_KEY,JSON.stringify(urlHistory),60*60*24);}}} 12725const 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;});; 12726 12727/* /im_livechat/static/src/embed/common/livechat_button.js */ 12728odoo.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]);} 12729onClick(){this.state.animateNotification=false;this.livechatService.open();}
12730get isShown(){return(this.store.livechat_available&&this.store.activeVisitorLivechats.length===0&&this.livechatService.options.channel_id);}} 12731return __exports;});; 12732 12733/* /im_livechat/static/src/embed/common/livechat_service.js */ 12734odoo.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( 12735 /:\/{0,2}/g, 12736 "_" 12737)}_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);} 12738setup(env,services){this.env=env;this.notificationService=services.notification;this.store=services["mail.store"];} 12739async 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);}} 12740async open(options={}){const thread=await this._createThread({persist:false,options});await thread?.openChatWindow({focus:true});return thread;} 12741async persist(thread){if(!thread.isTransient){return thread;} 12742if(this._persistDeferred){return this._persistDeferred;} 12743this._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;} 12744savedThread.fetchNewMessages();this.env.services["mail.store"].initialize();savedThread.readyToSwapDeferred.then(async()=>{if(!savedThread?.exists()){return;} 12745savedThread.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;}} 12746async leave(thread){await rpc("/im_livechat/visitor_leave_session",{channel_id:thread.id});} 12747async _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;} 12748this.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;} 12749getSessionExtraParams(thread,options){return{};} 12750get options(){return session.livechatData?.options??{};}} 12751const livechatService=__exports.livechatService={dependencies:["mail.store","notification"],start(env,services){const livechat=reactive(new LivechatService(env,services));if(canLoadLivechat()){livechat.initialize();} 12752return livechat;},};registry.category("services").add("im_livechat.livechat",livechatService);return __exports;});; 12753 12754/* /im_livechat/static/src/embed/common/mail_popout_service_patch.js */ 12755odoo.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);},};
12755patch(mailPopoutService,popoutPatch);return __exports;});; 12756 12757/* /im_livechat/static/src/embed/common/message_model_patch.js */ 12758odoo.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;} 12759return["channel-joined","channel-left"].includes(this.notificationType);},};patch(Message.prototype,messagePatch);return __exports;});; 12760 12761/* /im_livechat/static/src/embed/common/message_patch.js */ 12762odoo.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;} 12763this.props.message.disableChatbotAnswers=true;return this.props.message.thread.post(answer.name,{},{selected_answer_id:answer.id});},});return __exports;});; 12764 12765/* /im_livechat/static/src/embed/common/misc.js */ 12766odoo.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;} 12767return __exports;});; 12768 12769/* /im_livechat/static/src/embed/common/store_service_patch.js */ 12770odoo.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;} 12771expirableStorage.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;});; 12772 12773/* /im_livechat/static/src/embed/common/thread_actions.js */ 12774odoo.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});}
12774,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;});; 12775 12776/* /im_livechat/static/src/embed/common/thread_model_patch.js */ 12777odoo.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;} 12778await 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;} 12779return super.avatarUrl;},get displayName(){if(this.channel_type==="livechat"&&this.livechat_operator_id){return this.getPersonaName(this.livechat_operator_id);} 12780return 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;} 12781if(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);} 12782const 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;} 12783if(!thread){return;} 12784await thread.isLoadedDeferred;return thread.post(...arguments).then(()=>thread.readyToSwapDeferred.resolve());} 12785const 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;} 12786return(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;} 12787if(this.chatbot.completed){return _t("This livechat conversation has ended.");} 12788if(this.chatbot.currentStep?.step_type==="question_selection"&&!this.chatbot.currentStep.selectedAnswer){return _t("Select an option above");} 12789return _t("Say something");},});return __exports;});; 12790 12791/* /website/static/src/common/website_model.js */ 12792odoo.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;
12792name;} 12793Website.register();return __exports;});; 12794 12795/* /website/static/src/common/website_visitor_model.js */ 12796odoo.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");} 12797WebsiteVisitor.register();return __exports;});; 12798 12799/* /website_livechat/static/src/common/thread_model_patch.js */ 12800odoo.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;});; 12801 12802/* /ai/static/src/discuss/core/common/chat_window_model_patch.js */ 12803odoo.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";} 12804return super.computeCanShow();},async _onClose(){const thread=this.thread;if(thread?.ai_agent_id){await rpc("/ai/close_ai_chat",{channel_id:thread.id});} 12805await super._onClose(...arguments);},});return __exports;});; 12806 12807/* /ai/static/src/discuss/core/common/thread_model_patch.js */ 12808odoo.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;} 12809await 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;}}} 12810return message;},});return __exports;});; 12811 12812/* /ai/static/src/discuss/core/common/view_details.js */ 12813odoo.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?");});} 12814__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.");} 12815useBus(bus,"REQUEST_VIEW_DETAILS?",async()=>{bus.trigger("SEND_VIEW_DETAILS!",await getter());});} 12816return __exports;});; 12817 12818/* /im_livechat/static/src/embed/external/boot.js */ 12819odoo.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;} 12820session.origin=session.livechatData.serverUrl;await whenReady();if(session.test_mode){await loadBundle("im_livechat.assets_livechat_support_tours");} 12821const 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;});; 12822 12823/* /im_livechat/static/src/embed/external/bus_parameters_service_patch.js */ 12824odoo.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;});; 12825 12826/* /im_livechat/static/src/embed/external/emoji_loader_patch.js */ 12827odoo.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;}); 12828 12829 /******************************************* 12830 * Templates * 12831 *******************************************/ 12832 12833 odoo.define("im_livechat.assets_embed_external.bundle.xml", ["@web/core/templates"], function(require) { 12834 "use strict"; 12835 const { checkPrimaryTemplateParents, registerTemplate, registerTemplateExtension } = require("@web/core/templates"); 12836 /* im_livechat.assets_embed_external */ 12837 registerTemplate("web.ActionSwiper", `/web/static/src/core/action_swiper/action_swiper.xml`, `<t t-name="web.ActionSwiper" xml:space="preserve"> 12838 <t t-if="props.onRightSwipe || props.onLeftSwipe"> 12839 <div class="o_actionswiper" t-on-touchend="_onTouchEndSwipe" t-on-touchmove="_onTouchMoveSwipe" t-on-touchstart="_onTouchStartSwipe" t-ref="root"> 12840 <div class="o_actionswiper_overflow_container position-relative overflow-hidden"> 12841 <div class="o_actionswiper_target_container" t-ref="targetContainer" t-att-style="state.containerStyle" t-att-class="{ o_actionswiper_swiping: state.isSwiping }"> 12842 <t t-slot="default"/> 12843 <t t-if="localizedProps.onRightSwipe and (localizedProps.onRightSwipe.icon or localizedProps.onRightSwipe.bgColor)"> 12844 <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">
12845 <span><i class="fa fa-2x" t-att-class="localizedProps.onRightSwipe.icon"/></span> 12846 </div> 12847 </t> 12848 <t t-if="localizedProps.onLeftSwipe and (localizedProps.onLeftSwipe.icon or localizedProps.onLeftSwipe.bgColor)"> 12849 <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"> 12850 <span><i class="fa fa-2x" t-att-class="localizedProps.onLeftSwipe.icon"/></span> 12851 </div> 12852 </t> 12853 </div> 12854 </div> 12855 </div> 12856 </t> 12857 <t t-else=""> 12858 <t t-slot="default"/> 12859 </t> 12860 </t> 12861`); 12862registerTemplate("web.AutoComplete", `/web/static/src/core/autocomplete/autocomplete.xml`, `<t t-name="web.AutoComplete" xml:space="preserve"> 12863 <div class="o-autocomplete" t-ref="root" t-att-class="autoCompleteRootClass"> 12864 <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"/> 12865 <t t-if="displayOptions"> 12866 <ul role="menu" class="o-autocomplete--dropdown-menu ui-widget show" t-att-class="ulDropdownClass" t-ref="sourcesList"> 12867 <t t-foreach="sources" t-as="source" t-key="source.id"> 12868 <t t-if="source.isLoading"> 12869 <li class="ui-menu-item" t-att-class="{ 'o-autocomplete--dropdown-item': props.dropdown, 'd-block': !props.dropdown }"> 12870 <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"> 12871 <i class="fa fa-spin fa-circle-o-notch"/>
12871 <t t-esc="source.placeholder"/> 12872 </a> 12873 </li> 12874 </t> 12875 <t t-else=""> 12876 <t t-foreach="source.options" t-as="option" t-key="option.id"> 12877 <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)"> 12878 <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'"> 12879 <t t-slot="{{ source.optionSlot }}" label="option.label" data="option.data"> 12880 <t t-if="!option.labelTermOrder" t-out="option.label"/> 12881 <t t-else=""> 12882 <t t-foreach="option.labelTermOrder.labelBits" t-as="bit" t-key="bit.id"> 12883 <t t-if="!option.labelTermOrder.searchTermIndexes.includes(bit.id)" t-esc="bit.bit"/> 12884 <mark t-else="" class="o-autocomplete--mark" t-esc="bit.bit"/> 12885 </t> 12886 </t> 12887 </t> 12888 </t> 12889 </li> 12890 </t> 12891 </t> 12892 </t> 12893 </ul> 12894 </t> 12895 </div> 12896 </t> 12897 12898`); 12899registerTemplate("web.BarcodeDialog", `/web/static/src/core/barcode/barcode_dialog.xml`, `<t t-name="web.BarcodeDialog" xml:space="preserve"> 12900 <Dialog title.translate="Barcode Scanner" fullscreen="true" footer="false" contentClass="'o-barcode-modal'"> 12901 <BarcodeVideoScanner t-if="state.barcodeScannerSupported" t-props="props" onError.bind="onError" onResult.bind="onResult"/> 12902 <div t-else="" t-ref="videoPreview" class="h-100 d-flex flex-column justify-content-center align-items-center gap-1"> 12903 <i class="fa fa-2x fa-camera text-muted"/> 12904 <strong>Unable to access camera</strong> 12905 <span class="text-muted" t-out="state.errorMessage"/> 12906 </div> 12907 </Dialog> 12908 </t> 12909`); 12910registerTemplate("web.BarcodeVideoScanner", `/web/static/src/core/barcode/barcode_video_scanner.xml`, `<t t-name="web.BarcodeVideoScanner" xml:space="preserve"> 12911 <CropOverlay onResize.bind="this.onResize" isReady="state.isReady"> 12912 <video t-ref="videoPreview" muted="true" autoplay="true" playsinline="true" t-att-class="props.cssClass"/> 12913 </CropOverlay> 12914 </t> 12915`); 12916registerTemplate("web.CropOverlay", `/web/static/src/core/barcode/crop_overlay.xml`, `<t t-name="web.CropOverlay" xml:space="preserve"> 12917 <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"> 12918 <t t-slot="default"/> 12919 <t t-if="props.isReady"> 12920 <div class="o_crop_overlay" t-att-class="{'o_crop_overlay_ios': isIOS}"/> 12921 <img class="o_crop_icon" src="/web/static/img/transform.svg" draggable="false"/> 12922 </t> 12923 </div> 12924 </t> 12925`); 12926registerTemplate("web.BottomSheet", `/web/static/src/core/bottom_sheet/bottom_sheet.xml`, `<t t-name="web.BottomSheet" xml:space="preserve"> 12927 <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"> 12928 12929 <div class="o_bottom_sheet_rail" t-att-class="{ o_bottom_sheet_rail_prevent_overscroll : props.preventDism
12929issOnContentScroll }" t-ref="scrollRail"> 12930 12931 <div class="o_bottom_sheet_backdrop" t-on-click="slideOut"/> 12932 12933 12934 <div class="o_bottom_sheet_dismiss"/> 12935 12936 12937 <div class="o_bottom_sheet_spacer"/> 12938 12939 12940 <div class="o_bottom_sheet_sheet offcanvas position-relative overflow-hidden" role="dialog" t-ref="sheet"> 12941 12942 12943 <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"> 12944 <div class="o_bottom_sheet_handle_bar pt-1 mx-auto rounded-pill d-inline-block px-5 bg-dark"/> 12945 </div> 12946 12947 12948 <div class="o_bottom_sheet_body offcanvas-body" role="menu" t-att-class="props.class" t-ref="ref"> 12949 12950 12951 <t t-if="props.component"> 12952 <t t-component="props.component" t-props="props.componentProps || {}"/> 12953 </t> 12954 12955 12956 <t t-else=""> 12957 <t t-slot="default" close="close" back="back"/> 12958 </t> 12959 </div> 12960 </div> 12961 </div> 12962 </div> 12963 </t> 12964`); 12965registerTemplate("web.CheckBox", `/web/static/src/core/checkbox/checkbox.xml`, `<t t-name="web.CheckBox" xml:space="preserve"> 12966 <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"> 12967 <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"/> 12968 <label t-att-for="props.id or id" class="form-check-label"> 12969 <t t-slot="default"/> 12970 </label> 12971 </div> 12972</t> 12973 12974`); 12975registerTemplate("web.CodeEditor", `/web/static/src/core/code_editor/code_editor.xml`, `<t t-name="web.CodeEditor" xml:space="preserve"> 12976 <div t-ref="editorRef" class="w-100" t-att-class="props.class" t-att-data-mode="state.activeMode"/> 12977 </t> 12978 12979`); 12980registerTemplate("web.ColorPicker", `/web/static/src/core/color_picker/color_picker.xml`, `<t t-name="web.ColorPicker" xml:space="preserve"> 12981 <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"> 12982 <div class="px-1 mb-1 pt-2 d-flex"> 12983 <t t-foreach="this.tabs" t-as="tab" t-key="tab.id"> 12984 <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)"> 12985 <t t-out="tab.name"/> 12986 </button> 12987 </t> 12988 <div class="flex-grow-1"/>
12989 <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"/> 12990 </div> 12991 <t t-set="activeTab" t-value="this.tabs.find((tab) => state.activeTab === tab.id)"/> 12992 <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, }"/> 12993 </div> 12994</t> 12995 12996`); 12997registerTemplate("web.CustomColorPicker", `/web/static/src/core/color_picker/custom_color_picker/custom_color_picker.xml`, `<t t-name="web.CustomColorPicker" xml:space="preserve"> 12998 <div class="o_colorpicker_widget" t-ref="el" t-on-click="onClick" t-on-keydown="onKeydown"> 12999 <div class="d-flex justify-content-between align-items-stretch mb-2"> 13000 <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"> 13001 <div t-ref="colorPickerPointer" id="picker_pointer" class="o_picker_pointer rounded-circle p-1 position-absolute" tabindex="0" t-on-keydown="onPickerKeydown"/> 13002 </div> 13003 <div t-ref="colorSlider" class="o_color_slider position-relative" t-on-pointerdown="onPointerDownSlider"> 13004 <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"/> 13005 </div> 13006 <div t-ref="opacitySlider" class="o_opacity_slider position-relative" t-if="!props.noTransparency" t-on-pointerdown="onPointerDownOpacitySlider"> 13007 <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"/> 13008 </div> 13009 </div> 13010 <div class="o_color_picker_inputs d-flex justify-content-between mb-2" t-on-change="debouncedOnChangeInputs"> 13011 <t t-set="input_classes" t-value="'p-0 border-0 text-center font-monospace bg-transparent'"/> 13012 13013 <div class="o_hex_div d-flex align-items-baseline me-1"> 13014 <input type="text" t-attf-class="o_hex_input {{input_classes}}
13014" data-color-method="hex" size="1" t-on-input="onHexColorInput"/> 13015 <label class="flex-grow-0 ms-1 mb-0">hex</label> 13016 </div> 13017 </div> 13018 </div> 13019</t> 13020 13021`); 13022registerTemplate("web.ColorPickerCustomTab", `/web/static/src/core/color_picker/tabs/color_picker_custom_tab.xml`, `<t t-name="web.ColorPickerCustomTab" xml:space="preserve"> 13023 <div class="d-flex flex-column align-items-start p-2 pb-0" t-on-keydown="props.colorPickerNavigation"> 13024 <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"> 13025 <t t-foreach="usedCustomColors" t-as="color" t-key="color_index"> 13026 <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}}"/> 13027 </t> 13028 <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"/> 13029 <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"/> 13030 </div> 13031 <t t-foreach="Object.values(props.grayscales)" t-as="grayscaleColors" t-key="grayscaleColors"> 13032 <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"> 13033 <t t-foreach="grayscaleColors" t-as="color" t-key="color"> 13034 <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}})"/> 13035 </t> 13036 </div> 13037 </t> 13038 <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"/> 13039 </div> 13040</t> 13041`); 13042registerTemplate("web.ColorPickerSolidTab", `/web/static/src/core/color_picker/tabs/color_picker_solid_tab.xml`, `<t t-name="web.ColorPickerSolidTab" xml:space="preserve"> 13043 <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"> 13044 <div class="o_colorpicker_section"> 13045 <t t-foreach="props.defaultThemeColorVars" t-as="color" t-key="color"> 13046 <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"/> 13047 </t> 13048 </div> 13049 13050 <div class="o_color_section"> 13051 <t t-foreach="props.defaultColors" t-as="line" t-key="line_index"> 13052 <t t-foreach="line" t-as="color" t-key="color_index"> 13053 <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}}"/> 13054 </t> 13055 </t> 13056 </div> 13057 </div> 13058</t> 13059`); 13060registerTemplate("web.ColorList", `/web/static/src/core/colorlist/colorlist.xml`, `<t t-name="web.ColorList" xml:space="preserve"> 13061 <div class="o_colorlist d-grid gap-3 gap-md-2" aria-atomic="true" t-ref="colorlist"> 13062 <t t-if="!props.forceExpanded and !state.isExpanded"> 13063 <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 }}"/> 13064 </t> 13065 <t t-else="" t-foreach="props.colors" t-as="colorId" t-key="colorId"> 13066 <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' : '' }}"/> 13067 </t> 13068 </div> 13069 </t> 13070 13071`); 13072registerTemplate("web.DefaultFooter", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.DefaultFooter" owl="1" xml:space="preserve"> 13073 <span>
13074 <span class="fw-bolder text-primary">TIP</span> â search for 13075 <t t-foreach="elements" t-as="element" t-key="element.namespace"> 13076 <t t-if="!(element_first || element_last)">, </t> 13077 <t t-if="element_last and !element_first"> and </t> 13078 <span class="o_namespace btn-link text-primary cursor-pointer" t-on-click="() => this.onClick(element.namespace)"> 13079 <span t-out="element.namespace" class="fw-bolder text-primary"/><t t-out="element.name"/> 13080 </span> 13081 </t> 13082 </span> 13083 </t> 13084 13085 `); 13086registerTemplate("web.DefaultCommandItem", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.DefaultCommandItem" xml:space="preserve"> 13087 <div class="o_command_default d-flex align-items-center justify-content-between px-4 py-2 cursor-pointer"> 13088 <t t-slot="name"/> 13089 <t t-slot="focusMessage"/> 13090 </div> 13091 </t> 13092 13093 `); 13094registerTemplate("web.HotkeyCommandItem", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.HotkeyCommandItem" xml:space="preserve"> 13095 <div class="o_command_hotkey d-flex align-items-center justify-content-between px-4 py-2 cursor-pointer"> 13096 <t t-slot="name"/> 13097 <span> 13098 <t t-foreach="getKeysToPress(props)" t-as="key" t-key="key_index"> 13099 <kbd t-out="key" class="d-inline-block px-3 py-1"/> 13100 <span t-if="!key_last"> + </span> 13101 </t> 13102 </span> 13103 </div> 13104 </t> 13105 13106`); 13107registerTemplate("web.CommandPalette", `/web/static/src/core/commands/command_palette.xml`, `<t t-name="web.CommandPalette" xml:space="preserve"> 13108 <Dialog header="false" footer="false" size="'md'" contentClass="'o_command_palette'"> 13109 <div t-ref="root"> 13110 <div class="o_command_palette_search input-group mb-2 px-4 py-3 border-bottom"> 13111 <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"/> 13112 <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"/> 13113 <div class="input-group-text border-0 bg-transparent"> 13114 <i t-if="state.isLoading" title="Loading..." role="img" aria-label="Loading..." class="fa fa-circle-o-notch fa-spin"/> 13115 <i t-else="" t-att-title="state.placeholder" role="img" t-att-aria-label="state.placeholder" class="oi oi-search"/> 13116 </div> 13117 </div> 13118 13119 <div t-ref="listbox" role="listbox" class="o_command_palette_listbox position-relative overflow-auto"> 13120 <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"/> 13121 <t t-if="!isFuzzySearch" t-foreach="commandsByCategory" t-as="category" t-key="category.keyId"> 13122 <div class="o_command_category px-0"> 13123 <span t-if="category.name" class="text-uppercase fw-bold px-3 text-muted smaller opacity-50" t-out="category.name"/> 13124 <t t-foreach="category.commands" t-as="command" t-key="command.keyId"> 13125 <t t-set="commandIndex" t-value="state.commands.indexOf(command)"/> 13126 <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()"> 13127 <a t-att-href="command.href" t-att-class="command.className"> 13128 <t t-component="command.Component || DefaultCommandItem" name="command.name" searchValue="state.searchValue" t-props="command.props" executeCommand="() => this.executeCommand(command)"> 13129 <t t-set-slot="name">
13130 <span class="o_command_name text-ellipsis" t-att-title="command.name" t-out="command.text"/> 13131 </t> 13132 <t t-set-slot="focusMessage"> 13133 <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> 13134 </t> 13135 </t> 13136 </a> 13137 </div> 13138 </t> 13139 </div> 13140 13141 <hr class="my-2 mx-0" t-if="!category_last"/> 13142 </t> 13143 </div> 13144 13145 <div t-if="state.FooterComponent" class="o_command_palette_footer mt-2 px-4 py-2 border-top rounded-bottom bg-100 text-muted"> 13146 <t t-component="state.FooterComponent" switchNamespace="(namespace) => this.debounceSearch(namespace.concat(this.state.searchValue))"/> 13147 </div> 13148 </div> 13149 </Dialog> 13150 </t> 13151 13152`); 13153registerTemplate("web.ConfirmationDialog", `/web/static/src/core/confirmation_dialog/confirmation_dialog.xml`, `<t t-name="web.ConfirmationDialog" xml:space="preserve"> 13154 <Dialog size="'md'" title="props.title" modalRef="modalRef"> 13155 <p t-out="props.body" class="text-prewrap"/> 13156 <t t-set-slot="footer"> 13157 <button class="btn" t-att-class="props.confirmClass" t-on-click="_confirm" t-esc="props.confirmLabel" data-hotkey="q"/> 13158 <button t-if="props.cancel" class="btn btn-secondary" t-on-click="_cancel" t-esc="props.cancelLabel" data-hotkey="x"/> 13159 </t> 13160 </Dialog> 13161 </t> 13162 13163 `); 13164registerTemplate("web.AlertDialog", `/web/static/src/core/confirmation_dialog/confirmation_dialog.xml`, `<t t-name="web.AlertDialog" xml:space="preserve"> 13165 <Dialog size="'sm'" title="props.title" contentClass="props.contentClass"> 13166 <p t-out="props.body" class="text-prewrap"/> 13167 <t t-set-slot="footer"> 13168 <button class="btn" t-att-class="props.confirmClass" t-on-click="_confirm" t-esc="props.confirmLabel"/> 13169 <button t-if="props.cancel" class="btn btn-secondary" t-on-click="_cancel" t-esc="props.cancelLabel"/> 13170 </t> 13171 </Dialog> 13172 </t> 13173 13174`); 13175registerTemplate("web.CopyButton", `/web/static/src/core/copy_button/copy_button.xml`, `<t t-name="web.CopyButton" xml:space="preserve"> 13176 <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"> 13177 <span class="mx-1" t-attf-class="fa {{ props.icon || 'fa-clipboard' }}"/> 13178 <span t-if="props.copyText" t-esc="props.copyText"/> 13179 </button> 13180 </t> 13181 13182`); 13183registerTemplate("web.DateTimeInput", `/web/static/src/core/datetime/datetime_input.xml`, `<t t-name="web.DateTimeInput" xml:space="preserve"> 13184 <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"/> 13185 </t> 13186`); 13187registerTemplate("web.DateTimePicker.Days", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Days" xml:space="preserve"> 13188 <div class="d-flex gap-3"> 13189 <t t-foreach="items" t-as="month" t-key="month.id"> 13190 <div class="o_date_picker d-grid flex-grow-1 rounded overflow-auto" t-on-pointerleave="() => (state.hoveredDate = null)"> 13191 <t t-foreach="month.daysOfWeek" t-as="dayOfWeek" t-key="dayOfWeek[0]"> 13192 <div class="o_day_of_week_cell fw-bolder d-flex align-items-center justify-content-center" t-att-title="dayOfWeek[1]"> 13193 <div class="text-nowrap overflow-hidden" t-esc="props.daysOfWeekFormat === 'narrow' ? dayOfWeek[2] : dayOfWeek[0]"/> 13194 </div> 13195 </t> 13196 <t t-foreach="month.weeks" t-as="week" t-key="week.number"> 13197 <t t-if="props.showWeekNumbers"> 13198 <div class="o_week_number_cell d-flex justify-content-end align-items-center pe-3 fw-bolder" t-esc="week.number"/> 13199 </t> 13200 <t t-foreach="week.days" t-as="itemInfo" t-key="itemInfo.id"> 13201 <t t-set="arInfo" t-value="getActiveRangeInfo(itemInfo)"/> 13202 <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, }
13202" t-att-disabled="!itemInfo.isValid" t-on-pointerenter="() => (state.hoveredDate = itemInfo.range[0])" t-on-click="() => this.zoomOrSelect(itemInfo)"> 13203 <div t-att-class="{'w-75 align-content-center text-center rounded-circle': itemInfo.includesToday}"> 13204 <t t-esc="itemInfo.label"/> 13205 </div> 13206 </div> 13207 </t> 13208 </t> 13209 </div> 13210 </t> 13211 </div> 13212 <div t-if="props.type === 'datetime'" class="d-flex gap-3 justify-content-between"> 13213 <div class="d-flex gap-1 align-items-center"> 13214 <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'"/> 13215 <i t-if="state.timeValues[0] and state.timeValues[1]" class="fa fa-long-arrow-right"/> 13216 <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'"/> 13217 </div> 13218 <t t-slot="buttons"/> 13219 </div> 13220 </t> 13221 13222 `); 13223registerTemplate("web.DateTimePicker.Grid", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Grid" xml:space="preserve"> 13224 <div class="o_date_item_picker d-grid"> 13225 <t t-foreach="items" t-as="itemInfo" t-key="itemInfo.id"> 13226 <t t-set="arInfo" t-value="getActiveRangeInfo(itemInfo)"/> 13227 <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)"> 13228 <t t-esc="itemInfo.label"/> 13229 </div> 13230 </t> 13231 </div> 13232 </t> 13233 13234 `); 13235registerTemplate("web.DateTimePicker", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker" xml:space="preserve"> 13236 <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 }}"> 13237 <nav class="o_datetime_picker_header d-flex"> 13238 <button class="o_previous btn btn-sm opacity-75 opacity-100-hover" t-on-click="previous" tabindex="-1"> 13239 <i class="oi oi-chevron-left" t-att-title="activePrecisionLevel.prevTitle"/> 13240 </button> 13241 <button class="o_next btn btn-sm opacity-75 opacity-100-hover" t-on-click="next" tabindex="-1"> 13242 <i class="oi oi-chevron-right" t-att-title="activePrecisionLevel.nextTitle"/> 13243 </button> 13244 <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"> 13245 <t t-foreach="titles" t-as="title" t-key="title"> 13246 <strong class="o_header_part" t-esc="title"/> 13247 </t> 13248 </button> 13249 <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}"> 13250 <i class="fa fa-calendar-plus-o"/> 13251 </button> 13252 </nav> 13253 <t t-if="state.precision === 'days'"> 13254 <t t-call="web.DateTimePicker.Days"/> 13255 </t> 13256 <t t-else=""> 13257 <t t-call="web.DateTimePicker.Grid"/> 13258 </t> 13259 </div> 13260 </t> 13261`); 13262registerTemplate("web.DateTimePickerPopover", `/web/static/src/core/datetime/datetime_picker_popover.xml`, `<t t-name="web.DateTimePickerPopover" xml:space="preserve">
13263 <DateTimePicker t-props="props.pickerProps"> 13264 <t t-set-slot="buttons"> 13265 <div class="o_datetime_buttons d-flex gap-2"> 13266 <button class="btn btn-sm btn-secondary" title="Clear" tabindex="-1" t-on-click="props.pickerProps.onReset"> 13267 <i class="fa fa-eraser"/> 13268 </button> 13269 <button class="btn btn-sm btn-primary" tabindex="-1" t-on-click="props.close"> 13270 <span>Apply</span> 13271 </button> 13272 </div> 13273 </t> 13274 </DateTimePicker> 13275 </t> 13276`); 13277registerTemplate("web.DebugMenu", `/web/static/src/core/debug/debug_menu.xml`, `<t t-name="web.DebugMenu" xml:space="preserve"> 13278 <div class="o_debug_manager"> 13279 <Dropdown beforeOpen.bind="loadGroupedItems" position="'bottom-end'"> 13280 <button t-att-class="\`o-dropdown--narrow \${env.inDialog?'btn btn-link':''}\`"> 13281 <i class="fa fa-bug" role="img" aria-label="Open developer tools"/> 13282 </button> 13283 <t t-set-slot="content"> 13284 <t t-foreach="sectionEntries" t-as="entry" t-key="entry[0]"> 13285 <div class="dropdown-menu_group dropdown-header"> 13286 <t t-esc="getSectionLabel(entry[0])"/> 13287 </div> 13288 <t t-foreach="entry[1]" t-as="element" t-key="element_index"> 13289 <DropdownItem t-if="element.type == 'item'" onSelected="element.callback" attrs="{ href: element.href }"> 13290 <span t-att-class="entry[0] and 'ps-3'" t-esc="element.description"/> 13291 </DropdownItem> 13292 <t t-if="element.type == 'component'" t-component="element.Component" t-props="element.props"/> 13293 </t> 13294 </t> 13295 </t> 13296 </Dropdown> 13297 </div> 13298 </t> 13299 13300`); 13301registerTemplate("web.DebugMenu.SetDefaultDialog", `/web/static/src/core/debug/debug_menu_items.xml`, `<t t-name="web.DebugMenu.SetDefaultDialog" xml:space="preserve"> 13302 <Dialog title.translate="Set Default Values"> 13303 <table style="width: 100%"> 13304 <tr> 13305 <td> 13306 <label for="formview_default_fields" class="oe_label oe_align_right"> 13307 Default: 13308 </label> 13309 </td> 13310 <td class="oe_form_required"> 13311 <select id="formview_default_fields" class="o_input" t-model="state.fieldToSet"> 13312 <option value=""/> 13313 <option t-foreach="defaultFields" t-as="field" t-att-value="field.name" t-key="field.name"> 13314 <t t-esc="field.string"/> = <t t-esc="field.displayed"/> 13315 </option> 13316 </select> 13317 </td> 13318 </tr> 13319 <tr t-if="conditions.length"> 13320 <td> 13321 <label for="formview_default_conditions" class="oe_label oe_align_right"> 13322 Condition: 13323 </label> 13324 </td> 13325 <td> 13326 <select id="formview_default_conditions" class="o_input" t-model="state.condition"> 13327 <option value=""/> 13328 <option t-foreach="conditions" t-as="cond" t-att-value="cond.name + '=' + cond.value" t-key="cond.name"> 13329 <t t-esc="cond.string"/>=<t t-esc="cond.displayed"/> 13330 </option> 13331 </select> 13332 </td> 13333 </tr> 13334 <tr> 13335 <td colspan="2"> 13336 <input type="radio" id="formview_default_self" value="self" name="scope" t-model="state.scope"/> 13337 <label for="formview_default_self" class="oe_label" style="display: inline;"> 13338 Only you 13339 </label> 13340 <br/> 13341 <input type="radio" id="formview_default_all" value="all" name="scope" t-model="state.scope"/> 13342 <label for="formview_default_all" class="oe_label" style="display: inline;"> 13343 All users 13344 </label> 13345 </td> 13346 </tr> 13347 </table> 13348 <t t-set-slot="footer"> 13349 <button class="btn btn-secondary" t-on-click="props.close">Close</button> 13350 <button class="btn btn-secondary" t-on-click="saveDefault">Save default</button> 13351 </t> 13352 </Dialog> 13353 </t> 13354 13355 `); 13356registerTemplate("web.DebugMenu.GetMetadataDialog", `/web/static/src/core/debug/debug_menu_items.xml`, `<t t-name="web.DebugMenu.GetMetadataDialog" xml:space="preserve"> 13357 <Dialog title.translate="Metadata"> 13358 <table class="table table-sm table-striped"> 13359 <tr> 13360 <th>ID:</th> 13361 <td><t t-esc="state.id"/></td> 13362 </tr> 13363 <tr> 13364 <th>XML ID:</th> 13365 <td> 13366 <t t-if="state.xmlids.length > 1"> 13367 <t t-foreach="state.xmlids" t-as="imd" t-key="imd['xmlid']"> 13368 <div t-att-class=""p-0 " + (imd["xmlid"] === state.xmlid ? "fw-bolder " : "") + (imd["noupdate"] === true ? "fst-italic " : "")" t-esc="imd['xmlid']"/> 13369 </t> 13370 </t> 13371 <t t-elif="state.xmlid" t-esc="state.xmlid"/> 13372 <t t-else=""> 13373 / <a t-on-click="onClickCreateXmlid"> (create)</a> 13374 </t> 13375 </td> 13376 </tr> 13377 <tr> 13378 <th>No Update:</th> 13379 <td> 13380 <t t-esc="state.noupdate"/> 13381 <t t-if="state.xmlid"> 13382 <a t-on-click="toggleNoupdate"> (change)</a> 13383 </t> 13384 </td> 13385 </tr> 13386 <tr> 13387 <th>Creation User:</th> 13388 <td><t t-esc="state.creator"/></td> 13389 </tr> 13390 <tr> 13391 <th>Creation Date:</th> 13392 <td><t t-esc="state.createDate"/></td> 13393 </tr> 13394 <tr> 13395 <th>Latest Modification by:</th> 13396 <td><t t-esc="state.lastModifiedBy"/></td> 13397 </tr> 13398 <tr> 13399 <th>Latest Modification Date:</th> 13400 <td><t t-esc="state.writeDate"/></td> 13401 </tr> 13402 </table> 13403 </Dialog> 13404 </t> 13405 13406 `); 13407registerTemplate("web.DebugMenu.GetViewDialog", `/web/static/src/core/debug/debug_menu_items.xml`, `<t t-name="web.DebugMenu.GetViewDialog" xml:space="preserve"> 13408 <Dialog title.translate="Computed Arch"> 13409 <pre t-esc="props.arch"/> 13410 <t t-set-slot="footer"> 13411 <button class="btn btn-primary" t-on-click="() => props.close()">Close</button>
13412 <CopyButton className="'btn-secondary'" copyText.translate="Copy Arch" successText.translate="Copied" content="props.arch"/> 13413 </t> 13414 </Dialog> 13415 </t> 13416`); 13417registerTemplate("web.Dialog", `/web/static/src/core/dialog/dialog.xml`, `<t t-name="web.Dialog" xml:space="preserve"> 13418 <div class="o_dialog" t-att-id="id" t-att-class="{ o_inactive_modal: !data.isActive }"> 13419 <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"> 13420 <div class="modal-dialog modal-dialog-centered" t-attf-class="modal-{{props.size}}"> 13421 <div class="modal-content" t-att-class="props.contentClass" t-att-style="contentStyle"> 13422 <header t-if="props.header" class="modal-header"> 13423 <t t-slot="header" close="data.close" isFullscreen="isFullscreen"> 13424 <t t-call="web.Dialog.header"> 13425 <t t-set="fullscreen" t-value="isFullscreen"/> 13426 <t t-set="onExpand" t-value="props.onExpand"/> 13427 </t> 13428 </t> 13429 </header> 13430 <main class="modal-body" t-attf-class="{{ props.bodyClass }} {{ !props.withBodyPadding ? 'p-0': '' }}" t-att-tabindex="this.bodyTabIndex"> 13431 <t t-slot="default" close="() => this.data.close()"/> 13432 </main> 13433 <footer t-if="props.footer" class="modal-footer d-empty-none justify-content-around justify-content-md-start flex-wrap gap-1 w-100"> 13434 <t t-slot="footer" close="() => this.data.close()"/> 13435 </footer> 13436 </div> 13437 </div> 13438 </div> 13439 </div> 13440 </t> 13441 13442 `); 13443registerTemplate("web.Dialog.header", `/web/static/src/core/dialog/dialog.xml`, `<t t-name="web.Dialog.header" xml:space="preserve"> 13444 <t t-if="fullscreen"> 13445 <button class="btn oi oi-arrow-left" aria-label="Close" tabindex="-1" t-on-click="dismiss"/> 13446 </t> 13447 <h4 class="modal-title text-break flex-grow-1" t-att-class="{ 'me-auto': fullscreen }"> 13448 <t t-esc="props.title"/> 13449 </h4> 13450 <t t-if="onExpand"> 13451 <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"/> 13452 </t> 13453 <t t-if="!fullscreen"> 13454 <button type="button" class="btn-close" aria-label="Close" tabindex="-1" t-on-click="dismiss"/> 13455 </t> 13456 </t> 13457`); 13458registerTemplate("web.DomainSelector", `/web/static/src/core/domain_selector/domain_selector.xml`, `<t t-name="web.DomainSelector" xml:space="preserve"> 13459 <div class="o_domain_selector w-100" aria-atomic="true" t-att-class="props.className"> 13460 <t t-if="tree"> 13461 <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"> 13462 <CheckBox t-if="showArchivedCheckbox" value="includeArchived" disabled="props.readonly" className="'form-switch'" onChange.bind="toggleIncludeArchived"> 13463 Include archived 13464 </CheckBox> 13465 </TreeEditor> 13466 </t> 13467 <t t-else=""> 13468 <div class="o_domain_selector_row d-flex align-items-center"> 13469 This domain is not supported. 13470 <t t-if="!props.readonly"> 13471 <button class="btn btn-sm btn-primary ms-2" t-on-click="() => this.resetDomain()">Reset domain</button> 13472 </t> 13473 </div> 13474 </t> 13475 <t t-if="props.isDebugMode and (!tree or !props.readonly)"> 13476 <label class="o_domain_selector_debug_container d-block mt-3 border rounded p-3 bg-100 text-muted font-monospace">
13477 <span class="small"># Code editor</span> 13478 <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)"/> 13479 </label> 13480 </t> 13481 </div> 13482 </t> 13483 13484`); 13485registerTemplate("web.DomainSelectorDialog", `/web/static/src/core/domain_selector_dialog/domain_selector_dialog.xml`, `<t t-name="web.DomainSelectorDialog" xml:space="preserve"> 13486 <Dialog title="dialogTitle" size="'xl'"> 13487 <div t-if="props.text" class="mb-3" t-out="props.text"/> 13488 <DomainSelector t-props="domainSelectorProps"/> 13489 <t t-set-slot="footer"> 13490 <t t-if="props.readonly"> 13491 <button class="btn btn-secondary" t-on-click="() => props.close()">Close</button> 13492 </t> 13493 <t t-else=""> 13494 <button class="btn btn-primary" t-att-disabled="disabled" t-on-click="onConfirm" t-ref="confirm"><t t-esc="confirmButtonText"/></button> 13495 <button class="btn btn-secondary" t-on-click="onDiscard"><t t-esc="discardButtonText"/></button> 13496 </t> 13497 </t> 13498 </Dialog> 13499 </t> 13500 13501`); 13502registerTemplate("web.AccordionItem", `/web/static/src/core/dropdown/accordion_item.xml`, `<t t-name="web.AccordionItem" xml:space="preserve"> 13503 <div class="o_accordion position-relative"> 13504 <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"/> 13505 <t t-if="state.open"> 13506 <div class="o_accordion_values ms-4 border-start"> 13507 <t t-slot="default"/> 13508 </div> 13509 </t> 13510 </div> 13511 </t> 13512 13513`); 13514registerTemplate("web.DropdownItem", `/web/static/src/core/dropdown/dropdown_item.xml`, `<t t-name="web.DropdownItem" xml:space="preserve"> 13515 <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"> 13516 <t t-slot="default"/> 13517 </t> 13518 </t> 13519 13520 13521 `); 13522registerTemplate("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"> 13523 <xpath expr="//t[@role='menuitem']" position="attributes"> 13524 <attribute name="role">menuitemcheckbox</attribute> 13525 <attribute name="t-att-aria-checked">props.checked ? 'true' : 'false'</attribute> 13526 </xpath> 13527 </t> 13528 13529`); 13530registerTemplate("web.Dropzone", `/web/static/src/core/dropzone/dropzone.xml`, `<t t-name="web.Dropzone" xml:space="preserve"> 13531 <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"> 13532 <t t-slot="default"> 13533 <h4>Drag Files Here <i class="fa fa-download"/></h4> 13534 </t> 13535 </div> 13536</t> 13537 13538`); 13539registerTemplate("web.RainbowMan", `/web/static/src/core/effects/rainbow_man.xml`, `<t t-name="web.RainbowMan" xml:space="preserve"> 13540 <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"> 13541 <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"> 13542 <defs> 13543 <radialGradient id="o_reward_gradient_bg" cx="200" cy="200" r="200" gradientUnits="userSpaceOnUse"> 13544 <stop offset="0.3" stop-color="#edeff4"/> 13545 <stop offset="1" stop-color="#edeff4" stop-opacity="0"/> 13546 </radialGradient> 13547 <symbol id="o_reward_star"> 13548 <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"/> 13549 </symbol> 13550 <symbol id="o_reward_thumb"> 13551 <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"/> 13552 <polygon fill="#ECF1FF" points="25 11 25 51 5 52 5 12"/> 13553 <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"/> 13554 </symbol> 13555 </defs> 13556 <rect width="400" height="400" fill="url(#o_reward_gradient_bg)"/> 13557 <g transform="translate(47 45) scale(0.9)" class="o_reward_rainbow"> 13558 <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"/> 13559 <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"/> 13560 <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"/> 13561 <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"/> 13562 </g> 13563 <g transform="translate(80 125)"> 13564 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_01"/> 13565 </g> 13566 <g transform="translate(140 75)"> 13567 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_02"/> 13568 </g> 13569 <g transform="translate(230 90)"> 13570 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_03"/> 13571 </g> 13572 <g transform="translate(275 120)"> 13573 <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_04"/> 13574 </g> 13575 <g class="o_reward_face_group o_reward_box" transform-origin="center top"> 13576 <g class="o_reward_shadow_container o_reward_box"> 13577 <ellipse class="o_reward_shadow o_reward_box" cx="200" cy="105%" rx="100" ry="6" fill="#000" opacity="0.25" transform-origin="center"/> 13578 </g> 13579 <g class="o_reward_face_wrap o_reward_box" transform-origin="center"> 13580 <image class="o_reward_face" x="132" y="125" width="136" height="136" t-attf-href="{{props.imgUrl}}"/> 13581 </g> 13582 <g transform="translate(258 174)"> 13583 <use href="#o_reward_thumb" class="o_reward_box o_reward_thumbup" transform-origin="center"/> 13584 </g> 13585 </g> 13586 </svg> 13587 <div class="o_reward_rainbow_man o_reward_msg_container position-absolute top-0 bottom-0 start-0 end-0 m-auto"> 13588 <div class="o_reward_face_group h-100 w-75 mx-auto"> 13589 <svg viewBox="0 0 42 60" preserveAspectRatio="xMinYMax meet" width="37" height="65%" class="overflow-visible position-relative ms-5"> 13590 <g class="o_reward_box"> 13591 <use href="#o_reward_thumb" x="-60%" y="0" transform="rotate(-90) scale(1 -1)" transform-origin="center"/> 13592 </g> 13593 </svg> 13594 <div class="o_reward_msg mx-4"> 13595 <div class="o_reward_msg_card"> 13596 <div class="o_reward_msg_content text-muted px-3 py-4 bg-view d-inline-block border border-light border-top-0"> 13597 <t t-if="!props.Component"> 13598 <t t-out="props.message"/> 13599 </t> 13600 <t t-else="" t-component="props.Component" t-props="props.props"/> 13601 </div> 13602 </div> 13603 </div> 13604 </div> 13605 </div> 13606 </div> 13607 </t> 13608`); 13609registerTemplate("web.EmojiPicker", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker" xml:space="preserve"> 13610 <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"> 13611 <t t-if="emojis.length === 0">
13612 <span class="o-EmojiPicker-empty">ðµâð«</span> 13613 <span class="fs-5 text-muted">Failed to load emojis...</span> 13614 </t> 13615 <t t-else=""> 13616 <div class="o-EmojiPicker-search d-flex align-items-center mx-2 mt-2 rounded"> 13617 <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"> 13618 <t t-call="web.EmojiPicker.searchInput"> 13619 <t t-if="props.state" t-set="localState" t-value="props.state"/> 13620 <t t-else="" t-set="localState" t-value="state"/> 13621 </t> 13622 <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..."/> 13623 </span> 13624 </div> 13625 <t t-set="itemIndex" t-value="0"/> 13626 <t t-set="emojisFromSearch" t-value="getEmojisFromSearch()"/> 13627 <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"> 13628 <t t-if="searchTerm and emojisFromSearch.length === 0" class="d-flex flex-column"> 13629 <span class="o-EmojiPicker-empty">ð¢</span> 13630 <span class="fs-5 text-muted">No emojis match your search</span> 13631 </t> 13632 <t t-if="recentEmojis.length > 0"> 13633 <t t-if="!searchTerm" t-call="web.EmojiPicker.section"> 13634 <t t-set="category" t-value="recentCategory"/> 13635 </t> 13636 <t t-foreach="recentEmojis" t-as="emoji" t-key="'recent_' + emoji_index"> 13637 <t t-call="web.EmojiPicker.emoji"> 13638 <t t-set="inRecent" t-value="true"/> 13639 <t t-set="emoji" t-value="emoji"/> 13640 </t> 13641 <t t-set="itemIndex" t-value="itemIndex + 1"/> 13642 </t> 13643 </t> 13644 <t t-set="current" t-value=""/> 13645 <t t-foreach="getEmojis()" t-as="emoji" t-key="emoji_index"> 13646 <t t-if="!searchTerm and current !== emoji.category"> 13647 <t t-set="current" t-value="emoji.category"/> 13648 <t t-set="category" t-value="categories.find(c => c.name === current)"/> 13649 <t t-call="web.EmojiPicker.section"> 13650 <t t-set="category" t-value="category"/> 13651 </t> 13652 </t> 13653 <t t-elif="searchTerm" t-set="categorySortId" t-value="null"/> 13654 <t t-call="web.EmojiPicker.emoji"> 13655 <t t-set="emoji" t-value="emoji"/> 13656 </t> 13657 <t t-set="itemIndex" t-value="itemIndex + 1"/> 13658 </t> 13659 </div> 13660 <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"> 13661 <t t-if="currentNavbarPanel"> 13662 <t t-set="allCategories" t-value="getAllCategories()"/> 13663 <t t-foreach="currentNavbarPanel" t-as="navbarItemId" t-key="navbarItemId"> 13664 <t t-if="navbarItemId === 'next'" t-call="web.EmojiPicker.tabNext"/> 13665 <t t-elif="navbarItemId === 'previous'" t-call="web.EmojiPicker.tabPrev"/> 13666 <t t-elif="typeof navbarItemId === 'string' and navbarItemId.startsWith('empty')" t-call="web.EmojiPicker.tabEmpty"/> 13667 <t t-else=""> 13668 <t t-set="category" t-value="allCategories.find(cat => cat.sortId === navbarItemId)"/> 13669 <t t-if="category" t-call="web.EmojiPicker.tab"> 13670 <t t-set="category" t-value="category"/> 13671 </t> 13672 </t> 13673 </t> 13674 </t> 13675 </div> 13676 </t> 13677 </div> 13678</t> 13679 13680`); 13681registerTemplate("web.EmojiPicker.tab", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tab" xml:space="preserve"> 13682 <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)">
13683 <span t-esc="category.title"/> 13684 </span> 13685</t> 13686 13687`); 13688registerTemplate("web.EmojiPicker.tabNext", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabNext" xml:space="preserve"> 13689 <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"> 13690 <span class="position-relative"> 13691 <i class="oi oi-chevron-right fa-fw smaller opacity-0"/> 13692 <i class="oi oi-chevron-right fa-fw smaller position-absolute opacity-75" style="left: 3px; transform: translateY(75%);"/> 13693 <i class="oi oi-chevron-right fa-fw smaller position-absolute opacity-75" style="left: -3px; transform: translateY(75%);"/> 13694 </span> 13695 </span> 13696</t> 13697 13698`); 13699registerTemplate("web.EmojiPicker.tabPrev", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabPrev" xml:space="preserve"> 13700 <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"> 13701 <span class="position-relative"> 13702 <i class="oi oi-chevron-left fa-fw smaller opacity-0"/> 13703 <i class="oi oi-chevron-left fa-fw smaller position-absolute opacity-75" style="left: 3px; transform: translateY(75%);"/> 13704 <i class="oi oi-chevron-left fa-fw smaller position-absolute opacity-75" style="left: -3px; transform: translateY(75%);"/> 13705 </span> 13706 </span> 13707</t> 13708 13709`); 13710registerTemplate("web.EmojiPicker.tabEmpty", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabEmpty" xml:space="preserve"> 13711 <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch opacity-0"> 13712 <span>ð«¥</span> 13713 </span> 13714</t> 13715 13716`); 13717registerTemplate("web.EmojiPicker.section", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.section" xml:space="preserve"> 13718 <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> 13719 <span class="o-EmojiPicker-category opacity-100 fs-7 py-2" t-att-data-category="category.sortId"/> 13720</t> 13721 13722`); 13723registerTemplate("web.EmojiPicker.emoji", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.emoji" xml:space="preserve"> 13724 <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)"> 13725 <span t-esc="emoji.codepoints"/> 13726 </span> 13727</t> 13728 13729`); 13730registerTemplate("web.EmojiPicker.searchInput", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.searchInput" xml:space="preserve"> 13731 <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"/> 13732</t> 13733 13734`); 13735registerTemplate("web.WarningDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.WarningDialog" xml:space="preserve"> 13736 <Dialog title="title" size="'xl'" contentClass="'o_error_dialog'"> 13737 <div role="alert"> 13738 <p t-esc="message" class="text-prewrap"/> 13739 </div> 13740 <t t-set-slot="footer"> 13741 <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button> 13742 </t> 13743 </Dialog> 13744 </t> 13745 13746 `); 13747registerTemplate("web.RedirectWarningDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.RedirectWarningDialog" xml:space="preserve"> 13748 <Dialog title="title" size="'xl'" contentClass="'o_error_dialog'"> 13749 <div role="alert"> 13750 <p t-esc="message" class="text-prewrap"/> 13751 </div> 13752 <t t-set-slot="footer"> 13753 <button class="btn btn-primary" t-on-click="onClick" t-esc="buttonText"/> 13754 <button class="btn btn-secondary" t-on-click="props.close">Close</button> 13755 </t> 13756 </Dialog> 13757 </t> 13758 13759 `); 13760registerTemplate("web.Error504Dialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.Error504Dialog" xml:space="preserve"> 13761 <Dialog title.translate="Request timeout" size="'xl'" contentClass="'o_error_dialog'"> 13762 <div role="alert"> 13763 <p class="text-prewrap"> 13764 The operation was interrupted. This usually means that the current operation is taking too much time. 13765 </p> 13766 </div> 13767 <t t-set-slot="footer"> 13768 <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button> 13769 </t> 13770 </Dialog> 13771 </t> 13772 13773 `); 13774registerTemplate("web.SessionExpiredDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.SessionExpiredDialog" xml:space="preserve"> 13775 <Dialog title.translate="Odoo Session Expired" size="'xl'" contentClass="'o_error_dialog'"> 13776 <div role="alert"> 13777 <p class="text-prewrap"> 13778 Your Odoo session expired. The current page is about to be refreshed. 13779 </p> 13780 </div> 13781 <t t-set-slot="footer"> 13782 <button class="btn btn-primary o-default-button" t-on-click="onClick">Close</button> 13783 </t> 13784 </Dialog> 13785 </t> 13786 13787 `); 13788registerTemplate("web.ErrorDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.ErrorDialog" xml:space="preserve"> 13789 <Dialog title.translate="Oops!" size="'xl'" contentClass="'o_error_dialog'"> 13790 <div role="alert"> 13791 <p class="text-prewrap"> 13792 Something went wrong... If you really are stuck, share the report with your friendly support service 13793 </p> 13794 <button class="btn btn-link p-0" t-on-click="() => { state.showTraceback = !state.showTraceback }" t-esc="state.showTraceback ? this.constructor.hideTracebackButtonText : this.constructor.showTracebackButtonText"/> 13795 <div t-if="state.showTraceback" class="bg-100 mb-0 clearfix mt-3 position-relative o_error_detail"> 13796 <button class="btn position-absolute bg-100" t-ref="copyButton" t-on-click="onClickClipboard">
13797 <span class="fa fa-clipboard"/> 13798 </button> 13799 <div class="ps-3 pt-3"> 13800 <p class="m-0"><b t-esc="title or this.constructor.title"/></p> 13801 <code t-if="props.name" t-esc="props.name"/> 13802 <p class="m-0" t-if="props.message" t-esc="props.message"/> 13803 <p class="m-0" t-if="contextDetails" t-esc="contextDetails"/> 13804 <pre class="m-0 p-0 mt-2" t-esc="traceback or props.traceback"/> 13805 </div> 13806 </div> 13807 </div> 13808 <t t-set-slot="footer"> 13809 <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button> 13810 </t> 13811 </Dialog> 13812 </t> 13813 13814`); 13815registerTemplate("web.ExpressionEditor", `/web/static/src/core/expression_editor/expression_editor.xml`, `<t t-name="web.ExpressionEditor" xml:space="preserve"> 13816 <div class="o_expression_editor w-100" aria-atomic="true"> 13817 <t t-if="tree"> 13818 <TreeEditor resModel="props.resModel" tree="tree" isDebugMode="isDebugMode" update.bind="update" getDefaultCondition.bind="getDefaultCondition" getDefaultOperator.bind="getDefaultOperator" getOperatorEditorInfo.bind="getOperatorEditorInfo" getPathEditorInfo.bind="getPathEditorInfo"/> 13819 </t> 13820 <t t-else=""> 13821 This expression is not supported. 13822 <button t-on-click="() => this.resetExpression()">Reset expression</button> 13823 </t> 13824 <t t-if="isDebugMode"> 13825 <div class="o_expression_editor_debug_container d-block mt-3 border rounded p-3 bg-100 text-muted font-monospace"> 13826 <span class="small"># Code editor</span> 13827 <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)"/> 13828 </div> 13829 </t> 13830 </div> 13831 </t> 13832 13833`); 13834registerTemplate("web.ExpressionEditorDialog", `/web/static/src/core/expression_editor_dialog/expression_editor_dialog.xml`, `<t t-name="web.ExpressionEditorDialog" xml:space="preserve"> 13835 <Dialog title.translate="Edit Condition" size="'xl'"> 13836 <ExpressionEditor t-props="expressionEditorProps"/> 13837 <t t-set-slot="footer"> 13838 <button class="btn btn-primary" t-on-click="onConfirm" t-ref="confirm">Confirm</button> 13839 <button class="btn btn-secondary" t-on-click="onDiscard">Discard</button> 13840 </t> 13841 </Dialog> 13842 </t> 13843 13844`); 13845registerTemplate("web.FileInput", `/web/static/src/core/file_input/file_input.xml`, `<t t-name="web.FileInput" xml:space="preserve"> 13846 <span class="o_file_input" t-att-class="{ 'd-none': props.hidden, 'show opacity-50 pe-none': state.isDisable}" aria-atomic="true"> 13847 <span t-if="!props.hidden" class="o_file_input_trigger" t-on-click.prevent="onTriggerClicked"> 13848 <t t-slot="default"> 13849 <button class="btn btn-primary">Choose File</button> 13850 </t> 13851 </span> 13852 <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"/> 13853 </span> 13854 </t> 13855 13856`); 13857registerTemplate("web.FileUploadProgressBar", `/web/static/src/core/file_upload/file_upload_progress_bar.xml`, `<t t-name="web.FileUploadProgressBar" xml:space="preserve"> 13858 <div class="position-absolute top-0 start-0 h-100 w-100"> 13859 <div class="o-file-upload-progress-bar-value h-100" t-ref="bar" t-att-style="'width: ' + (this.props.fileUpload.progress * 100) + '%;'"/> 13860 <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"/> 13861 </div> 13862 </t> 13863`); 13864registerTemplate("web.FileUploadProgressContainer", `/web/static/src/core/file_upload/file_upload_progress_container.xml`, `<t t-name="web.FileUploadProgressContainer" xml:space="preserve"> 13865 <t t-foreach="Object.values(props.fileUploads)" t-as="fileUpload" t
13865-key="fileUpload.id"> 13866 <t t-if="!props.shouldDisplay || props.shouldDisplay(fileUpload)" t-component="props.Component" fileUpload="fileUpload" selector="props.selector"/> 13867 </t> 13868 </t> 13869`); 13870registerTemplate("web.FileUploadProgressKanbanRecord", `/web/static/src/core/file_upload/file_upload_progress_record.xml`, `<t t-name="web.FileUploadProgressKanbanRecord" xml:space="preserve"> 13871 <t t-set="progressTexts" t-value="getProgressTexts()"/> 13872 <div class="o_kanban_record d-flex flex-grow-1 flex-md-shrink-1 flex-shrink-0"> 13873 <div class="o_kanban_progress_card o_kanban_attachment position-relative p-0 cursor-pointer"> 13874 <div class="o_kanban_image_wrapper"> 13875 <div class="o_image o_image_thumbnail" t-att-data-mimetype="props.fileUpload.type"/> 13876 </div> 13877 <div t-att-title="props.fileUpload.title" t-att-aria-label="props.fileUpload.title" class="fw-bold fs-5 mb-2 p-2"> 13878 <span t-esc="props.fileUpload.title"/> 13879 </div> 13880 <div class="o_kanban_record_body"/> 13881 <div class="d-flex p-2 text-dark"> 13882 <div class="o_file_upload_progress_text_left" t-esc="progressTexts.left"/> 13883 <span class="o_file_upload_progress_text_right ms-auto" t-esc="progressTexts.right"/> 13884 </div> 13885 <FileUploadProgressBar fileUpload="props.fileUpload"/> 13886 </div> 13887 </div> 13888 </t> 13889 13890 `); 13891registerTemplate("web.FileUploadProgressDataRow", `/web/static/src/core/file_upload/file_upload_progress_record.xml`, `<t t-name="web.FileUploadProgressDataRow" xml:space="preserve"> 13892 <t t-set="progressTexts" t-value="getProgressTexts()"/> 13893 <div class="o_data_row o_list_progress_card position-relative align-middle p-0"> 13894 <span class="o_file_upload_upload_title" t-esc="props.fileUpload.title"/> 13895 <span class="o_file_upload_progress_text_left" t-esc="progressTexts.left"/> 13896 <span class="o_file_upload_progress_text_right" t-esc="progressTexts.right"/> 13897 <FileUploadProgressBar fileUpload="props.fileUpload"/> 13898 </div> 13899 </t> 13900 13901`); 13902registerTemplate("web.FileViewer", `/web/static/src/core/file_viewer/file_viewer.xml`, `<t t-name="web.FileViewer" xml:space="preserve"> 13903 <div class="d-flex justify-content-center" t-att-class="{ 'modal modal-fullscreen': props.modal }"> 13904 <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)"> 13905 <div class="o-FileViewer-header position-absolute top-0 d-flex w-100" t-on-click.stop=""> 13906 <div t-if="isViewable" class="d-flex align-items-center ms-4 me-2"> 13907 <i t-if="state.file.isImage" class="fa fa-picture-o" role="img" title="Image"/> 13908 <i t-if="state.file.isPdf" class="fa fa-file-text" role="img" title="PDF file"/> 13909 <i t-if="state.file.isText" class="fa fa-file-text" role="img" title="Text file"/> 13910 <i t-if="state.file.isVideo" class="fa fa-video-camera" role="img" title="Video"/> 13911 </div> 13912 <div class="d-flex align-items-center ms-4 overflow-auto"> 13913 <span class="text-truncate" t-out="state.file.name"/> 13914 </div> 13915 <div class="flex-grow-1"/> 13916 <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"> 13917 <span class="text-reset d-flex align-items-baseline"> 13918 <i class="fa fa-download fa-fw me-1" role="img"/> 13919 <span>Download</span> 13920 </span> 13921 </div> 13922 13923 <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"> 13924 <i class="fa fa-fw fa-times" role="img"/> 13925 </div> 13926 </div> 13927 <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 }"> 13928 <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"> 13929 <div t-if="!state.imageLoaded" class="position-absolute"> 13930 <i class="fa fa-3x fa-circle-o-notch fa-fw fa-spin text-white" role="img" title="Loading"/> 13931 </div> 13932 <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"/> 13933 </div> 13934 <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"/> 13935 <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"/> 13936 <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"/> 13937 <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"> 13938 <source t-att-data-type="state.file.mimetype" t-att-src="state.file.defaultSource"/> 13939 </video> 13940 </div> 13941 <div t-if="state.file.isImage" class="position-absolute bottom-0 d-flex" role="toolbar"> 13942 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="zoomIn" title="Zoom In (+)" role="button"> 13943 <i class="fa fa-fw fa-plus" role="img"/> 13944 </div> 13945 <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)"> 13946 <i class="fa fa-fw fa-search" role="img"/> 13947 </div> 13948 <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"> 13949 <i class="fa fa-fw fa-minus" role="img"/> 13950 </div> 13951 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="rotate" title="Rotate (r)" role="button"> 13952 <i class="fa fa-fw fa-repeat" role="img"/> 13953 </div> 13954 <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="onClickPrint" title="Print" role="button"> 13955 <i class="fa fa-fw fa-print" role="img"/> 13956 </div> 13957 <div class="o-FileViewer-download o-FileViewer-toolbarButton p-3 rounded-0 cursor-pointer" title="Download" role="button" t-on-click.stop="onClickDownload"> 13958 <i class="fa fa-download fa-fw" role="img"/> 13959 </div> 13960 </div> 13961 <t t-if="props.files.length > 1"> 13962 <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">
13963 <span class="oi oi-chevron-left" role="img"/> 13964 </div> 13965 <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"> 13966 <span class="oi oi-chevron-right" role="img"/> 13967 </div> 13968 </t> 13969 </div> 13970 </div> 13971 </t> 13972 13973`); 13974registerTemplate("web.InstallScopedApp", `/web/static/src/core/install_scoped_app/install_scoped_app.xml`, `<t t-name="web.InstallScopedApp" xml:space="preserve"> 13975 <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"> 13976 <button class="btn btn-link m-1 position-absolute start-0 top-0" t-on-click="() => window.close()"> 13977 <svg xmlns="http://www.w3.org/2000/svg" style="transform:rotate(135deg);" width="28" height="28" viewBox="-7 -7 24 24" preserveAspectRatio="xMinYMin"> 13978 <path fill="#000" d="M8 8V1a1 1 0 1 1 2 0v8a1 1 0 0 1-1 1H1a1 1 0 1 1 0-2h7z"/> 13979 </svg> 13980 </button> 13981 <i t-if="!state.showInstallUI" class="fa fa-circle-o-notch fa-spin fa-2x text-primary position-absolute"/> 13982 <div t-attf-class="h-100 w-100 d-flex align-items-center justify-content-center flex-column fade {{state.showInstallUI ? 'show': ''}}"> 13983 <div class="d-flex align-items-center justify-content-center flex-wrap gap-3 m-4 mw-75 mw-md-50"> 13984 <img style="height:100px;width:100px;" class="rounded-4 p-4 bg-white shadow" t-att-src="state.manifest.icons?.[0]?.src"/> 13985 <div class="d-inline-block"> 13986 <div class="d-flex align-items-center"> 13987 <h1 class="mb-0" t-esc="state.manifest.name"/> 13988 <Dropdown t-if="pwa.isAvailable" menuClass="'p-2'"> 13989 <button class="btn btn-link fa fa-pencil"/> 13990 <t t-set-slot="content"> 13991 <label class="mb-1">Application name</label> 13992 <input class="form-control" t-att-value="state.manifest.name" t-on-change="onChangeName"/> 13993 </t> 13994 </Dropdown> 13995 </div> 13996 <a class="text-primary text-decoration-none" href="https://odoo.com" alt="Odoo" target="_blank">Odoo S.A.</a> 13997 </div> 13998 </div> 13999 <button t-if="pwa.isAvailable" class="btn btn-primary btn-lg rounded-5 shadow py-2 px-3" t-on-click="onInstall">Install</button> 14000 <div t-else="" class="p-2 px-4 overflow-hidden rounded-2 mw-75 bg-info text-white"> 14001 <t t-if="pwa.isSupportedOnBrowser"> 14002 <span t-if="pwa.hasScopeBeenInstalled()">The app seems to be installed on your device</span> 14003 <span t-else="">
14003You can install the app from the browser menu</span> 14004 </t> 14005 <span t-else="">The app cannot be installed with this browser</span> 14006 </div> 14007 </div> 14008 </div> 14009 </t> 14010`); 14011registerTemplate("web._ModelFieldSelector", `/web/static/src/core/model_field_selector/model_field_selector.xml`, `<t t-name="web._ModelFieldSelector" xml:space="preserve"> 14012 <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)"> 14013 <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"> 14014 <t t-foreach="state.displayNames" t-as="displayName" t-key="displayName_index"> 14015 <t t-if="!displayName_first"> 14016 <i class="oi oi-chevron-right m-1" role="img" aria-label="Followed by" data-tooltip="Followed by"/> 14017 </t> 14018 <span t-attf-class="o_model_field_selector_chain_part mb-1 #{props.readonly ? 'border-0 fw-bolder' : 'px-1'} text-nowrap"> 14019 <t t-esc="displayName"/> 14020 </span> 14021 </t> 14022 </div> 14023 <div t-if="!props.readonly and state.isInvalid" class="o_model_field_selector_controls ms-2" tabindex="0"> 14024 <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"/> 14025 </div> 14026 <div t-if="!props.readonly and props.allowEmpty and state.displayNames.length" class="o_model_field_selector_controls ms-2" tabindex="0"> 14027 <i class="fa fa-times" t-on-click.stop="clear" aria-label="Clear" data-tooltip="Clear"/> 14028 </div> 14029 </div> 14030 </t> 14031 14032`); 14033registerTemplate("web.ModelFieldSelectorPopover", `/web/static/src/core/model_field_selector/model_field_selector_popover.xml`, `<t t-name="web.ModelFieldSelectorPopover" xml:space="preserve"> 14034 <div class="o_model_field_selector_popover d-flex flex-column" tabindex="-1" t-ref="root" t-on-keydown="onInputKeydown"> 14035 <div class="border-bottom p-2 text-dark fw-bolder"> 14036 <div class="d-flex justify-content-between align-items-center"> 14037 <t t-if="state.page.previousPage"> 14038 <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()"/> 14039 </t> 14040 <div class="o_model_field_selector_popover_title px-2 text-truncate"> 14041 <t t-esc="state.page.title"/> 14042 </div> 14043 <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()"/> 14044 </div> 14045 <t t-if="props.showSearchInput"> 14046 <div class="o_model_field_selector_popover_search mt-1"> 14047 <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)"/> 14048 </div> 14049 </t> 14050 </div> 14051 <div class="o_model_field_selector_popover_body overflow-auto"> 14052 <ul class="o_model_field_selector_popover_page list-unstyled mb-0"> 14053 <t t-foreach="fieldNames" t-as="fieldName" t-key="fieldName"> 14054 <t t-set="fieldDef" t-value="state.page.fieldDefs[fieldName]"/> 14055 <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"> 14056 <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)"> 14057 <t t-esc="fieldDef.string"/> 14058 <t t-if="fieldDef.record_name"> (<t t-esc="fieldDef.record_name"/>)</t> 14059 <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> 14060 </button> 14061 <t t-if="this.canFollowRelationFor(fieldDef)"> 14062 <t t-set="label"> 14063 <t t-if="fieldDef.relation">Relation to follow</t> 14064 <t t-else="">Show options</t> 14065 </t> 14066 <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)"> 14067 <i class="oi oi-chevron-right o_model_field_selector_popover_relation_icon" role="img"/> 14068 </button> 14069 </t> 14070 </li> 14071 </t> 14072 </ul> 14073 </div> 14074 <div t-if="showDebugInput" class="o_model_field_selector_popover_footer border-top py-1 px-2"> 14075 <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)"/> 14076 </div> 14077 </div> 14078 </t> 14079 14080`); 14081registerTemplate("web.ModelSelector", `/web/static/src/core/model_selector/model_selector.xml`, `<t t-name="web.ModelSelector" xml:space="preserve"> 14082 <div class="o_model_selector" t-ref="autocomplete_container"> 14083 <input t-if="env.isSmall" type="text" class="o_input" readonly="" t-att-id="props.id" t-att-value="props.value"/> 14084 <AutoComplete t-else="" id="props.id" value="props.value || ''" sources="sources" placeholder="this.placeholder" autoSelect="props.autoSelect" autofocus="props.autofocus"/>
14085 <span class="o_dropdown_button"/> 14086 </div> 14087 </t> 14088`); 14089registerTemplate("web.Notebook", `/web/static/src/core/notebook/notebook.xml`, `<t t-name="web.Notebook" xml:space="preserve"> 14090 <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"> 14091 <div class="o_notebook_headers" t-att-class="{ 'm-0': props.orientation === 'vertical' }"> 14092 <ul t-attf-class="nav nav-tabs {{ props.orientation === 'horizontal' ? 'flex-row flex-nowrap' : 'flex-column p-0' }}"> 14093 <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' : '' }}"> 14094 <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"> 14095 <i t-if="props.icons and props.icons[navItem[0]]" t-attf-class="fa {{ props.icons[navItem[0]] }} me-2"/> 14096 <t t-esc="navItem[1].title"/> 14097 </a> 14098 </li> 14099 </ul> 14100 </div> 14101 <div class="o_notebook_content tab-content"> 14102 <div class="tab-pane active fade" t-ref="activePane"> 14103 <t t-if="page" t-component="page.Component" t-key="state.currentPage" t-props="page.props"/> 14104 <t t-else="" t-slot="{{ state.currentPage }}"/> 14105 </div> 14106 </div> 14107 </div> 14108 </t> 14109 14110`); 14111registerTemplate("web.NotificationWowl", `/web/static/src/core/notifications/notification.xml`, `<t t-name="web.NotificationWowl" xml:space="preserve"> 14112 <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"> 14113 <span t-attf-class="o_notification_bar bg-{{props.type}} rounded-start"/> 14114 <div class="w-100 py-2 ps-3 pe-5 border border-start-0 rounded-end text-break"> 14115 <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"/> 14116 <div class="o_notification_body d-flex align-items-center"> 14117 <span class="me-auto o_notification_content w-100"> 14118 14119 <t t-if="props.title"><t t-out="props.title"/>. </t> 14120 <t t-out="props.message"/> 14121 </span> 14122 <div t-if="props.buttons.length" class="o_notification_buttons justify-content-end w-50"> 14123 <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"> 14124 <t t-if="button.icon"> 14125 <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"/> 14126 <img t-else="" t-att-src="button.icon" t-att-alt="button.name"/> 14127 </t> 14128 <span class="fw-bolder" t-esc="button.name"/> 14129 </button> 14130 </div> 14131 </div> 14132 <div t-ref="autoclose_progress_bar" t-attf-class="o_notification_progress opacity-75 bg-{{props.type}}"/> 14133 </div> 14134 </div> 14135 </t> 14136 14137`); 14138registerTemplate("web.OverlayContainer", `/web/static/src/core/overlay/overlay_container.xml`, `<t t-name="web.OverlayContainer" xml:space="preserve"> 14139 <div class="o-overlay-container" t-ref="root"> 14140 <t t-foreach="sortedOverlays" t-as="overlay" t-key="overlay.id"> 14141 <ErrorHandler t-if="isVisible(overlay)" onError="(error) => this.handleError(overlay, error)"> 14142 <OverlayItem env="overlay.env" component="overlay.component" props="overlay.props"/> 14143 </ErrorHandler> 14144 </t> 14145 </div> 14146 </t> 14147 14148 `); 14149registerTemplate("web.OverlayContainer.Item", `/web/static/src/core/overlay/overlay_container.xml`, `<t t-name="web.OverlayContainer.Item" xml:space="preserve"> 14150 <div t-ref="rootRef" class="o-overlay-item"> 14151 <t t-component="props.component" t-props="props.props"/> 14152 </div> 14153 </t> 14154 14155`); 14156registerTemplate("web.Pager", `/web/static/src/core/pager/pager.xml`, `<t t-name="web.Pager" xml:space="preserve"> 14157 <nav class="o_pager d-flex gap-2 h-100" aria-label="Pager">
14158 <span t-if="!env.isSmall" class="o_pager_counter align-self-center" t-on-click.stop=""> 14159 <t t-if="state.isEditing"> 14160 <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"/> 14161 </t> 14162 <t t-else=""> 14163 <span class="o_pager_value d-inline-block border-bottom border-transparent mb-n1" t-esc="value" t-on-click="onValueClick"/> 14164 </t> 14165 <span> / </span> 14166 <t t-if="props.updateTotal"> 14167 <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> 14168 </t> 14169 <t t-else=""> 14170 <span class="o_pager_limit" t-esc="props.total"/> 14171 </t> 14172 </span> 14173 <span class="btn-group d-print-none" aria-atomic="true"> 14174 14175 <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)"> 14176 <i class="oi oi-chevron-left"/> 14177 </button> 14178 <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)"> 14179 <i class="oi oi-chevron-right"/> 14180 </button> 14181 </span> 14182 </nav> 14183 </t> 14184 14185`); 14186registerTemplate("web.PagerIndicator", `/web/static/src/core/pager/pager_indicator.xml`, `<t t-name="web.PagerIndicator" xml:space="preserve"> 14187 <Transition visible="state.show" name="'o-fade'" t-slot-scope="transition" leaveDuration="400"> 14188 <div class="o_pager_indicator position-fixed top-0 end-0 m-1 d-flex" t-att-class="transition.className"> 14189 <span class="o_pager_indicator_inner m-1 px-1 text-center shadow"> 14190 <span class="o_pager_value" t-esc="state.value"/> 14191 <span> / </span> 14192 <span class="o_pager_limit" t-esc="state.total"/> 14193 </span> 14194 </div> 14195 </Transition> 14196 </t> 14197 14198`); 14199registerTemplate("web.Popover", `/web/static/src/core/popover/popover.xml`, `<t t-name="web.Popover" xml:space="preserve"> 14200 <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()"> 14201 <t t-component="props.component" t-props="props.componentProps" close="props.close"/> 14202 <div t-if="props.arrow" class="popover-arrow position-absolute z-n1"/> 14203 </div> 14204 </t> 14205 14206`); 14207registerTemplate("web.InstallPrompt", `/web/static/src/core/pwa/install_prompt.xml`, `<t t-name="web.InstallPrompt" xml:space="preserve"> 14208 <Dialog contentClass="'o_install_prompt position-fixed px-2 py-3 m-2 user-select-none'" size="'md'" footer="false"> 14209 <t t-set-slot="header"> 14210 <div class="d-flex w-100"> 14211 <h4>How to get the application</h4> 14212 <div t-on-click="onClose" type="button" class="btn-close" aria-label="Close"/> 14213 </div> 14214 </t> 14215 <p>Install the app on your device to access it easily. Here are the steps to follow:</p> 14216 <t t-call="web.InstallStepsSafari"/> 14217 </Dialog> 14218 </t> 14219 `); 14220registerTemplate("web.InstallStepsSafari", `/web/static/src/core/pwa/install_prompt.xml`, `<t t-name="web.InstallStepsSafari" xml:space="preserve"> 14221 <t t-if="isMobileSafari"> 14222 <ul class="mb-0"> 14223 <li> 14224 Tap on the share icon 14225 </li> 14226 <li> 14227 Select "Add to home screen" 14228 </li> 14229 </ul> 14230 </t> 14231 <t t-else=""> 14232 <ul class="mb-0"> 14233 <li> 14234 Open "File" menu from your browser 14235 </li> 14236 <li> 14237 Select "Add to dock" 14238 </li> 14239 </ul> 14240 </t> 14241 </t> 14242`); 14243registerTemplate("web.MultiRecordSelector", `/web/static/src/core/record_selectors/multi_record_selector.xml`, `<t t-name="web.MultiRecordSelector" xml:space="preserve"> 14244 <div class="o_input d-flex flex-wrap gap-1 o_multi_record_selector" t-ref="multiRecordSelector"> 14245 <TagsList tags="tags"/> 14246 <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"> 14247 <t t-set-slot="autoCompleteItem" t-slot-scope="autoCompleteItemScope">
14248 <span t-if="isAvatarModel" class="o_avatar_many2x_autocomplete o_avatar d-flex align-items-center"> 14249 <img class="rounded me-1" t-attf-src="/web/image/{{props.resModel}}/{{autoCompleteItemScope.data.record.id}}/avatar_128"/> 14250 <t t-esc="autoCompleteItemScope.label"/> 14251 </span> 14252 <t t-else="" t-esc="autoCompleteItemScope.label"/> 14253 </t> 14254 </RecordAutocomplete> 14255 </div> 14256 </t> 14257 14258`); 14259registerTemplate("web.RecordAutocomplete", `/web/static/src/core/record_selectors/record_autocomplete.xml`, `<t t-name="web.RecordAutocomplete" xml:space="preserve"> 14260 <AutoComplete placeholder="props.placeholder" value="props.value" autoSelect="true" resetOnSelect="props.multiSelect" class="props.className" sources="sources" onChange.bind="onChange"> 14261 <t t-set-slot="option" t-slot-scope="optionScope"> 14262 <t t-if="optionScope.data.record"> 14263 <t t-slot="autoCompleteItem" label="optionScope.label" data="optionScope.data"/> 14264 </t> 14265 <t t-else=""> 14266 <t t-esc="optionScope.label"/> 14267 </t> 14268 </t> 14269 </AutoComplete> 14270 </t> 14271 14272`); 14273registerTemplate("web.RecordSelector", `/web/static/src/core/record_selectors/record_selector.xml`, `<t t-name="web.RecordSelector" xml:space="preserve"> 14274 <div class="o_input d-flex flex-wrap gap-1 o_record_selector"> 14275 <span t-if="hasAvatarImg" class="o_avatar o_m2o_avatar"> 14276 <img class="rounded" t-attf-src="/web/image/{{props.resModel}}/{{props.resId}}/avatar_128"/> 14277 </span> 14278 <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"> 14279 <t t-set-slot="autoCompleteItem" t-slot-scope="autoCompleteItemScope"> 14280 <span t-if="isAvatarModel" class="o_avatar_many2x_autocomplete o_avatar d-flex align-items-center"> 14281 <img class="rounded me-1" t-attf-src="/web/image/{{props.resModel}}/{{autoCompleteItemScope.data.record.id}}/avatar_128"/> 14282 <t t-esc="autoCompleteItemScope.label"/> 14283 </span> 14284 <t t-else="" t-esc="autoCompleteItemScope.label"/> 14285 </t> 14286 </RecordAutocomplete> 14287 <span class="o_dropdown_button"/> 14288 </div> 14289 </t> 14290 14291`); 14292registerTemplate("web_studio.ResizablePanel", `/web/static/src/core/resizable_panel/resizable_panel.xml`, `<t t-name="web_studio.ResizablePanel" xml:space="preserve"> 14293 <div class="o_resizable_panel d-flex flex-column" t-att-class="class" t-ref="containerRef"> 14294 <t t-slot="default"/> 14295 <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"/> 14296 </div> 14297 </t> 14298 14299`); 14300registerTemplate("web.SelectMenu.search", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu.search" xml:space="preserve"> 14301 <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"/> 14302 </t> 14303 14304 `); 14305registerTemplate("web.SelectMenu", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu" xml:space="preserve"> 14306 <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"> 14307 <Dropdown menuClass="this.menuClass" menuRef="this.menuRef" position="'bottom-fit'" beforeOpen.bind="onBeforeOpen" focusToggleOnClosed="!isBottomSheet" onStateChanged.bind="onStateChanged" navigationOptions="navigationOptions" state="dropdownState"> 14308 <t t-if="displayInputInToggler"> 14309 <t t-set="inputClass" t-value="'o_select_menu_toggler ' + (!displayInputInDropdown ? 'o_select_menu_input ' : '') + props.togglerClass"/> 14310 <div class="w-100 d-flex flex-column"> 14311 <t t-if="props.multiSelect"> 14312 <div t-if="props.value.length" class="d-flex flex-wrap mb-1"> 14313 <TagsList tags="multiSelectChoices"/> 14314 </div> 14315 </t> 14316 <div class="position-relative d-flex"> 14317 <t t-call="web.SelectMenu.search"/>
14318 <span class="o_select_menu_caret align-self-center"/> 14319 </div> 14320 </div> 14321 </t> 14322 <t t-else=""> 14323 <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"> 14324 <span class="o_select_menu_toggler_slot text-start text-truncate"> 14325 <span t-if="props.placeholder and !props.value" class="text-muted" t-out="props.placeholder"/> 14326 <t t-slot="default"/> 14327 </span> 14328 <span t-if="canDeselect" t-on-click.stop="onInputClear" class="o_select_menu_toggler_clear position-absolute top-50 end-0 me-3"> 14329 <i class="fa fa-times"/> 14330 </span> 14331 <span class="o_select_menu_caret align-self-center"/> 14332 </button> 14333 </t> 14334 <t t-set-slot="content"> 14335 <button t-if="isBottomSheet and canDeselect" class="btn o_clear_button px-4 d-block ms-auto" t-on-click="onInputClear">Clear</button> 14336 <div class="o_select_menu_searchbox position-sticky start-0 d-empty-none" t-att-data-id="selectMenuId"> 14337 <t t-if="displayInputInDropdown"> 14338 <t t-set="inputClass" t-value="'o_select_menu_input dropdown-item'"/> 14339 <t t-call="web.SelectMenu.search"/> 14340 </t> 14341 </div> 14342 <t t-if="state.choices.length === 0"> 14343 <p class="text-muted fst-italic mx-4 my-1">No results</p> 14344 </t> 14345 <t t-foreach="state.displayedOptions" t-as="choice" t-key="choice_index"> 14346 <t t-call="{{ this.constructor.choiceItemTemplate }}"> 14347 <t t-set="choice" t-value="choice"/> 14348 <t t-set="choice_index" t-value="choice_index"/> 14349 </t> 14350 </t> 14351 <t t-if="props.slots and props.slots.bottomArea" t-slot="bottomArea" data="state"/> 14352 </t> 14353 </Dropdown> 14354 </div> 14355 </t> 14356 14357 `); 14358registerTemplate("web.SelectMenu.ChoiceItem", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu.ChoiceItem" xml:space="preserve"> 14359 <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 }"> 14360 <span t-esc="choice.label"/> 14361 </div> 14362 <DropdownItem t-if="!choice.isGroup" onSelected="() => this.onItemSelected(choice.value)" class="getItemClass(choice) + ' text-wrap'" attrs="{ 'data-choice-index': choice_index }"> 14363 <t t-if="props.slots and props.slots.choice" t-slot="choice" data="choice"/> 14364 <t t-else=""> 14365 <div t-esc="choice.label || choice.value"/> 14366 </t> 14367 </DropdownItem> 14368 </t> 14369 14370`); 14371registerTemplate("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"> 14372 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" t-att-width="width" t-att-height="height"> 14373 <defs> 14374 <style type="text/css"> 14375 @font-face { 14376 font-family: "font"; 14377 src: url(data:font/ttf;base64,<t t-esc="font"/>) format("woff"); 14378 font-weight: normal; 14379 font-style: normal; 14380 } 14381 </style> 14382 </defs> 14383 14384 <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
14384-att-lengthAdjust="'spacing' + (type === 'signature' ? 'AndGlyphs' : '')" t-attf-style="font-family:'font'; stroke: none; fill: {{color}};" text-anchor="middle"/> 14385 </svg> 14386 </t> 14387 14388 14389 `); 14390registerTemplate("web.NameAndSignature", `/web/static/src/core/signature/name_and_signature.xml`, `<t t-name="web.NameAndSignature" xml:space="preserve"> 14391 <div class="o_web_sign_name_and_signature"> 14392 <div t-if="!props.noInputName" class="o_web_sign_name_group"> 14393 <label class="col-form-label" t-att-for="'o_web_sign_name_input_' + htmlId">Full Name</label> 14394 <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=""/> 14395 </div> 14396 14397 14398 <div t-if="state.showSignatureArea" class="o_web_sign_signature_group bg-100 card mt-3" style="overflow: hidden;"> 14399 <div class="card-header bg-transparent"> 14400 <div class="row g-0"> 14401 <div t-if="!props.noInputName or defaultName" class="col-auto"> 14402 <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': '' }}"> 14403 Auto 14404 </a> 14405 </div> 14406 <div class="col-auto"> 14407 <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': '' }}"> 14408 Draw 14409 </a> 14410 </div> 14411 <div class="col-auto"> 14412 <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': '' }}"> 14413 Load 14414 </a> 14415 </div> 14416 14417 <div class="col-auto division ms-auto"/> 14418 14419 <div t-if="state.signMode === 'auto'" class="o_web_sign_auto_select_style col-auto"> 14420 <Dropdown> 14421 <button type="button" class="btn btn-link fa fa-font o-dropdown-caret"/> 14422 <t t-set-slot="content"> 14423 <t t-foreach="fonts" t-as="font" t-key="font_index"> 14424 <DropdownItem onSelected="() => this.onSelectFont(font_index)"> 14425 <img class="img-fluid" t-att-src="getSVGTextFont(font)"/> 14426 </DropdownItem> 14427 </t> 14428 </t> 14429 </Dropdown> 14430 </div> 14431 14432 <div t-if="state.signMode === 'draw'" t-attf-class="o_web_sign_draw_clear col-auto"> 14433 <a role="button" href="#" t-on-click.prevent="onClickSignDrawClear" class="btn btn-link fa fa-trash"/> 14434 </div> 14435 14436 <div t-if="state.signMode === 'load'" class="o_web_sign_load_file col-auto"> 14437 <button type="button" id="loadFileXml" t-on-click="uploadFile" class="btn btn-link fa fa-upload"/> 14438 <input t-ref="signInputLoad" type="file" role="button" name="files[]" class="d-none" t-on-change="onChangeSignLoadInput"/> 14439 </div> 14440 </div> 14441 </div> 14442 14443 <div class="o_web_sign_signature_container position-relative"> 14444 <div class="o_signature_stroke position-absolute"/> 14445 <canvas t-if="state.showSignatureArea" t-ref="signature" class="o_web_sign_signature z-1"/> 14446 </div> 14447 14448 <div t-if="loadIsInvalid" t-attf-class="o_web_sign_load_invalid card-footer d-none"> 14449 <div class="alert alert-danger mb-0" role="alert">
14450 This file is invalid. Please select an image. 14451 </div> 14452 </div> 14453 </div> 14454 </div> 14455 </t> 14456`); 14457registerTemplate("web.SignatureDialog", `/web/static/src/core/signature/signature_dialog.xml`, `<t t-name="web.SignatureDialog" xml:space="preserve"> 14458 <Dialog title.translate="Adopt Your Signature"> 14459 <div> 14460 <NameAndSignature t-props="nameAndSignatureProps"/> 14461 <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> 14462 </div> 14463 <t t-set-slot="footer"> 14464 <button class="btn btn-primary" t-att-disabled="signature.isSignatureEmpty" t-on-click="onClickConfirm">Adopt & Sign</button> 14465 <button class="btn btn-secondary" t-on-click="props.close">Cancel</button> 14466 </t> 14467 </Dialog> 14468 </t> 14469 14470`); 14471registerTemplate("web.TagsList", `/web/static/src/core/tags_list/tags_list.xml`, `<t t-name="web.TagsList" xml:space="preserve"> 14472 <t t-foreach="visibleTags" t-as="tag" t-key="tag.id or tag_index"> 14473 <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)"> 14474 14475 14476 <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"/> 14477 14478 <img t-if="tag.img" t-att-src="tag.img" class="o_avatar o_m2m_avatar position-relative rounded" t-att-class="tag.imageClass"/> 14479 14480 <i t-if="tag.icon" t-attf-class="p-1 fa {{ tag.icon }}" t-att-class="tag.className"/> 14481 14482 <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"/> 14483 14484 <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="#"> 14485 <i class="oi oi-close align-text-top"/> 14486 </a> 14487 </span> 14488 </t> 14489 <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=""> 14490 <span t-if="otherTags.length > 9" t-esc="'9+'"/> 14491 <span t-else="" t-esc="'+' + otherTags.length"/> 14492 </span> 14493 </t> 14494 14495 `); 14496registerTemplate("web.TagsList.Tooltip", `/web/static/src/core/tags_list/tags_list.xml`, `<t t-name="web.TagsList.Tooltip" xml:space="preserve"> 14497 <t t-foreach="tags" t-as="tag" t-key="tag.id or tag_index"> 14498 <div t-esc="tag.text"/> 14499 </t> 14500 </t> 14501 14502`); 14503registerTemplate("web.TimePicker", `/web/static/src/core/time_picker/time_picker.xml`, `<t t-name="web.TimePicker" xml:space="preserve"> 14504 <div class="o_time_picker d-flex align-items-center justify-content-center" t-att-class="cssClass"> 14505 <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">
14506 <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"/> 14507 <t t-set-slot="content"> 14508 <t t-foreach="suggestions" t-as="value" t-key="value_index"> 14509 <DropdownItem class="'o_time_picker_option'" t-out="value.toString()" onSelected="() => this.onItemSelected(value)" closingMode="'none'"/> 14510 </t> 14511 </t> 14512 </Dropdown> 14513 </div> 14514 </t> 14515`); 14516registerTemplate("web.Tooltip", `/web/static/src/core/tooltip/tooltip.xml`, `<t t-name="web.Tooltip" xml:space="preserve"> 14517 <div class="o-tooltip tooltip-inner d-print-none text-start"> 14518 <t t-if="props.template" t-call="{{props.template}}" t-call-context="{ env, ...props.info }"/> 14519 <span t-else="" t-esc="props.tooltip"/> 14520 </div> 14521 </t> 14522 14523`); 14524registerTemplate("web.TreeEditor", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor" xml:space="preserve"> 14525 <div class="o_tree_editor w-100" aria-atomic="true" t-att-class="className"> 14526 <div t-attf-class="o_tree_editor_node d-flex flex-column #{props.readonly ? (props.isSubTree ? 'gap-0' : 'gap-2') : 'gap-1'}"> 14527 <t t-set="ancestors" t-value="[]"/> 14528 <t t-set="node" t-value="tree"/> 14529 <div class="o_tree_editor_row o_tree_editor_connector d-flex align-items-center flex-wrap" t-att-class="{'ps-4': props.isSubTree}"> 14530 <div class="d-flex flex-grow-1 align-items-center"> 14531 <t t-if="node.children.length"> 14532 <span t-if="!props.isSubTree">Match</span> 14533 <t t-call="web.TreeEditor.connector.value"/> 14534 <span t-if="props.isSubTree">of:</span> 14535 <span t-else="">of the following rules:</span> 14536 </t> 14537 <t t-elif="node.value === '|' ? node.negate : !node.negate"> 14538 <span><span t-if="!props.isSubTree">Match </span><strong>all records</strong></span> 14539 </t> 14540 <t t-else=""> 14541 <span><span t-if="!props.isSubTree">Match </span><strong>no records</strong></span> 14542 </t> 14543 </div> 14544 <t t-slot="default"/> 14545 </div> 14546 <t t-if="node.children.length" t-call="web.TreeEditor.connector.children"/> 14547 <t t-if="!props.readonly"> 14548 <div class="o_tree_editor_row d-flex align-items-center" t-att-class="{ 'ps-4': addPadding || props.isSubTree }"> 14549 <a href="#" role="button" t-on-click="() => this.addNewCondition(node)">New Rule</a> 14550 </div> 14551 </t> 14552 </div> 14553 </div> 14554 </t> 14555 14556 `); 14557registerTemplate("web.TreeEditor.controls", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.controls" xml:space="preserve"> 14558 <div class="o_tree_editor_node_control_panel d-flex" role="toolbar" aria-label="Domain node"> 14559 <t t-if="node.type !== 'connector'"> 14560 <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)"> 14561 <i class="fa fa-sitemap"/> 14562 </button> 14563 <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)"> 14564 <i class="fa fa-plus"/> 14565 </button> 14566 </t> 14567 <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)">
14568 <i class="fa fa-trash"/> 14569 </button> 14570 </div> 14571 </t> 14572 14573 `); 14574registerTemplate("web.TreeEditor.connector.value", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.value" xml:space="preserve"> 14575 <t t-set="title"> 14576 <t t-if="node.value === '|'"> 14577 <t t-if="node.negate">none</t> 14578 <t t-else="">any</t> 14579 </t> 14580 <t t-else=""> 14581 <t t-if="node.negate">not all</t> 14582 <t t-else="">all</t> 14583 </t> 14584 </t> 14585 <t t-if="props.readonly"> 14586 <div class="o_tree_editor_connector_value px-1"> 14587 <strong class="text-primary" t-esc="title"/> 14588 </div> 14589 </t> 14590 <t t-else=""> 14591 <div class="o_tree_editor_connector_value px-1" aria-atomic="true"> 14592 <button class="btn o-dropdown o-dropdown-caret p-0 opacity-75" t-on-click="() => this.updateConnector(node)"> 14593 <strong class="text-primary" t-esc="title"/> 14594 </button> 14595 </div> 14596 </t> 14597 </t> 14598 14599 `); 14600registerTemplate("web.TreeEditor.connector.children", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.children" xml:space="preserve"> 14601 <t t-foreach="node.children" t-as="child" t-key="child.type + '_' + child_index"> 14602 <div class="o_tree_editor_node" t-att-class="{ 'ps-4': addPadding || props.isSubTree }"> 14603 <t t-call="web.TreeEditor.{{ child.type }}"> 14604 <t t-set="ancestors" t-value="[...ancestors, node]"/> 14605 <t t-set="parent" t-value="node"/> 14606 <t t-set="node" t-value="child"/> 14607 </t> 14608 </div> 14609 </t> 14610 </t> 14611 14612 `); 14613registerTemplate("web.TreeEditor.connector", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector" xml:space="preserve"> 14614 <div class="o_tree_editor_row o_tree_editor_connector d-flex align-items-center"> 14615 <div class="d-flex flex-grow-1"> 14616 <t t-call="web.TreeEditor.connector.value"/> 14617 <span>of:</span> 14618 </div> 14619 <t t-if="!props.readonly"> 14620 <t t-call="web.TreeEditor.controls"/> 14621 </t> 14622 </div> 14623 <t t-call="web.TreeEditor.connector.children"> 14624 <t t-set="addPadding" t-value="true"/> 14625 </t> 14626 </t> 14627 14628 `); 14629registerTemplate("web.TreeEditor.condition", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition" xml:space="preserve"> 14630 <div class="o_tree_editor_row d-flex align-items-center"> 14631 <t t-if="props.readonly"> 14632 <t t-call="web.TreeEditor.condition:readonly"/> 14633 </t> 14634 <t t-else=""> 14635 <t t-call="web.TreeEditor.condition:editable"/> 14636 <t t-call="web.TreeEditor.controls"/> 14637 </t> 14638 </div> 14639 <t t-if="isTree(node.value)"> 14640 <TreeEditor t-props="props" update="(value) => this.updateLeafValue(node, value)" slots="{}" isSubTree="true" tree="node.value" resModel="getResModel(node)"/> 14641 </t> 14642 </t> 14643 14644 `); 14645registerTemplate("web.TreeEditor.condition:readonly", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition:readonly" xml:space="preserve"> 14646 <t t-set="description" t-value="getConditionDescription(node)"/> 14647 <div class="o_tree_editor_condition d-flex gap-1 px-2 border bg-100"> 14648 <div class="fw-bolder text-nowrap" t-esc="description.pathDescription"/> 14649 <div class="fst-italic text-nowrap" t-esc="description.operatorDescription"/> 14650 <t t-if="description.valueDescription"> 14651 <t t-set="values" t-value="description.valueDescription.values"/> 14652 <t t-set="join" t-value="description.valueDescription.join"/> 14653 <t t-set="addParenthesis" t-value="description.valueDescription.addParenthesis"/> 14654 <t t-if="addParenthesis">( </t> 14655 <t t-foreach="values" t-as="val" t-key="val_index">
14656 <span class="text-primary fw-bolder"><t t-esc="val"/></span> 14657 <t t-if="!val_last"> <t t-esc="join"/> </t> 14658 </t> 14659 <t t-if="addParenthesis"> )</t> 14660 </t> 14661 </div> 14662 </t> 14663 14664 `); 14665registerTemplate("web.TreeEditor.Editor", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.Editor" xml:space="preserve"> 14666 <t t-if="!info.isSupported(value)"> 14667 <div t-attf-class="o_tree_editor_editor #{_classes}"> 14668 <div class="o_input d-flex align-items-center"> 14669 <span class="flex-grow-1 text-truncate" t-esc="info.stringify(value)"/> 14670 <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"/> 14671 <i class="fa fa-times" data-tooltip="Clear" t-on-click="() => update(info.defaultValue())"/> 14672 </div> 14673 </div> 14674 </t> 14675 <t t-elif="info.component"> 14676 <div t-attf-class="o_tree_editor_editor #{_classes}"> 14677 <t t-component="info.component" t-props="info.extractProps({ update, value, displayPlaceholder })"/> 14678 </div> 14679 </t> 14680 </t> 14681 14682 `); 14683registerTemplate("web.TreeEditor.condition:editable", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition:editable" xml:space="preserve"> 14684 <div class="o_tree_editor_condition d-flex flex-grow-1 align-items-end gap-2"> 14685 <t t-call="web.TreeEditor.Editor"> 14686 <t t-set="_classes" t-value="'col col-md-4 pe-0'"/> 14687 <t t-set="info" t-value="getPathEditorInfo()"/> 14688 <t t-set="value" t-value="node.path"/> 14689 <t t-set="update" t-value="(path) => this.updatePath(node, path)"/> 14690 </t> 14691 <t t-call="web.TreeEditor.Editor"> 14692 <t t-set="_classes" t-value="'col col-md-2 px-3'"/> 14693 <t t-set="info" t-value="getOperatorEditorInfo(node)"/> 14694 <t t-set="value" t-value="[node.operator, node.negate]"/> 14695 <t t-set="update" t-value="(operator, negate) => this.updateLeafOperator(node, operator, negate)"/> 14696 </t> 14697 <t t-call="web.TreeEditor.Editor"> 14698 <t t-set="_classes" t-value="'col ps-0 overflow-hidden'"/> 14699 <t t-set="info" t-value="getValueEditorInfo(node)"/> 14700 <t t-set="value" t-value="node.value"/> 14701 <t t-set="update" t-value="(value) => this.updateLeafValue(node, value)"/> 14702 </t> 14703 </div> 14704 </t> 14705 14706 `); 14707registerTemplate("web.TreeEditor.complex_condition", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.complex_condition" xml:space="preserve"> 14708 <div class="o_tree_editor_row d-flex align-items-center"> 14709 <div class="o_tree_editor_complex_condition flex-grow-1"> 14710 <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)"/> 14711 </div> 14712 <t t-call="web.TreeEditor.controls"/> 14713 </div> 14714 </t> 14715 14716 14717`); 14718registerTemplate("web.TreeEditor.Input", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Input" xml:space="preserve"> 14719 <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)"/> 14720 </t> 14721 14722 `); 14723registerTemplate("web.TreeEditor.Select", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Select" xml:space="preserve"> 14724 <select class="o_input pe-3 text-truncate" t-on-change="(ev) => props.update(deserialize(ev.target.value))"> 14725 <option class="o_select_placeholder" t-if="props.addBlankOption" hidden="true" t-esc="props.placeholder ? props.placeholder : ''"/> 14726 <t t-foreach="props.options" t-as="option" t-key="serialize(option[0])"> 14727 <option class="text-black" t-att-value="serialize(option[0])" t-att-selected="!props.addBlankOption and option[0] === props.value" t-esc="option[1]"/> 14728 </t> 14729 </select> 14730 </t> 14731 14732 `); 14733registerTemplate("web.TreeEditor.Range", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Range" xml:space="preserve"> 14734 <div class="d-flex align-items-center"> 14735 <t t-call="web.TreeEditor.Editor"> 14736 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14737 <t t-set="info" t-value="props.editorInfo"/> 14738 <t t-set="value" t-value="props.value[0]"/> 14739 <t t-set="update" t-value="(val) => this.update(0, val)"/> 14740 </t> 14741 <i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow"/> 14742 <t t-call="web.TreeEditor.Editor"> 14743 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14744 <t t-set="info" t-value="props.editorInfo"/> 14745 <t t-set="value" t-value="props.value[1]"/> 14746 <t t-set="update" t-value="(val) => this.update(1, val)"/> 14747 </t> 14748 </div> 14749 </t> 14750 14751 `); 14752registerTemplate("web.TreeEditor.InRange", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.InRange" xml:space="preserve"> 14753 <div class="d-flex flex-column gap-2"> 14754 <t t-call="web.TreeEditor.Editor"> 14755 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14756 <t t-set="info" t-value="props.valueTypeEditorInfo"/> 14757 <t t-set="value" t-value="props.value[1]"/> 14758 <t t-set="update" t-value="(val) =>
14758 this.updateValueType(val)"/> 14759 </t> 14760 <t t-if="props.value[1] === 'custom range'"> 14761 <t t-call="web.TreeEditor.Editor"> 14762 <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/> 14763 <t t-set="info" t-value="props.betweenEditorInfo"/> 14764 <t t-set="value" t-value="props.value.slice(2)"/> 14765 <t t-set="update" t-value="(val) => this.updateValues(val)"/> 14766 </t> 14767 </t> 14768 </div> 14769 </t> 14770 14771 `); 14772registerTemplate("web.TreeEditor.List", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.List" xml:space="preserve"> 14773 <div class="o_input d-flex flex-wrap gap-1"> 14774 <TagsList tags="tags"/> 14775 <div class="flex-grow-1"> 14776 <t t-call="web.TreeEditor.Editor"> 14777 <t t-set="info" t-value="props.editorInfo"/> 14778 <t t-set="value" t-value="props.editorInfo.defaultValue()"/> 14779 <t t-set="update" t-value="(val) => this.update(val)"/> 14780 <t t-set="displayPlaceholder" t-value="!tags.length"/> 14781 </t> 14782 </div> 14783 </div> 14784 </t> 14785 14786`); 14787registerTemplate("web.BlockUI", `/web/static/src/core/ui/block_ui.xml`, `<t t-name="web.BlockUI" xml:space="preserve"> 14788 <t t-if="state.blockState === BLOCK_STATES.UNBLOCKED"> 14789 <div/> 14790 </t> 14791 <t t-else=""> 14792 <t t-set="visiblyBlocked" t-value="state.blockState === BLOCK_STATES.VISIBLY_BLOCKED"/> 14793 <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'"> 14794 <t t-if="visiblyBlocked"> 14795 <div class="o_spinner mb-4"> 14796 <img src="/web/static/img/spin.svg" alt="Loading..."/> 14797 </div> 14798 <div class="o_message text-center px-4"> 14799 <t t-esc="state.line1"/><br/> 14800 <t t-esc="state.line2"/> 14801 </div> 14802 </t> 14803 </div> 14804 </t> 14805</t> 14806`); 14807registerTemplate("web.login_user_switch", `/web/static/src/core/user_switch/user_switch.xml`, `<t t-name="web.login_user_switch" xml:space="preserve"> 14808 <t t-if="state.users.length"> 14809 <t t-if="state.displayUserChoice"> 14810 <div class="oe_login_form o_user_switch user-select-none my-4" t-ref="root"> 14811 <p>Choose a user</p> 14812 <div class="list-group my-3"> 14813 <t t-foreach="state.users" t-as="user" t-key="user_index"> 14814 <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)"> 14815 <span class="d-flex justify-content-begin align-items-center"> 14816 <img class="o_avatar o_user_avatar rounded me-2" t-attf-src="{{getAvatarUrl(user)}}" t-att-alt="user.login"/> 14817 <t t-esc="user.name"/> 14818 </span> 14819 <i class="fa fa-times" title="Remove user from switcher" t-on-click.stop="() => this.remove(user)"/> 14820 </button> 14821 </t> 14822 </div> 14823 <button type="button" class="btn btn-link btn-sm w-100" t-on-click="() => this.fillForm()"> 14824 <i class="fa fa-user-circle-o"/> <span class="ms-1">Use another user</span> 14825 </button> 14826 </div> 14827 </t> 14828 <t t-else="" t-portal="'label.form-label'"> 14829 <button type="button" class="o_user_switch_btn btn btn-sm btn-link m-0 p-0" tabindex="1" t-on-click="() => this.toggleFormDisplay()"> 14830 Choose a user 14831 </button> 14832 </t> 14833 </t> 14834 </t> 14835`); 14836registerTemplate("web.FileUploader", `/web/static/src/views/fields/file_handler.xml`, `<t t-name="web.FileUploader" xml:space="preserve"> 14837 <div class="d-contents" t-on-click.stop=""> 14838 <t t-if="state.isUploading and props.showUploadingText">Uploading...</t>
14839 <span t-else="" t-on-click.prevent="onSelectFileButtonClick" style="display:contents"> 14840 <t t-slot="toggler"/> 14841 </span> 14842 <t t-slot="default"/> 14843 <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"/> 14844 </div> 14845 </t> 14846 14847`); 14848registerTemplateExtension("mail.Composer.suggestionPartner", `/hr_holidays/static/src/core/common/composer_patch.xml`, `<t t-inherit="mail.Composer.suggestionPartner" t-inherit-mode="extension" xml:space="preserve"> 14849 <xpath expr="//span[@t-if='partner.email']" position="before"> 14850 <span t-if="partner.outOfOfficeDateEndText" class="text-warning me-1 smaller fw-bold opacity-75 flex-shrink-0" t-esc="partner.outOfOfficeDateEndText"/> 14851 </xpath> 14852 </t> 14853`); 14854registerTemplateExtension("mail.ImStatus", `/whatsapp/static/src/core/common/im_status_patch.xml`, `<t t-name="whatsapp.ImStatus" t-inherit="mail.ImStatus" t-inherit-mode="extension" xml:space="preserve"> 14855 <xpath expr="//i[@title='Bot']" position="after"> 14856 <i t-elif="props.member?.eq(props.member.channel_id.whatsappMember)" class="fa fa-whatsapp text-success" title="WhatsApp User" role="img" aria-label="WhatsApp User"/> 14857 </xpath> 14858 </t> 14859 14860`); 14861registerTemplateExtension("mail.Message", `/whatsapp/static/src/core/common/message_patch.xml`, `<t t-name="whatsapp.Message" t-inherit="mail.Message" t-inherit-mode="extension" xml:space="preserve"> 14862 <xpath expr="//div[hasclass('o-mail-Message-header')]" position="inside"> 14863 <t t-if="message.message_type === 'whatsapp_message'"> 14864 <span class="fa fa-whatsapp ms-1" t-att-class="getWhatsappStatusClass()" t-att-title="getWhatsappStatusTitle()"/> 14865 </t> 14866 </xpath> 14867 </t> 14868 14869`); 14870registerTemplateExtension("mail.ThreadIcon", `/whatsapp/static/src/core/common/thread_icon_patch.xml`, `<t t-name="whatsapp.ThreadIcon" t-inherit="mail.ThreadIcon" t-inherit-mode="extension" xml:space="preserve"> 14871 <xpath expr="//*[hasclass('o-mail-ThreadIcon')]" position="inside"> 14872 <t t-if="props.thread.channel_type === 'whatsapp'"> 14873 <t name="whatsapp"> 14874 <t name="whatsapp_static"> 14875 <div class="fa fa-whatsapp text-success" title="WhatsApp"/> 14876 </t> 14877 </t> 14878 </t> 14879 </xpath> 14880 </t> 14881`); 14882registerTemplateExtension("mail.Thread", `/whatsapp/static/src/core/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 14883 <xpath expr="//div[hasclass('o-mail-Thread')]" position="before"> 14884 <span t-if="isWhatsAppThreadExpired" class="o-mail-Thread-banner d-flex border-bottom border-warning smaller fw-bolder"> 14885 <span class="alert alert-warning m-0 border-start-0 py-1 flex-grow-1"> 14886 This conversation has been closed as more than 24 hours have passed since the last message received. 14887 </span> 14888 </span> 14889 </xpath> 14890 </t> 14891 14892`); 14893registerTemplateExtension("discuss.ChannelMemberList", `/whatsapp/static/src/discuss/core/common/channel_member_list_patch.xml`, `<t t-name="whatsapp.ChannelMemberList" t-inherit="discuss.ChannelMemberList" t-inherit-mode="extension" xml:space="preserve"> 14894 <xpath expr="//t[@name='offlineMembers']" position="after"> 14895 <t t-if="props.thread.whatsappMember"> 14896 <t t-call="discuss.ChannelMemberList.section"> 14897 <t t-set="sectionName">WhatsApp User</t> 14898 </t> 14899 <t t-set="member" t-value="props.thread.whatsappMember"/> 14900 <t t-call="discuss.channel_member"/> 14901 </t> 14902 </xpath> 14903 </t> 14904 14905`); 14906registerTemplate("html_editor.AttachmentError", `/html_editor/static/src/main/media/media_dialog/attachment_error.xml`, `<t t-name="html_editor.AttachmentError" xml:space="preserve"> 14907 <Dialog title="title"> 14908 <div class="form-text"> 14909 <p>The image could not be deleted because it is used in the 14910 following pages or views:</p> 14911 <ul t-foreach="props.views" t-as="view" t-key="view.id"> 14912 <li> 14913 <a t-att-href="'/odoo/ir.ui.view/' + window.encodeURIComponent(view.id)"> 14914 <t t-esc="view.name"/> 14915 </a> 14916 </li> 14917 </ul> 14918 </div> 14919 <t t-set-slot="footer"> 14920 <button class="btn btn-primary" t-on-click="() => this.props.close()"> 14921 Ok 14922 </button> 14923 </t> 14924 </Dialog> 14925</t> 14926`); 14927registerTemplate("html_editor.DocumentAttachment", `/html_editor/static/src/main/media/media_dialog/document_selector.xml`, `<t t-name="html_editor.DocumentAttachment" xml:space="preserve">
14928 <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 }"> 14929 <RemoveButton remove="() => this.remove()"/> 14930 <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"/> 14931 <button class="o_btn_reset o_button_area cursor-pointer" t-on-click="props.selectAttachment" t-att-aria-label="props.name"/> 14932 <small class="o_file_name d-block text-truncate" t-esc="props.name"/> 14933 </div> 14934</t> 14935 14936`); 14937registerTemplate("html_editor.DocumentsListTemplate", `/html_editor/static/src/main/media/media_dialog/document_selector.xml`, `<t t-name="html_editor.DocumentsListTemplate" xml:space="preserve"> 14938 <div class="o_we_existing_attachments o_we_documents" t-ref="existing-attachments"> 14939 <div t-if="!hasContent" class="o_nocontent_help"> 14940 <p class="o_empty_folder_image">No documents found.</p> 14941 <p class="o_empty_folder_subtitle">You can upload documents with the button located in the top left of the screen.</p> 14942 </div> 14943 <div t-else="" class="d-flex flex-wrap gap-2"> 14944 <t t-foreach="state.attachments" t-as="attachment" t-key="attachment.id"> 14945 <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)"/> 14946 </t> 14947 </div> 14948 </div> 14949</t> 14950`); 14951registerTemplate("html_editor.FileSelectorControlPanel", `/html_editor/static/src/main/media/media_dialog/file_selector.xml`, `<t t-name="html_editor.FileSelectorControlPanel" xml:space="preserve"> 14952 <div class="o_we_file_selector_control_panel sticky-top d-flex flex-wrap gap-2 mb-1 p-3 align-items-end"> 14953 <SearchMedia searchPlaceholder="props.searchPlaceholder" needle="props.needle" search="props.search"/> 14954 <div class="d-flex gap-3 justify-content-start align-items-center"> 14955 <div t-if="props.showOptimizedOption" class="flex-shrink-0 form-check form-switch align-items-center" t-on-change="props.changeShowOptimized"> 14956 <input class="o_we_show_optimized form-check-input" type="checkbox" t-att-checked="props.showOptimized" id="o_we_show_optimized_switch"/> 14957 <label class="form-check-label" for="o_we_show_optimized_switch"> 14958 Show optimized images 14959 </label> 14960 </div> 14961 <select t-if="showSearchServiceSelect" class="o_input o_we_search_select form-select pe-5" t-on-change="ev => props.changeSearchService(ev.target.value)"> 14962 <option t-att-selected="props.searchService === 'all'" value="all">All</option> 14963 <option t-att-selected="props.searchService === 'database'" value="database">My Images</option> 14964 <option t-if="props.useMediaLibrary" t-att-selected="props.searchService === 'media-library'" value="media-library">Illustrations</option> 14965 </select> 14966 </div> 14967 <div class="col justify-content-end flex-nowrap input-group has-validation"> 14968 <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"/> 14969 <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"> 14970 <t t-esc="props.addText"/> 14971 </button> 14972 <div class="d-flex align-items-center">
14973 <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..."/> 14974 <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."/> 14975 <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."/> 14976 <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"/> 14977 </div> 14978 </div> 14979 <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'"/> 14980 <div class="col-auto btn-group"> 14981 <button type="button" class="btn btn-secondary o_upload_media_button" t-on-click="onClickUpload"> 14982 <t t-esc="props.uploadText"/> 14983 </button> 14984 </div> 14985 </div> 14986</t> 14987 14988`); 14989registerTemplate("html_editor.FileSelector", `/html_editor/static/src/main/media/media_dialog/file_selector.xml`, `<t t-name="html_editor.FileSelector" xml:space="preserve"> 14990 <div> 14991 <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"/> 14992 <t t-call="{{ constructor.attachmentsListTemplate }}"/> 14993 <div name="load_more_attachments" class="pt-3 pb-1 text-center mx-auto o_we_load_more" t-ref="load-more-button"> 14994 <button t-if="canLoadMore" class="btn btn-primary o_load_more" type="button" t-on-click="handleLoadMore"> 14995 Load more... 14996 </button> 14997 <div t-elif="hasContent" class="mt-2 o_load_done_msg"> 14998 <span><i t-esc="allLoadedText"/></span> 14999 </div> 15000 </div> 15001 <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"/> 15002 </div> 15003</t> 15004`); 15005registerTemplate("html_editor.IconSelector", `/html_editor/static/src/main/media/media_dialog/icon_selector.xml`, `<t t-name="html_editor.IconSelector" xml:space="preserve"> 15006 <div> 15007 <div class="o_we_file_selector_control_panel sticky-top d-flex gap-2 align-items-center mb-1 py-4 px-3"> 15008 <SearchMedia searchPlaceholder.translate="Search a pictogram" search.bind="this.search" needle="state.needle"/> 15009 </div> 15010 <div class="font-icons-icons"> 15011 <t t-foreach="state.fonts" t-as="font" t-key="font.base"> 15012 <div t-if="!font.icons.length" class="o_nocontent_help"> 15013 <p class="o_empty_folder_image">No pictograms found.</p> 15014 <p class="o_empty_folder_subtitle">Try searching with other keywords.</p> 15015 </div> 15016 <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)"/> 15017 </t> 15018 </div> 15019 </div> 15020</t> 15021`); 15022registerTemplate("html_editor.AutoResizeImage", `/html_editor/static/src/main/media/media_dialog/image_selector.xml`, `<t t-name="html_editor.AutoResizeImage" xml:space="preserve"> 15023 <div t-ref="auto-resize-image-container" class="o_existing_attachment_cell o_
15023we_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, }"> 15024 <RemoveButton t-if="props.isRemovable" model="props.model" remove="() => this.remove()"/> 15025 <div class="o_we_media_dialog_img_wrapper" t-att-class="{ 'bg-light': props.unselectable }"> 15026 <t t-set="unselectable_attachment_title">You can not use this image in a field</t> 15027 <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"/> 15028 <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"/> 15029 </div> 15030 <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"/> 15031 <span t-if="props.isOptimized" class="badge position-absolute bottom-0 end-0 m-1 text-bg-success">Optimized</span> 15032 </div> 15033</t> 15034 15035`); 15036registerTemplate("html_editor.ExternalImage", `/html_editor/static/src/main/media/media_dialog/image_selector.xml`, `<t t-name="html_editor.ExternalImage" xml:space="preserve"> 15037 <t t-if="record.mediaType == 'libraryMedia'"> 15038 <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)"/> 15039 </t> 15040</t> 15041 15042`); 15043registerTemplate("html_editor.ImagesListTemplate", `/html_editor/static/src/main/media/media_dialog/image_selector.xml`, `<t t-name="html_editor.ImagesListTemplate" xml:space="preserve"> 15044 <div class="o_we_existing_attachments o_we_images d-flex flex-wrap my-0" t-ref="existing-attachments"> 15045 <t t-if="!hasContent and !isFetching"> 15046 <div t-if="state.needle" class="o_nocontent_help"> 15047 <p class="o_empty_folder_image">No images found.</p> 15048 <p class="o_empty_folder_subtitle">Wow, it feels a bit empty in here. Upload from the button in the top right corner!</p> 15049 </div> 15050 <div t-else="" class="o_we_search_prompt"> 15051 <h2>Search the web for royalty-free images</h2> 15052 </div> 15053 </t> 15054 <t t-else=""> 15055 <t t-if="['all', 'database'].includes(state.searchService)"> 15056 <t t-foreach="state.attachments" t-as="attachment" t-key="attachment.id"> 15057 <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)"/> 15058 </t> 15059 </t> 15060 <t id="o_we_media_library_images" t-if="['all', 'media-library'].includes(state.searchService)"> 15061 <t t-foreach="state.libraryMedia" t-as="record" t-key="record.id"> 15062 <t t-call="html_editor.ExternalImage"/> 15063 </t> 15064 </t> 15065 15066 <t t-foreach="[...Array(20).keys()]" t-as="i" t-key="i"> 15067 <div class="o_we_attachment_placeholder"/> 15068 </t> 15069 </t> 15070 </div> 15071</t> 15072`); 15073registerTemplate("html_editor.MediaDialog", `/html_editor/static/src/main/media/media_dialog/media_dialog.xml`, `<t t-name="html_editor.MediaDialog" xml:space="preserve"> 15074 <Dialog contentClass="contentClass" size="size" title="title" modalRef="modalRef"> 15075 <Notebook pages="notebookPages" onPageUpdate.bind="onTabChange" defaultPage="state.activeTab"/> 15076 <t t-set-slot="footer"> 15077 <button class="btn btn-primary" t-on-click="() => this.save()" t-ref="add-button">Add</button> 15078 <button class="btn btn-secondary" t-on-click="() => this.close()">Discard</button> 15079 </t> 15080 </Dialog> 15081</t> 15082`); 15083registerTemplate("html_editor.SearchMedia", `/html_editor/static/src/main/media/media_dialog/search_media.xml`, `<t t-name="html_editor.SearchMedia" xml:space="preserve"> 15084 <div class="position-relative mw-lg-25 flex-grow-1 me-auto"> 15085 <input type="text" class="o_we_search o_input form-control pe-4" t-att-placeholder="props.searchPlaceholder.trim()" t
15085-model="state.input" t-ref="autofocus"/> 15086 <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"/> 15087 </div> 15088</t> 15089`); 15090registerTemplate("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"> 15091 <small class="text-info d-flex align-items-center me-2"> 15092 <span t-if="!props.hasError and !props.uploaded"><i class="fa fa-circle-o-notch fa-spin me-2"/></span> 15093 <span class="fst-italic fw-bold text-truncate flex-grow-1 me-2" t-esc="props.name"/> 15094 <span class="fw-bold text-nowrap" t-esc="props.size"/> 15095 </small> 15096 <small t-if="props.uploaded or props.hasError" class="d-flex align-items-center mt-1"> 15097 <span t-if="props.uploaded" class="text-success"><i class="fa fa-check my-1 me-1"/> File has been uploaded</span> 15098 <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> 15099 </small> 15100 <div t-else="" class="progress mt-2"> 15101 <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> 15102 </div> 15103 <hr/> 15104</t> 15105 15106`); 15107registerTemplate("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"> 15108 <div class="editor_notification_manager o_notification_manager o_upload_progress_toast"> 15109 <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"> 15110 <div class="editor_notification_body o_notification_body ps-2 py-2"> 15111 <div class="me-auto o_notification_content"> 15112 <div t-foreach="state.files" t-as="file" t-key="file" class="o_we_progressbar"> 15113 <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"/> 15114 </div> 15115 </div> 15116 </div> 15117 <button type="button" class="btn btn-close o_notification_close p-2" aria-label="Close" t-on-click="props.close"/> 15118 </div> 15119 </div> 15120</t> 15121`); 15122registerTemplate("html_editor.VideoOption", `/html_editor/static/src/main/media/media_dialog/video_selector.xml`, `<t t-name="html_editor.VideoOption" xml:space="preserve"> 15123 <div class="mb-1" t-attf-class="{{ showStartAtInput ? 'd-flex align-items-start gap-2 cursor-pointer' : ''}}"> 15124 <Switch value="!!props.value" onChange="props.onChangeOption" label="props.label" description="props.description" extraClasses="'d-flex align-items-start cursor-pointer flex-shrink-0'"/> 15125 <t t-if="showStartAtInput"> 15126 <input type="text" placeholder="MM:SS" class="o_input w-lg-auto" t-att-value="props.value" t-on-input="props.onChangeStartAt"/> 15127 </t> 15128 </div> 15129</t> 15130 15131`); 15132registerTemplate("html_editor.VideoIframe", `/html_editor/static/src/main/media/media_dialog/video_selector.xml`, `<t t-name="html_editor.VideoIframe" xml:space="preserve"> 15133 <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"/> 15134</t> 15135 15136`); 15137registerTemplate("html_editor.VideoSelector", `/html_editor/static/src/main/media/media_dialog/video_selector.xml`, `<t t-name="html_editor.VideoSelector" xml:space="preserve"> 15138 <div class="row"> 15139 <div class="col mt-4 o_video_dialog_form"> 15140 <div class="mb-2"> 15141 <label for="o_video_text"> 15142 <b>Video code </b>(URL or Embed) 15143 </label> 15144 <div class="text-start"> 15145 <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> 15146 </div> 15147 <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 }"/> 15148 </div> 15149 <div t-if="shownOptions.length" class="o_video_dialog_options"> 15150 <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"/> 15151 </div> 15152 <t t-if="state.vimeoPreviews.length">
15153 <span class="fw-bold">Suggestions</span> 15154 <div id="video-suggestion" class="mt-4 d-flex flex-wrap mh-75 overflow-auto"> 15155 <t t-foreach="state.vimeoPreviews" t-as="vimeoPreview" t-key="vimeoPreview.id"> 15156 <div class="o_sample_video w-25 mh-100 cursor-pointer" t-on-click="() => this.onClickSuggestion(vimeoPreview.src)"> 15157 <img class="mw-100 mh-100 p-1" t-att-src="vimeoPreview.thumbnailSrc"/> 15158 </div> 15159 </t> 15160 </div> 15161 </t> 15162 </div> 15163 <div class="col-md-6"> 15164 <div class="o_video_preview position-relative border-0 p-3"> 15165 <div t-if="this.state.src and !this.state.errorMessage" class="o_video_dialog_preview_text mb-2">Preview</div> 15166 <div class="media_iframe_video"> 15167 <div class="media_iframe_video_size"/> 15168 <VideoIframe t-if="this.state.src and !this.state.errorMessage" src="this.state.src"/> 15169 <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"/> 15170 </div> 15171 </div> 15172 </div> 15173 </div> 15174</t> 15175`); 15176registerTemplateExtension("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"> 15177 <xpath expr="//t[@t-if]" position="after"> 15178 <t t-elif="record.mediaType === 'unsplashRecord'"> 15179 <AutoResizeImage src="record.url" author="record.user.n
15179ame" 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)"/> 15180 </t> 15181 </xpath> 15182 </t> 15183 15184 `); 15185registerTemplateExtension("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"> 15186 <xpath expr="//t[@id='o_we_media_library_images']" position="replace"> 15187 <t id="o_we_media_library_images" t-if="['all', 'unsplash', 'media-library'].includes(state.searchService)"> 15188 <t t-foreach="combinedRecords" t-as="record" t-key="record.id"> 15189 <t t-call="html_editor.ExternalImage"/> 15190 </t> 15191 </t> 15192 </xpath> 15193 </t> 15194 15195 `); 15196registerTemplateExtension("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"> 15197 <xpath expr="//div[@name='load_more_attachments']" position="before"> 15198 <div t-if="unsplashState?.unsplashError" class="d-flex mt-2 unsplash_error"> 15199 <UnsplashError title="errorTitle" subtitle="errorSubtitle" showCredentials="['key_not_found', 401].includes(unsplashState.unsplashError)" submitCredentials="(key, appId) => this.submitCredentials(key, appId)" hasCredentialsError="unsplashState.unsplashError === 401"/> 15200 </div> 15201 </xpath> 15202 </t> 15203 15204 `); 15205registerTemplateExtension("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"> 15206 <xpath expr="//FileSelectorControlPanel" position="attributes"> 15207 <attribute name="useUnsplash">unsplashState?.useUnsplash</attribute> 15208 </xpath> 15209 </t> 15210`); 15211registerTemplateExtension("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"> 15212 <xpath expr="//option[@value='media-library']" position="after"> 15213 <option t-if="props.useUnsplash" t-att-selected="props.searchService === 'unsplash'" value="unsplash">Photos (via Unsplash)</option> 15214 </xpath> 15215 </t> 15216 15217 `); 15218registerTemplate("web_unsplash.UnsplashCredentials", `/web_unsplash/static/src/unsplash_credentials/unsplash_credentials.xml`, `<t t-name="web_unsplash.UnsplashCredentials" xml:space="preserve"> 15219 <div class="d-flex align-items-center flex-wrap"> 15220 <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> 15221 and paste it here: 15222 <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 }"/> 15223 and paste 15224 <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> 15225 here: 15226 <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 }"/> 15227 <button type="button" class="btn btn-primary w-auto ms-3 p-auto save_unsplash" t-on-click="() => this.submitCredentials()">Apply</button> 15228 </div> 15229 </t> 15230`); 15231registerTemplate("web_unsplash.UnsplashError", `/web_unsplash/static/src/unsplash_error/unsplash_error.xml`, `<t t-name="web_unsplash.UnsplashError" xml:space="preserve"> 15232 <div class="alert alert-info w-100"> 15233 <h4><t t-esc="props.title"/></h4> 15234 <p><t t-esc="props.subtitle"/></p> 15235 <UnsplashCredentials t-if="props.showCredentials" submitCredentials="props.submitCredentials" hasCredentialsError="props.hasCredentialsError"/> 15236 </div> 15237 </t> 15238`); 15239registerTemplate("html_editor.HtmlViewer", `/html_editor/static/src/components/html_viewer/html_viewer.xml`, `<t t-name="html_editor.HtmlViewer" xml:space="preserve"> 15240 <t t-if="this.showIframe"> 15241 <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"/> 15242 </t> 15243 <t t-else="">
15244 <div t-ref="readonlyContent" class="o_readonly" t-out="state.value"/> 15245 </t> 15246 </t> 15247`); 15248registerTemplate("html_editor.LocalOverlayContainer", `/html_editor/static/src/local_overlay_container.xml`, `<t t-name="html_editor.LocalOverlayContainer" xml:space="preserve"> 15249 <div class="o-wysiwyg-local-overlay position-relative h-0 w-0" t-ref="localOverlay"/> 15250 <div class="o-wysiwyg-local-overlay position-relative h-0 w-0"> 15251 <t t-foreach="Components.entries" t-as="C" t-key="C[0]"> 15252 <div class="oe-local-overlay" t-att-data-oe-local-overlay-id="C[0]"> 15253 <ErrorHandler onError="error => this.handleComponentError(error, C)"> 15254 <t t-component="C[1].Component" t-props="C[1].props"/> 15255 </ErrorHandler> 15256 </div> 15257 </t> 15258 </div> 15259 </t> 15260`); 15261registerTemplate("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"> 15262 <span class="o_embedded_toolbar d-flex justify-content-end align-items-center"> 15263 <span t-attf-class="btn-group d-flex flex-wrap #{ props.buttonsGroupClass ? props.buttonsGroupClass : '' }"> 15264 <t t-slot="buttons"/> 15265 </span> 15266 </span> 15267 </t> 15268 `); 15269registerTemplate("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"> 15270 <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"> 15271 <i t-if="props.icon" t-attf-class="fa #{props.icon} me-1"/> 15272 <span class="o_embedded_toolbar_button_text" t-out="props.label"/> 15273 </button> 15274 </t> 15275`); 15276registerTemplate("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"> 15277 <xpath expr="//span[hasclass('o_file_image')]" position="inside"> 15278 <a t-att-href="fileModel.downloadUrl" t-on-click.prevent.stop="onClickFileImage" class="w-100"/> 15279 </xpath> 15280 15281 <xpath expr="//span[hasclass('o_file_name_container')]/a" position="replace"> 15282 <span class="o_file_name" t-out="fileModel.filename"/> 15283 </xpath> 15284 15285 <xpath expr="//span[hasclass('o_file_name_container')]" position="after"> 15286 <span class="flex-grow-1 d-flex justify-content-end"> 15287 15288 <EmbeddedComponentToolbar> 15289 <t t-set-slot="buttons"/> 15290 </EmbeddedComponentToolbar> 15291 </span> 15292 </xpath> 15293 15294 </t> 15295 15296`); 15297registerTemplate("html_editor.StaticFileBox", `/html_editor/static/src/others/embedded_components/core/file/static_file.xml`, `<t t-name="html_editor.StaticFileBox" xml:space="preserve"> 15298 <span class="d-flex flex-grow-1 align-items-center alert alert-info"> 15299 15300 <span class="o_file_image d-flex o_image user-select-none" t-att-title="fileModel.filename" t-att-data-mimetype="fileModel.mimetype"/> 15301 15302 <span class="o_file_name_container mx-2 d-flex flex-grow-1"> 15303 <a class="o_link_readonly w-100" t-att-href="fileModel.downloadUrl" t-out="fileModel.filename" contenteditable="false"/> 15304 </span> 15305 </span> 15306 </t> 15307`); 15308registerTemplate("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"> 15309 <div class="px-1" t-att-class="{ 'pb-1' : !state.folded and state.toc.headings.length }"> 15310 <div class="d-flex align-items-center cursor-pointer user-select-none" t-on-click="() => { this.state.folded = !this.state.folded; }"> 15311 <div class="o_embedded_toc_label p-1 fw-bold"> 15312 Table of Contents 15313 <i t-attf-class="align-self-center fa fa-fw fa-caret-#{ state.folded ? 'right' : 'down' }"/> 15314 </div> 15315 </div> 15316 <div t-if="!state.folded" class="o_embedded_toc_content"> 15317 <t t-foreach="this.state.toc.headings" t-as="heading" t-key="heading_index"> 15318 <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}"/> 15319 </t> 15320 </div> 15321 </div> 15322 <div class="p-1" t-if="displayTocHint()"> 15323 <i class="o_embedded_toc_hint px-1"> 15324 Add headings to fill the Table of Contents 15325 </i> 15326 </div> 15327</t> 15328`); 15329registerTemplate("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"> 15330 <div class="d-flex flex-row align-items-center"> 15331 <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"> 15332 <i t-attf-class="fa align-self-center fa-caret-{{this.state.showContent ? 'down' : 'right'}}"/> 15333 </button> 15334 <div class="flex-fill ms-1" t-ref="title"/> 15335 </div> 15336 <div class="ps-4 ms-1" t-att-class="{ 'd-none': !state.showContent }" t-ref="content"/> 15337 </t> 15338`); 15339registerTemplate("html_editor.EmbeddedVideo", `/html_editor/static/src/others/embedded_components/core/video/readonly_video.xml`, `<t t-name="html_editor.EmbeddedVideo" xml:space="preserve"> 15340 <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"> 15341 Your browser does not support iframe. 15342 </iframe> 15343 </t> 15344`); 15345registerTemplate("html_editor.Wysiwyg", `/html_editor/static/src/wysiwyg.xml`, `<t t-name="html_editor.Wysiwyg" xml:space="preserve"> 15346 <div class="o-wysiwyg d-flex flex-column p-0" t-att-class="props.class" t-att-style="props.style"> 15347 <LocalOverlayContainer localOverlay="overlayRef" identifier="env.localOverlayContainerKey"/> 15348 <div class="flex-grow-1" t-att-class="{'overflow-auto': !props.iframe}"> 15349 <t t-if="props.iframe">
15350 <iframe t-ref="content" class="w-100 h-100" t-att-data-class="props.contentClass" t-on-focusout="props.onBlur"/> 15351 </t> 15352 <t t-else=""> 15353 <div t-att-class="props.contentClass" t-ref="content" t-on-focusout="props.onBlur" contenteditable="true"/> 15354 </t> 15355 </div> 15356 </div> 15357 </t> 15358`); 15359registerTemplate("html_editor.HistoryDialog", `/html_editor/static/src/components/history_dialog/history_dialog.xml`, `<t t-name="html_editor.HistoryDialog" xml:space="preserve"> 15360 <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"> 15361 <div t-attf-class="dialog-container html-history-dialog #{state.revisionLoading ? 'html-history-loading' : 'html-history-loaded'}"> 15362 <div class="revision-list d-flex flex-column align-content-stretch" t-attf-style="max-height: {{state.cssMaxHeight}}px;"> 15363 <t t-if="!state.revisionsData.length"> 15364 <div class="text-center w-100 pb-2 pt-0 px-0 fw-bolder">No history</div> 15365 </t> 15366 15367 <t t-foreach="state.revisionsData" t-as="rev" t-key="rev.revision_id"> 15368 <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 )"> 15369 <small><t t-esc="this.getRevisionDate(rev)"/></small> 15370 <div class="o_avatar"> 15371 <img class="rounded" t-att-src="this.getRevisionAuthorAvatar(rev)" t-att-alt="rev.create_user_name" t-att-title="rev.create_user_name"/> 15372 </div> 15373 </a> 15374 </t> 15375 </div> 15376 <div class="history-container" t-attf-style="max-height: {{state.cssMaxHeight}}px;"> 15377 <div t-attf-class="history-content-view #{state.currentView === 'content' ? '' : 'd-none'}"> 15378 <div class="history-view-top-bar"> 15379 <div> 15380 <div class="text-info smaller"> 15381 <i class="fa fa-info-circle me-1" title="Version date"/> 15382 Showing the document as it was on <t t-esc="this.getRevisionDate(this.currentRevision)"/>, submited by <t t-esc="this.currentRevision.create_user_name"/> 15383 </div> 15384 </div> 15385 <div> 15386 <a type="object" href="#" role="button" class="btn btn-secondary" t-on-click="() => state.currentView = 'comparison'"> 15387 <i class="fa fa-exchange" title="View comparison"/> 15388 View comparison 15389 </a> 15390 </div> 15391 </div> 15392 <div class="history-view-inner" t-attf-style="max-height: {{state.cssMaxHeight-20}}px;"> 15393 <t t-if="state.revisionLoading"> 15394 <div class="d-flex flex-column justify-content-center align-items-center"> 15395 <img src="/web/static/img/spin.svg" alt="Loading..." class="me-2" style="filter: invert(1); opacity: 0.5; width: 30px; height: 30px;"/> 15396 <p class="m-0 text-muted loading-text"> 15397 <em>Loading...</em> 15398 </p> 15399 </div> 15400 </t> 15401 <t t-elif="state.revisionContent?.length"> 15402 <div class="pe-none"> 15403 <HtmlViewer config="getConfig('revisionContent')"/> 15404 </div> 15405 </t> 15406 <t t-else="" t-out="props.noContentHelper"/> 15407 </div> 15408 </div> 15409 <div t-attf-class="history-comparison-view #{state.currentView === 'comparison' ? '' : 'd-none'}"> 15410 <div class="history-view-top-bar"> 15411 <t t-if="env.debug"> 15412 <div class="toggle-view-btns"> 15413 <div class="btn-group" role="group"> 15414 <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'"/> 15415 <label class="btn btn-secondary" for="unified-view-btn">Unified view</label> 15416 <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' : ''"/> 15417 <label class="btn btn-secondary" for="split-view-btn">Split view</label> 15418 </div> 15419 </div> 15420 </t> 15421 <div> 15422 <div class="text-info smaller"> 15423 <i class="fa fa-info-circle me-1" title="Version date"/> 15424 Showing all differences between the current version and the selected one updated by <t t
15424-esc="this.currentRevision.create_user_name"/> on <t t-esc="this.getRevisionDate(this.currentRevision)"/> 15425 </div> 15426 </div> 15427 <div> 15428 <a type="object" href="#" role="button" class="btn btn-secondary" t-on-click="() => state.currentView = 'content'"> 15429 <i class="fa fa-eye" title="View Content"/> 15430 View content 15431 </a> 15432 </div> 15433 </div> 15434 <div class="history-view-inner" t-attf-style="max-height: {{state.cssMaxHeight-60}}px;"> 15435 <t t-if="state.revisionLoading"> 15436 <div class="d-flex flex-column justify-content-center align-items-center"> 15437 <img src="/web/static/img/spin.svg" alt="Loading..." class="me-2" style="filter: invert(1); opacity: 0.5; width: 30px; height: 30px;"/> 15438 <p class="m-0 text-muted loading-text"> 15439 <em>Loading...</em> 15440 </p> 15441 </div> 15442 </t> 15443 <t t-elif="state.revisionComparison?.length"> 15444 <div t-attf-class="history-comparison-split #{state.isComparisonSplit ? '' : 'd-none'}"> 15445 <HtmlViewer config="getConfig('revisionComparisonSplit')"/> 15446 </div> 15447 <div t-attf-class="pe-none history-comparison-unified #{state.isComparisonSplit ? 'd-none' : ''}"> 15448 <HtmlViewer config="getConfig('revisionComparison')"/> 15449 </div> 15450 </t> 15451 <t t-else=""> 15452 <span class="text-muted fst-italic">This is the current version, nothing to compare.</span> 15453 </t> 15454 </div> 15455 </div> 15456 </div> 15457 </div> 15458 <t t-set-slot="footer"> 15459 <button class="btn btn-primary" t-on-click="_onRestoreRevisionClick" t-att-disabled="state.revisionLoading || state.revisionId === -1">Restore history</button> 15460 <button class="btn btn-secondary" t-on-click="props.close">Discard</button> 15461 </t> 15462 </Dialog> 15463 </t> 15464`); 15465registerTemplate("html_editor.AlignSelector", `/html_editor/static/src/main/align/align_selector.xml`, `<t t-name="html_editor.AlignSelector" xml:space="preserve"> 15466 <Dropdown menuClass="'o-we-toolbar-dropdown'" bottomSheet="false" menuRef="menuRef"> 15467 <button class="btn btn-light" t-att-title="props.title" name="text_align"> 15468 <span class="px-1 d-flex align-items-center"> 15469 <i t-att-class="\`fa fa-align-\${state.displayName}\`"/> 15470 </span> 15471 </button> 15472 <t t-set-slot="content"> 15473 <div data-prevent-closing-overlay="true"> 15474 <t t-foreach="items" t-as="item" t-key="item_index"> 15475 <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="() => {}"/> 15476 </t> 15477 </div> 15478 </t> 15479 </Dropdown> 15480 </t> 15481`); 15482registerTemplate("html_editor.ChatGPTTranslateDialog", `/html_editor/static/src/main/chatgpt/chatgpt_translate_dialog.xml`, `<t t-name="html_editor.ChatGPTTranslateDialog" xml:space="preserve"> 15483 <Dialog size="'lg'" title.translate="Translate with AI"> 15484 <div t-if="state.translationInProgress" class="d-flex"> 15485 <img src="/web/static/img/spin.svg" alt="Loading..." class="me-2" style="filter:invert(1); opacity: 0.5; width: 30px; height: 30px;"/> 15486 <p class="m-0 text-muted align-self-center"> 15487 <em>Translating...</em> 15488 </p> 15489 </div> 15490 <t t-else=""> 15491 <t t-set="message" t-value="state.messages[0]"/> 15492 <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"> 15493 <t t-out="formatContent(message.text)"/> 15494 </div> 15495 </t> 15496 15497 15498 <t t-set-slot="footer"> 15499 <button class="btn btn-primary" t-on-click="_confirm" t-att-disabled="state.translationInProgress || state.messages[0].isError">Insert</button> 15500 <button class="btn btn-secondary" t-on-click="_cancel">Cancel</button> 15501 </t> 15502 </Dialog> 15503</t> 15504`); 15505registerTemplate("html_editor.LanguageSelector", `/html_editor/static/src/main/chatgpt/language_selector.xml`, `<t t-name="html_editor.LanguageSelector" xml:space="preserve"> 15506 <t t-if="state.languages.length === 1"> 15507 <t t-call="html_editor.translateButton"> 15508 <t t-set="onClick" t-value="() => this.onSelected(state.languages[0][1])"/> 15509 </t> 15510 </t> 15511 <Dropdown t-else="" menuRef="menuRef"> 15512 <t t-call="html_editor.translateButton"> 15513 <t t-set="onClick" t-value="() => {}"/> 15514 </t> 15515 <t t-set-slot="content"> 15516 <div data-prevent-closing-overlay="true"> 15517 <t t-foreach="state.languages" t-as="language" t-key="language[0]"> 15518 <DropdownItem class="'user-select-none'" onSelected="() => this.onSelected(language[1])"> 15519 <div class="lang" t-esc="language[1]"/> 15520 </DropdownItem> 15521 </t> 15522 </div> 15523 </t> 15524 </Dropdown> 15525 </t> 15526 15527 `); 15528registerTemplate("html_editor.translateButton", `/html_editor/static/src/main/chatgpt/language_selector.xml`, `<t t-name="html_editor.translateButton" xml:space="preserve"> 15529 <button class="btn btn-light" name="translate" t-att-title="props.title" t-att-disabled="props.isDisabled" t-on-click="onClick"> 15530 15531 <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"> 15532 <g> 15533 <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"/> 15534 <g> 15535 <g> 15536 <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"/> 15537 </g> 15538 </g> 15539 </g> 15540 </svg> 15541 </button> 15542 </t> 15543 15544`); 15545registerTemplate("html_editor.ColorPickerGradientTab", `/html_editor/static/src/main/font/color_picker_gradient_tab.xml`, `<t t-name="html_editor.ColorPickerGradientTab" xml:space="preserve"> 15546 <t t-set="currentGradient" t-value="getCurrentGradientColor()"/> 15547 <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"> 15548 <t t-set="gradientsWithOpacity" t-value="DEFAULT_GRADIENT_COLORS.map((gradient) => applyOpacityToGradient(gradient, props.defaultOpacity))"/> 15549 <t t-foreach="gradientsWithOpacity" t-as="gradient" t-key="gradient"> 15550 <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"/> 15551 </t> 15552 </div> 15553 <div class="px-2"> 15554 <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"> 15555 Custom 15556 </button> 15557 <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"/> 15558 </div> 15559</t> 15560`); 15561registerTemplate("html_editor.ColorSelector", `/html_editor/static/src/main/font/color_selector.xml`, `<t t-name="html_editor.ColorSelector" xml:space="preserve"> 15562 <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"> 15563 <t t-if="props.type === 'foreground'"> 15564 <i class="fa fa-fw fa-font py-1" t-att-style="this.get
15564SelectedColorStyle()"/> 15565 </t> 15566 <t t-else=""> 15567 <i class="fa fa-fw fa-paint-brush py-1" t-att-style="this.getSelectedColorStyle()"/> 15568 </t> 15569 </button> 15570</t> 15571 15572`); 15573registerTemplate("html_editor.FontFamilySelector", `/html_editor/static/src/main/font/font_family_selector.xml`, `<t t-name="html_editor.FontFamilySelector" xml:space="preserve"> 15574 <Dropdown menuClass="'o_font_family_selector_menu'" menuRef="menuRef"> 15575 <button class="btn btn-light" t-att-title="props.title" name="font_family" t-att-disabled="props.isDisabled"> 15576 <span class="px-1" t-esc="props.currentFontFamily.displayName"/> 15577 </button> 15578 <t t-set-slot="content"> 15579 <div data-prevent-closing-overlay="true"> 15580 <t t-foreach="props.fontFamilyItems" t-as="item" t-key="item_index"> 15581 <DropdownItem attrs="{ name: item.nameShort }" onSelected="() => props.onSelected(item)" t-on-pointerdown.prevent="() => {}"> 15582 <t t-esc="item.name"/> 15583 </DropdownItem> 15584 </t> 15585 </div> 15586 </t> 15587 </Dropdown> 15588 </t> 15589`); 15590registerTemplate("html_editor.FontSelector", `/html_editor/static/src/main/font/font_selector.xml`, `<t t-name="html_editor.FontSelector" xml:space="preserve"> 15591 <Dropdown menuClass="'o_font_selector_menu'" menuRef="menuRef"> 15592 <button class="btn btn-light" t-att-title="props.title" name="font" t-att-disabled="props.isDisabled"> 15593 <span class="px-1" t-esc="state.displayName"/> 15594 </button> 15595 <t t-set-slot="content"> 15596 <div data-prevent-closing-overlay="true"> 15597 <t t-foreach="items" t-as="item" t-key="item_index"> 15598 <DropdownItem attrs="{ name: item.tagName }" onSelected="() => this.onSelected(item)" t-on-pointerdown.prevent="() => {}"> 15599 <t t-esc="item.name"/> 15600 </DropdownItem> 15601 </t> 15602 </div> 15603 </t> 15604 </Dropdown> 15605 </t> 15606`); 15607registerTemplate("html_editor.FontSizeSelector", `/html_editor/static/src/main/font/font_size_selector.xml`, `<t t-name="html_editor.FontSizeSelector" xml:space="preserve"> 15608 <Dropdown state="dropdown" menuClass="'o_font_size_selector_menu'" menuRef="menuRef"> 15609 <button class="btn btn-light" t-att-title="props.title" name="font_size_selector" t-att-disabled="props.isDisabled"> 15610 <iframe t-ref="iframeContent" style="width: 4ch; height:100%;"/> 15611 </button> 15612 <t t-set-slot="content"> 15613 <div data-prevent-closing-overlay="true"> 15614 <t t-foreach="items" t-as="item" t-key="item_index"> 15615 <DropdownItem onSelected="() => this.onSelected(item)" t-on-pointerdown.prevent="() => {}"> 15616 <t t-out="item.name"/> 15617 </DropdownItem> 15618 </t> 15619 </div> 15620 </t> 15621 </Dropdown> 15622 </t> 15623`); 15624registerTemplate("html_editor.GradientPicker", `/html_editor/static/src/main/font/gradient_picker/gradient_picker.xml`, `<t t-name="html_editor.GradientPicker" xml:space="preserve"> 15625 <div class="d-flex flex-column"> 15626 15627 <div class="align-items-center d-flex justify-content-between my-2 o_type_row"> 15628 Type 15629 <span class="d-flex justify-content-between"> 15630 <button t-attf-class="btn btn-sm btn-light {{ this.state.type === 'linear' ? 'active' : ''}}" t-on-click="() => this.selectType('linear')"> Linear </button> 15631 <button t-attf-class="btn btn-sm btn-light {{ this.state.type === 'radial' ? 'active' : ''}}" t-on-click="() => this.selectType('radial')"> Radial </button> 15632 </span> 15633 </div> 15634 15635 <div t-if="this.state.type === 'linear'" class="d-flex align-items-center justify-content-between mb-1"> 15636 Angle 15637 <span class="d-flex justify-content-between align-items-center"> 15638 <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"> 15639 <div class="position-absolute gradient-angle-thumb"/> 15640 </div> 15641 <div class="o_color_gradient_input d-flex align-items-center">
15642 <input name="angle" type="number" min="0" max="360" t-att-value="this.state.angle" t-on-change="onAngleChange"/> 15643 <label class="flex-grow-0 ms-1 mb-0">deg</label> 15644 </div> 15645 </span> 15646 </div> 15647 <div t-else="" class="d-flex flex-column gap-1 mb-1"> 15648 Size 15649 <div class="d-flex align-items-center justify-content-between"> 15650 <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"> 15651 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15652 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15653 <path d="M3 4H9V8C9 8.55228 8.55228 9 8 9H4C3.44772 9 3 8.55228 3 8V4Z" fill="#8C8C92"/> 15654 <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"/> 15655 <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"/> 15656 <rect x="2" y="3" width="12" height="1" fill="white"/> 15657 </svg> 15658 </button> 15659 <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"> 15660 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15661 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15662 <path d="M2 4H9V7C9 9.20914 7.20914 11 5 11H2V4Z" fill="#8C8C92"/> 15663 <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"/> 15664 <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"/> 15665 <rect x="1" y="3" width="8" height="1" fill="white"/> 15666 <rect x="1" y="11" width="8" height="1" transform="rotate(-90 1 11)" fill="white"/> 15667 </svg> 15668 </button> 15669 <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"> 15670 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15671 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15672 <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"/> 15673 <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"/> 15674 <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"/> 15675 <rect x="14" y="4" width="1" height="12" fill="white"/> 15676 </svg> 15677 </button> 15678 <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"> 15679 <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 16 20" fill="none"> 15680 <rect x="1.5" y="3.5" width="13" height="13" stroke="#AAAAAD"/> 15681 <path d="M2 4H14V10C14 13.3137 11.3137 16 8 16H2V4Z" fill="#8C8C92"/> 15682 <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"/> 15683 <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"/> 15684 <rect x="15" y="17" width="7" height="0.999999" transform="rotate(-180 15 17)" fill="white"/> 15685 <rect x="15" y="10" width="7" height="1" transform="rotate(90 15 10)" fill="white"/> 15686 </svg> 15687 </button> 15688 </div> 15689 <div class="d-flex align-items-center justify-content-between"> 15690 Position X
15691 <span class="o_color_gradient_input"> 15692 <input name="positionX" type="number" min="0" max="100" t-att-value="this.positions['x']" t-on-change="(ev) => this.onPositionChange('x', ev)"/> 15693 </span> 15694 </div> 15695 <div class="d-flex align-items-center justify-content-between"> 15696 Position Y 15697 <span class="o_color_gradient_input"> 15698 <input name="positionY" type="number" min="0" max="100" t-att-value="this.positions['y']" t-on-change="(ev) => this.onPositionChange('y', ev)"/> 15699 </span> 15700 </div> 15701 </div> 15702 15703 <div class="custom-gradient-configurator"> 15704 <div class="gradient-checkers"/> 15705 <div class="gradient-preview" t-attf-style="background-image: #{this.cssGradients.preview};" t-on-click="this.onGradientPreviewClick"> 15706 </div> 15707 <style><t t-out="this.cssGradients.sliderThumbStyle"/></style> 15708 <div class="gradient-colors"> 15709 <div t-foreach="this.colors" t-as="color" t-key="color_index"> 15710 <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)"/> 15711 </div> 15712 </div> 15713 <div class="gradient-color-bin"> 15714 <t t-if="this.colors.length > 2"> 15715 <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> 15716 </t> 15717 </div> 15718 </div> 15719 15720 <ColorPicker onColorSelect.bind="onColorChange" onColorPreview.bind="onColorPreview" setOnCloseCallback.bind="props.setOnCloseCallback" setOperationCallbacks.bind="props.setOperationCallbacks" defaultColor="this.currentColorHex" selectedColor="this.currentColorHex" noTransparency="props.noTransparency"/> 15721 </div> 15722 </t> 15723`); 15724registerTemplate("html_editor.linkPopover", `/html_editor/static/src/main/link/link_popover.xml`, `<t t-name="html_editor.linkPopover" xml:space="preserve"> 15725 <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"> 15726 <div t-if="state.editing" class="container-fluid d-flex vertical-center p-2" t-ref="editing-wrapper"> 15727 <div t-if="state.isImage" class="col p-2 o_link_popover_container"> 15728 <div class="input-group mb-1"> 15729 <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"/> 15730 <button class="o_we_apply_link btn btn-sm btn-primary" t-att-class="{'mx-1': state.type === ''}" t-on-click="onClickApply">Apply</button> 15731 </div> 15732 </div> 15733 <div t-else="" class="d-flex"> 15734 <t t-if="state.showAdvancedOptions"> 15735 <div class="o_advance_option_panel"> 15736 <div class="o_advance_options_grid" style="width: 200px;"> 15737 <button t-if="state.showAdvancedOptions" class="fa fa-angle-left btn btn-secondary border-10" t-on-click="toggleAdvancedOptions"/> 15738 <t t-foreach="Object.values(state.relAttributeOptions)" t-as="opt" t-key="opt.label"> 15739 <t t-if="opt.label !== 'noopener'"> 15740 <div class="o_seo_option_row d-flex justify-content-between align-items-center py-1 gap-2">
15741 <span t-att-title="opt.description"><t t-out="opt.label"/></span> 15742 <CheckBox value="opt.isChecked" onChange="toggleRelAttr.bind(this, opt.label)"/> 15743 </div> 15744 </t> 15745 </t> 15746 <div class="o_seo_option_row d-flex justify-content-between align-items-center py-1 gap-2"> 15747 <span>Open in new tab</span> 15748 <CheckBox value="state.linkTarget === '_blank'" onChange="onClickNewWindow.bind(this)" className="'target-blank-option'"/> 15749 </div> 15750 <t t-if="state.linkTarget === '_blank'"> 15751 <div class="o_seo_option_row o_seo_option_child d-flex justify-content-between align-items-center py-1 gap-2 ps-4"> 15752 <span>noopener</span> 15753 <CheckBox value="state.relAttributeOptions.noopener.isChecked" onChange="toggleRelAttr.bind(this, 'noopener')"/> 15754 </div> 15755 </t> 15756 </div> 15757 </div> 15758 </t> 15759 <t t-else=""> 15760 <div class="col p-2 o_link_popover_container"> 15761 <div class="input-group mb-2" t-att-class="{'d-none': !state.showLabel}"> 15762 <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"/> 15763 </div> 15764 <div class="input-group mb-2"> 15765 <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"/> 15766 <span class="ms-1" t-if="props.canUpload"> 15767 or <button class="btn btn-light btn-sm" t-on-click="uploadFile"><i class="fa fa-upload"/></button> 15768 </span> 15769 15770 </div> 15771 <div class="input-group"> 15772 <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"> 15773 <t t-foreach="this.colorsData" t-as="colorData" t-key="colorData.type"> 15774 <t t-if="props.allowCustomStyle or colorData.type !== 'custom'"> 15775 <option t-att-value="colorData.type" t-att-selected="state.type === colorData.type" t-attf-class="o_btn_preview" t-out="colorData.label"/> 15776 </t> 15777 </t> 15778 </select> 15779 </div> 15780 <div t-if="state.type" class="input-group"> 15781 <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"> 15782 <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"/> 15783 </select> 15784 <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"> 15785 <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"/> 15786 </select> 15787 </div> 15788 15789 <t t-if="state.type === 'custom'"> 15790 <div class="d-flex mb-1 custom-text-color"> 15791 <label>Text Color</label> 15792 <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)}}"/> 15793 <label>Fill Color</label> 15794 <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)}}"/> 15795 </div> 15796 <div class="d-flex mb-1 custom-border align-items-center"> 15797 <label class="flex-shrink-0">Border</label> 15798 <div class="input-group me-1"> 15799 <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"/>
15800 <span class="input-group-text">px</span> 15801 </div> 15802 <div class="d-flex align-items-center" t-if="state.customBorderSize > 0"> 15803 <select name="link_style_border" class="form-select form-select-sm custom-border-style me-1" t-model="state.customBorderStyle" t-on-change="onChange"> 15804 <t t-foreach="this.borderData" t-as="borderData" t-key="borderData.style"> 15805 <option t-att-value="borderData.style" t-att-selected="state.customBorderStyle === borderData.style"> 15806 <span t-esc="borderData.label"/> 15807 </option> 15808 </t> 15809 </select> 15810 <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)}}"/> 15811 </div> 15812 </div> 15813 </t> 15814 <t t-if="props.allowTargetBlank"> 15815 <t t-if="state.isDocument"> 15816 <CheckBox value="state.directDownload" onChange="onClickDirectDownload.bind(this)" className="'direct-download-option'"> 15817 Direct download 15818 </CheckBox> 15819 </t> 15820 </t> 15821 <t t-if="props.allowStripDomain and isAbsoluteURLInCurrentDomain()"> 15822 <CheckBox value="state.stripDomain" onChange="onClickStripDomain.bind(this)" className="'strip-domain-option'"> 15823 Autoconvert to relative link 15824 </CheckBox> 15825 </t> 15826 <div class="d-flex justify-content-between align-items-center mt-1"> 15827 <div> 15828 <button class="o_we_apply_link btn btn-sm btn-primary" t-att-disabled="!state.url" t-on-click="onClickApply">Apply</button> 15829 <button class="o_we_discard_link btn btn-sm btn-secondary ms-1" t-on-click="this.discard">Discard</button> 15830 </div> 15831 <div class="d-flex align-items-center gap-1"> 15832 <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"> 15833 <i class="fa fa-chain-broken"/> 15834 </a> 15835 <button class="btn btn-sm btn-secondary" title="Advanced mode" t-att-disabled="!state.url" t-on-click="toggleAdvancedOptions"> 15836 <i class="fa fa-gear"/> 15837 </button> 15838 </div> 15839 </div> 15840 </div> 15841 </t> 15842 </div> 15843 </div> 15844 <div t-else="" style="width: 274px;" data-prevent-closing-overlay="true"> 15845 <div class="d-flex flex-column p-2"> 15846 <div class="d-flex"> 15847 <span class="o_we_preview_favicon" style="width: 16px; height: 18px"> 15848 <img t-if="state.previewIcon.type === 'imgSrc'" t-att-src="state.previewIcon.value" class="align-content-center"/> 15849 <span t-elif="state.previewIcon.type === 'mimetype'" class="o_image" t-att-data-mimetype="state.previewIcon.value"/> 15850 <i t-else="" t-attf-class="fa fa-fw {{state.previewIcon.value}}"/> 15851 </span> 15852 <div class="ms-1 w-100"> 15853 <div class="d-flex"> 15854 <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}}"> 15855 <t t-esc="state.urlTitle"/> 15856 </a> 15857 <div class="flex-grow-1 d-flex justify-content-end align-items-center gap-1"> 15858 <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"> 15859 <i class="fa fa-magic"/> 15860 </a> 15861 <t t-if="props.canEdit"> 15862 <a href="#" class="o_we_edit_link btn btn-sm btn-secondary" t-on-click="onClickEdit" title="Edit Link">Edit</a> 15863 </t> 15864 </div> 15865 </div> 15866 <div t-if="state.urlTitle and state.url and state.urlTitle !== state.url" class="text-truncate" style="max-width: 200px; font-size: 12px;">
15867 <span t-attf-class="o_we_full_url text-muted o_we_webkit_box" t-attf-title="{{state.url}}"> 15868 <t t-if="state.url" t-esc="state.url"/> 15869 <t t-else="">No URL specified</t> 15870 </span> 15871 </div> 15872 </div> 15873 </div> 15874 <div t-if="state.imgSrc" class="o_extra_info_card" style="align-self: center; max-width: 235px"> 15875 <a href="#" target="_blank" t-attf-href="{{state.url}}" title="Open in a new tab"> 15876 <img t-att-src="state.imgSrc" class="img-fluid mb-1" style="max-width: 230; max-height: 100%;"/> 15877 </a> 15878 </div> 15879 <div t-if="state.urlDescription" class="d-flex"> 15880 <i class="fa fa-align-right align-content-center"/> 15881 <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}}"> 15882 <t t-esc="state.urlDescription"/> 15883 </span> 15884 </div> 15885 </div> 15886 <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);"> 15887 <i class="fa fa-magic fa-fw m-1" style="color: var(--o-cc1-btn-primary-text);"/> 15888 <span class="me-2 flex-grow-1" style="color: var(--o-cc1-btn-primary-text);font-size: smaller;">Replace URL with its title?</span> 15889 <button class=" btn btn-sm btn-primary o_we_replace_title_btn" style="margin: 1px;font-size: smaller;" t-on-click="onClickReplaceTitle">Yes</button> 15890 </div> 15891 </div> 15892 </div> 15893 </t> 15894 15895`); 15896registerTemplate("html_editor.ListSelector", `/html_editor/static/src/main/list/list_selector.xml`, `<t t-name="html_editor.ListSelector" xml:space="preserve"> 15897 <Dropdown menuClass="'o-we-toolbar-dropdown'" bottomSheet="false" menuRef="menuRef"> 15898 <button class="btn btn-light fa fa-list-ul" t-att-title="props.title" name="list_selector"/> 15899 <t t-set-slot="content" t-key="props.key.value"> 15900 <div data-prevent-closing-overlay="true"> 15901 <t t-set="activeMode" t-value="getActiveMode()"/> 15902 <t t-foreach="props.getButtons()" t-as="button" t-key="button_index"> 15903 <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="() => {}"/> 15904 </t> 15905 </div> 15906 </t> 15907 </Dropdown> 15908 </t> 15909`); 15910registerTemplate("html_editor.ImageCrop", `/html_editor/static/src/main/media/image_crop.xml`, `<t t-name="html_editor.ImageCrop" xml:space="preserve"> 15911 <div class="o_we_crop_widget" tabindex="-1" contenteditable="false" t-ref="el" t-on-zoom="this.onCropZoom"> 15912 <div class="o_we_cropper_wrapper" t-ref="cropperWrapper"> 15913 <img class="o_we_cropper_img" t-ref="imageRef"/> 15914 <div class="o_we_crop_buttons text-center mt16 position-fixed o_we_no_overlay" contenteditable="false"> 15915 <div class="btn-group btn-group-toggle" title="Aspect Ratio" data-bs-toggle="buttons"> 15916 <t t-foreach="this.aspectRatios" t-as="ratio" t-key="ratio"> 15917 <t t-set="is_active" t-value="ratio === this.aspectRatio"/> 15918 <label t-attf-class="btn #{is_active and 'active' or ''}" t-on-click="() => this.setAspectRatio(ratio)"> 15919 <input type="radio"/><t t-esc="ratio_value.label"/> 15920 </label> 15921 </t> 15922 </div> 15923 <div class="btn-group" role="group"> 15924 <button type="button" title="Zoom In" t-on-click="() => this.onZoom(0.1)"><i class="fa fa-fw fa-search-plus"/></button> 15925 <button type="button" title="Zoom Out" t-on-click="() => this.onZoom(-0.1)"><i class="fa fa-fw fa-search-minus"/></button> 15926 </div> 15927 <div class="btn-group" role="group"> 15928 <button type="button" title="Rotate Left" t-on-click="() => this.onRotate(-90)"><i class="fa fa-fw fa-rotate-left"/></button> 15929 <button type="button" title="Rotate Right" t-on-click="() => this.onRotate(90)"><i class="fa fa-fw fa-rotate-right"/></button> 15930 </div> 15931 <div class="btn-group" role="group"> 15932 <button type="button" title="Flip Horizontal" t-on-click="() => this.onFlip('scaleX')"><i class="oi oi-fw oi-arrows-h"/></button> 15933 <button type="button" title="Flip Vertical" t-on-click="() => this.onFlip('scaleY')"><i class="oi oi-fw oi-arrows-v"/></button> 15934 </div> 15935 <div class="btn-group" role="group"> 15936 <button type="button" title="Reset Image" t-on-click="this.onReset"><i class="fa fa-refresh"/> Reset Image</button> 15937 </div> 15938 <div class="btn-group" role="group"> 15939 <button type="button" t-ref="applyButton" t-on-click="this.save" class="btn btn-primary"><i class="fa fa-check" role="presentation"/> Apply</button> 15940 <button type="button" t-ref="discardButton" t-on-click="this.closeCropper" class="btn btn-danger"><i class="oi oi-close" role="presentation"/> Discard</button> 15941 </div> 15942 </div> 15943 </div> 15944 </div> 15945 </t> 15946`); 15947registerTemplate("html_editor.ImageDescription", `/html_editor/static/src/main/media/image_description.xml`, `<t t-name="html_editor.ImageDescription" xml:space="preserve"> 15948 <button class="btn btn-light" t-att-title="props.title" t-on-click="this.props.openImageDescriptionPopover"> 15949 Description 15950 </button> 15951 </t> 15952 15953 `); 15954registerTemplate("html_editor.ImageDescriptionPopover", `/html_editor/static/src/main/media/image_description.xml`, `<t t-name="html_editor.ImageDescriptionPopover" xml:space="preserve"> 15955 <div class="o-we-image-description-popover p-3"> 15956 <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"/> 15957 <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"/> 15958 <div class="mt-3"> 15959 <button class="o_we_apply_link btn btn-sm btn-primary" t-on-click="this.onSave">Apply</button> 15960 <button class="o_we_discard_link btn btn-sm btn-dark ms-1" t-on-click="this.props.close">Discard</button> 15961 </div> 15962 </div> 15963 </t> 15964`); 15965registerTemplate("html_editor.ImageToolbarDropdown", `/html_editor/static/src/main/media/image_toolbar_dropdown.xml`, `<t t-name="html_editor.ImageToolbarDropdown" xml:space="preserve"> 15966 <Dropdown menuClass="\`\${props.name}_selector\`" menuRef="menuRef"> 15967 <button t-att-title="props.title" class="btn btn-light"> 15968 <t t-if="props.icon" t-call="{{props.icon}}"/> 15969 <t t-elif="state && state.displayName" t-esc="state.displayName"/> 15970 <t t-else="" t-esc="props.title"/> 15971 </button> 15972 <t t-set-slot="content"> 15973 <div data-prevent-closing-overlay="true"> 15974 <t t-foreach="items" t-as="item" t-key="item_index"> 15975 <DropdownItem class="'user-select-none'" onSelected="() => this.onSelected(item)"> 15976 <t t-esc="item.name"/> 15977 </DropdownItem> 15978 </t> 15979 </div> 15980 </t> 15981 </Dropdown> 15982 </t> 15983 15984 `); 15985registerTemplate("html_editor.ImagePaddingIcon", `/html_editor/static/src/main/media/image_toolbar_dropdown.xml`, `<t t-name="html_editor.ImagePaddingIcon" xml:space="preserve"> 15986 <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"> 15987 <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"/> 15988 <path d="M8 16v.01"/> 15989 <path d="M8 12v.01"/> 15990 <path d="M8 8v.01"/> 15991 <path d="M16 16v.01"/> 15992 <path d="M16 12v.01"/> 15993 <path d="M16 8v.01"/> 15994 <path d="M12 8v.01"/> 15995 <path d="M12 16v.01"/> 15996 </svg> 15997 </t> 15998`); 15999registerTemplate("html_editor.ImageTransformButton", `/html_editor/static/src/main/media/image_transform_button.xml`, `<t t-name="html_editor.ImageTransformButton" xml:space="preserve"> 16000 <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">
16001 <span class="fa fa-fw" t-att-class="props.icon"/> 16002 </button> 16003 </t> 16004`); 16005registerTemplate("html_editor.ImageTransformation", `/html_editor/static/src/main/media/image_transformation.xml`, `<t t-name="html_editor.ImageTransformation" xml:space="preserve"> 16006 <div class="transfo-container" t-ref="transfoContainer" t-on-mousedown.prevent="mouseDown"> 16007 <div class="transfo-controls" t-ref="transfoControls"> 16008 <div style="cursor: crosshair; position: absolute; margin: -30px; top: 0; right: 0; padding: 1px 0 0 1px;" class="transfo-rotator"> 16009 <span class="fa-stack fa-lg"> 16010 <i class="fa fa-circle fa-stack-2x"/> 16011 <i class="fa fa-repeat fa-stack-1x fa-inverse"/> 16012 </span> 16013 </div> 16014 <div style="top: 0%; left: 0%; cursor: nw-resize;" class="transfo-scaler transfo-scaler-tl"/> 16015 <div style="top: 0%; left: 100%; cursor: ne-resize;" class="transfo-scaler transfo-scaler-tr"/> 16016 <div style="top: 100%; left: 100%; cursor: se-resize;" class="transfo-scaler transfo-scaler-br"/> 16017 <div style="top: 100%; left: 0%; cursor: sw-resize;" class=" transfo-scaler transfo-scaler-bl"/> 16018 <div style="top: 0%; left: 50%; cursor: n-resize;" class="transfo-scaler transfo-scaler-tc"/> 16019 <div style="top: 100%; left: 50%; cursor: s-resize;" class="transfo-scaler transfo-scaler-bc"/> 16020 <div style="top: 50%; left: 0%; cursor: w-resize;" class="transfo-scaler transfo-scaler-ml"/> 16021 <div style="top: 50%; left: 100%; cursor: e-resize;" class="transfo-scaler transfo-scaler-mr"/> 16022 <div style="border: 0; width: 0px; height: 0px; top: 50%; left: 50%;" class="transfo-scaler transfo-scaler-mc" t-ref="transfoCenter"/> 16023 </div> 16024 </div> 16025 </t> 16026`); 16027registerTemplate("html_editor.Powerbox", `/html_editor/static/src/main/powerbox/powerbox.xml`, `<t t-name="html_editor.Powerbox" xml:space="preserve"> 16028 <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"> 16029 <t t-foreach="commands" t-as="command" t-key="command_index"> 16030 <t t-if="showCategories and command.categoryId !== lastCategory"> 16031 <div class="o-we-category mx-3 my-1 text-uppercase"><t t-esc="command.categoryName"/></div></t> 16032 <t t-set="lastCategory" t-value="command.categoryId"> 16033 </t> 16034 <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)"> 16035 <div class="border rounded"> 16036 <i class="o-we-command-img d-flex align-items-center justify-content-center fa" t-att-class="command.icon"/> 16037 </div> 16038 <div class="ms-3"> 16039 <div class="o-we-command-name" t-esc="command.title"/> 16040 <div class="o-we-command-description" t-esc="command.description"/> 16041 </div> 16042 </div> 16043 </t> 16044 </div> 16045 </t> 16046`); 16047registerTemplate("html_editor.Signature", `/html_editor/static/src/main/signature.xml`, `<t t-name="html_editor.Signature" xml:space="preserve"> 16048 <div t-att-class="signatureClass" t-out="signature"/> 16049 </t> 16050`); 16051registerTemplate("html_editor.TableAlignSelector", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.TableAlignSelector" xml:space="preserve"> 16052 <Dropdown menuClass="'o-we-toolbar-dropdown'" bottomSheet="false" menuRef="menuRef"> 16053 <button class="btn btn-light" t-att-title="props.title" name="vertical_align"> 16054 <t t-set="selectedItem" t-value="items.find(item => item.mode === state.displayName)"/> 16055 <t t-call="{{ selectedItem ? selectedItem.template : 'html_editor.VerticalAlignTop' }}"/> 16056 </button> 16057 <t t-set-slot="content"> 16058 <div data-prevent-closing-overlay="true"> 16059 <t t-foreach="items" t-as="item" t-key="item.mode"> 16060 <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)"> 16061 <t t-call="{{item.template}}"/> 16062 </button> 16063 </t> 16064 </div> 16065 </t> 16066 </Dropdown> 16067 </t> 16068 16069 `); 16070registerTemplate("html_editor.VerticalAlignTop", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.VerticalAlignTop" xml:space="preserve"> 16071 <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"> 16072 <g> 16073 <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"/> 16074 <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"/> 16075 <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"/> 16076 </g> 16077 </svg> 16078 </t> 16079 16080 `); 16081registerTemplate("html_editor.VerticalAlignMiddle", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.VerticalAlignMiddle" xml:space="preserve"> 16082 <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"> 16083 <g> 16084 <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
160846.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"/> 16085 </g> 16086 </svg> 16087 </t> 16088 16089 `); 16090registerTemplate("html_editor.VerticalAlignBottom", `/html_editor/static/src/main/table/table_align_selector.xml`, `<t t-name="html_editor.VerticalAlignBottom" xml:space="preserve"> 16091 <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"> 16092 <g> 16093 <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"/> 16094 <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"/> 16095 <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"/> 16096 </g> 16097 </svg> 16098 </t> 16099`); 16100registerTemplate("html_editor.TableMenu", `/html_editor/static/src/main/table/table_menu.xml`, `<t t-name="html_editor.TableMenu" xml:space="preserve"> 16101 <Dropdown menuClass="'m-0'" position="props.type === 'column' ? 'bottom' : 'right'" state="props.dropdownState" bottomSheet="false"> 16102 <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"/> 16103 <t t-set-slot="content"> 16104 <div t-on-pointerdown.stop="() => {}"> 16105 <t t-foreach="items" t-as="item" t-key="item_index"> 16106 <DropdownItem onSelected="() => this.onSelected(item)"> 16107 <div class="user-select-none" t-att-name="item.name"> 16108 <span t-if="item.icon" class="me-2 fa" t-att-class="item.icon"/> 16109 <span t-esc="item.text"/> 16110 </div> 16111 </DropdownItem> 16112 </t> 16113 </div> 16114 </t> 16115 </Dropdown> 16116 </t> 16117`); 16118registerTemplate("html_editor.TablePicker", `/html_editor/static/src/main/table/table_picker.xml`, `<t t-name="html_editor.TablePicker" xml:space="preserve"> 16119 <div class="o-we-tablepicker bg-light p-1 my-1" t-on-click="insertTable" t-on-mousedown.stop=""> 16120 <t t-foreach="new Array(state.rows + 1)" t-as="row" t-key="row_index"> 16121 <div class="o-we-row d-flex"> 16122 <t t-foreach="new Array(state.cols + 1)" t-as="col" t-key="col_index"> 16123 <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)"/> 16124 </t> 16125 </div> 16126 </t> 16127 <div class="text-center"><t t-esc="state.cols"/>x<t t-esc="state.rows"/></div> 16128 </div> 16129 </t> 16130`); 16131registerTemplate("html_editor.MobileToolbar", `/html_editor/static/src/main/toolbar/mobile_toolbar.xml`, `<t t-name="html_editor.MobileToolbar" xml:space="preserve"> 16132 <div t-ref="toolbarWrapper" class="o-toolbar-above-keyboard"> 16133 <Toolbar state="props.state" getSelection="props.getSelection" focusEditable="props.focusEditable" class="props.class"/> 16134 </div> 16135 </t> 16136`); 16137registerTemplate("html_editor.Toolbar", `/html_editor/static/src/main/toolbar/toolbar.xml`, `<t t-name="html_editor.Toolbar" xml:space="preserve"> 16138 <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"> 16139 <t t-foreach="state.buttonGroups" t-as="buttonGroup" t-key="buttonGroup.id">
16140 <span class="o-we-toolbar-vertical-separator"/> 16141 <div class="btn-group" t-att-name="buttonGroup.id"> 16142 <t t-foreach="buttonGroup.buttons" t-as="button" t-key="button.id"> 16143 <t t-if="button.Component"> 16144 <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"/> 16145 </t> 16146 <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)"> 16147 <span t-if="button.icon" t-att-class="button.icon.includes('fa-') ? 'fa fa-fw ' + button.icon : 'oi oi-fw ' + button.icon"/> 16148 <span t-if="button.text" t-esc="button.text"/> 16149 </button> 16150 </t> 16151 </div> 16152 </t> 16153 </div> 16154 </t> 16155`); 16156registerTemplate("html_editor.EmbeddedCaption", `/html_editor/static/src/others/embedded_components/backend/caption/caption.xml`, `<t t-name="html_editor.EmbeddedCaption" xml:space="preserve"> 16157 <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"/> 16158 </t> 16159`); 16160registerTemplate("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"> 16161 <xpath expr="//span[hasclass('o_file_name_container')]" position="after"> 16162 <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"/> 16163 </xpath> 16164 <xpath expr="//span[hasclass('o_file_name_container')]" position="attributes"> 16165 <attribute name="t-att-class">{ 16166 "d-none": localState.editFileName, 16167 "cursor-pointer": true, 16168 }</attribute> 16169 <attribute name="t-on-focus">onFocusFileName</attribute> 16170 <attribute name="tabindex">-1</attribute> 16171 </xpath> 16172 <xpath expr="//span[hasclass('o_file_name')]" position="after"> 16173 <i class="fa fa-pencil mx-1 invisible align-items-center d-inline-flex"/> 16174 </xpath> 16175 </t> 16176`); 16177registerTemplate("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"> 16178 <div t-att-class="props.isActive ? 'show' : ''" class="o_code_toolbar"> 16179 <div data-prevent-closing-overlay="true"> 16180 <Dropdown menuClass="'o_language_selector'" focusToggleOnClosed="false"> 16181 <button class="btn" t-att-title="languages[props.currentLanguage]" name="language"> 16182 <span class="px-1" t-esc="languages[props.currentLanguage]"/> 16183 <i class="fa fa-caret-down"/> 16184 </button> 16185 <t t-set-slot="content"> 16186 <t t-foreach="Object.entries(languages)" t-as="language" t-key="language[0]"> 16187 <DropdownItem attrs="{ name: language[1] }" onSelected="() => props.onLanguageChange(language[0])" t-on-pointerdown.prevent="() => {}"> 16188 <t t-esc="language[1]"/> 16189 </DropdownItem> 16190 </t> 16191 </t> 16192 </Dropdown>
16193 <CopyButton content="props.getContent" copyText.translate="Copy" successText.translate="Code copied to the clipboard." t-on-pointerdown.prevent="() => {}"/> 16194 <button class="text-nowrap btn" t-on-click="this.props.convertToParagraph"> 16195 <span class="mx-1 fa fa-paragraph" title="Convert to paragraph"/> 16196 </button> 16197 </div> 16198 </div> 16199 </t> 16200`); 16201registerTemplate("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"> 16202 <CodeToolbar target="state.host" currentLanguage="embeddedState.languageId" getContent="() => this.textarea.value" onLanguageChange="onLanguageChange.bind(this)" convertToParagraph="this.props.convertToParagraph"/> 16203 <pre t-ref="pre"/> 16204 <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"/> 16205 </t> 16206`); 16207registerTemplate("html_editor.VideoSettings", `/html_editor/static/src/others/embedded_components/backend/video/video.xml`, `<t t-name="html_editor.VideoSettings" xml:space="preserve"> 16208 <Dropdown state="this.props.dropdown"> 16209 <button t-ref="menuRef" class="btn btn-light shadow border py-1 px-1 ms-1" title="More options"> 16210 <i class="oi oi-fw oi-ellipsis-v"/> 16211 </button> 16212 <t t-set-slot="content"> 16213 <DropdownItem onSelected="props.replaceVideo"> 16214 <i class="fa-fw fa fa-exchange me-1"/>Replace 16215 </DropdownItem> 16216 <DropdownItem onSelected="props.removeVideo" class="'text-danger'"> 16217 <i class="fa fa-fw fa-trash me-1"/>Remove 16218 </DropdownItem> 16219 </t> 16220 </Dropdown> 16221 </t> 16222`); 16223registerTemplate("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"> 16224 <figcaption contenteditable="false" class="mt-2"> 16225 <span class="o_caption_editable" contenteditable="true" t-att-data-caption-id="captionId"/> 16226 </figcaption> 16227 </t> 16228`); 16229registerTemplate("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"> 16230 <span t-att-data-embedded-props="embeddedProps" data-embedded="file" data-oe-protected="true" contenteditable="false" class="o_file_box o-contenteditable-false"/> 16231 </t> 16232`); 16233registerTemplate("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"> 16234 <div t-att-data-embedded-props="embeddedProps" data-embedded="syntaxHighlighting" data-oe-protected="true" contenteditable="false" class="o_syntax_highlighting"/> 16235 </t> 16236`); 16237registerTemplate("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"> 16238 <div data-embedded="tableOfContent" data-oe-protected="true" contenteditable="false"/> 16239 </t> 16240`); 16241registerTemplate("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"> 16242 <div data-embedded="toggleBlock" data-oe-protected="true" contenteditable="false" t-att-data-embedded-props="embeddedProps"> 16243 <div data-embedded-editable="title" data-oe-protected="false" contenteditable="true"> 16244 <t t-tag="baseContainerNodeName" t-att="baseContainerAttributes"><br/></t> 16245 </div> 16246 <div data-embedded-editable="content" data-oe-protected="false" contenteditable="true"> 16247 <t t-tag="baseContainerNodeName" t-att="baseContainerAttributes"><br/></t> 16248 </div> 16249 </div> 16250 </t> 16251`); 16252registerTemplate("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"> 16253 <div t-att-data-embedded-props="embeddedProps" data-embedded="video" data-oe-protected="true" contenteditable="false"/> 16254 </t> 16255`); 16256registerTemplate("html_editor.QWebPicker", `/html_editor/static/src/others/qweb_picker.xml`, `<t t-name="html_editor.QWebPicker" xml:space="preserve"> 16257 <div class="o-we-qweb-picker bg-white my-1"> 16258 <t t-foreach="state.groups" t-as="group" t-key="group_index"> 16259 <select class="form-select" t-on-change="onChange"> 16260 <t t-foreach="group" t-as="element" t-key="element_index"> 16261 <option t-attf-value="{{group_index}},{{element_index}}" t-att-selected="element.isActive"> 16262 <t t-esc="element.label"/> 16263 </option> 16264 </t> 16265 </select> 16266 </t> 16267 </div> 16268 </t> 16269`); 16270registerTemplate("mail.ActionList", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.ActionList" xml:space="preserve"> 16271 <div class="o-mail-ActionList flex-shrink-0 d-flex" t-att-class="{ 'align-items-center': props.inline,'flex-column': !props.inline }"> 16272 <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, }"/> 16273 <t t-foreach="groups" t-as="group" t-key="group_index">
16274 <span t-if="group.length" class="o-mail-ActionList-group btn-group" t-att-class="groupAttClass"> 16275 <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 })"/> 16276 </span> 16277 <t t-if="!group_last" t-call="mail.ActionList.groupSeparator"/> 16278 </t> 16279 </div> 16280</t> 16281 16282`); 16283registerTemplate("mail.ActionList.groupSeparator", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.ActionList.groupSeparator" xml:space="preserve"> 16284 <span t-if="props.inline" class="text-muted align-self-stretch ms-2 me-1"/> 16285 <hr t-else="" class="mx-2 my-1 o-rounded-bubble"/> 16286</t> 16287 16288`); 16289registerTemplate("mail.Action", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action" xml:space="preserve"> 16290 <t t-if="action.dropdown"> 16291 <t t-component="Dropdown" menuClass="(action.dropdownMenuClass ?? '') + ' ' + store.discussDropdownMenuClass(this)" position="action.dropdownPosition" state="action.dropdownState"> 16292 <t t-call="mail.Action.main"/> 16293 <t t-set-slot="content"> 16294 <t t-if="action.dropdownComponent" t-component="action.dropdownComponent" t-props="action.dropdownComponentProps"/> 16295 <t t-elif="action.dropdownTemplate" t-call="{{ action.dropdownTemplate }}"> 16296 <t t-set="templateParams" t-value="action.dropdownTemplateParams"/> 16297 </t> 16298 <t t-elif="action.definition?.isMoreAction"> 16299 <t t-component="ActionList" actions="action.definition.actions" dropdown="true"/> 16300 </t> 16301 <t t-else="">No content.</t> 16302 </t> 16303 </t> 16304 </t> 16305 <t t-else="" t-call="mail.Action.main"/> 16306</t> 16307 16308`); 16309registerTemplate("mail.Action.main", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action.main" xml:space="preserve"> 16310 <t t-set="isComposerRoundedBtn" t-value="props.inline and env.inComposer"/> 16311 <t t-set="isThreadRoundedBtn" t-value="props.inline and action.tags.includes('JOIN_LEAVE_CALL') and action.icon and !action.inlineName"/> 16312 <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('
16312CALL_LAYOUT'), 'bg-transparent': store.shouldSimulateDarkTheme(this) and action.tags.includes('CALL_LAYOUT'), })"/> 16313 <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 }"/> 16314 <t t-if="action.component and action.componentCondition" t-component="action.component" t-props="action.componentProps"/> 16315 <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"> 16316 <t t-call="mail.Action.content"/> 16317 </DropdownItem> 16318 <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"> 16319 <t t-call="mail.Action.content"/> 16320 <t t-if="action.badge" t-call="mail.Action.badge"> 16321 <t t-set="extraBadgeClass" t-value="'position-absolute me-n1 mt-n1 end-0'"/> 16322 </t> 16323 </button> 16324</t> 16325 16326`); 16327registerTemplate("mail.Action.content", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action.content" xml:space="preserve"> 16328 <t t-if="action.icon?.template" t-call="{{ action.icon.template }}"> 16329 <t t-set="templateParams" t-value="action.icon.params"/> 16330 </t> 16331 <i t-elif="action.icon" t-attf-class="{{ action.icon }}" t-att-class="{ 'o-fs-small': props.dropdown, 'fa-fw': props.fw }"/> 16332 <i t-elif="props.dropdown" class="fa-question fa-fw opacity-0" t-att-class="props.fw ? 'fa-fw' : ''"/> 16333 <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"/> 16334 <t t-if="props.dropdown and action.badge" t-call="mail.Action.badge"/> 16335</t> 16336 16337`); 16338registerTemplate("mail.Action.badge", `/mail/static/src/core/common/action_list.xml`, `<t t-name="mail.Action.badge" xml:space="preserve"> 16339 <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;"> 16340 <i t-if="action.badgeIcon" t-att-class="action.badgeIcon"/><span t-elif="action.badgeText" t-esc="action.badgeText"/> 16341 </span> 16342</t> 16343 16344`); 16345registerTemplate("mail.AttachmentList", `/mail/static/src/core/common/attachment_list.xml`, `<t t-name="mail.AttachmentList" xml:space="preserve"> 16346 <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, }"> 16347 <div class="d-flex flex-wrap gap-2" t-att-class="{'justify-content-end': isInChatWindowAndIsAlignedRight and !env.inComposer}" role="menu"> 16348 <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"> 16349 16350 <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, })"/> 16351 <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"/> 16352 16353 <div t-else="" class="o-mail-AttachmentCard d-flex flex-column w-100 h-100"> 16354 <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)"> 16355 <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"/> 16356 <img t-else="" t-att-src="attachment.thumbnailUrl" t-att-alt="attachment.name"/> 16357 </div> 16358 <div class="o-mail-AttachmentCard-info d-flex align-items-center px-2 py-1 bg-200 rounded-bottom-3"> 16359 <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"/> 16360 <div t-if="attachment.name" class="text-truncate align-items-center fw-bold" t-out="props.messageSearch?.highlight(attachment.name) ?? attachment.name"/> 16361 </div> 16362 </div> 16363 16364 <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 }"> 16365 <div class="d-flex flex-row align-items-start gap-2"> 16366 <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"/> 16367 <div t-else="" class="o-mail-Attachment-hover-image o_image flex-shrink-0" t-att-data-mimetype="attachment.mimetype"/> 16368 <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"/> 16369 </div> 16370 <div t-if="attachment.file_size" class="ms-4 o-mt-0_5" t-att-class="{ 'ps-1': !attachment.isImage }">
16371 <span class="opacity-75" t-att-class="{ 'o-text-white': attachment.isImage }"><t t-out="Math.round(attachment.file_size / 1024, 4)"/>KB</span> 16372 </div> 16373 16374 <div class="o-mail-AttachmentButtons d-flex justify-content-start ms-1 mb-1 mt-auto pt-2 gap-2"> 16375 <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"> 16376 <i class="fa fa-external-link o-text-white" role="img" aria-label="Open Link"/> 16377 </a> 16378 <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"> 16379 <i class="fa fa-download o-text-white" role="img" aria-label="Download"/> 16380 </button> 16381 <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"> 16382 <i class="fa fa-trash o-text-white" role="img" aria-label="Remove"/> 16383 </button> 16384 </div> 16385 </div> 16386 16387 <Actions t-else="" actions="getActions(attachment)"/> 16388 16389 <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"> 16390 <i class="fa fa-circle-o-notch fa-spin"/> 16391 </div> 16392 16393 <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"> 16394 <i class="fa fa-check"/> 16395 </div> 16396 </div> 16397 </div> 16398 </div> 16399 </t> 16400 16401 `); 16402registerTemplate("mail.Actions", `/mail/static/src/core/common/attachment_list.xml`, `<t t-name="mail.Actions" xml:space="preserve"> 16403 <div class="position-absolute end-0 p-1 o-text-white"> 16404 <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"> 16405 <i t-att-class="props.actions[0].icon"/> 16406 </button> 16407 <Dropdown t-else="" menuClass="'d-flex flex-column py-0'" state="actionsMenuState" position="'right-start'"> 16408 <button class="btn btn-sm btn-light rounded px-1 py-0" tabindex="0" aria-label="Actions" title="Actions" role="menuitem"> 16409 <i class="oi oi-chevron-down"/> 16410 </button> 16411 <t t-set-slot="content"> 16412 <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"> 16413 <i class="fa-fw" t-att-class="action.icon"/> 16414 <span class="mx-2" t-out="action.label"/> 16415 </DropdownItem> 16416 </t> 16417 </Dropdown> 16418 </div> 16419 </t> 16420 16421`); 16422registerTemplate("mail.AttachmentView", `/mail/static/src/core/common/attachment_view.xml`, `<t t-name="mail.AttachmentView" xml:space="preserve"> 16423 <div t-if="state.thread.attachmentsInWebClientView.length > 0" class="o-mail-Attachment"> 16424 <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"> 16425 <i class="fa fa-window-restore" aria-hidden="Pop out"/> 16426 </div> 16427 <t t-if="state.thread.message_main_attachment_id"> 16428 <h3 t-if="!state.thread.message_main_attachment_id.isPdf" class="mt0 mb8 ps-2 text-muted text-center"><t t-esc="displayName"/></h3> 16429 <div t-if="state.thread.message_main_attachment_id.isImage" class="o-mail-Attachment-imgContainer"> 16430 <img id="attachment_img" class="img img-fluid d-block" t-att-src="state.thread.message_main_attachment_id.defaultSource"/> 16431 </div> 16432 <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"/> 16433 <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))"> 16434 <a class="arrow o_move_previous text-center" href="#" t-on-click.prevent="onClickPrevious">
16435 <span class="oi oi-chevron-left"/> 16436 </a> 16437 <a class="arrow o_move_next text-center" href="#" t-on-click.prevent="onClickNext"> 16438 <span class="oi oi-chevron-right"/> 16439 </a> 16440 </t> 16441 </t> 16442 </div> 16443 </t> 16444 16445 `); 16446registerTemplate("mail.PopoutAttachmentView", `/mail/static/src/core/common/attachment_view.xml`, `<t t-name="mail.PopoutAttachmentView" xml:space="preserve"> 16447 <div class="o-mail-PopoutAttachmentView"> 16448 <t t-call="mail.AttachmentView"/> 16449 </div> 16450 </t> 16451 16452`); 16453registerTemplate("mail.AutoresizeInput", `/mail/static/src/core/common/autoresize_input.xml`, `<t t-name="mail.AutoresizeInput" xml:space="preserve"> 16454 <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"/> 16455</t> 16456 16457`); 16458registerTemplate("mail.ChatBubble", `/mail/static/src/core/common/chat_bubble.xml`, `<t t-name="mail.ChatBubble" xml:space="preserve"> 16459 <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"> 16460 <span class="o-mail-ChatBubble-unreadIndicator position-absolute" t-att-class="{ 'opacity-0': !thread?.isUnread or thread?.importantCounter }"><i class="fa fa-circle"/></span> 16461 <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"/> 16462 <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> 16463 <ImStatus t-if="showImStatus" className="'o-mail-ChatBubble-status position-absolute'" member="thread.correspondent"> 16464 <t t-set-slot="pre_icon"> 16465 <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, }"/> 16466 </t> 16467 </ImStatus> 16468 <CountryFlag t-if="thread?.showCorrespondentCountry" country="thread.correspondentCountry" class="'o-mail-ChatBubble-country position-absolute bottom-0 border shadow-sm'"/> 16469 <button class="o-mail-ChatHub-bubbleBtn btn shadow"> 16470 <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"/> 16471 </button> 16472 </div> 16473 </t> 16474 16475 `); 16476registerTemplate("mail.ChatBubblePreview", `/mail/static/src/core/common/chat_bubble.xml`, `<t t-name="mail.ChatBubblePreview" xml:space="preserve"> 16477 <div class="o-mail-ChatBubble-preview o-mail-ChatBubble-menu px-0 py-1 shadow-sm border border-secondary bg-100 o-rounded-bubble"> 16478 <div class="text-truncate base-fs fw-bolder mb-0 mx-2 px-1" t-esc="props.chatWindow.displayName"/> 16479 <t t-set="message" t-value="thread?.newestPersistentOfAllMessage"/> 16480 <div t-if="previewText" class="text-truncate small mx-2 px-1 text-muted"> 16481 <t t-call="mail.message_preview_prefix"> 16482 <t t-set="message" t-value="message"/> 16483 </t> 16484 <t t-if="message.hasOnlyAttachments"> 16485 <i class="fa me-1" t-att-class="message.previewIcon"/> 16486 <t t-out="message.previewText"/> 16487 </t> 16488 <t t-else="" t-out="previewText"/> 16489 </div> 16490 </div> 16491 </t> 16492 16493 16494 `); 16495registerTemplate("mail.message_preview_prefix", `/mail/static/src/core/common/chat_bubble.xml`, `<t t-name="mail.message_preview_prefix" xml:space="preserve"> 16496 <t t-if="message.isSelfAuthored"> 16497 <i class="fa fa-mail-reply me-1 opacity-75"/>You: 16498 </t>
16499 <t t-elif="!message.author?.eq(thread.correspondent?.persona)"> 16500 <t t-esc="message.authorName"/>: 16501 </t> 16502 </t> 16503 16504`); 16505registerTemplate("mail.ChatHub", `/mail/static/src/core/common/chat_hub.xml`, `<t t-name="mail.ChatHub" xml:space="preserve"> 16506 <div class="o-mail-ChatHub d-print-none"> 16507 16508 <t t-set="visibleChatWindows" t-value="chatHub.compact ? chatHub.opened.filter(({ bypassCompact }) => bypassCompact) : chatHub.opened "/> 16509 <t t-foreach="visibleChatWindows" t-as="cw" t-key="cw.localId"> 16510 <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)"/> 16511 </t> 16512 <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"> 16513 <div class="d-flex flex-column align-content-start justify-content-end align-items-center gap-1"> 16514 <Dropdown t-if="(chatHub.showConversations and !chatHub.compact) or position.dragged" state="options" position="'top-end'" menuClass="'m-0 mb-1 ' + store.discussDropdownMenuClass(this)"> 16515 <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> 16516 <t t-set-slot="content"> 16517 <ActionList actions="optionActions" dropdown="true"/> 16518 </t> 16519 </Dropdown> 16520 <t t-if="store.chatHub.compact and chatHub.showConversations" t-call="mail.ChatHub.compactButton"/> 16521 <t t-else=""> 16522 <t t-foreach="chatHub.folded.slice(0, chatHub.maxFolded)" t-as="cw" t-key="cw.localId"> 16523 <ChatBubble t-if="cw.canShow" chatWindow="cw"/> 16524 </t> 16525 <div class="o-mail-ChatHub-extraActions"/> 16526 <t t-if="chatHub.showConversations and chatHub.folded.length > chatHub.maxFolded" t-call="mail.ChatHub.hiddenButton"/> 16527 </t> 16528 </div> 16529 </div> 16530 </div> 16531</t> 16532 16533`); 16534registerTemplate("mail.ChatHub.compactButton", `/mail/static/src/core/common/chat_hub.xml`, `<t t-name="mail.ChatHub.compactButton" xml:space="preserve"> 16535 16536 <Dropdown manual="true"> 16537 <div class="o-mail-ChatHub-bubbleBtn o-mail-ChatHub-compact o-mail-ChatBubble justify-content-center"> 16538 <div t-if="compactCounter > 0" class="o-mail-ChatHub-hiddenBtnCounter position-absolute badge rounded-pill fw-bold o-discuss-badge shadow"> 16539 <t t-out="compactCounter"/> 16540 </div> 16541 <button class="o-mail-ChatHub-bubbleBtn btn fs-2 shadow" t-on-click="expand"> 16542 <i class="o-mail-ChatHub-hiddenBtnIcon d-flex justify-content-center align-items-center btn rounded-circle shadow-sm fa fa-comments"/> 16543 </button> 16544 </div> 16545 </Dropdown> 16546</t> 16547 16548`); 16549registerTemplate("mail.ChatHub.hiddenButton", `/mail/static/src/core/common/chat_hub.xml`, `<t t-name="mail.ChatHub.hiddenButton" xml:space="preserve"> 16550 <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"> 16551 <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"> 16552 <div t-if="hiddenCounter > 0" class="o-mail-ChatHub-hiddenBtnCounter position-absolute badge rounded-pill fw-bold o-discuss-badge shadow"> 16553 <t t-out="hiddenCounter"/> 16554 </div> 16555 <button class="o-mail-ChatHub-bubbleBtn btn outline-0 shadow">
16556 <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> 16557 </button> 16558 </div> 16559 <t t-set-slot="content"> 16560 <ul class="m-0 p-0 overflow-auto o-scrollbar-thin bg-100" role="menu" t-ref="more-menu"> 16561 <t t-foreach="chatHub.folded.slice(chatHub.maxFolded)" t-as="cw" t-key="cw.localId"> 16562 <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 })"> 16563 <img class="o-mail-ChatHub-hiddenAvatar rounded-circle object-fit-cover" t-att-src="cw.thread?.avatarUrl" alt="Thread image" draggable="false"/> 16564 <p class="text-truncate fw-bold mb-0" t-esc="cw.displayName"/> 16565 <div t-if="cw.thread?.importantCounter > 0" class="o-mail-ChatHub-hiddenCounter badge rounded-pill fw-bold o-discuss-badge" style="padding: 3px 6px"> 16566 <t t-out="cw.thread?.importantCounter"/> 16567 </div> 16568 <button class="o-mail-ChatHub-hiddenClose o-mail-ChatBubble-close d-flex align-items-center rounded" t-on-click.stop="() => cw.close()"> 16569 <i class="oi oi-close"/> 16570 </button> 16571 </li> 16572 </t> 16573 </ul> 16574 </t> 16575 </Dropdown> 16576</t> 16577 16578`); 16579registerTemplate("mail.ChatWindow", `/mail/static/src/core/common/chat_window.xml`, `<t t-name="mail.ChatWindow" xml:space="preserve"> 16580 <t t-set="partitionedActions" t-value="threadActions.partition"/> 16581 <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"> 16582 <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 }"> 16583 <t t-if="hasActionsMenu"> 16584 <div class="d-flex text-truncate bg-inherit"> 16585 <Dropdown position="ui.isSmall ? 'bottom-end' : 'left-start'" onStateChanged="isOpen => this.onActionsMenuStateChanged(isOpen)" menuClass="store.discussDropdownMenuClass(this)"> 16586 <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"> 16587 <t t-call="mail.ChatWindow.headerContent"/> 16588 <i t-if="!state.editingName" class="fa fa-fw fa-caret-down"/> 16589 </button> 16590 <t t-set-slot="content"> 16591 <t t-set="quickActionsInDropdown" t-value="partitionedActions.quick.slice(ui.isSmall ? 2 : 4)"/> 16592 <ActionList actions="[quickActionsInDropdown, partitionedActions.other, ...partitionedActions.group]" dropdown="true" thread="thread"/> 16593 </t> 16594 </Dropdown> 16595 </div> 16596 <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"/> 16597 <i t-if="state.editingName" class="fa fa-fw fa-caret-down opacity-50"/> 16598 </t> 16599 <t t-else=""> 16600 <t t-call="mail.ChatWindow.headerContent"/> 16601 </t> 16602 <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"> 16603 <t t-out="thread.importantCounter"/> 16604 </div> 16605 <div class="ms-1 flex-grow-1"/> 16606 <div class="d-flex flex-shrink-0 me-1"> 16607 <ActionList actions="partitionedActions.quick.slice(0, ui.isSmall ? 2 : 4).reverse()" inline="true" thread="thread"/> 16608 </div> 16609 <t t-if="this.store.inPublicPage and !this.store.self_partner"> 16610 <button class="btn ps-1" t-if="!state.editingGuestName"> 16611 <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"/> 16612 </button> 16613 <AutoresizeInput t-if="state.editingGuestName" className="'py-1 me-2'" autofocus="true" onValidate.bind="renameGuest" value="store.self.name"/> 16614 </t> 16615 </div> 16616 <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"> 16617 <t name="thread content"> 16618 <div t-if="threadActions.activeAction?.actionPanelComponentCondition" class="h-100 bg-inherit" t-attf-class="{{ threadActions.activeAction.panelOuterClass }}"> 16619 <t t-component="threadActions.activeAction.actionPanelComponent" t-props="{ ...threadActions.activeAction.actionPanelComponentProps, thread }"/> 16620 </div> 16621 <t t-elif="thread"> 16622 <Thread autofocus="autofocusThread" isInChatWindow="true" thread="thread" t-key="thread.localId" jumpPresent="state.jumpThreadPresent" jumpToNewMessage="props.chatWindow.jumpToNewMessage"/> 16623 <t t-call="mail.ChatWindow.memberTyping"/> 16624 <Composer composer="thread.composer" autofocus="autofocusComposer" mode="'compact'" onPostCallback.bind="() => this.state.jumpThreadPresent++" dropzoneRef="contentRef" type="composerType"/> 16625 </t> 16626 </t> 16627 </div> 16628 </div> 16629</t> 16630 16631`); 16632registerTemplate("mail.ChatWindow.headerContent", `/mail/static/src/core/common/chat_window.xml`, `<t t-name="mail.ChatWindow.headerContent" xml:space="preserve"> 16633 <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"> 16634 <img t-if="thread" class="rounded-3 object-fit-cover" t-att-src="thread.parent_channel_id?.avatarUrl ?? thread.avatarUrl" alt="Thread Image"/> 16635 <ImStatus t-if="showImStatus" className="'o-mail-ChatWindow-imStatus position-absolute'" member="thread.correspondent" size="'sm'"/> 16636 </div> 16637 <t t-if="thread?.parent_channel_id">
16638 <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 })"/> 16639 <i class="fa fa-chevron-right o-xsmaller ms-1 mt-1 text-muted opacity-75"/> 16640 </t> 16641 <CountryFlag t-if="thread?.showCorrespondentCountry" country="thread.correspondentCountry" class="'o-mail-ChatWindow-country border shadow-sm'"/> 16642 <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 }"/> 16643</t> 16644 16645`); 16646registerTemplate("mail.ChatWindow.memberTyping", `/mail/static/src/core/common/chat_window.xml`, `<t t-name="mail.ChatWindow.memberTyping" xml:space="preserve"> 16647 <div t-if="thread.hasOtherMembersTyping" class="d-flex bg-inherit position-relative"> 16648 <div class="o-mail-ChatWindow-typing d-flex px-3 position-absolute bottom-0 start-0 w-100 bg-inherit align-items-center"> 16649 <Typing channel="thread" size="'medium'"/> 16650 </div> 16651 </div> 16652</t> 16653 16654`); 16655registerTemplate("mail.Composer", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer" xml:space="preserve"> 16656 <t t-set="isChatterComposer" t-value="extended and !props.composer.message"/> 16657 <t t-set="partitionedActions" t-value="composerActions.partition"/> 16658 <t t-set="compact" t-value="props.mode === 'compact'"/> 16659 <t t-set="normal" t-value="props.mode === 'normal'"/> 16660 <t t-set="extended" t-value="props.mode === 'extended'"/> 16661 <t t-set="actionsContainerClass" t-value="'o-mail-Composer-actions d-flex o-rounded-bubble'"/> 16662 <div t-ref="root"> 16663 <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 }}"> 16664 <FileUploader t-if="allowUpload" multiUpload="isMultiUpload" onUploaded.bind="(data) => { attachmentUploader.uploadData(data) }"> 16665 <t t-set-slot="toggler"> 16666 <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> 16667 </t> 16668 </FileUploader> 16669 <div t-if="showComposerAvatar" class="o-mail-Composer-sidebarMain flex-shrink-0 d-flex"> 16670 <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"/> 16671 </div> 16672 <div class="o-mail-Composer-coreHeader"> 16673 <div t-if="props.composer.replyToMessage" class="text-truncate small p-2"> 16674 <span class="cursor-pointer" t-on-click="() => env.messageHighlight?.highlightMessage(props.composer.replyToMessage, props.composer.thread)"> 16675 Replying to <b t-esc="props.composer.replyToMessage.authorName"/> 16676 </span> 16677 <span t-if="props.composer.replyToMessage.thread?.notEq(props.composer.thread)"> 16678 on: <b><t t-esc="props.composer.replyToMessage.thread.displayName"/></b> 16679 </span> 16680 <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)"/> 16681 </div>
16682 <span t-if="props.composer.message and ui.isSmall" class="px-1" t-on-click="onClickCancelOrSaveEditText"> 16683 <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"> 16684 <i class="oi oi-close pe-2" t-att-data-type="EDIT_CLICK_TYPE.CANCEL"/> 16685 Discard editing 16686 </button> 16687 </span> 16688 </div> 16689 <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 }"> 16690 <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"> 16691 <div t-if="!extended" t-attf-class="{{ actionsContainerClass }}"> 16692 <Dropdown t-if="partitionedActions.other.length > 0" position="'top-start'" menuClass="store.discussDropdownMenuClass(this)"> 16693 <t t-call="mail.Composer.moreActions"/> 16694 <t t-set-slot="content"> 16695 <ActionList actions="partitionedActions.other" dropdown="true"/> 16696 </t> 16697 </Dropdown> 16698 </div> 16699 <div class="position-relative flex-grow-1"> 16700 <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, }"/> 16701 <Wysiwyg t-if="composerService.htmlEnabled" class="'w-100 text-break overflow-auto'" config="this.wysiwygConfig" onLoad.bind="onLoadWysiwyg"/> 16702 <t t-else=""> 16703 <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"/> 16704 16705 <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"/> 16706 </t> 16707 </div> 16708 <t t-call="mail.Composer.quickActions"/> 16709 </div> 16710 </div> 16711 <div class="o-mail-Composer-footer overflow-auto o-scrollbar-thin"> 16712 <AttachmentList t-if="props.composer.attachments.length > 0" attachments="props.composer.attachments" unlinkAttachment.bind="(...args) => attachmentUploader.unlink(...args)"/> 16713 <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"> 16714 <div t-if="partitionedActions.pickers.length > 1 and composerActions.activePicker and ui.isSmall" class="o-mail-Composer-pickerSelection btn-group w-100"> 16715 <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 }"/> 16716 </div> 16717 <div t-ref="picker-target"/> 16718 </div> 16719 <div t-else="" class="d-flex align-items-center gap-1 w-100 pe-2"> 16720 <div class="pt-1" t-att-class="{ 'mt-2': !props.composer.message }">
16721 <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"/> 16722 <t t-elif="!props.composer.message and !props.composer.restoredFromFullComposer"> 16723 <t t-call="mail.Composer.sendButton"/> 16724 <span t-if="!isSendButtonDisabled and !isMobileOS" class="text-muted small ms-1" t-out="OR_PRESS_SEND_KEYBIND"/> 16725 </t> 16726 </div> 16727 <span class="flex-grow-1"/> 16728 <t t-if="!props.composer.message" t-call="mail.Composer.extraActions"/> 16729 </div> 16730 </div> 16731 </div> 16732 </div> 16733 <NavigableList t-if="suggestion" class="'o-mail-Composer-suggestionList'" t-props="navigableListProps"/> 16734</t> 16735 16736`); 16737registerTemplate("mail.Composer.sendButton", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.sendButton" xml:space="preserve"> 16738 <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"> 16739 <t t-if="thread and thread.model !== 'discuss.channel'" t-out="SEND_TEXT"/> 16740 <t t-else=""><i class="fa fa-fw fa-lg fa-paper-plane-o"/></t> 16741 </button> 16742</t> 16743 16744`); 16745registerTemplate("mail.Composer.quickActions", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.quickActions" xml:space="preserve"> 16746 <div class="o-mail-Composer-quickActions o-mail-Composer-bg" t-attf-class="{{ actionsContainerClass }}" t-ref="quick-actions"> 16747 <div class="o-mail-Composer-mainActions d-flex flex-grow-1 align-items-baseline"> 16748 <ActionList actions="partitionedActions.quick" inline="true"/> 16749 </div> 16750 </div> 16751</t> 16752 16753`); 16754registerTemplate("mail.Composer.moreActions", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.moreActions" xml:space="preserve"> 16755 <div class="o-mail-Composer-bg" t-attf-class="{{ actionsContainerClass }}" t-ref="more-actions"> 16756 <div class="o-mail-Composer-mainActions d-flex flex-grow-1 align-items-baseline"> 16757 <t t-set="moreName">More Actions</t> 16758 <ActionList inline="true" actions="[{ 'disabledCondition': areAllActionsDisabled, 'icon': 'fa fa-plus-circle', 'id': 'more-actions', 'name': moreName, 'tags': [], }]"/> 16759 </div> 16760 </div> 16761</t> 16762 16763`); 16764registerTemplate("mail.Composer.extraActions", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.extraActions" xml:space="preserve"> 16765 <div class="me-2 o-mail-Composer-extraActions" t-attf-class="{{ actionsContainerClass }}" t-ref="extra-actions"> 16766 <div class="o-mail-Composer-mainActions d-flex flex-grow-1 align-items-baseline"> 16767 <ActionList actions="partitionedActions.other" inline="true"/> 16768 </div> 16769 </div> 16770</t> 16771 16772 `); 16773registerTemplate("mail.Composer.suggestionSpecial", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionSpecial" xml:space="preserve"> 16774 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate"> 16775 <t t-esc="option.displayName"/> 16776 </strong> 16777 <em class="text-600 text-truncate align-self-center"> 16778 <t t-esc="option.description"/> 16779 </em> 16780 </t> 16781 16782 `); 16783registerTemplate("mail.Composer.suggestionPartner", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionPartner" xml:space="preserve"> 16784 <t t-set="partner" t-value="option.partner"/> 16785 <ImStatus t-if="partner" persona="partner"/> 16786 <t t-set="title" t-value="partner.name"/> 16787 <t t-if="partner.email" t-set="title" t-value="\`\${title} (\${partner.email})\`"/> 16788 <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"> 16789 <t t-esc="partner.name"/> 16790 <t t-if="option.thread and partner.name !== option.thread.getPersonaName(partner)"> 16791 "<t t-esc="option.thread.getPersonaName(partner)"/>" 16792 </t> 16793 </strong>
16794 <span t-if="partner.email" class="text-600 text-truncate align-self-center" t-att-title="title">(<t t-esc="partner.email"/>)</span> 16795 </t> 16796 16797 `); 16798registerTemplate("mail.Composer.suggestionRole", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionRole" xml:space="preserve"> 16799 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate" t-esc="option.label"/> 16800 <em class="text-600 text-truncate align-self-center"> 16801 <t t-if="option.thread?.channel_type === 'channel'">Notify users with this role who have permission to view this channel</t> 16802 <t t-else="">Notify users with this role</t> 16803 </em> 16804 </t> 16805 16806 `); 16807registerTemplate("mail.Composer.suggestionThread", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionThread" xml:space="preserve"> 16808 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate"> 16809 <i t-attf-class="fa #{option.thread.parent_channel_id ? 'fa-comments-o' : 'fa-hashtag'} me-2"/> 16810 <t t-if="option.thread.parent_channel_id"> 16811 <t t-esc="option.thread.parent_channel_id.displayName"/> 16812 <i class="oi oi-chevron-right o-xsmaller mx-1"/> 16813 </t> 16814 <t t-esc="option.thread.displayName"/> 16815 </strong> 16816 </t> 16817 16818 `); 16819registerTemplate("mail.Composer.suggestionChannelCommand", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionChannelCommand" xml:space="preserve"> 16820 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate"> 16821 <t t-esc="option.label"/> 16822 </strong> 16823 <span class="text-600 text-truncate align-self-center"> 16824 <t t-esc="option.help"/> 16825 </span> 16826 </t> 16827 16828 `); 16829registerTemplate("mail.Composer.suggestionCannedResponse", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionCannedResponse" xml:space="preserve"> 16830 <strong class="px-2 py-1 align-self-center flex-shrink-0 text-truncate mw-100"> 16831 <t t-esc="option.source"/> 16832 </strong> 16833 <span class="text-600 text-truncate align-self-center"> 16834 <t t-esc="option.label"/> 16835 </span> 16836 </t> 16837 `); 16838registerTemplate("mail.Composer.suggestionEmoji", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.Composer.suggestionEmoji" xml:space="preserve"> 16839 <strong class="px-2 align-self-center flex-shrink-1 fs-3"> 16840 <t t-esc="option.emoji.codepoints"/> 16841 </strong> 16842 <em class="text-600 text-truncate align-self-center"> 16843 <t t-esc="option.emoji.shortcodes.join(' ')"/> 16844 </em> 16845 </t> 16846 16847 16848 `); 16849registerTemplate("mail.FullComposerRecoveryPopover", `/mail/static/src/core/common/composer.xml`, `<t t-name="mail.FullComposerRecoveryPopover" xml:space="preserve"> 16850 <div class="px-2"> 16851 <div> 16852 <p class="mb-0 fs-5 fw-bold">Continue with Full Composer?</p> 16853 <p class="mb-0 small text-muted">Formatting can only be restored in Full Composer.</p> 16854 </div> 16855 <div class="d-flex align-items-center justify-content-center gap-1 mt-2"> 16856 <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> 16857 <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> 16858 </div> 16859 </div> 16860 </t> 16861 16862`); 16863registerTemplate("mail.CountryFlag", `/mail/static/src/core/common/country_flag.xml`, `<t t-name="mail.CountryFlag" xml:space="preserve"> 16864 <img class="o-mail-CountryFlag" t-att-class="props.class" t-att-title="props.country.name" t-att-src="props.country.flagUrl"/> 16865 </t> 16866 16867`); 16868registerTemplate("mail.DateSection", `/mail/static/src/core/common/date_section.xml`, `<t t-name="mail.DateSection" xml:space="preserve"> 16869 <div class="o-mail-DateSection d-flex align-items-center w-100 fw-bold z-1" t-attf-class="{{ props.className }}"> 16870 <hr class="o-discuss-separator flex-grow-1"/>
16871 <span class="px-2 smaller text-muted opacity-50" t-att-class="{ 'user-select-none': isMobileOS }"><t t-esc="props.date"/></span> 16872 <hr class="o-discuss-separator flex-grow-1"/> 16873 </div> 16874</t> 16875`); 16876registerTemplate("mail.Gif", `/mail/static/src/core/common/gif.xml`, `<t t-name="mail.Gif" xml:space="preserve"> 16877 <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"/> 16878 </t> 16879`); 16880registerTemplate("mail.ImStatus", `/mail/static/src/core/common/im_status.xml`, `<t t-name="mail.ImStatus" xml:space="preserve"> 16881 <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, }"> 16882 <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', }"> 16883 <t t-slot="pre_icon"/> 16884 <t name="icon"> 16885 <t t-if="(!props.member or !props.member.isTyping) and persona"> 16886 <i t-if="persona.im_status === 'online'" class="fa fa-circle text-success" title="Online" role="img" aria-label="User is online"/> 16887 <i t-elif="persona.im_status === 'away'" class="fa fa-circle o-yellow" title="Idle" role="img" aria-label="User is idle"/> 16888 <i t-elif="persona.im_status === 'busy'" class="fa fa-minus-circle text-danger" title="Busy" role="img" aria-label="User is busy"/> 16889 <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"/> 16890 <i t-elif="persona.im_status === 'bot'" class="fa fa-heart text-success" title="Bot" role="img" aria-label="User is a bot"/> 16891 <i t-else="" class="fa fa-question-circle opacity-75" title="No IM status available"/> 16892 </t> 16893 <div t-if="props.member?.isTyping" class="rounded-pill" style="padding: 1px;" t-att-class="{ 'bg-300': env.inChatBubble, 'bg-inherit': !env.inChatBubble }"> 16894 <div class="bg-success rounded-pill" style="padding: 3px;"> 16895 <Typing member="props.member" channel="props.member.threadAsTyping" size="['sm', 'smaller'].includes(props.size) ? 'sm' : 'md'" displayText="false"/> 16896 </div> 16897 </div> 16898 </t> 16899 </span> 16900 </div> 16901 </t> 16902 16903`); 16904registerTemplate("mail.ImStatusDropdown", `/mail/static/src/core/common/im_status_dropdown.xml`, `<t t-name="mail.ImStatusDropdown" xml:space="preserve"> 16905 <Dropdown menuClass="'o-mail-ImStatusDropdown'"> 16906 <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> 16907 <t t-set-slot="content"> 16908 <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> 16909 <hr class="my-1"/> 16910 <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> 16911 <DropdownItem class="{ 'active': this.store.self.im_status.includes('busy') }" onSelected="() => this.setManualImStatus('busy')"> 16912 <i class="fa fa-minus-circle text-danger me-1" title="Busy" role="img"/> Do Not Disturb 16913 <div class="small text-muted">You will not receive any notifications</div> 16914 </DropdownItem> 16915 <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> 16916 </t> 16917 </Dropdown> 16918 </t> 16919`); 16920registerTemplate("mail.LinkPreview", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreview" xml:space="preserve"> 16921 <t t-if="props.linkPreview.isCard"> 16922 <t t-call="mail.LinkPreviewCard"/> 16923 </t> 16924 <t t-if="props.linkPreview.isVideo"> 16925 <t t-call="mail.LinkPreviewVideo"/> 16926 </t> 16927 <t t-if="props.linkPreview.isImage"> 16928 <t t-call="mail.LinkPreviewImage"/> 16929 </t> 16930 </t> 16931 16932 `); 16933registerTemplate("mail.LinkPreviewCard", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewCard" xml:space="preserve"> 16934 <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 }}"> 16935 <div class="row g-0 flex-row-reverse h-100"> 16936 <div class="col min-w-0" t-att-class="{ 'd-flex align-items-center': !props.linkPreview.og_description }"> 16937 <div class="px-3 py-2"> 16938 <h6 class="card-title mb-0 me-2" t-attf-class="{{ props.linkPreview.og_description ? 'text-truncate' : 'overflow-hidden' }}"> 16939 <a t-att-href="props.linkPreview.source_url" target="_blank" t-out="props.linkPreview.og_title"/> 16940 </h6>
16941 <span t-if="props.linkPreview.og_site_name" t-out="props.linkPreview.og_site_name"/> 16942 <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"/> 16943 </div> 16944 </div> 16945 <div class="o-mail-LinkPreviewCard-imageLinkWrap col-4 d-block"> 16946 <a t-att-href="props.linkPreview.source_url" target="_blank"> 16947 <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"/> 16948 <span t-else="" class="d-flex align-items-center justify-content-center w-100 h-100 bg-100 text-300"> 16949 <i class="fa fa-camera fa-2x"/> 16950 </span> 16951 </a> 16952 </div> 16953 </div> 16954 <t t-if="props.delete" t-call="mail.LinkPreview.aside"> 16955 <t t-set="className" t-value="'fa fa-stack p-0 opacity-75 opacity-100-hover'"/> 16956 </t> 16957 </div> 16958 </t> 16959 16960 `); 16961registerTemplate("mail.LinkPreviewImage", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewImage" xml:space="preserve"> 16962 <div class="o-mail-LinkPreviewImage position-relative mb-2 rounded" t-att-class="{ 'me-2': env.inChatter }" t-attf-class="{{ className }}"> 16963 <a t-if="props.linkPreview.imageUrl" t-att-href="props.linkPreview.imageUrl" target="_blank"> 16964 <Gif t-if="props.linkPreview.isGif" paused="props.gifPaused" class="'h-auto w-auto rounded'" src="props.linkPreview.imageUrl" onLoad.bind="onImageLoaded"/> 16965 <img t-else="" class="h-auto w-auto rounded" t-att-src="props.linkPreview.imageUrl" t-on-load="onImageLoaded"/> 16966 </a> 16967 <t t-if="props.delete" t-call="mail.LinkPreview.aside"> 16968 <t t-set="className" t-value="'btn btn-sm btn-dark mt-2 me-2 rounded opacity-75 opacity-100-hover'"/> 16969 </t> 16970 </div> 16971 </t> 16972 16973 `); 16974registerTemplate("mail.LinkPreviewVideo", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewVideo" xml:space="preserve"> 16975 <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 }}"> 16976 <div class="row g-0 flex-row-reverse"> 16977 <div class="col min-w-0" t-att-class="{ 'd-flex align-items-center': !props.linkPreview.og_description }"> 16978 <div class="d-flex flex-column gap-1 px-3 py-1 bg-view"> 16979 <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"/> 16980 <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' }}"> 16981 <a t-att-href="props.linkPreview.source_url" target="_blank" t-esc="props.linkPreview.og_title"/> 16982 </h6> 16983 <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"/> 16984 </div> 16985 </div> 16986 <div t-if="!props.linkPreview.videoURL" class="col-4 d-block"> 16987 <a t-att-href="props.linkPreview.source_url" target="_blank"><t t-call="mail.LinkPreviewVideo.preview"/></a> 16988 </div> 16989 </div> 16990 <div t-if="props.linkPreview.videoURL" class="o-mail-LinkPreviewVideo-container mx-3 mb-2"> 16991 <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> 16992 <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"/> 16993 </div> 16994 <t t-if="props.delete" t-call="mail.LinkPreview.aside"> 16995 <t t-set="className" t-value="'fa fa-stack p-0 opacity-75 opacity-100-hover'"/> 16996 </t> 16997 </div> 16998 </t> 16999 17000 `); 17001registerTemplate("mail.LinkPreview.aside", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreview.aside" xml:space="preserve"> 17002 <div t-if="props.message?.allowsEdition" class="position-absolute top-0 end-0 small"> 17003 <button t-attf-class="{{ className }}" class="o-mail-LinkPreview-aside btn" aria-label="Remove" t-on-click="onClick"> 17004 <i class="fa fa-times"/> 17005 </button> 17006 </div> 17007 </t> 17008 17009 `); 17010registerTemplate("mail.LinkPreviewVideo.preview", `/mail/static/src/core/common/link_preview.xml`, `<t t-name="mail.LinkPreviewVideo.preview" xml:space="preserve"> 17011 <div class="o-mail-LinkPreviewVideo-overlay position-relative h-100 rounded-bottom" t-att-class="{'bg-dark': !props.linkPreview.og_image}"> 17012 <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"/> 17013 <i t-elif="props.linkPreview.videoURL" class="fa fa-television fa-8x position-absolute top-50 start-50 translate-middle"/>
17014 <span t-else="" class="d-flex align-items-center justify-content-center w-100 h-100 bg-100 text-300"> 17015 <i class="fa fa-camera fa-2x"/> 17016 </span> 17017 <div class="position-absolute top-50 start-50 translate-middle"> 17018 <div t-if="!state.startVideo" class="o-mail-LinkPreviewVideo-play btn btn-lg rounded transition-base"> 17019 <i class="fa fa-play"/> 17020 </div> 17021 <div t-elif="!props.linkPreview.og_image" class="spinner-border text-muted"/> 17022 </div> 17023 </div> 17024 </t> 17025`); 17026registerTemplate("mail.LinkPreviewConfirmDelete", `/mail/static/src/core/common/link_preview_confirm_delete.xml`, `<t t-name="mail.LinkPreviewConfirmDelete" xml:space="preserve"> 17027 <Dialog size="'md'" title.translate="Confirmation" modalRef="modalRef"> 17028 <p class="mx-3 mb-3">Do you really want to delete this preview?</p> 17029 <t t-component="props.LinkPreview" linkPreview="props.linkPreview"/> 17030 <t t-set-slot="footer"> 17031 <button class="btn btn-danger me-2" t-on-click="onClickOk">Delete</button> 17032 <button t-if="props.deleteAll" class="btn btn-outline-danger me-2" t-on-click="onClickDeleteAll">Delete all previews</button> 17033 <button class="btn btn-secondary me-2" t-on-click="onClickCancel">Cancel</button> 17034 </t> 17035 </Dialog> 17036 </t> 17037`); 17038registerTemplate("mail.MailAttachmentDropzone", `/mail/static/src/core/common/mail_attachment_dropzone.xml`, `<t t-name="mail.MailAttachmentDropzone" xml:space="preserve"> 17039 <Dropzone t-props="this.props"> 17040 <h4>Drop Files here <i class="fa fa-paperclip"/></h4> 17041 </Dropzone> 17042 </t> 17043`); 17044registerTemplate("mail.Fullscreen", `/mail/static/src/core/common/mail_fullscreen.xml`, `<t t-name="mail.Fullscreen" xml:space="preserve"> 17045 <div class="fixed-top vw-100 vh-100"> 17046 <t t-component="props.component" t-props="props.props"/> 17047 </div> 17048 </t> 17049`); 17050registerTemplate("mail.Message", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message" xml:space="preserve"> 17051 <ActionSwiper onRightSwipe="hasTouch() and props.thread?.eq(store.inbox) ? { action: () => this.message.setDone(), bgColor: 'bg-success', icon: 'fa-check-circle' } : undefined"> 17052 <t t-set="dummy" t-value="computeActions()"/> 17053 <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()"> 17054 <div class="o-mail-Message-jumpTarget position-absolute top-0 pe-none"/> 17055 <div t-if="props.asCard and isMobileOS" class="position-absolute end-0 z-1 m-n2"><t t-call="mail.Message.actions"/></div> 17056 <div class="o-mail-Message-core position-relative d-flex flex-shrink-0 bg-inherit"> 17057 <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 }"> 17058 <t t-if="!props.squashed"> 17059 <div class="o-mail-Message-avatarContainer position-relative bg-inherit rounded-3" t-att-class="getAvatarContainerAttClass()"> 17060 <img class="o-mail-Message-avatar w-100 h-100 rounded-3" t-att-src="authorAvatarUrl" t-att-class="authorAvatarAttClass"/> 17061 </div> 17062 <t t-if="message.starred" t-call="mail.Message.sidebarStarred"/> 17063 </t> 17064 <t t-elif="message.isPending" t-call="mail.Message.pendingStatus"/> 17065 <t t-elif="!message.is_transient"> 17066 <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"> 17067 <t t-esc="message.dateSimple"/> 17068 </small> 17069 <t t-elif="message.starred" t-call="mail.Message.sidebarStarred"/> 17070 </t> 17071 </div> 17072 <div class="w-100 o-min-width-0" t-att-class="{ 'flex-grow-1': isEditing }" t-ref="messageContent"> 17073 <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">
17074 <span t-if="message.authorName and shouldDisplayAuthorName" class="o-mail-Message-author smaller" t-att-class="getAuthorAttClass()"> 17075 <strong class="me-1 o-fw-600" t-esc="message.authorName"/> 17076 </span> 17077 <t t-if="!isAlignedRight" t-call="mail.Message.notification"/> 17078 <t t-if="isAlignedRight and !message.bubbleColor and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 17079 <small t-if="!message.is_transient" class="o-mail-Message-date o-xsmaller" t-att-title="message.datetimeShort"> 17080 <t t-if="message.isPending" t-call="mail.Message.pendingStatus"/> 17081 <t t-else="" t-out="message.dateSimpleWithDay"/> 17082 </small> 17083 <small t-if="isPersistentMessageFromAnotherThread" t-on-click.prevent="openRecord" class="ms-1 text-500"> 17084 <t t-if="message.thread.model !== 'discuss.channel'"> 17085 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> 17086 </t> 17087 <t t-else=""> 17088 (from <a t-att-href="message.resUrl"><t t-esc="message.thread.prefix"/><t t-esc="message.thread.displayName or message.default_subject"/></a>) 17089 </t> 17090 </small> 17091 <div t-if="props.message.scheduledDatetime" t-att-class="{ 'ms-2': (props.isInChatWindow and isAlignedRight) or (isPersistentMessageFromAnotherThread) }" t-att-title="props.message.scheduledDateSimple"> 17092 <span class="text-600 cursor-pointer"> 17093 <i class="fa fa-calendar-o"/> 17094 </span> 17095 </div> 17096 <t t-if="isAlignedRight" t-call="mail.Message.notification"/> 17097 <t t-if="!isAlignedRight and !message.bubbleColor and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 17098 </div> 17099 <div class="o-mail-Message-contentContainer position-relative d-flex" t-att-class="{ 'flex-row-reverse': isAlignedRight }"> 17100 <div class="o-mail-Message-content o-min-width-0" t-att-class="{ 'w-100': isEditing, 'opacity-50': message.isPending, 'pt-1': message.isNote }"> 17101 <div class="o-mail-Message-textContent position-relative d-flex" t-att-class="{ 'w-100': isEditing }"> 17102 <t t-set="showTextVisually" t-value="!message.linkPreviewSquash and (message.hasTextContent or message.subtype_id?.description or message.isEmpty)"/> 17103 <t t-if="message.message_type === 'notification' and message.richBody" t-call="mail.Message.bodyAsNotification" name="bodyAsNotification"/> 17104 <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))"> 17105 <MessageLinkPreviewList t-if="!isEditing and message.linkPreviewSquash and !message.parent_id" messageLinkPreviews="message.message_link_preview_ids"/> 17106 <t t-else=""> 17107 <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', }"> 17108 <svg viewBox="0 0 6 12" height="12" width="6" x="0px" y="0px"> 17109 <path class="o-mail-Message-bubbleTailBorder" fill="currentColor" d="M 0, 0 L 5, 9 V 0 z"/> 17110 <path class="o-mail-Message-bubbleTailBg" fill="currentColor" d="M 2, 1 L 5, 7 V 1 z"/> 17111 </svg> 17112 </div> 17113 <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, }"> 17114 <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', }"/> 17115 <MessageInReply t-if="message.parent_id" class="'mx-2 p-1 pb-0 ' + (showTextVisually ? 'mt-1' : 'my-1')" message="message" onClick="props.onParentMessageClick"/> 17116 <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"> 17117 <i t-if="message.isEmpty" class="text-muted opacity-75" t-out="message.inlineBody"/> 17118 <Composer t-elif="isEditing" autofocus="true" composer="message.composer" dropzoneRef="messageBody" onDiscardCallback.bind="exitEditMode" onPostCallback.bind="exitEditMode" mode="'compact'" sidebar="false"/> 17119 <t t-else=""> 17120 <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> 17121 <div class="overflow-x-auto" t-if="message.message_type and message.message_type.includes('email')" t-ref="shadowBody"/> 17122 <t t-elif="message.showTranslation" t-out="message.richTranslationValue"/> 17123 <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"/> 17124 <p class="fst-italic text-muted small" t-if="message.showTranslation"> 17125 <t t-if="message.translationSource" t-esc="translatedFromText"/> 17126 </p> 17127 <p class="fst-italic text-muted small" t-if="message.translationErrors"> 17128 <i class="text-danger fa fa-warning" role="img" aria-label="Translation Failure"/> 17129 <t t-if="message.translationErrors" t-esc="translationFailureText"/> 17130 </p> 17131 <t t-if="showSubtypeDescription" t-out="props.messageSearch?.highlight(message.subtype_id?.description) ?? message.subtype_id?.description"/> 17132 </t> 17133 </div> 17134 </div> 17135 </t> 17136 </t> 17137 <t t-if="message.bubbleColor and message.hasTextContent and !env.inChatWindow and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 17138 </div> 17139 <div class="position-relative"> 17140 <AttachmentList t-if="message.extra_body_attachment_ids.length > 0" attachments="message.extra_body_attachment_ids" unlinkAttachment.bind="onClickAttachmentUnlink" messageSearch="props.messageSearch"/> 17141 </div> 17142 <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"/> 17143 </div> 17144 <t t-if="message.bubbleColor and (!message.hasTextContent or env.inChatWindow) and !(props.asCard and isMobileOS)" t-call="mail.Message.actions"/> 17145 </div> 17146 <MessageReactions message="message" openReactionMenu="openReactionMenu" t-if="message.reactions.length"/> 17147 <t name="after-reactions"/> 17148 </div> 17149 </div> 17150 </div> 17151 </ActionSwiper> 17152 </t> 17153 17154`); 17155registerTemplate("mail.Message.edited", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.edited" xml:space="preserve">
17156 <span class="o-xsmaller opacity-50"> (edited)</span> 17157</t> 17158 17159`); 17160registerTemplate("mail.Message.actions", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.actions" xml:space="preserve"> 17161 <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 }"> 17162 <t t-if="isMobileOS"> 17163 <Dropdown state="optionsDropdown" menuClass="store.discussDropdownMenuClass(this)"> 17164 <button class="d-none"/> 17165 <t t-set-slot="content"> 17166 <ActionList actions="messageActions.actions" dropdown="true"/> 17167 </t> 17168 </Dropdown> 17169 </t> 17170 <t t-set="isReverse" t-value="env.inChatWindow and isAlignedRight"/> 17171 <t t-if="isMobileOS and isReverse" t-call="mail.Message.emptyQuickAction"/> 17172 <div class="d-flex rounded-1 overflow-hidden gap-1" t-att-class="{ 'flex-row-reverse': isReverse }"> 17173 <ActionList actions="actions" inline="true" fw="false"/> 17174 <t t-foreach="Array.from({ length: quickActionCount - quickActions.length - 1 })" t-as="emptyQuickAction" t-key="emptyQuickAction_index"> 17175 <t t-call="mail.Message.emptyQuickAction"/> 17176 </t> 17177 </div> 17178 <t t-if="isMobileOS and !isReverse" t-call="mail.Message.emptyQuickAction"/> 17179 </div> 17180</t> 17181 17182`); 17183registerTemplate("mail.Message.emptyQuickAction", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.emptyQuickAction" xml:space="preserve"> 17184 <button class="btn border-0 o-p-0_5 rounded-0 opacity-0 pe-none"> 17185 <i class="fa-lg fa fa-question"/> 17186 </button> 17187</t> 17188 17189`); 17190registerTemplate("mail.Message.notification", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.notification" xml:space="preserve"> 17191 <div t-if="message.thread?.eq(props.thread) and message.notification_ids.length > 0" class="mx-1"> 17192 <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"> 17193 <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"/> 17194 </span> 17195 </div> 17196 <div t-elif="message.thread?.eq(props.thread) and (message.incoming_email_to?.length or message.incoming_email_cc?.length)" class="mx-1"> 17197 <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"> 17198 <i class="fa fa-envelope-o" role="img"/> 17199 </span> 17200 </div> 17201</t> 17202 17203`); 17204registerTemplate("mail.Message.bodyAsNotification", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.bodyAsNotification" xml:space="preserve"> 17205 <div class="o-mail-Message-body text-break mb-0 w-100" t-att-class="{'o-note': message.message_type == 'notification'}"> 17206 <t t-out="props.messageSearch?.highlight(message.richBody) ?? message.richBody"/> 17207 </div> 17208</t> 17209 17210`); 17211registerTemplate("mail.Message.pendingStatus", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.pendingStatus" xml:space="preserve"> 17212 <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> 17213 <span t-else="" class="o-mail-Message-pendingProgress"><i class="fa fa-fw fa-circle-o-notch fa-spin opacity-50"/></span> 17214</t> 17215 17216`); 17217registerTemplate("mail.Message.mentionedChannelIcon", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.mentionedChannelIcon" xml:space="preserve"> 17218 <i t-att-class="icon"/> 17219</t> 17220 17221`); 17222registerTemplate("mail.Message.sidebarStarred", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.sidebarStarred" xml:space="preserve"> 17223 <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"> 17224 <i class="fa fa-star o-mail-Message-starred"/> 17225 </small> 17226</t> 17227 17228 `); 17229registerTemplate("mail.Message.messageLink", `/mail/static/src/core/common/message.xml`, `<t t-name="mail.Message.messageLink" xml:space="preserve">
17230 <span> 17231 <span class="me-1" t-out="message.thread.displayName"/> 17232 <span class="fa fa-angle-right me-1" aria-hidden="true"/> 17233 <span class="fa fa-comment" aria-hidden="true"/> 17234 </span> 17235 </t> 17236 17237`); 17238registerTemplate("mail.MessageCardList", `/mail/static/src/core/common/message_card_list.xml`, `<t t-name="mail.MessageCardList" xml:space="preserve"> 17239 <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"> 17240 <div class="card mb-2 rounded-3 border-dark shadow-sm" t-foreach="props.messages" t-as="message" t-key="message.id"> 17241 <div class="card-body ps-0 py-2 rounded-3"> 17242 <div class="position-absolute top-0 end-0 z-1 mx-2 my-1 d-flex align-items-center"> 17243 <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> 17244 <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"> 17245 <i class="oi oi-close"/> 17246 </button> 17247 </div> 17248 <Message hasActions="false" message="message" thread="props.thread" messageSearch="props.messageSearch"/> 17249 </div> 17250 </div> 17251 <span t-if="props.loadMore" class="mb-1" t-ref="load-more"/> 17252 <p t-if="props.showEmpty !== undefined ? props.showEmpty : props.messages.length === 0" t-esc="emptyText" class="text-center fst-italic text-500 fs-6"/> 17253 </div> 17254 </t> 17255 17256`); 17257registerTemplate("mail.MessageConfirmDialog", `/mail/static/src/core/common/message_confirm_dialog.xml`, `<t t-name="mail.MessageConfirmDialog" xml:space="preserve"> 17258 <Dialog size="props.size" title="props.title" contentClass="'o-bg-body'"> 17259 <p class="mx-3 mb-3" t-esc="props.prompt"/> 17260 <blockquote class="mx-3 mb-3 fst-normal" style="pointer-events:none;"> 17261 <t t-component="messageComponent" message="props.message" isReadOnly="true" hasActions="false"/> 17262 </blockquote> 17263 <t t-set-slot="footer"> 17264 <button class="btn me-2" t-att-class="props.confirmColor" t-on-click="onClickConfirm" t-out="props.confirmText"/> 17265 <button class="btn btn-secondary me-2" t-on-click="props.close">Cancel</button> 17266 </t> 17267 </Dialog> 17268</t> 17269 17270`); 17271registerTemplate("mail.MessageInReply", `/mail/static/src/core/common/message_in_reply.xml`, `<t t-name="mail.MessageInReply" xml:space="preserve"> 17272 <div class="o-mail-MessageInReply" t-attf-class="{{ props.class }}"> 17273 <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', }"> 17274 <span class="d-inline-flex align-items-center" t-att-class="{ 'cursor-pointer': props.onClick }" t-on-click="() => this.props.onClick?.()"> 17275 <t t-if="!props.message.parent_id.isEmpty"> 17276 <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"/> 17277 <span class="o-mail-MessageInReply-content overflow-hidden smaller"> 17278 <b class="o-mail-MessageInReply-author o-fw-600"><t t-out="props.message.parent_id.authorName"/></b>: 17279 <span class="o-mail-MessageInReply-message ms-1 text-break"> 17280 <t t-if="!props.message.parent_id.isBodyEmpty"> 17281 <t t-out="props.message.parent_id.inlineBody"/> 17282 <em t-if="props.message.parent_id.edited" class="smaller fw-bold text-500"> (edited)</em> 17283 </t> 17284 <t t-elif="props.message.parent_id.attachment_ids.length > 0">
17285 <span class="me-2 fst-italic">Click to see the attachments</span> 17286 <i class="fa fa-image"/> 17287 </t> 17288 </span> 17289 </span> 17290 </t> 17291 <i t-else="">Original message was deleted</i> 17292 </span> 17293 </small> 17294 </div> 17295 </t> 17296`); 17297registerTemplate("mail.MessageLinkPreviewList", `/mail/static/src/core/common/message_link_preview_list.xml`, `<t t-name="mail.MessageLinkPreviewList" xml:space="preserve"> 17298 <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 }"> 17299 <div class="d-flex flex-grow-1 flex-wrap"> 17300 <t t-if="props.messageLinkPreviews.length > 1"> 17301 <t t-foreach="props.messageLinkPreviews" t-as="messageLinkPreview" t-key="messageLinkPreview.id"> 17302 <LinkPreview linkPreview="messageLinkPreview.link_preview_id" delete.bind="messageLinkPreview.hide" deleteAll.bind="messageLinkPreview.message_id.hideAllLinkPreviews" gifPaused="messageLinkPreview.gifPaused" message="messageLinkPreview.message_id"/> 17303 </t> 17304 </t> 17305 <t t-else=""> 17306 <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"/> 17307 </t> 17308 </div> 17309 </div> 17310 </t> 17311`); 17312registerTemplate("mail.MessageNotificationPopover", `/mail/static/src/core/common/message_notification_popover.xml`, `<t t-name="mail.MessageNotificationPopover" xml:space="preserve"> 17313 <div class="o-mail-MessageNotificationPopover m-2"> 17314 <t t-set="otherNotifications" t-value="this.props.message.notification_ids.filter((notif) => !notif._proxy.isFollowerNotification)"/> 17315 <t t-set="followerNotifications" t-value="this.props.message.notification_ids.filter((notif) => notif._proxy.isFollowerNotification)"/> 17316 <div t-foreach="otherNotifications" t-as="notification" t-key="notification.id"> 17317 <i class="me-2 fa-fw" t-att-class="notification.statusIcon" t-att-title="notification.statusTitle" role="img"/> 17318 <span t-if="notification.res_partner_id"> 17319 <t t-esc="props.message.getPersonaName(notification.res_partner_id)"/> 17320 <t t-if="notification.res_partner_id.email and !notification.isFailure"> (<t t-out="notification.res_partner_id.email"/>)</t> 17321 </span> 17322 <span t-elif="notification.mail_email_address" t-out="notification.mail_email_address"/> 17323 <span class="ms-1 text-muted" t-if="notification.isFailure">(<t t-esc="notification.failureMessage"/>)</span> 17324 </div> 17325 <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"> 17326 <i class="me-2 fa fa-fw fa-send-o"/> 17327 <span t-if="incomingEmail[0]" t-out="incomingEmail[0]" class="pe-1"/> 17328 <span t-if="incomingEmail[1]" t-out="incomingEmail[1]" class="ps-1"/> 17329 </div> 17330 <div t-foreach="followerNotifications" t-as="notification" t-key="notification.id"> 17331 <i class="me-2 fa-fw" t-att-class="notification.statusIcon" t-att-title="notification.statusTitle" role="img"/> 17332 <span t-if="notification.res_partner_id"> 17333 <t t-esc="props.message.getPersonaName(notification.res_partner_id)"/> 17334 <t t-if="notification.res_partner_id.email and !notification.isFailure"> (<t t-out="notification.res_partner_id.email"/>)</t> 17335 </span> 17336 <span t-elif="notification.mail_email_address" t-out="notification.mail_email_address"/>
17337 <span class="ms-1 text-muted" t-if="notification.isFailure">(<t t-esc="notification.failureMessage"/>)</span> 17338 </div> 17339 </div> 17340 </t> 17341 17342`); 17343registerTemplate("mail.MessageReactionList", `/mail/static/src/core/common/message_reaction_list.xml`, `<t t-name="mail.MessageReactionList" xml:space="preserve"> 17344 <Dropdown state="preview" position="'top-middle'" menuClass="'mt-1 p-0 overflow-hidden ' + store.discussDropdownMenuClass(this)" manual="true" bottomSheet="false"> 17345 <t t-call="mail.MessageReactionList.button"/> 17346 <t t-set-slot="content"> 17347 <t t-call="mail.MessageReactionList.preview"/> 17348 </t> 17349 </Dropdown> 17350 </t> 17351 17352 `); 17353registerTemplate("mail.MessageReactionList.button", `/mail/static/src/core/common/message_reaction_list.xml`, `<t t-name="mail.MessageReactionList.button" xml:space="preserve"> 17354 <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(), }"> 17355 <span t-esc="props.reaction.content"/> 17356 <span class="small" t-esc="props.reaction.count"/> 17357 </button> 17358 </t> 17359 17360 `); 17361registerTemplate("mail.MessageReactionList.preview", `/mail/static/src/core/common/message_reaction_list.xml`, `<t t-name="mail.MessageReactionList.preview" xml:space="preserve"> 17362 <div class="o-mail-MessageReactionList-preview px-0 py-2 cursor-pointer d-flex" t-on-click="(ev) => this.onClickReactionList(props.reaction)" t-ref="reactionList"> 17363 <div class="d-flex align-items-center mx-2 gap-2"> 17364 <span class="fs-1" t-esc="props.reaction.content"/> 17365 <span class="o-mail-MessageReactionList-previewText small me-1" t-esc="previewText(props.reaction)"/> 17366 </div> 17367 </div> 17368 </t> 17369 17370`); 17371registerTemplate("mail.MessageReactionMenu", `/mail/static/src/core/common/message_reaction_menu.xml`, `<t t-name="mail.MessageReactionMenu" xml:space="preserve"> 17372 <Dialog size="'md'" header="false" footer="false" contentClass="contentClass"> 17373 <div class="d-flex h-100" t-on-keydown="onKeydown" t-att-class="{'flex-column': store.useMobileView}" t-ref="root"> 17374 <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}"> 17375 <t t-foreach="props.message.reactions" t-as="reaction" t-key="reaction.content"> 17376 <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"> 17377 <span class="mx-1 fs-2" t-esc="reaction.content"/> 17378 <span class="mx-1 pe-2" t-att-class="{ 'text-primary': reaction.eq(state.reaction) }" t-esc="reaction.count"/> 17379 </button> 17380 </t> 17381 </div> 17382 <div class="d-flex overflow-auto o-scrollbar-thin flex-column flex-grow-1 bg-view p-2 h-100"> 17383 <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 }"> 17384 <img class="rounded object-fit-cover o-mail-MessageReactionMenu-avatar" t-att-src="persona.avatarUrl"/> 17385 <span class="d-flex flex-grow-1 align-items-center">
17386 <span class="mx-2 text-truncate fs-6" t-esc="props.message.getPersonaName(persona)"/> 17387 <div class="flex-grow-1"/> 17388 <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()"/> 17389 </span> 17390 </div> 17391 </div> 17392 </div> 17393 </Dialog> 17394 </t> 17395 17396`); 17397registerTemplate("mail.MessageReactions", `/mail/static/src/core/common/message_reactions.xml`, `<t t-name="mail.MessageReactions" xml:space="preserve"> 17398 <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, }"> 17399 <t t-foreach="props.message.reactions" t-as="reaction" t-key="reaction.content"> 17400 <MessageReactionList message="this.props.message" openReactionMenu="this.props.openReactionMenu" reaction="reaction"/> 17401 </t> 17402 <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"/> 17403 </div> 17404</t> 17405`); 17406registerTemplate("mail.NavigableList", `/mail/static/src/core/common/navigable_list.xml`, `<t t-name="mail.NavigableList" xml:space="preserve"> 17407 <div class="o-mail-NavigableList bg-view m-0 p-0 shadow-sm" t-ref="root" t-att-class="props.class"> 17408 <div t-if="show" class="o-open d-flex flex-column bg-inherit" t-on-mousedown.prevent=""> 17409 <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 }"> 17410 <t t-call="mail.NavigableList.spinner"/> 17411 </div> 17412 <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 })"> 17413 <hr class="my-2" t-if="option.group != lastGroup and option_index != 0"/> 17414 <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 }}"> 17415 <t t-if="option.optionTemplate" t-call="{{ option.optionTemplate }}"/> 17416 <t t-elif="props.optionTemplate" t-call="{{ props.optionTemplate }}"/> 17417 <t t-else="" t-esc="option.label"/> 17418 </a> 17419 <t t-set="lastGroup" t-value="option.group"/> 17420 </div> 17421 </div> 17422 </div> 17423 </t> 17424 17425 `); 17426registerTemplate("mail.NavigableList.spinner", `/mail/static/src/core/common/navigable_list.xml`, `<t t-name="mail.NavigableList.spinner" xml:space="preserve"> 17427 <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 }"> 17428 <i class="fa fa-spin fa-circle-o-notch"/> 17429 Loading⦠17430 </span> 17431 </t> 17432`); 17433registerTemplate("mail.NotificationMessage", `/mail/static/src/core/common/notification_message.xml`, `<t t-name="mail.NotificationMessage" xml:space="preserve"> 17434 <div class="o-mail-NotificationMessage text-break mx-auto px-3 text-center smaller position-relative" t-on-click="onClickNotificationMessage" t-ref="root"> 17435 <div class="o-mail-Message-jumpTarget position-absolute top-0 pe-none"/> 17436 <i t-if="message.notificationIcon" t-attf-class="{{ message.notificationIcon }} me-1 text-muted"/> 17437 <t t-if="message.notificationType === 'call'">
17438 <span class="text-muted" t-esc="callInformation"/> 17439 </t> 17440 <t t-elif="['channel_rename', 'thread_deletion'].includes(message.notificationType)"> 17441 <span class="text-muted" t-out="message.inlineBody"/> 17442 </t> 17443 <t t-else=""> 17444 <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"/> 17445 </t> 17446 <span class="o-mail-Message-date o-xsmaller ms-1" t-esc="message.dateSimpleWithDay"/> 17447 </div> 17448 </t> 17449`); 17450registerTemplate("mail.QuickReactionMenu", `/mail/static/src/core/common/quick_reaction_menu.xml`, `<t t-name="mail.QuickReactionMenu" xml:space="preserve"> 17451 <t t-if="ui.isSmall" t-call="mail.QuickReactionMenu.toggler"/> 17452 <Dropdown t-else="" state="dropdown" manual="true" menuClass="\`o-mail-QuickReactionMenu-popover shadow-none\`" position="'top-middle'" navigationOptions="navigationOptions" bottomSheet="false"> 17453 <t t-call="mail.QuickReactionMenu.toggler"/> 17454 <t t-set-slot="content"> 17455 <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"> 17456 <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)"> 17457 <span class="fs-2" t-esc="emoji"/> 17458 </button> 17459 <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()"> 17460 <i class="oi oi-close"/> 17461 </button> 17462 </div> 17463 </t> 17464 </Dropdown> 17465 </t> 17466 17467 `); 17468registerTemplate("mail.QuickReactionMenu.toggler", `/mail/static/src/core/common/quick_reaction_menu.xml`, `<t t-name="mail.QuickReactionMenu.toggler" xml:space="preserve"> 17469 <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"> 17470 <i t-att-class="props.action.icon"/> 17471 </button> 17472 </t> 17473`); 17474registerTemplate("mail.SearchMessageInput", `/mail/static/src/core/common/search_message_input.xml`, `<t t-name="mail.SearchMessageInput" xml:space="preserve"> 17475 <div class="o-mail-SearchMessageInput d-flex py-2"> 17476 <div class="input-group"> 17477 <div class="o_searchview form-control d-flex align-items-center bg-view p-0" role="search" aria-autocomplete="list"> 17478 <div class="o_searchview_input_container d-flex flex-grow-1 flex-wrap gap-1 h-100"> 17479 <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"/> 17480 </div> 17481 </div> 17482 <button class="btn" t-att-class="state.searchedTerm === state.searchTerm ? 'btn-outline-secondary' : 'btn-secondary'" t-on-click="() => this.search()" aria-label="Search button"> 17483 <i t-if="!props.messageSearch.searching" class="o_searchview_icon oi oi-search" role="img" aria-label="Search Messages" title="Search Messages"/> 17484 <i t-else="" class="fa fa-circle-o-notch fa-spin" aria-label="Search in progress" title="Search in progress"/> 17485 </button> 17486 </div> 17487 <Dropdown t-if="env.inChatter"> 17488 <button class="btn btn-outline-secondary ms-3" aria-label="Filter Messages" title="Filter Messages"> 17489 <i class="fa fa-filter" role="img"/> 17490 </button> 17491 <t t-set-slot="content"> 17492 <t t-foreach="searchFilters" t-as="searchFilter" t-key="searchFilter.label"> 17493 <DropdownItem onSelected="() => this.onChangeSearchFilter(searchFilter)"> 17494 <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"/> 17495 <t t-esc="searchFilter.name"/> 17496 </DropdownItem> 17497 </t> 17498 </t> 17499 </Dropdown> 17500 <button t-if="env.inChatter" class="btn btn-outline-secondary ms-3" t-on-click="() => this.clear()" aria-label="Close button"> 17501 <i class="o_searchview_icon oi oi-close cursor-pointer" role="img" aria-label="Close search" title="Close"/> 17502 </button> 17503 </div> 17504 </t> 17505`); 17506registerTemplate("mail.SearchMessageResult", `/mail/static/src/core/common/search_message_result.xml`, `<t t-name="mail.SearchMessageResult" xml:space="preserve"> 17507 <div class="o-mail-SearchMessageResult"> 17508 <p t-if="MESSAGE_FOUND" class="o-mail-SearchMessagesPanel-title py-1 mb-0 fw-bolder text-center text-uppercase text-muted smaller"> 17509 <t t-out="MESSAGE_FOUND"/> 17510 </p> 17511 <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"/> 17512 </div> 17513 </t> 17514`); 17515registerTemplate("mail.SearchMessagesPanel", `/mail/static/src/core/common/search_messages_panel.xml`, `<t t-name="mail.SearchMessagesPanel" xml:space="preserve"> 17516 <ActionPanel title="title" minWidth="200" initialWidth="400" icon="'oi oi-search'"> 17517 <SearchMessageInput closeSearch="props.closeSearch" messageSearch="messageSearch" thread="props.thread"/> 17518 <SearchMessageResult thread="props.thread" messageSearch="messageSearch"/> 17519 </ActionPanel> 17520 </t> 17521`); 17522registerTemplate("mail.Thread", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread" xml:space="preserve"> 17523 <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"> 17524 <t t-if="!props.thread.isEmpty or props.thread.loadOlder or props.thread.hasLoadingFailed" name="content"> 17525 <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'}">
17526 <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%)\`"/> 17527 <t t-set="currentDay" t-value="0"/> 17528 <t t-if="props.order === 'asc'"> 17529 <t t-if="showLoadOlder" t-call="mail.Thread.loadOlder"/> 17530 <t t-elif="props.thread.hasLoadingFailed" t-call="mail.Thread.loadingError"/> 17531 <t t-elif="showStartMessage" t-call="mail.Thread.startMessage"/> 17532 </t> 17533 <span t-else="" class="pt-1" t-ref="load-newer"/> 17534 <t t-set="messages" t-value="orderedMessages"/> 17535 <t t-foreach="messages" t-as="msg" t-key="msg.id"> 17536 <t t-set="prevMsg" t-value="messages[msg_index -1]"/> 17537 <t t-if="msg.dateDay !== currentDay and props.showDates"> 17538 <DateSection date="msg.dateDay" className="'pt-2 px-2'"/> 17539 <t t-set="currentDay" t-value="msg.dateDay"/> 17540 </t> 17541 <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"> 17542 <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> 17543 </div> 17544 <NotificationMessage t-if="msg.isNotification and !msg.notificationHidden" message="msg" thread="props.thread" registerMessageRef="registerMessageRef"/> 17545 <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"/> 17546 </t> 17547 <span t-if="props.order === 'asc'" class="pt-1" t-ref="load-newer"/> 17548 <t t-else=""> 17549 <t t-if="showLoadOlder" t-call="mail.Thread.loadOlder"/> 17550 <t t-if="props.thread.hasLoadingFailed" t-call="mail.Thread.loadingError"/> 17551 </t> 17552 </div> 17553 </t> 17554 <t t-else=""> 17555 <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 }"> 17556 <t t-if="props.thread.isLoaded and props.showEmptyMessage"> 17557 <t name="empty-message"> 17558 <t t-if="showStartMessage" t-call="mail.Thread.startMessage"/> 17559 <div t-else="" class="d-flex flex-column align-items-center"> 17560 <span class="fs-1" style="filter: grayscale(1);">ð¶</span> 17561 <span>The conversation is empty.</span> 17562 </div> 17563 </t> 17564 </t> 17565 </div> 17566 </t> 17567 <t t-call="mail.Thread.jumpPresent"/> 17568 </div> 17569</t> 17570 17571`); 17572registerTemplate("mail.Thread.jumpPresent", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.jumpPresent" xml:space="preserve"> 17573 <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> 17574</t> 17575 17576`); 17577registerTemplate("mail.Thread.loadOlder", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.loadOlder" xml:space="preserve"> 17578 <button class="btn btn-link" t-att-class="{ 'opacity-0': !state.mountedAndLoaded }" t-on-click="onClickLoadOlder" t-ref="load-older">Load More</button> 17579</t> 17580 17581`); 17582registerTemplate("mail.Thread.loadingError", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.loadingError" xml:space="preserve"> 17583 <div class="d-flex flex-grow-1 align-items-center justify-content-center flex-column"> 17584 <div class="o-mail-Thread-error"> 17585 An error occurred while fetching messages. 17586 </div>
17587 <span t-if="props.thread.hasLoadingFailedError" class="o-xsmaller text-muted" t-esc="props.thread.hasLoadingFailedError"/> 17588 <button class="btn btn-link" t-on-click="onClickRetry"> 17589 Click here to retry 17590 </button> 17591 </div> 17592</t> 17593 17594 17595`); 17596registerTemplate("mail.discuss_badge", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.discuss_badge" xml:space="preserve"> 17597 <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;')"> 17598 <span class="rounded-pill o-innerBadge" t-attf-class="{{ counterClass }}" t-esc="counter" style="top: 0 !important;"/> 17599 </span> 17600</t> 17601 17602`); 17603registerTemplate("mail.Thread.startMessage", `/mail/static/src/core/common/thread.xml`, `<t t-name="mail.Thread.startMessage" xml:space="preserve"> 17604 <div class="pt-4" t-att-class="{ 'px-3': env.inChatWindow, 'px-2': env.inDiscussApp or env.inMeetingChat }"> 17605 <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, }"> 17606 <div class="o-mail-Thread-avatar d-inline" t-att-class="{'o-mail-Thread-avatarChatWindow': env.inChatWindow }"> 17607 <img t-if="!props.thread.parent_channel_id" class="rounded-3 object-fit-cover" t-att-src="props.thread?.avatarUrl" alt="Thread Image"/> 17608 <i t-else="" class="fa fa-comments-o text-muted" role="presentation"/> 17609 </div> 17610 <div role="heading" aria-level="1" class="text-break" t-att-class="{ 'fs-1': !env.inChatWindow, 'fs-3': env.inChatWindow }" t-esc="startMessageTitle"/> 17611 </div> 17612 <p class="text-muted mb-0 small text-break" t-esc="startMessageSubtitle"/> 17613 </div> 17614</t> 17615`); 17616registerTemplate("mail.ThreadIcon", `/mail/static/src/core/common/thread_icon.xml`, `<t t-name="mail.ThreadIcon" xml:space="preserve"> 17617 <div class="o-mail-ThreadIcon d-flex justify-content-center flex-shrink-0" t-att-class="props.className"> 17618 <t t-set="largeClass" t-value="props.size === 'large' ? 'fa-lg' : ''"/> 17619 <t t-if="props.thread.channel_type === 'channel'"> 17620 <div t-if="props.thread.group_public_id" class="fa fa-fw fa-hashtag" t-att-class="largeClass" t-att-title="props.thread.accessRestrictedToGroupText"/> 17621 <div t-else="" class="fa fa-fw fa-globe" t-att-class="largeClass" title="Public Channel"/> 17622 </t> 17623 <t t-elif="props.thread.channel_type?.includes('chat') and correspondent"> 17624 <t name="chat"> 17625 <t name="chat_static"> 17626 <ImStatus t-if="correspondent.im_status" member="correspondent" size="'md'"/> 17627 <div t-else="" class="d-flex rounded-circle bg-inherit"> 17628 <i class="fa-fw" t-att-class="largeClass" t-attf-class="#{ defaultChatIcon.class }" t-att-title="defaultChatIcon.title"/> 17629 </div> 17630 </t> 17631 </t> 17632 </t> 17633 <div t-elif="props.thread.channel_type === 'group'" class="o-mail-ThreadIcon oi fa-fw oi-users" t-att-class="largeClass" title="Grouped Chat"/> 17634 <t t-elif="props.thread.model === 'mail.box'"> 17635 <div t-if="props.thread.id === 'inbox'" class="fa fa-fw fa-inbox" t-att-class="largeClass"/> 17636 <div t-elif="props.thread.id === 'starred'" class="fa fa-fw fa-star-o" t-att-class="largeClass"/> 17637 <div t-elif="props.thread.id === 'history'" class="fa fa-fw fa-history" t-att-class="largeClass"/> 17638 </t> 17639 </div> 17640 </t> 17641 17642`); 17643registerTemplate("mail.ActionPanel", `/mail/static/src/discuss/core/common/action_panel.xml`, `<t t-name="mail.ActionPanel" xml:space="preserve"> 17644 <ResizablePanel t-if="props.resizable and !env.inChatWindow and !env.inChatter and !ui.isSmall" class="classNames" handleSide="'start'" initialWidth="initialWidth" minWidth="minWidth"> 17645 <t t-call="mail.ActionPanel.content"/> 17646 </ResizablePanel> 17647 <div t-else="" t-att-class="classNames"> 17648 <t t-call="mail.ActionPanel.content"/> 17649 </div> 17650 </t> 17651 17652 `); 17653registerTemplate("mail.ActionPanel.content", `/mail/static/src/discuss/core/common/action_panel.xml`, `<t t-name="mail.ActionPanel.content" xml:space="preserve"> 17654 <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 }"> 17655 <div class="d-flex align-items-center gap-1"> 17656 <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"> 17657 <i class="oi oi-arrow-left fa-fw"/> 17658 </button> 17659 <i t-if="props.icon" class="text-muted fa-fw" t-att-class="props.icon"/> 17660 <p t-if="props.title" class="fw-bold text-uppercase m-0 flex-grow-1" t-esc="props.title"/> 17661 <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"> 17662 <i class="oi oi-close fa-fw"/> 17663 </button> 17664 </div> 17665 <t t-slot="header"/> 17666 </div> 17667 <div class="o-mail-ActionPanel-content px-1 d-flex flex-column flex-grow-1 bg-inherit o-min-height-0" t-ref="contentRef"> 17668 <t t-slot="default"/> 17669 </div> 17670 </t> 17671 17672`); 17673registerTemplate("mail.AttachmentPanel", `/mail/static/src/discuss/core/common/attachment_panel.xml`, `<t t-name="mail.AttachmentPanel" xml:space="preserve"> 17674 <ActionPanel title.translate="Attachments" minWidth="200" initialWidth="400" icon="'fa fa-paperclip'"> 17675 <div class="d-flex flex-column py-2 flex-grow-1"> 17676 <div class="flex-grow-1" t-att-class="{ 'd-flex justify-content-center align-items-center': props.thread.attachments.length === 0, }"> 17677 <p t-if="props.thread.attachments.length === 0" class="text-center fst-italic text-500"> 17678 <t t-if="props.thread.channel_type === 'channel'">This channel doesn't have any attachments.</t> 17679 <t t-else="">This conversation doesn't have any attachments.</t> 17680 </p> 17681 <div t-else="" t-foreach="attachmentsByDate" t-as="dateDay" t-key="dateDay" class="d-flex flex-column">
17682 <DateSection date="dateDay" className="'my-1'"/> 17683 <AttachmentList attachments="dateDay_value" unlinkAttachment="(attachment) => this.attachmentUploadService.unlink(attachment)"/> 17684 </div> 17685 </div> 17686 <span t-ref="load-older"/> 17687 </div> 17688 </ActionPanel> 17689 </t> 17690`); 17691registerTemplate("mail.AvatarStack", `/mail/static/src/discuss/core/common/avatar_stack.xml`, `<t t-name="mail.AvatarStack" xml:space="preserve"> 17692 <div t-if="props.personas.length > 0" class="bg-inherit" t-att-class="props.containerClass" t-on-click="props.onClick"> 17693 <div class="d-flex bg-inherit position-relative z-1" t-att-class="{'flex-column': props.direction === 'v'}"> 17694 <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)}}"> 17695 <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)}}"/> 17696 <t t-slot="avatarExtraInfo" persona="persona"/> 17697 </span> 17698 <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> 17699 </div> 17700 </div> 17701 </t> 17702`); 17703registerTemplate("discuss.ChannelInvitation", `/mail/static/src/discuss/core/common/channel_invitation.xml`, `<t t-name="discuss.ChannelInvitation" xml:space="preserve"> 17704 <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'"> 17705 <t t-call="discuss.ChannelInvitation.main"/> 17706 </ActionPanel> 17707 <t t-else="" t-call="discuss.ChannelInvitation.main"/> 17708 </t> 17709 17710 `); 17711registerTemplate("discuss.ChannelInvitation.main", `/mail/static/src/discuss/core/common/channel_invitation.xml`, `<t t-name="discuss.ChannelInvitation.main" xml:space="preserve"> 17712 <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 }"> 17713 <t t-if="store.self_partner"> 17714 <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"/> 17715 <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 }"> 17716 <div t-if="selectablePartners.length === 0 and state.selectableEmails.length === 0" class="smaller text-muted mx-1 opacity-50"> 17717 <t t-if="props.thread">No user found that is not already a member of this channel.</t> 17718 <t t-else="">No user found.</t> 17719 </div> 17720 <div t-if="state.searchResultCount > selectablePartners.length" class="smaller text-muted mx-1 mb-1 fst-italic" t-esc="showingResultNarrowText"/> 17721 <t t-foreach="selectablePartners" t-as="selectablePartner" t-key="selectablePartner.id"> 17722 <t t-call="discuss.ChannelInvitation-selectableItem"> 17723 <t t-set="selectableItemIndex" t-value="selectablePartner_index"/> 17724 </t> 17725 </t> 17726 <t t-foreach="state.selectableEmails" t-as="selectableEmailAddress" t-key="selectableEmailAddress"> 17727 <t t-call="discuss.ChannelInvitation-selectableItem"> 17728 <t t-set="selectableEmailAddress" t-value="selectableEmailAddress"/> 17729 <t t-set="selectableItemIndex" t-value="selectablePartners.length + selectableEmailAddress_index"/> 17730 </t> 17731 </t> 17732 </ul> 17733 </t> 17734 <div class="o-discuss-ChannelInvitation-invitationBox pt-0 pb-1 bg-inherit"> 17735 <t t-if="store.self_partner"> 17736 <div t-if="selectedPartners.length > 0 or state.selectedEmails.length > 0" class="pt-2"> 17737 <div class="o-discuss-ChannelInvitation-selectedList d-flex flex-wrap overflow-auto o-scrollbar-thin"> 17738 <t t-foreach="selectedPartners" t-as="selectedPartner" t-key="selectedPartner.id"> 17739 <button class="btn btn-light fw-bolder smaller pe-1" title="Unselect person" t-on-click="() => this.onClickSelectedPartner(selectedPartner)"> 17740 <t t-esc="selectedPartner.name"/>Â <i class="oi oi-close border border-dark-subtle ms-1"/> 17741 </button> 17742 </t> 17743 <t t-foreach="state.selectedEmails" t-as="selectedEmail" t-key="selectedEmail"> 17744 <button class="btn btn-light fw-bolder smaller pe-1" title="Unselect person" t-on-click="() => this.onClickSelectedEmail(selectedEmail)"> 17745 <t t-esc="selectedEmail"/>Â <i class="oi oi-close border border-dark-subtle ms-1"/> 17746 </button> 17747 </t> 17748 </div> 17749 </div> 17750 <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"> 17751 <t t-esc="invitationButtonText"/> 17752 </button> 17753 </t> 17754 <hr t-if="props.thread?.invitationLink" class="border-dark-subtle"/> 17755 <div t-if="props.thread?.invitationLink" class="input-group"> 17756 <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"/> 17757 <button class="btn btn-primary px-2 o-py-0_5" t-on-click="onClickCopy"> 17758 <i class="fa fa-copy"/> 17759 </button> 17760 </div> 17761 <div t-if="props.thread?.accessRestrictedToGroupText" class="mt-2 text-muted smaller mx-1" t-esc="props.thread.accessRestrictedToGroupText"/> 17762 </div> 17763 </div> 17764 </t> 17765 `); 17766registerTemplate("discuss.ChannelInvitation-selectableItem", `/mail/static/src/discuss/core/common/channel_invitation.xml`, `<t t-name="discuss.ChannelInvitation-selectableItem" xml:space="preserve"> 17767 <t t-set="isSelected" t-value="selectablePartner ? selectablePartner.in(selectedPartners) : state.selectedEmails.includes(selectableEmailAddress)"/> 17768 <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) "> 17769 <div class="d-flex align-items-center p-1 bg-inherit"> 17770 <div class="o-discuss-ChannelInvitation-avatar position-relative d-flex flex-shrink-0 bg-inherit"> 17771 <t t-if="selectablePartner"> 17772 <img class="w-100 h-100 rounded-3 object-fit-cover" t-att-src="selectablePartner.avatarUrl"/> 17773 <ImStatus persona="selectablePartner" className="'position-absolute top-100 start-100 translate-middle mt
17773-n1 ms-n1'" size="'md'"/> 17774 </t> 17775 <div t-else="" class="w-100 h-100 d-flex align-items-center justify-content-center rounded-3 bg-primary text-white"> 17776 <i class="fa fa-envelope"/> 17777 </div> 17778 </div> 17779 </div> 17780 <div class="d-flex flex-column mx-2 flex-grow-1 overflow-hidden o-mt-0_5"> 17781 <t t-if="selectablePartner"> 17782 <div class="d-flex overflow-hidden align-items-baseline" name="selectablePartnerName"> 17783 <span class="text-truncate" t-esc="selectablePartner.name"/> 17784 </div> 17785 <div class="d-flex flex-column flex-grow-1 gap-1" name="selectablePartnerDetail"> 17786 <span t-if="selectablePartner.email" t-esc="selectablePartner.email" class="text-truncate text-start smaller text-600 fw-normal lh-1"/> 17787 </div> 17788 </t> 17789 <div t-else="" class="overflow-hidden d-flex flex-column align-items-baseline"> 17790 <span class="text-truncate text-start w-100" t-esc="selectableEmailAddress"/> 17791 <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> 17792 </div> 17793 </div> 17794 <input class="form-check-input flex-shrink-0 me-1" type="checkbox" t-att-checked="isSelected ? 'checked' : undefined"/> 17795 </li> 17796 </t> 17797`); 17798registerTemplate("discuss.ChannelMemberList", `/mail/static/src/discuss/core/common/channel_member_list.xml`, `<t t-name="discuss.ChannelMemberList" xml:space="preserve"> 17799 <ActionPanel title.translate="Members" minWidth="200" initialWidth="env.inMeetingView ? 400 : 250" icon="'oi oi-users'"> 17800 <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> 17801 <t t-if="props.thread.onlineMembers.length > 0"> 17802 <t t-call="discuss.ChannelMemberList.section"> 17803 <t t-set="sectionName" t-value="onlineSectionText"/> 17804 </t> 17805 <div class="d-flex flex-column bg-inherit gap-1"> 17806 <t t-foreach="props.thread.onlineMembers" t-as="member" t-key="member.id" t-call="discuss.channel_member"/> 17807 </div> 17808 </t> 17809 <t name="offlineMembers" t-if="props.thread.offlineMembers.length > 0"> 17810 <t t-call="discuss.ChannelMemberList.section"> 17811 <t t-set="sectionName" t-value="offlineSectionText"/> 17812 </t> 17813 <div class="d-flex flex-column bg-inherit gap-1"> 17814 <t t-foreach="props.thread.offlineMembers" t-as="member" t-key="member.id" t-call="discuss.channel_member"> 17815 <t t-set="offline" t-value="1"/> 17816 </t> 17817 </div> 17818 </t> 17819 <span t-if="props.thread.unknownMembersCount === 1" class="mx-2 mt-2">And 1 other member.</span> 17820 <span t-if="props.thread.unknownMembersCount > 1" class="mx-2 mt-2">And <t t-esc="props.thread.unknownMembersCount"/> other members.</span> 17821 <div t-if="!props.thread.areAllMembersLoaded" class="mx-2 my-1"> 17822 <button class="btn btn-secondary" title="Load more" t-on-click.stop="() => props.thread.fetchChannelMembers()">Load more</button> 17823 </div> 17824 </ActionPanel> 17825 </t> 17826 17827 `); 17828registerTemplate("discuss.ChannelMemberList.section", `/mail/static/src/discuss/core/common/channel_member_list.xml`, `<t t-name="discuss.ChannelMemberList.section" xml:space="preserve"> 17829 <h6 class="text-muted pt-4 text-uppercase o-xsmaller opacity-75" t-esc="sectionName"/> 17830 </t> 17831 17832 `); 17833registerTemplate("discuss.channel_member", `/mail/static/src/discuss/core/common/channel_member_list.xml`, `<t t-name="discuss.channel_member" xml:space="preserve"> 17834 <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)"> 17835 <div class="bg-inherit o-discuss-ChannelMember-avatar position-relative d-flex flex-shrink-0 rounded-3"> 17836 <img class="w-100 h-100 rounded-3 object-fit-cover" t-att-src="member.avatarUrl"/> 17837 <ImStatus member="member" className="'position-absolute top-100 start-100 translate-middle mt
17837-n1 ' + (member.isTyping ? 'ms-n2' : 'ms-n1')" size="'md'"/> 17838 </div> 17839 <div t-ref="displayName" class="d-flex overflow-hidden flex-column lh-sm"> 17840 <span class="ms-2 text-truncate text-muted fw-bold" t-esc="member.name" t-att-title="member.name"/> 17841 </div> 17842 <span class="ms-auto"> 17843 <span t-if="member.in(props.thread.invited_member_ids)" class="p-1 oi oi-user-plus opacity-75"/> 17844 <span t-if="member.rtcSession?.is_muted and !member.rtcSession?.is_deaf" class="p-1 fa fa-microphone-slash opacity-75"/> 17845 <span t-elif="member.rtcSession?.is_deaf" class="p-1 fa fa-deaf opacity-75"/> 17846 <span t-if="member.rtcSession?.raisingHand" class="p-1 fa fa-hand-paper-o"/> 17847 </span> 17848 17849 </div> 17850 </t> 17851 17852`); 17853registerTemplate("discuss.DeleteThreadDialog", `/mail/static/src/discuss/core/common/delete_thread_dialog.xml`, `<t t-name="discuss.DeleteThreadDialog" xml:space="preserve"> 17854 <ActionPanel title.translate="Delete Thread" icon="'fa fa-trash'" resizable="false"> 17855 <div class="d-flex justify-content-between align-items-center"> 17856 <p class="fs-5 mb-0">Permanently delete this thread?</p> 17857 <button class="btn btn-danger" t-on-click="onConfirmation"> 17858 Delete Thread 17859 </button> 17860 </div> 17861 </ActionPanel> 17862 </t> 17863`); 17864registerTemplate("mail.DiscussNotificationSettings", `/mail/static/src/discuss/core/common/discuss_notification_settings.xml`, `<t t-name="mail.DiscussNotificationSettings" xml:space="preserve"> 17865 <div class="o-mail-DiscussNotificationSettings d-flex flex-column"> 17866 <div class="d-flex flex-column my-1"> 17867 <h5>Channel Notifications</h5> 17868 <span class="mb-1 text-muted small">This setting will be applied to all channels using the default notification settings.</span> 17869 <t t-foreach="store.settings.NOTIFICATIONS" t-as="notif" t-key="notif.label"> 17870 <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)"> 17871 <input class="form-check-input" type="radio" t-att-checked="notif.label === store.settings.channel_notifications"/> 17872 <div class="d-flex flex-column text-start flex-grow-1 mx-3"> 17873 <span t-esc="notif.name"/> 17874 </div> 17875 </button> 17876 </t> 17877 </div> 17878 <hr class="o-discuss-separator my-1"/> 17879 <label class="cursor-pointer d-flex align-items-center my-1"> 17880 <h5>Message sound</h5> 17881 <div class="flex-grow-1"/> 17882 <div class="form-check form-switch"> 17883 <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()"/> 17884 </div> 17885 </label> 17886 </div> 17887 </t> 17888`); 17889registerTemplateExtension("mail.Message", `/mail/static/src/discuss/core/common/message_patch.xml`, `<t t-inherit="mail.Message" t-inherit-mode="extension" xml:space="preserve"> 17890 <xpath expr="//div[hasclass('o-mail-Message-body')]" position="after"> 17891 <div class="o-mail-Message-seenContainer position-absolute"> 17892 <MessageSeenIndicator t-if="showSeenIndicator" message="props.message" thread="props.thread"/> 17893 </div> 17894 </xpath> 17895 <xpath expr="//AttachmentList" position="after"> 17896 <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"> 17897 <MessageSeenIndicator t-if="showSeenIndicator" message="props.message" thread="props.thread"/> 17898 </div> 17899 </xpath> 17900 </t> 17901`); 17902registerTemplate("mail.MessageSeenIndicator", `/mail/static/src/discuss/core/common/message_seen_indicator.xml`, `<t t-name="mail.MessageSeenIndicator" xml:space="preserve">
17903 <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"> 17904 <t t-if="!props.message.isMessagePreviousToLastSelfMessageSeenByEveryone"> 17905 <i t-if="props.message.hasSomeoneFetched or props.message.hasSomeoneSeen" class="fa fa-check ps-1"/> 17906 <i t-if="props.message.hasSomeoneSeen" class="o-second start-0 fa fa-check position-absolute"/> 17907 </t> 17908 </span> 17909 </t> 17910 17911 `); 17912registerTemplate("mail.MessageSeenIndicatorPopover.card", `/mail/static/src/discuss/core/common/message_seen_indicator.xml`, `<t t-name="mail.MessageSeenIndicatorPopover.card" xml:space="preserve"> 17913 <div class="o-mail-MessageSeenIndicatorPopover-card d-flex align-items-center gap-2"> 17914 <span class="o_avatar position-relative o_card_avatar" style="width: 30px;height:30px;"> 17915 <img t-att-src="member.avatarUrl" class="w-100 h-100 rounded object-fit-cover"/> 17916 </span> 17917 <span class="fw-bold" t-esc="member.name"/> 17918 </div> 17919 </t> 17920 17921 `); 17922registerTemplate("mail.MessageSeenIndicatorDialog", `/mail/static/src/discuss/core/common/message_seen_indicator.xml`, `<t t-name="mail.MessageSeenIndicatorDialog" xml:space="preserve"> 17923 <Dialog size="'sm'" title.translate="Seen by:" footer="false" withBodyPadding="false" contentClass="'o-mail-MessageSeenIndicatorDialog'"> 17924 <ul class="list-group list-group-flush list-unstyled py-1" t-ref="content" tabindex="0"> 17925 <li class="list-group-item py-2" t-foreach="props.message.channelMemberHaveSeen" t-as="member" t-key="member.id"> 17926 <t t-call="mail.MessageSeenIndicatorPopover.card"/> 17927 </li> 17928 </ul> 17929 </Dialog> 17930 </t> 17931 17932`); 17933registerTemplate("discuss.NotificationSettings", `/mail/static/src/discuss/core/common/notification_settings.xml`, `<t t-name="discuss.NotificationSettings" xml:space="preserve"> 17934 <ActionPanel title.translate="Notification Settings" resizable="!!env.inMeetingView" initialWidth="400" icon="'fa fa-bell'"> 17935 <div class="o-discuss-NotificationSettings"> 17936 <t t-if="props.thread.self_member_id?.mute_until_dt"> 17937 <button class="btn w-100 d-flex p-1 opacity-75 border-0" t-on-click="()=>this.setMute(false)"> 17938 <div class="d-flex flex-column flex-grow-1 px-2 py-1 w-100 rounded"> 17939 <span class="fs-6 fw-bold text-wrap text-start text-break">Unmute Conversation</span> 17940 <span class="fw-normal smaller text-start" t-out="store.settings.getMuteUntilText(props.thread.self_member_id?.mute_until_dt)"/> 17941 </div> 17942 </button> 17943 </t> 17944 <div class="d-flex"> 17945 <Dropdown position="ui.isSmall ? 'bottom-end' : 'right-start'" menuClass="'o-mail-NotificationSettings-submenu my-0 ' + store.discussDropdownMenuClass(this)"> 17946 <button class="btn w-100 d-flex p-1 opacity-75 border-0"> 17947 <div class="d-flex flex-grow-1 align-items-center px-0 py-1 w-100 rounded"> 17948 <span class="text-wrap text-start text-break">Mute Conversation</span> 17949 <div class="o-discuss-NotificationSettings-separator flex-grow-1"/> 17950 <i class="oi oi-arrow-right ms-2 me-1"/> 17951 </div> 17952 </button> 17953 <t t-set-slot="content"> 17954 <t t-foreach="store.settings.MUTES" t-as="mute" t-key="mute.label"> 17955 <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> 17956 </t> 17957 </t> 17958 </Dropdown> 17959 </div> 17960 <t t-if="props.thread.channel_type === 'channel'"> 17961 <hr class="solid mx-1 my-2"/> 17962 <button class="btn d-flex w-100 p-0 border-0" t-on-click="() => store.settings.setCustomNotifications(false, props.thread)"> 17963 <div class="d-flex flex-grow-1 align-items-center px-2 rounded"> 17964 <div class="d-flex flex-column align-items-start">
17965 <span class="fs-6 text-wrap text-start text-break">Use Default</span> 17966 <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> 17967 </div> 17968 <div class="o-discuss-NotificationSettings-separator flex-grow-1"/> 17969 <input class="form-check-input shadow-sm" type="radio" t-att-checked="!props.thread.self_member_id?.custom_notifications"/> 17970 </div> 17971 </button> 17972 <t t-foreach="store.settings.NOTIFICATIONS" t-as="notif" t-key="notif.label"> 17973 <button class="btn w-100 d-flex p-0 border-0" t-on-click="() => store.settings.setCustomNotifications(notif.label, props.thread)"> 17974 <div class="d-flex flex-grow-1 align-items-center px-2 py-1 rounded"> 17975 <span class="fs-6 fw-normal text-wrap text-start text-break" t-esc="notif.name"/> 17976 <div class="o-discuss-NotificationSettings-separator flex-grow-1"/> 17977 <input class="form-check-input ms-2 shadow-sm" type="radio" t-att-checked="props.thread.self_member_id?.custom_notifications === notif.label"/> 17978 </div> 17979 </button> 17980 </t> 17981 </t> 17982 </div> 17983 </ActionPanel> 17984 </t> 17985 17986`); 17987registerTemplateExtension("mail.Thread", `/mail/static/src/discuss/core/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 17988 <xpath expr="//div[hasclass('o-mail-Thread')]" position="before"> 17989 <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"> 17990 <t t-set="alertClass" t-value="'alert alert-warning m-0 border-start-0 o-mail-Thread-bannerHover py-1 rounded-0'"/> 17991 <span t-attf-class="{{ alertClass }} flex-grow-1" t-on-click="onClickUnreadMessagesBanner" t-esc="newMessageBannerText"/> 17992 <span t-attf-class="{{ alertClass }}" t-on-click="() => props.thread.markAsRead()">Mark as Read<i class="ms-2 fa fa-check-square"/></span> 17993 </span> 17994 </xpath> 17995 </t> 17996`); 17997registerTemplate("discuss.BlurPerformanceWarning", `/mail/static/src/discuss/call/common/blur_performance_warning.xml`, `<t t-name="discuss.BlurPerformanceWarning" xml:space="preserve"> 17998 <CallDropdown class="'z-2'" menuClass="'o-discuss-BlurPerformanceWarning shadow bg-warning-subtle border-warning-subtle'" openByDefault="true"> 17999 <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"> 18000 <i class="fa fa-exclamation-triangle fa-fw"/> 18001 </div> 18002 <t t-set-slot="content"> 18003 <div class="position-relative p-3 rounded text-dark" style="min-width:275px;"> 18004 <div class="position-absolute top-0 end-0 m-2 cursor-pointer" t-on-click="onClickClose" title="Dismiss warning"> 18005 <i class="oi oi-close"/> 18006 </div> 18007 <div> 18008 <strong>Performance Warning:</strong><br/> 18009 Hardware acceleration is disabled. Blur effect impacts performance significantly. 18010 </div> 18011 </div> 18012 </t> 18013 </CallDropdown> 18014 </t> 18015`); 18016registerTemplate("discuss.Call", `/mail/static/src/discuss/call/common/call.xml`, `<t t-name="discuss.Call" xml:space="preserve"> 18017 <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"> 18018 <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"> 18019 <PttAdBanner t-if="!props.compact"/> 18020 <BlurPerformanceWarning t-if="store.settings.blurPerformanceWarning"/> 18021 <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"> 18022 <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"/>
18023 <span t-if="env.inChatWindow and visibleMainCards.length > 6" class="oi oi-ellipsis-h ps-1 pe-1"/> 18024 <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"/> 18025 </div> 18026 18027 18028 <t t-if="hasSidebarButton"> 18029 <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"/> 18030 <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"/> 18031 </t> 18032 <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 }"> 18033 <div t-on-mousemove="onMousemoveOverlay"> 18034 <CallActionList thread="channel" compact="props.compact or props.isPip"/> 18035 </div> 18036 </div> 18037 <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 }"> 18038 <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"/> 18039 </div> 18040 <div class="o-discuss-Call-layoutActions position-absolute z-2 bottom-0 end-0"> 18041 <ActionList actions="layoutActions" inline="true"/> 18042 </div> 18043 </div> 18044 <div t-if="state.sidebar and channel.activeRtcSession" class="o-discuss-Call-sidebar d-flex align-items-center h-100 flex-column"> 18045 <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"/> 18046 </div> 18047 <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"/> 18048 </div> 18049 </t> 18050 18051`); 18052registerTemplate("discuss.CallActionList", `/mail/static/src/discuss/call/common/call_action_list.xml`, `<t t-name="discuss.CallActionList" xml:space="preserve"> 18053 <div class="o-discuss-CallActionList d-flex flex-column justify-content-center" t-attf-class="{{ className }}" t-ref="root"> 18054 <div class="o-discuss-CallActionList-bar d-flex align-items-center justify-content-between" t-att-class="{ 'w-100 ps-2 pe-2': isSmall }"> 18055 <ActionList actions="actions" inline="true" hasBtnBg="true"/> 18056 </div> 18057 <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"> 18058 <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"> 18059 <span class="w-100 fs-4 text-center">Push to talk</span> 18060 </button> 18061 </div> 18062 </div> 18063 </t> 18064 18065`); 18066registerTemplate("discuss.CallContextMenu", `/mail/static/src/discuss/call/common/call_context_menu.xml`, `<t t-name="discuss.CallContextMenu" xml:space="preserve"> 18067 <div class="o-discuss-CallContextMenu d-flex flex-column p-3 rounded"> 18068 <div class="text-center pb-2 fw-bolder" t-out="props.rtcSession.name"/> 18069 <div t-if="!isSelf" class="d-flex flex-row gap-2 align-items-center"> 18070 <i class="fa fa-fw fa-lg opacity-75" t-attf-class="{{state.rangeV
18070olume > 0 ? 'fa-volume-up' : 'fa-volume-off'}}"/> 18071 <div class="position-relative"> 18072 <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"/> 18073 <output t-esc="\`\${Math.round(state.rangeVolume * 200)}%\`" class="o-mail-CallContextMenu-volumeTooltip fw-bold rounded" t-attf-style="--progress:{{state.rangeVolume * 100}}%;"/> 18074 </div> 18075 </div> 18076 <t t-if="env.debug and !isSelf and rtc.state.connectionType === rtcConnectionTypes.P2P"> 18077 <hr class="w-100 border-top"/> 18078 <div><span class="fw-bolder">RTC Session ID: </span><t t-out="props.rtcSession.id"/></div> 18079 <div><span class="fw-bolder">Connection type: </span><t t-out="rtc.state.connectionType"/></div> 18080 <div><span class="fw-bolder">To peer: </span><t t-out="outboundConnectionTypeText"/></div> 18081 <div><span class="fw-bolder">From peer: </span><t t-out="inboundConnectionTypeText"/></div> 18082 <div><span class="fw-bolder">Connection: </span><t t-out="state.peerStats.connectionState"/></div> 18083 <div><span class="fw-bolder">ICE connection: </span><t t-out="state.peerStats.iceConnectionState"/></div> 18084 <div><span class="fw-bolder">ICE: </span><t t-out="state.peerStats.iceState"/></div> 18085 <div><span class="fw-bolder">DTLS: </span><t t-out="state.peerStats.dtlsState"/></div> 18086 <div><span class="fw-bolder">Data channel: </span><t t-out="state.peerStats.dataChannelState"/></div> 18087 <div t-if="props.rtcSession.audioError"><span class="fw-bolder">Audio player: </span><t t-out="props.rtcSession.audioError"/></div> 18088 <div t-if="props.rtcSession.videoError"><span class="fw-bolder">Video player: </span><t t-out="props.rtcSession.videoError"/></div> 18089 <hr class="w-100 border-top"/> 18090 <div><span class="fw-bolder">ICE gathering: </span><t t-out="state.peerStats.iceGatheringState"/></div> 18091 <div><span class="fw-bolder">Packets sent: </span><t t-out="state.peerStats.packetsSent"/></div> 18092 <div><span class="fw-bolder">Packets received: </span><t t-out="state.peerStats.packetsReceived"/></div> 18093 <div><span class="fw-bolder">Log step: </span><t t-out="props.rtcSession.logStep"/></div> 18094 </t> 18095 <t t-elif="env.debug and isSelf and rtc.state.connectionType === rtcConnectionTypes.SERVER"> 18096 <div><span class="fw-bolder">Connection type: </span><t t-out="rtc.state.connectionType"/></div> 18097 <div><span class="fw-bolder">RTC Session ID: </span><t t-out="props.rtcSession.id"/></div> 18098 <hr class="w-100 border-top"/> 18099 <div><span class="fw-bolder">Upload: </span><t t-out="outboundConnectionTypeText"/></div> 18100 <div><span class="fw-bolder">up ICE: </span><t t-out="state.uploadStats.iceState"/></div> 18101 <div><span class="fw-bolder">up DTLS: </span><t t-out="state.uploadStats.dtlsState"/></div> 18102 <div><span class="fw-bolder">Packets sent: </span><t t-out="state.uploadStats.packetsSent"/></div> 18103 <div><span class="fw-bolder">available bitrate: </span><t t-out="state.uploadStats.availableOutgoingBitrate"/></div> 18104 <hr class="w-100 border-top"/> 18105 <div><span class="fw-bolder">Download: </span><t t-out="inboundConnectionTypeText"/></div> 18106 <div><span class="fw-bolder">down ICE: </span><t t-out="state.downloadStats.iceState"/></div> 18107 <div><span class="fw-bolder">down DTLS: </span><t t-out="state.downloadStats.dtlsState"/></div> 18108 <div><span class="fw-bolder">Packets received: </span><t t-out="state.downloadStats.packetsReceived"/></div> 18109 <t t-if="state.producerStats.audio"> 18110 <hr class="w-100 border-top"/> 18111 <div><span class="fw-bolder">microphone</span></div> 18112 <div><span class="fw-bolder">codec: </span><t t-out="state.producerStats.audio.codec"/></div> 18113 <div><span class="fw-bolder">clock rate: </span><t t-out="state.producerStats.audio.clockRate"/></div> 18114 </t> 18115 <t t-if="state.producerStats.camera and props.rtcSession.is_camera_on"> 18116 <hr class="w-100 border-top"/> 18117 <div><span class="fw-bolder">camera</span></div> 18118 <div><span class="fw-bolder">codec: </span><t t-out="state.producerStats.camera.codec"/></div> 18119 <div><span class="fw-bolder">clock rate: </span><t t-out="state.producerStats.camera.clockRate"/></div> 18120 </t> 18121 <t t-if="state.producerStats.screen and props.rtcSession.is_screen_sharing_on"> 18122 <hr class="w-100 border-top"/> 18123 <div><span class="fw-bolder">screen</span></div> 18124 <div><span class="fw-bolder">codec: </span><t t-out="state.producerStats.screen.codec"/></div> 18125 <div><span class="fw-bolder">clock rate: </span><t t-out="state.producerStats.screen.clockRate"/></div> 18126 </t> 18127 </t> 18128 </div> 18129 </t> 18130`); 18131registerTemplate("discuss.CallDropdown", `/mail/static/src/discuss/call/common/call_dropdown.xml`, `<t t-name="discuss.CallDropdown" xml:space="preserve"> 18132 <t t-slot="default"/> 18133 <div t-if="isOpen" class="o-discuss-CallDropdown" t-att-class="props.class"> 18134 <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"> 18135 <t t-slot="content"/> 18136 </div> 18137 </div> 18138 </t> 18139 18140`); 18141registerTemplate("discuss.CallInfiniteMirroringWarning", `/mail/static/src/discuss/call/common/call_infinite_mirroring_warning.xml`, `<t t-name="discuss.CallInfiniteMirroringWarning" xml:space="preserve"> 18142 <div class="d-flex justify-content-start align-items-start position-fixed top-0 end-0 w-100 pe-none"> 18143 <div class="d-flex o-discuss-CallInfiniteMirroringWarning rounded justify-content-between fs-3 w-100 m-5 px-3 py-2 pe-auto"> 18144 <div class="d-flex align-items-center fs-4"> 18145 To avoid the infinite mirror effect, please share a specific window or tab or another monitor. 18146 </div> 18147 <div class="d-flex gap-2 flex-shrink-0"> 18148 <button class="btn btn-link text-info fs-4" t-on-click="() => this.props.onClose({ stopScreensharing: true })"> 18149 Stop sharing 18150 </button> 18151 <button class="o-discuss-CallInfiniteMirroringWarning-dismiss border-0 bg-transparent opacity-50 opacity-100-hover pe-auto" t-on-click="() => this.props.onClose()"> 18152 <i class="fa fa-lg fa-times-circle"/> 18153 </button> 18154 </div> 18155 </div> 18156 </div> 18157 </t> 18158`); 18159registerTemplate("discuss.CallInvitation", `/mail/static/src/discuss/call/common/call_invitation.xml`, `<t t-name="discuss.CallInvitation" xml:space="preserve"> 18160 <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}"> 18161 <div class="d-flex flex-colum d-flex flex-column"> 18162 <div class="o-discuss-CallInvitation-main" t-ref="root"> 18163 <div class="ms-1 position-relative d-flex justify-content-between p-2"> 18164 <div class="d-flex align-items-center" style="min-width: 0;"> 18165 <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"> 18166 <img t-if="inviter" class="object-fit-cover h-100 w-100" t-att-src="inviter.avatarUrl" alt="Avatar"/> 18167 <i t-else="" class="fa fa-phone"/> 18168 </div> 18169 <div class="ms-2 me-3 flex-grow-1 overflow-hidden"> 18170 <p class="o-discuss-CallInvitation-channelName m-0 fw-bold small text-truncate" t-esc="props.thread.displayName"/> 18171 <p class="o-discuss-CallInvitation-description m-0 fst-italic
18171smaller text-truncate pe-1" t-esc="incomingCallText"/> 18172 </div> 18173 </div> 18174 <div class="d-flex align-items-center flex-shrink-0"> 18175 <ActionList actions="acceptOrRejectActions" inline="true" hasBtnBg="true"/> 18176 <ActionList actions="otherActions" inline="true"/> 18177 </div> 18178 </div> 18179 <div class="o-discuss-CallInvitation-cameraPreview" t-att-class="{'o-opened': state.showCameraPreview}"> 18180 <CallPreview activateCamera="state.activateCamera" activateMicrophone="state.activateMicrophone" onSettingsChanged="(settings) => this.onCallSettingsChanged(settings)"/> 18181 </div> 18182 </div> 18183 </div> 18184 </div> 18185 </t> 18186`); 18187registerTemplate("discuss.CallInvitations", `/mail/static/src/discuss/call/common/call_invitations.xml`, `<t t-name="discuss.CallInvitations" xml:space="preserve"> 18188 <div t-if="store.ringingThreads.length > 0" class="o-discuss-CallInvitations position-fixed top-0 end-0 d-flex flex-column p-2"> 18189 <t t-foreach="store.ringingThreads" t-as="thread" t-key="thread.localId"> 18190 <CallInvitation thread="thread"/> 18191 </t> 18192 </div> 18193 </t> 18194 18195`); 18196registerTemplate("discuss.CallMenu", `/mail/static/src/discuss/call/common/call_menu.xml`, `<t t-name="discuss.CallMenu" xml:space="preserve"> 18197 <div class="dropdown" t-attf-class="{{ className }}" t-ref="root"> 18198 <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"> 18199 <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 }"> 18200 <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"> 18201 <span class="position-relative small bg-transparent"> 18202 <i class="me-2 fa fa-fw" t-att-class="icon"/> 18203 <small class="d-flex position-absolute top-0 end-0 smaller bg-inherit"> 18204 <i class="o-discuss-CallMenu-animation fa fa-volume-up o-discuss-inCallIconColor bg-inherit" t-att-class="{ 'o-isOdooCommunity': !isEnterprise }"/> 18205 </small> 18206 </span> 18207 <span class="text-truncate fw-bold pe-1" t-esc="rtc.channel.displayName"/> 18208 </div> 18209 <Dropdown> 18210 <button class="o-discuss-CallMenu-dropdownMore btn btn-group-item m-0 pe-1 o-ps-0_5"> 18211 <i class="oi oi-chevron-down o-xsmaller"/> 18212 </button> 18213 <t t-set-slot="content"> 18214 <ActionList actions="callActions.actions" dropdown="true"/> 18215 </t> 18216 </Dropdown> 18217 </div> 18218 </button> 18219 </div> 18220 </t> 18221 18222`); 18223registerTemplate("discuss.CallParticipantCard", `/mail/static/src/discuss/call/common/call_participant_card.xml`, `<t t-name="discuss.CallParticipantCard" xml:space="preserve"> 18224 <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"> 18225 18226 <t t-if="!props.isSidebarItem and props.cardData.type === 'screen' and rtc.state.screenTrack and !rtc.state.screenTrack.enabled"> 18227 <div class="o-text-white display-5 gap-3"> 18228 <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)"> 18229 <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> 18230 </button> 18231 </div> 18232 </t> 18233 <CallParticipantVideo t-elif="hasVideo" session="rtcSession" type="props.cardData.type" inset="props.inset"/> 18234 <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"> 18235 <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
18235itation': !rtcSession, }"/> 18236 </div> 18237 <t t-if="rtcSession"> 18238 18239 <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"> 18240 <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"/> 18241 <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"> 18242 LIVE 18243 </small> 18244 </span> 18245 <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"> 18246 <span class="fw-bolder p-1 rounded-1 o-video-text o-proportional-text">Video visible in the call tab</span> 18247 </span> 18248 <CallDropdown t-if="isContextMenuAvailable and ((!isMobileOS and rootHover.isHover) or (isMobileOS and !props.minimized))" menuClass="'d-flex o-discuss-CallParticipantCard-contextMenu'"> 18249 <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"> 18250 <i class="fa fa-chevron-down fa-fw"/> 18251 </button> 18252 <t t-set-slot="content"> 18253 <CallContextMenu rtcSession="rtcSession"/> 18254 </t> 18255 </CallDropdown> 18256 <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 }"> 18257 <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"> 18258 <i class="fa fa-hand-paper-o"/> 18259 </span> 18260 <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"> 18261 <i class="fa fa-microphone-slash"/> 18262 </span> 18263 <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"> 18264 <i class="fa fa-deaf"/> 18265 </span> 18266 <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"> 18267 <i t-if="rootHover.isHover" class="fa fa-repeat text-danger"/> 18268 <i t-else="" class="fa fa-exclamation-triangle text-danger"/> 18269 </span> 18270 <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"> 18271 <i class="fa fa-exclamation-triangle text-warning"/> 18272 </span>
18273 <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"> 18274 LIVE 18275 </span> 18276 </div> 18277 </t> 18278 </div> 18279 </t> 18280 18281`); 18282registerTemplate("discuss.CallParticipantVideo", `/mail/static/src/discuss/call/common/call_participant_video.xml`, `<t t-name="discuss.CallParticipantVideo" xml:space="preserve"> 18283 <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"/> 18284 </t> 18285`); 18286registerTemplate("discuss.CallPermissionDialog", `/mail/static/src/discuss/call/common/call_permission_dialog.xml`, `<t t-name="discuss.CallPermissionDialog" xml:space="preserve"> 18287 <Dialog title="''" size="'md'"> 18288 <h5 class="fw-medium fs-2 mb-2" t-out="permissionPrompt"/> 18289 <small class="text-muted" t-out="permissionNote"/> 18290 <t t-set-slot="footer"> 18291 <button class="btn btn-primary px-4" t-on-click="props.media === 'microphone' ? onClickUseMicrophone : onClickUseCamera" t-out="primaryActionText"/> 18292 <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> 18293 </t> 18294 </Dialog> 18295 </t> 18296 18297`); 18298registerTemplate("mail.CallPreview", `/mail/static/src/discuss/call/common/call_preview.xml`, `<t t-name="mail.CallPreview" xml:space="preserve"> 18299 <div class="o-mail-CallPreview ratio ratio-16x9"> 18300 <div class="bg-dark"> 18301 <video class="object-fit-cover h-100 w-100" autoplay="" style="background-color: rgba(0, 0, 0, 0.5);" t-ref="video"/> 18302 <div class="position-absolute bottom-0 mb-3 w-100 d-flex justify-content-center"> 18303 <ActionList actions="actions" inline="true" hasBtnBg="true"/> 18304 </div> 18305 </div> 18306 <audio autoplay="" t-ref="audio"/> 18307 </div> 18308 </t> 18309`); 18310registerTemplate("discuss.CallSettings", `/mail/static/src/discuss/call/common/call_settings.xml`, `<t t-name="discuss.CallSettings" xml:space="preserve"> 18311 <ActionPanel t-if="props.withActionPanel" title.translate="Voice settings" icon="'fa fa-gear'"> 18312 <t t-call="discuss.CallSettings.content"/> 18313 </ActionPanel> 18314 <t t-else="" t-call="discuss.CallSettings.content"/> 18315 </t> 18316 18317 `); 18318registerTemplate("discuss.CallSettings.content", `/mail/static/src/discuss/call/common/call_settings.xml`, `<t t-name="discuss.CallSettings.content" xml:space="preserve"> 18319 <div class="o-discuss-CallSettings d-flex flex-column"> 18320 <h4>Voice</h4> 18321 <label class="d-flex align-items-baseline mb-2" title="Microphone" aria-label="Microphone"> 18322 <span class="flex-shrink-0 pe-2"> 18323 Microphone 18324 </span> 18325 <div class="flex-grow-1"/> 18326 <DeviceSelect kind="'audioinput'"/> 18327 </label> 18328 <label class="d-flex align-items-baseline mb-2" title="Audio Output" aria-label="Audio Output"> 18329 <span class="flex-shrink-0 pe-2"> 18330 Audio Output 18331 </span> 18332 <div class="flex-grow-1"/> 18333 <DeviceSelect kind="'audiooutput'"/> 18334 </label> 18335 <div class="d-flex flex-column"> 18336 <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)"> 18337 <input class="form-check-input" type="radio" t-att-checked="store.settings.use_push_to_talk ? '' : 'checked'"/> 18338 <span class="text-start flex-grow-1 mx-3">Voice Detection</span> 18339 </button> 18340 <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)"> 18341 <input class="form-check-input" type="radio" t-att-checked="store.settings.use_push_to_talk ? 'checked' : ''"/>
18342 <span class="text-start flex-grow-1 mx-3">Push to Talk</span> 18343 </button> 18344 <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"/> 18345 </div> 18346 <div class="d-flex flex-column"> 18347 <t t-if="!store.settings.use_push_to_talk"> 18348 <span class="me-2 my-1">Voice detection sensitivity</span> 18349 <div class="d-flex align-items-center w-100 h-100"> 18350 <button class="btn btn-primary" t-on-click="microphoneVolume.toggle" t-att-disabled="!microphoneVolume.isReady"> 18351 <div class="position-relative"> 18352 <span class="d-flex invisible text-nowrap"> 18353 <t t-out="testText.length > stopText.length ? testText : stopText"/> 18354 </span> 18355 <span class="position-absolute start-0 top-0"> 18356 <t t-if="microphoneVolume.isActive" t-out="stopText"/> 18357 <t t-else="" t-out="testText"/> 18358 </span> 18359 </div> 18360 </button> 18361 <label class="w-100 d-flex ms-2" title="Voice detection sensitivity" aria-label="Voice detection sensitivity"> 18362 <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"/> 18363 </label> 18364 </div> 18365 </t> 18366 <div t-if="store.settings.use_push_to_talk" class="d-flex" t-att-class="{'flex-column': props.isCompact}"> 18367 <div t-if="!isMobileOS" class="d-flex flex-column align-items-center" t-att-class="{'me-1 w-50': !props.isCompact}"> 18368 <label class="d-flex flex-column align-items-start flex-wrap w-100" title="Push-to-talk key" aria-label="Push-to-talk key"> 18369 <span class="me-2 my-1 text-truncate text-wrap">Push-to-talk key</span> 18370 <span class="d-flex border border-2 rounded w-100" t-attf-class="{{ store.settings.isRegisteringKey ? 'border-danger' : 'border-primary' }}"> 18371 <span t-if="store.settings.push_to_talk_key" class="ms-1 px-3 fs-3 flex-grow-1" t-esc="pushToTalkKeyText"/> 18372 <button class="btn btn-link px-2 py-0 text-black" t-on-click="onClickRegisterKeyButton"> 18373 <i t-if="store.settings.isRegisteringKey" title="Cancel" aria-label="Cancel" class="fa fa-2x fa-times-circle"/> 18374 <i t-else="" title="Register new key" aria-label="Register new key" class="fa fa-2x fa-keyboard-o"/> 18375 </button> 18376 </span> 18377 </label> 18378 </div> 18379 <div class="d-flex align-items-center" t-att-class="{'ms-1 w-50': !props.isCompact}"> 18380 <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"> 18381 <span class="me-2 my-1 text-truncate text-wrap">Delay after releasing push-to-talk</span> 18382 <div class="d-flex w-100 align-items-center"> 18383 <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"/> 18384 <span class="p-1 text-end"><t t-out="store.settings.voice_active_duration"/>ms</span> 18385 </div> 18386 </label> 18387 </div> 18388 </div>
18389 <span t-if="store.settings.isRegisteringKey">Press a key to register it as the push-to-talk shortcut.</span> 18390 </div> 18391 <hr class="o-discuss-separator my-2"/> 18392 <h4>Video</h4> 18393 <label class="d-flex align-items-baseline mb-2" title="Camera" aria-label="Camera"> 18394 <span class="flex-shrink-0 pe-2"> 18395 Camera 18396 </span> 18397 <div class="flex-grow-1"/> 18398 <DeviceSelect kind="'videoinput'"/> 18399 </label> 18400 <div class="d-flex flex-column my-1"> 18401 <t t-call="discuss.CallSettings.textToggler"> 18402 <t t-set="text">Show video participants only</t> 18403 <t t-set="value" t-value="store.settings.showOnlyVideo"/> 18404 <t t-set="onchange" t-value="onChangeShowOnlyVideo"/> 18405 </t> 18406 </div> 18407 <div t-if="store.settings.hasCanvasFilterSupport" class="d-flex flex-column my-1"> 18408 <t t-call="discuss.CallSettings.textToggler"> 18409 <t t-set="text">Blur video background</t> 18410 <t t-set="value" t-value="store.settings.useBlur"/> 18411 <t t-set="onchange" t-value="onChangeBlur"/> 18412 </t> 18413 </div> 18414 <t t-if="store.settings.useBlur"> 18415 <div class="d-flex mt-1" t-att-class="{'flex-column': props.isCompact}"> 18416 <div class="d-flex flex-column align-items-center" t-att-class="{'me-1 w-50': !props.isCompact}"> 18417 <label class="d-flex flex-column align-items-start flex-wrap w-100" title="Background blur intensity" aria-label="Background blur intensity"> 18418 <span class="me-2 text-truncate text-wrap">Background blur intensity</span> 18419 <div class="d-flex w-100 flex-grow-1 align-items-center"> 18420 <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"/> 18421 <span class="p-1 text-end o-discuss-DiscussCallSettings-width-text-percentage"><t t-out="Math.floor(store.settings.backgroundBlurAmount * 5)"/>%</span> 18422 </div> 18423 </label> 18424 </div> 18425 <div class="d-flex align-items-center" t-att-class="{'ms-1 w-50': !props.isCompact}"> 18426 <label class="d-flex flex-column align-items-start flex-wrap h-100 w-100" title="Edge blur intensity" aria-label="Edge blur intensity"> 18427 <span class="me-2 text-truncate text-wrap">Edge blur intensity</span> 18428 <div class="d-flex w-100 flex-grow-1 align-items-center"> 18429 <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"/> 18430 <span class="p-1 text-end o-discuss-DiscussCallSettings-width-text-percentage"><t t-out="Math.floor(store.settings.edgeBlurAmount * 5)"/>%</span> 18431 </div> 18432 </label> 18433 </div> 18434 </div> 18435 </t> 18436 <hr class="o-discuss-separator my-2"/> 18437 <h4>Technical Settings</h4> 18438 <t t-if="env.debug"> 18439 <div class="d-flex flex-column my-1"> 18440 <t t-call="discuss.CallSettings.textToggler"> 18441 <t t-set="text">Log RTC events</t> 18442 <t t-set="value" t-value="store.settings.logRtc"/> 18443 <t t-set="onchange" t-value="onChangeLogRtc"/> 18444 </t> 18445 </div> 18446 </t> 18447 <button class="btn btn-secondary mt-1 mb-2 w-100" t-on-click="onClickDownloadLogs">Download logs</button> 18448 </div> 18449 </t> 18450 `); 18451registerTemplate("discuss.CallSettings.textToggler", `/mail/static/src/discuss/call/common/call_settings.xml`, `<t t-name="discuss.CallSettings.textToggler" xml:space="preserve"> 18452 <div class="d-flex flex-wrap align-items-center"> 18453 <label class="d-flex align-items-center flex-wrap mw-100" t-att-title="text" t-att-aria-label="text">
18454 <span class="text-truncate text-wrap" t-out="text"/> 18455 </label> 18456 <div class="flex-grow-1"/> 18457 <div class="form-check form-switch"> 18458 <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"/> 18459 </div> 18460 </div> 18461 </t> 18462 18463`); 18464registerTemplateExtension("mail.ChatWindow", `/mail/static/src/discuss/call/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18465 <xpath expr="//Thread" position="before"> 18466 <PipBanner t-if="rtc.state.isPipMode and thread.eq(rtc.channel)" compact="true"/> 18467 <Call t-elif="thread.showCallView" thread="thread" compact="true"/> 18468 </xpath> 18469 </t> 18470`); 18471registerTemplate("discuss.CallDeviceSelect", `/mail/static/src/discuss/call/common/device_select.xml`, `<t t-name="discuss.CallDeviceSelect" xml:space="preserve"> 18472 <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)"> 18473 <option value="">Permission Needed</option> 18474 </select> 18475 <select t-else="" name="inputDevice" class="form-select d-flex shadow-sm" t-on-change="onChangeSelectAudioInput"> 18476 <option t-if="!isBrowserChrome" value="">Browser Default</option> 18477 <t t-foreach="state.userDevices" t-as="device" t-key="device_index"> 18478 <option t-if="device.kind === props.kind" t-att-selected="isSelected(device.deviceId)" t-att-value="device.deviceId"> 18479 <t t-esc="device.label || 'device ' + device_index"/> 18480 </option> 18481 </t> 18482 </select> 18483 </t> 18484 18485`); 18486registerTemplate("mail.DiscussCallSettingsClientAction", `/mail/static/src/discuss/call/common/discuss_call_settings_client_action.xml`, `<t t-name="mail.DiscussCallSettingsClientAction" xml:space="preserve"> 18487 <div class="o-mail-DiscussCallSettingsClientAction mx-3 my-2"> 18488 <CallSettings withActionPanel="false"/> 18489 </div> 18490 </t> 18491`); 18492registerTemplate("mail.Meeting", `/mail/static/src/discuss/call/common/meeting.xml`, `<t t-name="mail.Meeting" xml:space="preserve"> 18493 <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}"> 18494 <div class="d-flex flex-grow-1 h-100 o-min-height-0 gap-1 position-relative"> 18495 <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}"> 18496 <Call hasOverlay="false" isPip="props.isPip"/> 18497 </div> 18498 <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 }"> 18499 <t t-component="threadActions.activeAction.actionPanelComponent" t-props="threadActions.activeAction.actionPanelComponentProps" thread="thread"/> 18500 </div> 18501 </div> 18502 <div class="pt-2 d-flex justify-content-between overflow-x-auto flex-shrink-0" t-att-class="{'p-2 pb-3': ui.isSmall}"> 18503 <div/> 18504 <CallActionList thread="store.rtc.channel"/> 18505 <MeetingSideActions threadActions="threadActions"/> 18506 </div> 18507 </div> 18508 </t> 18509`); 18510registerTemplate("mail.MeetingChat", `/mail/static/src/discuss/call/common/meeting_chat.xml`, `<t t-name="mail.MeetingChat" xml:space="preserve"> 18511 <ActionPanel t-if="thread" title.translate="Chat" resizable="true" minWidth="300" initialWidth="400" icon="'fa fa-comments'" contentRef="panelContentRef"> 18512 <Thread thread="thread" jumpPresent="state.jumpPresent"/> 18513 <t t-call="mail.ChatWindow.memberTyping"/> 18514 <Composer composer="thread.composer" autofocus="!isMobileOS" onDiscardCallback="() =>
18514 (thread.composer.replyToMessage = undefined)" onPostCallback.bind="() => this.state.jumpPresent++" dropzoneRef="panelContentRef"/> 18515 </ActionPanel> 18516 </t> 18517`); 18518registerTemplate("mail.MeetingSideActions", `/mail/static/src/discuss/call/common/meeting_side_actions.xml`, `<t t-name="mail.MeetingSideActions" xml:space="preserve"> 18519 <t t-set="dummy" t-value="computeActions()"/> 18520 <div class="o-mail-MeetingSideActions d-flex"> 18521 <ActionList actions="actions" inline="true" hasBtnBg="true" thread="store.rtc.channel" odooControlPanelSwitchStyle="true"/> 18522 </div> 18523 </t> 18524`); 18525registerTemplate("discuss.pipBanner", `/mail/static/src/discuss/call/common/pip_banner.xml`, `<t t-name="discuss.pipBanner" xml:space="preserve"> 18526 <span class="o-discuss-PipBanner px-2 py-1 mx-1 mt-1 rounded-1"> 18527 <div class="d-flex justify-content-between align-items-center p-2"> 18528 <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> 18529 <button class="btn o-discuss-PipBannerButton d-flex rounded-1" title="Bring call back" t-on-click="onClickClose"> 18530 <t t-if="props.compact"> 18531 Bring back 18532 </t> 18533 <t t-else=""> 18534 Bring the call back here 18535 </t> 18536 </button> 18537 </div> 18538 <div class="d-flex justify-content-center"> 18539 <CallActionList thread="rtc.channel" compact="true"/> 18540 </div> 18541 </span> 18542</t> 18543 18544`); 18545registerTemplate("discuss.pttAdBanner", `/mail/static/src/discuss/call/common/ptt_ad_banner.xml`, `<t t-name="discuss.pttAdBanner" xml:space="preserve"> 18546 <span t-if="isVisible" class="o-discuss-PttAdBanner alert alert-info px-2 py-1 m-0 rounded-0"> 18547 <div class="d-flex justify-content-between align-items-center"> 18548 <span class="small" t-out="pttExtService.downloadText"/> 18549 <button class="btn d-flex opacity-75 opacity-100-hover" title="Close banner" t-on-click="onClickClose"> 18550 <i class="fa fa-fw fa-close"/> 18551 </button> 18552 </div> 18553 </span> 18554</t> 18555 18556`); 18557registerTemplate("discuss.QuickVideoSettings", `/mail/static/src/discuss/call/common/quick_video_settings.xml`, `<t t-name="discuss.QuickVideoSettings" xml:space="preserve"> 18558 <div class="o-discuss-QuickVideoSettings d-flex flex-column gap-1"> 18559 <label class="btn border-transparent d-flex flex-column align-items-baseline"> 18560 <span class="flex-shrink-0 pe-2"> 18561 Camera 18562 </span> 18563 <div class="flex-grow-1"/> 18564 <DeviceSelect kind="'videoinput'"/> 18565 </label> 18566 <div t-if="!isBrowserSafari()" class="btn border-transparent d-flex gap-2" t-on-click="() => store.settings.setUseBlur(!store.settings.useBlur)"> 18567 <label class="d-flex align-items-center flex-wrap mw-100 cursor-pointer gap-2"> 18568 <i class="fa fa-fw fa-photo"/><span class="text-truncate text-wrap">Blur background</span> 18569 </label> 18570 <div class="flex-grow-1"/> 18571 <div class="form-check form-switch"> 18572 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.settings?.useBlur ? 'checked' : ''"/> 18573 </div> 18574 </div> 18575 <button class="btn border-transparent d-flex align-items-center gap-2" t-on-click="onClickVideoSettings"> 18576 <i class="fa fa-fw fa-gear"/><span>Video Settings</span> 18577 </button> 18578 </div> 18579 </t> 18580 18581`); 18582registerTemplate("discuss.QuickVoiceSettings", `/mail/static/src/discuss/call/common/quick_voice_settings.xml`, `<t t-name="discuss.QuickVoiceSettings" xml:space="preserve"> 18583 <div class="o-discuss-QuickVoiceSettings d-flex flex-column gap-1"> 18584 <label class="btn border-transparent d-flex flex-column align-items-baseline"> 18585 <span class="flex-shrink-0 pe-2"> 18586 Microphone 18587 </span> 18588 <div class="flex-grow-1"/> 18589 <DeviceSelect kind="'audioinput'"/> 18590 </label> 18591 <label class="btn border-transparent d-flex flex-column align-items-baseline">
18592 <span class="flex-shrink-0 pe-2"> 18593 Audio Output 18594 </span> 18595 <div class="flex-grow-1"/> 18596 <DeviceSelect kind="'audiooutput'"/> 18597 </label> 18598 <button t-if="store.rtc.selfSession" class="btn border-transparent d-flex" t-on-click="() => this.store.rtc.toggleDeafen()"> 18599 <label class="d-flex align-items-center flex-wrap mw-100 cursor-pointer"> 18600 <span class="text-truncate text-wrap">Deafen</span> 18601 </label> 18602 <div class="flex-grow-1"/> 18603 <div class="form-check form-switch"> 18604 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.rtc.selfSession?.is_deaf ? 'checked' : ''"/> 18605 </div> 18606 </button> 18607 <button class="btn border-transparent d-flex" t-on-click="() => this.store.settings.use_push_to_talk = !this.store.settings.use_push_to_talk"> 18608 <label class="d-flex align-items-center flex-wrap mw-100 cursor-pointer"> 18609 <span class="text-truncate text-wrap">Push-to-Talk</span> 18610 </label> 18611 <div class="flex-grow-1"/> 18612 <div class="form-check form-switch"> 18613 <input class="form-check-input" type="checkbox" role="switch" t-att-checked="store.settings.use_push_to_talk ? 'checked' : ''"/> 18614 </div> 18615 </button> 18616 <button class="btn border-transparent d-flex align-items-center gap-2" t-on-click="onClickVoiceSettings"> 18617 <i class="fa fa-fw fa-gear"/><span>Voice Settings</span> 18618 </button> 18619 </div> 18620 </t> 18621 18622`); 18623registerTemplateExtension("mail.Composer", `/mail/static/src/discuss/typing/common/composer_patch.xml`, `<t t-inherit="mail.Composer" t-inherit-mode="extension" xml:space="preserve"> 18624 <xpath expr="//*[hasclass('o-mail-Composer-coreHeader')]" position="before"> 18625 <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"> 18626 <Typing t-if="thread.hasOtherMembersTyping" channel="thread" size="'medium'"/> 18627 </div> 18628 </xpath> 18629 </t> 18630`); 18631registerTemplateExtension("mail.ThreadIcon", `/mail/static/src/discuss/typing/common/thread_icon_patch.xml`, `<t t-inherit="mail.ThreadIcon" t-inherit-mode="extension" xml:space="preserve"> 18632 <xpath expr="//t[@name='chat']" position="replace"> 18633 <div t-if="props.thread.hasOtherMembersTyping" class="bg-inherit rounded-pill" style="padding: 1px;"> 18634 <div class="bg-success rounded-pill" style="padding: 3px;"> 18635 <Typing member="props.member" channel="props.thread" size="props.size" displayText="false"/> 18636 </div> 18637 </div> 18638 <t t-else="">$0</t> 18639 </xpath> 18640 </t> 18641`); 18642registerTemplate("discuss.Typing", `/mail/static/src/discuss/typing/common/typing.xml`, `<t t-name="discuss.Typing" xml:space="preserve"> 18643 <t t-if="props.member ? props.member.isTyping : props.channel.hasOtherMembersTyping"> 18644 <div class="o-discuss-Typing-icon d-flex align-items-center bg-inherit" t-attf-class="{{ className }}" t-att-title="text"> 18645 <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), }"/> 18646 <span class="flex-grow-1 flex-shrink-0"/> 18647 <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), }"/> 18648 <span class="flex-grow-1 flex-shrink-0"/> 18649 <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), }"/> 18650 </div> 18651 <t t-if="props.displayText">
18652 <span class="ms-1"/> 18653 <span class="text-truncate smaller text-muted" t-out="text"/> 18654 </t> 18655 </t> 18656 </t> 18657 18658`); 18659registerTemplateExtension("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"> 18660 <xpath expr="//button[@name='inviteButton']" position="attributes"> 18661 <attribute name="t-if">!props.thread.livechat_end_dt</attribute> 18662 </xpath> 18663 </t> 18664`); 18665registerTemplateExtension("mail.ChatWindow", `/im_livechat/static/src/core/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18666 <xpath expr="//*[@name='thread content']" position="replace"> 18667 <t>$0</t> 18668 <t t-if="props.chatWindow.livechatStep === CW_LIVECHAT_STEP.CONFIRM_CLOSE"> 18669 <CloseConfirmation onCloseConfirmationDialog.bind="onCloseConfirmationDialog" onClickLeaveConversation.bind="close"/> 18670 </t> 18671 </xpath> 18672 <xpath expr="//Composer" position="replace"> 18673 <div t-if="thread?.composerDisabled" class="bg-200 py-1 text-center d-flex fst-italic fw-bold text-muted" t-ref="composerDisabledContainer"> 18674 <span t-if="!showGiveFeedbackBtn" class="flex-grow-1"/> 18675 <span t-esc="thread.composerDisabledText"/> 18676 <span class="flex-grow-1"/> 18677 </div> 18678 <t t-else="">$0</t> 18679 </xpath> 18680 </t> 18681`); 18682registerTemplate("im_livechat.CloseConfirmation", `/im_livechat/static/src/core/common/close_confirmation.xml`, `<t t-name="im_livechat.CloseConfirmation" xml:space="preserve"> 18683 <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()"> 18684 <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"> 18685 <div class="position-absolute top-0 end-0 p-1 o-xsmaller"> 18686 <button class="o-livechat-CloseConfirmation-close btn-close" t-on-click.stop="() => this.props.onCloseConfirmationDialog()"/> 18687 </div> 18688 <span class="pt-2 pb-3">Leaving will end the live chat. Do you want to proceed?</span> 18689 <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> 18690 </div> 18691 </div> 18692 </t> 18693`); 18694registerTemplate("im_livechat.LivechatCommandDialog", `/im_livechat/static/src/core/common/livechat_command_dialog.xml`, `<t t-name="im_livechat.LivechatCommandDialog" xml:space="preserve"> 18695 <ActionPanel title="props.title" icon="props.icon" resizable="false"> 18696 <div class="input-group my-2 shadow-sm"> 18697 <div class="o-livechat-LivechatCommandDialog-form form-control bg-view p-0" aria-autocomplete="list"> 18698 <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"/> 18699 </div> 18700 <button class="btn btn-primary" t-on-click="executeCommand" t-att-disabled="!state.inputText" t-out="props.title"/> 18701 </div> 18702 </ActionPanel> 18703 </t> 18704`); 18705registerTemplateExtension("mail.Thread", `/im_livechat/static/src/core/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 18706 <xpath expr="//div[hasclass('o-mail-Thread')]" position="before"> 18707 <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"/> 18708 </xpath> 18709 </t> 18710`); 18711registerTemplate("im_livechat.TranscriptSender", `/im_livechat/static/src/core/common/transcript_sender.xml`, `<t t-name="im_livechat.TranscriptSender" xml:space="preserve"> 18712 <div class="o-livechat-TranscriptSender"> 18713 <div class="input-group"> 18714 <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]"/> 18715 <button class="btn btn-primary" type="button" data-action="sendTranscript" t-att-disabled="isButtonDisabled" t-on-click="onClickSend"> 18716 <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, }"/> 18717 </button> 18718 </div> 18719 <div class="form-text ms-1"> 18720 <t t-if="state.status === STATUS.SENT">The conversation was sent.</t> 18721 <t t-elif="state.status === STATUS.FAILED">An error occurred. Please try again.</t> 18722 </div> 18723 </div> 18724 </t> 18725`); 18726registerTemplateExtension("mail.ChatHub", `/im_livechat/static/src/embed/common/chat_hub_patch.xml`, `<t t-inherit="mail.ChatHub" t-inherit-mode="extension" xml:space="preserve"> 18727 <xpath expr="//*[hasclass('o-mail-ChatHub')]" position="attributes"> 18728 <attribute name="part">ChatHub</attribute> 18729 </xpath> 18730 <xpath expr="//*[hasclass('o-mail-ChatHub-extraActions')]" position="inside"> 18731 <LivechatButton/> 18732 </xpath> 18733 </t> 18734`); 18735registerTemplateExtension("mail.ChatWindow", `/im_livechat/static/src/embed/common/chat_window_patch.xml`, `<t t-inherit="mail.ChatWindow" t-inherit-mode="extension" xml:space="preserve"> 18736 <xpath expr="//*[@name='thread content']" position="replace"> 18737 <FeedbackPanel t-if="props.chatWindow.livechatStep === CW_LIVECHAT_STEP.FEEDBACK" onClickClose
18737="() => this.close()" onClickNewSession="() => this.onClickNewSession()" thread="thread"/> 18738 <t t-else=""> 18739 <t>$0</t> 18740 </t> 18741 </xpath> 18742 <xpath expr="//*[@t-ref='needactionCounter']" position="replace"> 18743 <t t-if="!thread?.chatbot">$0</t> 18744 </xpath> 18745 <xpath expr="//*[hasclass('o-mail-ChatWindow-header')]" position="attributes"> 18746 <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=" "/> 18747 </xpath> 18748 <xpath expr="//*[@t-ref='composerDisabledContainer']" position="inside"> 18749 <button t-if="showGiveFeedbackBtn" class="btn btn-link p-0" title="Give your feedback" t-on-click="() => this.onClickFeedback()">Continue</button> 18750 </xpath> 18751 <xpath expr="//*[@t-ref='composerDisabledContainer']" position="attributes"> 18752 <attribute name="t-attf-class" add="{{ showGiveFeedbackBtn ? 'px-2' : '' }}" separator=" "/> 18753 </xpath> 18754 </t> 18755`); 18756registerTemplate("im_livechat.FeedbackPanel", `/im_livechat/static/src/embed/common/feedback_panel/feedback_panel.xml`, `<t t-name="im_livechat.FeedbackPanel" xml:space="preserve"> 18757<div class="d-flex flex-column bg-view flex-grow-1 p-3"> 18758 <div class="p-2"> 18759 <div class="mb-5"> 18760 <t t-if="state.step === STEP.RATING"> 18761 <p class="text-center fs-6 mb-4">Did we correctly answer your question?</p> 18762 <div class="d-flex justify-content-center"> 18763 <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)"/> 18764 <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)"/> 18765 <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)"/> 18766 </div> 18767 </t> 18768 <t t-else=""> 18769 <p class="text-center fs-5 fw-bold mb-4">Thank you for your feedback</p> 18770 </t> 18771 </div> 18772 <div t-if="state.rating and state.step === STEP.RATING" class="d-flex flex-column mb-5"> 18773 <textarea t-model="state.feedback" class="form-control my-2" placeholder="Explain your note"/> 18774 <button class="btn btn-primary align-self-end" t-on-click="onClickSendFeedback">Send</button> 18775 </div> 18776 <label class="mb-5 w-100" t-if="store.self_partner?.main_user_id?.share === false"> 18777 Receive a copy of this conversation 18778 <TranscriptSender thread="props.thread" disableOnSend="true"/> 18779 </label> 18780 <div class="d-flex gap-2 justify-content-center"> 18781 <button class="btn btn-outline-secondary" t-on-click="props.onClickClose">Close</button> 18782 <button t-if="allowNewSession" class="btn btn-outline-secondary" t-on-click="props.onClickNewSession">New Session</button> 18783 <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> 18784 </div> 18785 </div> 18786</div> 18787</t> 18788`); 18789registerTemplate("im_livechat.LivechatButton", `/im_livechat/static/src/embed/common/livechat_button.xml`, `<t t-name="im_livechat.LivechatButton" xml:space="preserve"> 18790 <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"> 18791 <i class="fa fa-commenting" style="font-size: 22px;"/> 18792 <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}"> 18793 <p class="m-0 text-dark text-truncate" t-esc="livechatService.options.button_text"/> 18794 </div> 18795 </button> 18796</t> 18797 18798`); 18799registerTemplateExtension("mail.Message", `/im_livechat/static/src/embed/common/message_patch.xml`, `<t t-inherit="mail.Message" t-inherit-mode="extension" xml:space="preserve"> 18800 <xpath expr="//*[@t-ref='messageContent']" position="replace"> 18801 <div t-if="props.isTypingMessage"> 18802 <img height="30" t-att-src="url('/im_livechat/static/src/img/chatbot_is_typing.gif')"/> 18803 </div> 18804 <t t-else="">$0</t> 18805 </xpath> 18806 <xpath expr="//*[hasclass('o-mail-Message-textContent')]" position="after"> 18807 <ul class="p-0 m-0" t-if="props.message.chatbotStep?.answer_ids.length and !props.message.chatbotStep.selectedAnswer"> 18808 <li class="list-unstyled" t-foreach="props.message.chatbotStep?.answer_ids" t-as="answer" t-key="answer.id"> 18809 <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"/> 18810 </li> 18811 </ul> 18812 </xpath> 18813 </t> 18814`); 18815registerTemplateExtension("mail.NotificationMessage", `/im_livechat/static/src/embed/common/notification_message_patch.xml`, `<t t-inherit="mail.NotificationMessage" t-inherit-mode="extension" xml:space="preserve"> 18816 <xpath expr="//*[hasclass('o-mail-NotificationMessage')]" position="attributes"> 18817 <attribute name="t-attf-class" add="{{ props.thread.channel_type === 'livechat' ? 'o-livechat-NoPinMenu' : '' }}" separator=" "/> 18818 </xpath> 18819</t>`); 18820registerTemplateExtension("mail.Thread", `/im_livechat/static/src/embed/common/thread_patch.xml`, `<t t-inherit="mail.Thread" t-inherit-mode="extension" xml:space="preserve"> 18821 <xpath expr="//*[@name='content']" position="before"> 18822 <div t-if="props.thread?.livechatWelcomeMessage" class="bg-100 py-3" data-name="LivechatWelcomeMessage"> 18823 <Message message="props.thread.livechatWelcomeMessage" hasActions="false" thread="props.thread"/> 18824 </div> 18825 </xpath> 18826 <xpath expr="(//div[hasclass('o-mail-Thread')])" position="inside"> 18827 <Message t-if="props.thread.chatbot?.typingMessage" message="props.thread.chatbot.typingMessage" hasActions="false" isInChatWindow="env.inChatWindow" isTypingMessage="true" thread="props.thread"/> 18828 </xpath> 18829 <xpath expr="//*[hasclass('o-mail-Thread-empty')]" position="replace"> 18830 <t t-if="props.thread.channel_type !== 'livechat'">$0</t> 18831 </xpath> 18832 <xpath expr="//*[hasclass('o-mail-Thread-newMessage')]" position="replace"> 18833 <t t-if="!props.thread.chatbot">$0</t> 18834 </xpath> 18835 </t> 18836`); 18837 });
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.