@odoo/o-spreadsheet 18.3.0-alpha.4 → 18.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  <!--
2
2
  This file is generated by o-spreadsheet build tools. Do not edit it.
3
3
  @see https://github.com/odoo/o-spreadsheet
4
- @version 18.3.0-alpha.4
5
- @date 2025-03-12T15:34:22.764Z
6
- @hash 2ea1c05
4
+ @version 18.3.1
5
+ @date 2025-05-02T12:34:13.360Z
6
+ @hash 7b9574b
7
7
  -->
8
8
  <odoo>
9
9
  <t t-name="o-spreadsheet-ValidationMessages">
@@ -29,7 +29,7 @@
29
29
 
30
30
  <t t-name="o-spreadsheet-TopBar">
31
31
  <div
32
- class="o-spreadsheet-topbar o-two-columns d-flex flex-column user-select-none overflow-hidden"
32
+ class="o-spreadsheet-topbar o-two-columns d-flex flex-column user-select-none"
33
33
  t-on-click="props.onClick">
34
34
  <div class="o-topbar-top d-flex justify-content-between">
35
35
  <!-- Menus -->
@@ -120,10 +120,11 @@
120
120
  </div>
121
121
  <Menu
122
122
  t-if="state.menuState.isOpen"
123
- position="state.menuState.position"
123
+ anchorRect="state.menuState.anchorRect"
124
124
  menuItems="state.menuState.menuItems"
125
125
  onClose="() => this.closeMenus()"
126
126
  onMenuClicked="() => this.props.onClick()"
127
+ popoverPositioning="'bottom-left'"
127
128
  />
128
129
  <Popover t-if="state.toolsPopoverState.isOpen" t-props="toolsPopoverProps">
129
130
  <div class="d-flex px-2 py-1 flex-wrap" style="background-color:white;">
@@ -154,7 +155,13 @@
154
155
  onClick.bind="toggleMenu"
155
156
  class="props.class"
156
157
  />
157
- <Menu t-if="isActive" position="state.position" menuItems="state.menuItems" onClose="() => {}"/>
158
+ <Menu
159
+ t-if="isActive"
160
+ anchorRect="state.anchorRect"
161
+ menuItems="state.menuItems"
162
+ onClose="() => {}"
163
+ popoverPositioning="'bottom-left'"
164
+ />
158
165
  </div>
159
166
 
160
167
  <t t-name="o-spreadsheet-TopBarFontSizeEditor">
@@ -282,7 +289,7 @@
282
289
  <Menu
283
290
  t-if="menu.isOpen"
284
291
  menuItems="menu.menuItems"
285
- position="menu.position"
292
+ anchorRect="menu.anchorRect"
286
293
  onClose.bind="this.closeMenu"
287
294
  />
288
295
  </t>
@@ -342,7 +349,7 @@
342
349
  </t>
343
350
 
344
351
  <t t-name="o-spreadsheet-Spreadsheet">
345
- <div class="o-spreadsheet" t-ref="spreadsheet" t-att-style="getStyle()">
352
+ <div class="o-spreadsheet h-100 w-100" t-ref="spreadsheet" t-att-style="getStyle()">
346
353
  <t t-if="env.isDashboard()">
347
354
  <SpreadsheetDashboard/>
348
355
  </t>
@@ -653,9 +660,10 @@
653
660
  <Menu
654
661
  t-if="state.isMenuOpen"
655
662
  menuItems="props.menuItems"
656
- position="menuPosition"
663
+ anchorRect="menuAnchorRect"
657
664
  onClose.bind="onMenuClosed"
658
665
  menuId="menuId"
666
+ popoverPositioning="'bottom-left'"
659
667
  />
660
668
  </t>
661
669
 
@@ -727,42 +735,44 @@
727
735
 
728
736
  <t t-name="o-spreadsheet-PivotSpreadsheetSidePanel">
729
737
  <t t-set="isReadonly" t-value="env.model.getters.isReadonly()"/>
730
- <div
731
- class="d-flex flex-column h-100 justify-content-between overflow-hidden"
732
- t-att="isReadonly ? ['inert', 1] : []"
733
- t-att-class="{ 'pe-none': isReadonly, 'opacity-50': isReadonly }">
738
+ <div class="d-flex flex-column h-100 justify-content-between overflow-hidden">
734
739
  <div class="h-100 position-relative overflow-x-hidden overflow-y-auto" t-ref="pivotSidePanel">
735
- <PivotTitleSection pivotId="props.pivotId" flipAxis.bind="flipAxis"/>
736
- <Section title.translate="Range">
737
- <SelectionInput
738
- ranges="ranges"
739
- required="true"
740
- isInvalid="shouldDisplayInvalidRangeError"
741
- hasSingleRange="true"
742
- onSelectionChanged="(ranges) => this.onSelectionChanged(ranges)"
743
- onSelectionConfirmed="() => this.onSelectionConfirmed()"
744
- />
745
- <span
746
- class="text-danger sp_range_error_message"
747
- t-if="shouldDisplayInvalidRangeError"
748
- t-esc="pivot.invalidRangeMessage"
749
- />
750
- </Section>
740
+ <div
741
+ t-att="isReadonly ? ['inert', 1] : []"
742
+ t-att-class="{ 'pe-none opacity-50': isReadonly }">
743
+ <PivotTitleSection pivotId="props.pivotId" flipAxis.bind="flipAxis"/>
744
+ <Section title.translate="Range">
745
+ <SelectionInput
746
+ ranges="ranges"
747
+ required="true"
748
+ isInvalid="shouldDisplayInvalidRangeError"
749
+ hasSingleRange="true"
750
+ onSelectionChanged="(ranges) => this.onSelectionChanged(ranges)"
751
+ onSelectionConfirmed="() => this.onSelectionConfirmed()"
752
+ />
753
+ <span
754
+ class="text-danger sp_range_error_message"
755
+ t-if="shouldDisplayInvalidRangeError"
756
+ t-esc="pivot.invalidRangeMessage"
757
+ />
758
+ </Section>
751
759
 
752
- <PivotLayoutConfigurator
753
- t-if="!pivot.isInvalidRange"
754
- unusedGroupableFields="store.unusedGroupableFields"
755
- measureFields="store.measureFields"
756
- unusedGranularities="store.unusedGranularities"
757
- dateGranularities="store.dateGranularities"
758
- datetimeGranularities="store.datetimeGranularities"
759
- definition="definition"
760
- onDimensionsUpdated.bind="onDimensionsUpdated"
761
- getScrollableContainerEl.bind="getScrollableContainerEl"
762
- pivotId="props.pivotId"
763
- />
760
+ <PivotLayoutConfigurator
761
+ t-if="!pivot.isInvalidRange"
762
+ unusedGroupableFields="store.unusedGroupableFields"
763
+ measureFields="store.measureFields"
764
+ unusedGranularities="store.unusedGranularities"
765
+ dateGranularities="store.dateGranularities"
766
+ datetimeGranularities="store.datetimeGranularities"
767
+ definition="definition"
768
+ onDimensionsUpdated.bind="onDimensionsUpdated"
769
+ getScrollableContainerEl.bind="getScrollableContainerEl"
770
+ pivotId="props.pivotId"
771
+ />
772
+ </div>
764
773
  </div>
765
774
  <PivotDeferUpdate
775
+ t-if="!isReadonly"
766
776
  deferUpdate="store.updatesAreDeferred"
767
777
  toggleDeferUpdate="(value) => store.deferUpdates(value)"
768
778
  isDirty="store.isDirty"
@@ -2062,25 +2072,26 @@
2062
2072
  <div class="" t-att-class="props.class">
2063
2073
  <div class="o_side_panel_collapsible_title o-fw-bold d-flex align-items-center">
2064
2074
  <div
2065
- t-att-id="'btn-collapse-'+currentId"
2066
- t-att-class="{ 'collapsed': props.collapsedAtInit }"
2067
2075
  class="collapsor w-100 d-flex align-items-center ps-1"
2068
- data-bs-toggle="collapse"
2069
- t-att-data-bs-target="'#box-collapse-'+currentId">
2076
+ t-att-class="state.isCollapsed ? 'collapsed' : ''"
2077
+ t-on-click="() => this.toggle()">
2070
2078
  <span class="collapsor-arrow">
2071
2079
  <t t-call="o-spreadsheet-Icon.ANGLE_DOWN"/>
2072
2080
  </span>
2073
2081
  <div class="ps-2" t-esc="props.title"/>
2074
2082
  </div>
2075
2083
  </div>
2076
- <div
2077
- t-att-id="'box-collapse-'+currentId"
2078
- t-att-class="{'show': !props.collapsedAtInit}"
2079
- class="collapsible_section collapse">
2084
+ <Collapse isCollapsed="state.isCollapsed">
2080
2085
  <div class="pt-2">
2081
2086
  <t t-slot="content"/>
2082
2087
  </div>
2083
- </div>
2088
+ </Collapse>
2089
+ </div>
2090
+ </t>
2091
+
2092
+ <t t-name="o-spreadsheet-Collapse">
2093
+ <div t-ref="content" class="os-collapse">
2094
+ <t t-slot="default"/>
2084
2095
  </div>
2085
2096
  </t>
2086
2097
 
@@ -2093,7 +2104,7 @@
2093
2104
  <Menu
2094
2105
  t-if="menuState.isOpen"
2095
2106
  menuId="menuId"
2096
- position="menuState.position"
2107
+ anchorRect="menuState.anchorRect"
2097
2108
  menuItems="menuState.menuItems"
2098
2109
  onClose="() => this.menuState.isOpen=false"
2099
2110
  width="160"
@@ -2162,7 +2173,7 @@
2162
2173
  </Section>
2163
2174
  </t>
2164
2175
  </GeneralDesignEditor>
2165
- <SidePanelCollapsible collapsedAtInit="true" title.translate="Waterfall design">
2176
+ <SidePanelCollapsible isInitiallyCollapsed="true" title.translate="Waterfall design">
2166
2177
  <t t-set-slot="content">
2167
2178
  <Section class="'pt-0'" title.translate="Options">
2168
2179
  <t t-set="firstValueAsSubtotal">Use first value as subtotal</t>
@@ -2214,7 +2225,7 @@
2214
2225
  </Section>
2215
2226
  </t>
2216
2227
  </SidePanelCollapsible>
2217
- <SidePanelCollapsible collapsedAtInit="true" title.translate="Axes">
2228
+ <SidePanelCollapsible isInitiallyCollapsed="true" title.translate="Axes">
2218
2229
  <t t-set-slot="content">
2219
2230
  <AxisDesignEditor
2220
2231
  axesList="axesList"
@@ -2226,6 +2237,199 @@
2226
2237
  </SidePanelCollapsible>
2227
2238
  </t>
2228
2239
 
2240
+ <t t-name="o-spreadsheet-TreeMapChartDesignPanel">
2241
+ <GeneralDesignEditor
2242
+ figureId="props.figureId"
2243
+ definition="props.definition"
2244
+ updateChart="props.updateChart"
2245
+ />
2246
+
2247
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Tree map colors">
2248
+ <t t-set-slot="content">
2249
+ <Section class="'pt-0'">
2250
+ <BadgeSelection
2251
+ choices="coloringOptionChoices"
2252
+ onChange.bind="changeColoringOption"
2253
+ selectedValue="coloringOptions.type"
2254
+ />
2255
+
2256
+ <t t-if="coloringOptions.type === 'categoryColor'">
2257
+ <TreeMapCategoryColors
2258
+ figureId="props.figureId"
2259
+ definition="props.definition"
2260
+ onColorChanged.bind="onCategoryColorChange"
2261
+ />
2262
+ </t>
2263
+ <t t-else="">
2264
+ <TreeMapColorScale
2265
+ figureId="props.figureId"
2266
+ definition="props.definition"
2267
+ onColorChanged.bind="onColorScaleChange"
2268
+ />
2269
+ </t>
2270
+ </Section>
2271
+ </t>
2272
+ </SidePanelCollapsible>
2273
+
2274
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Headers and labels">
2275
+ <t t-set-slot="content">
2276
+ <Section title.translate="Headers" class="'pt-0 pb-0'">
2277
+ <Checkbox
2278
+ name="'showHeaders'"
2279
+ label.translate="Show headers"
2280
+ value="showHeaders"
2281
+ onChange="(showHeaders) => props.updateChart(this.props.figureId, { showHeaders })"
2282
+ />
2283
+ </Section>
2284
+ <Section class="'pt-0'" t-if="showHeaders">
2285
+ <TextStyler
2286
+ class="'pt-0 o-header-style'"
2287
+ updateStyle="(headerDesign) => props.updateChart(this.props.figureId, { headerDesign })"
2288
+ style="props.definition.headerDesign || {}"
2289
+ defaultStyle="defaults.headerDesign"
2290
+ hasBackgroundColor="true"
2291
+ />
2292
+ </Section>
2293
+
2294
+ <Section title.translate="Labels" class="'pt-0 pb-0'">
2295
+ <div class="d-flex flex-row gap-4">
2296
+ <Checkbox
2297
+ name="'showLabels'"
2298
+ label.translate="Show labels"
2299
+ value="showLabels"
2300
+ onChange="(showLabels) => props.updateChart(this.props.figureId, { showLabels })"
2301
+ />
2302
+ <Checkbox
2303
+ name="'showValues'"
2304
+ label.translate="Show values"
2305
+ value="showValues"
2306
+ onChange="(showValues) => props.updateChart(this.props.figureId, { showValues })"
2307
+ />
2308
+ </div>
2309
+ </Section>
2310
+ <Section class="'pt-0'" t-if="showValues || showLabels">
2311
+ <TextStyler
2312
+ class="'pt-0 o-values-style'"
2313
+ updateStyle="(valuesDesign) => props.updateChart(this.props.figureId, { valuesDesign })"
2314
+ style="props.definition.valuesDesign || {}"
2315
+ defaultStyle="defaults.valuesDesign"
2316
+ hasVerticalAlign="true"
2317
+ />
2318
+ </Section>
2319
+ </t>
2320
+ </SidePanelCollapsible>
2321
+ </t>
2322
+
2323
+ <t t-name="o-spreadsheet-TreeMapColorScale">
2324
+ <div class="o-min-color d-flex align-items-center mb-2 mt-4">
2325
+ <RoundColorPicker
2326
+ currentColor="coloringOptions.minColor"
2327
+ onColorPicked="(color) => this.setColorScaleColor('minColor', color)"
2328
+ disableNoColor="true"
2329
+ />
2330
+ <span class="ps-2">Color of minimum values</span>
2331
+ </div>
2332
+ <div class="o-mid-color d-flex align-items-center mb-2">
2333
+ <RoundColorPicker
2334
+ currentColor="coloringOptions.midColor"
2335
+ onColorPicked="(color) => this.setColorScaleColor('midColor', color)"
2336
+ />
2337
+ <span class="ps-2">Color of middle values</span>
2338
+ </div>
2339
+ <div class="o-max-color d-flex align-items-center">
2340
+ <RoundColorPicker
2341
+ currentColor="coloringOptions.maxColor"
2342
+ onColorPicked="(color) => this.setColorScaleColor('maxColor', color)"
2343
+ disableNoColor="true"
2344
+ />
2345
+ <span class="ps-2">Color of maximum values</span>
2346
+ </div>
2347
+ </t>
2348
+
2349
+ <t t-name="o-spreadsheet-TreeMapCategoryColors">
2350
+ <div class="mt-3">
2351
+ <div class="o-fw-bold mb-2">Category</div>
2352
+ <t t-foreach="getTreeGroupAndColors()" t-as="group" t-key="group_index">
2353
+ <div class="d-flex align-items-center mb-2" t-att-data-id="group.label">
2354
+ <RoundColorPicker
2355
+ currentColor="group.color"
2356
+ onColorPicked="(color) => this.onGroupColorChanged(group_index, color)"
2357
+ />
2358
+ <span class="ps-2">
2359
+ <span t-esc="'(#' + (group_index +1 ) + ')'" class="o-text-bolder pe-1"/>
2360
+ <span class="text-muted" t-esc="group.label"/>
2361
+ </span>
2362
+ </div>
2363
+ </t>
2364
+
2365
+ <Checkbox
2366
+ name="'useValueBasedGradient'"
2367
+ label.translate="Use value-based gradient"
2368
+ value="coloringOptions.useValueBasedGradient"
2369
+ onChange.bind="useValueBasedGradient"
2370
+ className="'mt-4'"
2371
+ />
2372
+ </div>
2373
+ </t>
2374
+
2375
+ <t t-name="o-spreadsheet-SunburstChartDesignPanel">
2376
+ <GeneralDesignEditor
2377
+ figureId="props.figureId"
2378
+ definition="props.definition"
2379
+ updateChart="props.updateChart">
2380
+ <t t-set-slot="general-extension">
2381
+ <ChartLegend
2382
+ figureId="props.figureId"
2383
+ definition="props.definition"
2384
+ updateChart="props.updateChart"
2385
+ />
2386
+ </t>
2387
+ </GeneralDesignEditor>
2388
+
2389
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Sunburst options">
2390
+ <t t-set-slot="content">
2391
+ <Section class="'pt-0 o-sunburst-colors'" title.translate="Colors">
2392
+ <t t-foreach="groupColors" t-as="item" t-key="item.label">
2393
+ <div class="d-flex align-items-center mb-2" t-att-data-id="item.label">
2394
+ <RoundColorPicker
2395
+ currentColor="item.color"
2396
+ onColorPicked="(color) => this.onGroupColorChanged(item_index, color)"
2397
+ />
2398
+ <span class="ps-2">
2399
+ <span t-esc="'(#' + (item_index +1 ) + ')'" class="o-text-bolder pe-1"/>
2400
+ <span class="text-muted" t-esc="item.label"/>
2401
+ </span>
2402
+ </div>
2403
+ </t>
2404
+ </Section>
2405
+ <Section title.translate="Labels" class="'pt-0 pb-0'">
2406
+ <div class="d-flex flex-row gap-4">
2407
+ <Checkbox
2408
+ name="'showLabels'"
2409
+ label.translate="Show labels"
2410
+ value="showLabels"
2411
+ onChange="(showLabels) => props.updateChart(this.props.figureId, { showLabels })"
2412
+ />
2413
+ <Checkbox
2414
+ name="'showValues'"
2415
+ label.translate="Show values"
2416
+ value="showValues"
2417
+ onChange="(showValues) => props.updateChart(this.props.figureId, { showValues })"
2418
+ />
2419
+ </div>
2420
+ </Section>
2421
+ <Section class="'pt-0'" t-if="showValues || showLabels">
2422
+ <TextStyler
2423
+ class="'o-values-style'"
2424
+ updateStyle="(valuesDesign) => props.updateChart(this.props.figureId, { valuesDesign })"
2425
+ style="props.definition.valuesDesign || {}"
2426
+ defaultStyle="defaults.valuesDesign"
2427
+ />
2428
+ </Section>
2429
+ </t>
2430
+ </SidePanelCollapsible>
2431
+ </t>
2432
+
2229
2433
  <t t-name="o-spreadsheet-ScorecardChartDesignPanel">
2230
2434
  <t t-set="color_up">Color Up</t>
2231
2435
  <t t-set="color_down">Color Down</t>
@@ -2245,7 +2449,7 @@
2245
2449
  </Section>
2246
2450
  </t>
2247
2451
  </GeneralDesignEditor>
2248
- <SidePanelCollapsible collapsedAtInit="false" title.translate="Baseline">
2452
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Baseline">
2249
2453
  <t t-set-slot="content">
2250
2454
  <Section class="'pt-0'" title.translate="Baseline description">
2251
2455
  <input
@@ -2463,6 +2667,29 @@
2463
2667
  </div>
2464
2668
  </t>
2465
2669
 
2670
+ <t t-name="o-spreadsheet-HierarchicalChartConfigPanel">
2671
+ <div>
2672
+ <ChartDataSeries
2673
+ ranges="this.getDataSeriesRanges()"
2674
+ onSelectionChanged.bind="onDataSeriesRangesChanged"
2675
+ onSelectionConfirmed.bind="onDataSeriesConfirmed"
2676
+ onSelectionReordered.bind="onDataSeriesReordered"
2677
+ onSelectionRemoved.bind="onDataSeriesRemoved"
2678
+ title.translate="Hierarchy"
2679
+ />
2680
+ <ChartLabelRange
2681
+ range="this.getLabelRange()"
2682
+ isInvalid="isLabelInvalid"
2683
+ onSelectionChanged.bind="onLabelRangeChanged"
2684
+ onSelectionConfirmed.bind="onLabelRangeConfirmed"
2685
+ options="this.getLabelRangeOptions()"
2686
+ title.translate="Values"
2687
+ />
2688
+
2689
+ <ChartErrorSection t-if="errorMessages.length" messages="errorMessages"/>
2690
+ </div>
2691
+ </t>
2692
+
2466
2693
  <t t-name="o-spreadsheet-GeoChartRegionSelectSection">
2467
2694
  <Section class="'o-geo-region'" title.translate="Region">
2468
2695
  <select class="o-input" t-on-change="this.updateSelectedRegion">
@@ -2498,7 +2725,7 @@
2498
2725
  </t>
2499
2726
  </GeneralDesignEditor>
2500
2727
 
2501
- <SidePanelCollapsible collapsedAtInit="false" title.translate="Geo chart options">
2728
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Geo chart options">
2502
2729
  <t t-set-slot="content">
2503
2730
  <Section class="'pt-0 o-color-scale'" title.translate="Color Scale">
2504
2731
  <select class="o-input" t-on-change="this.updateColorScaleType">
@@ -2583,7 +2810,7 @@
2583
2810
  definition="props.definition"
2584
2811
  updateChart="props.updateChart"
2585
2812
  />
2586
- <SidePanelCollapsible collapsedAtInit="false" title.translate="Gauge Design">
2813
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Gauge Design">
2587
2814
  <t t-set-slot="content">
2588
2815
  <Section class="'pt-0'" title.translate="Range">
2589
2816
  <div class="o-subsection-left">
@@ -2735,7 +2962,7 @@
2735
2962
  </t>
2736
2963
  </GeneralDesignEditor>
2737
2964
 
2738
- <SidePanelCollapsible collapsedAtInit="false" title.translate="Funnel options">
2965
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Funnel options">
2739
2966
  <t t-set-slot="content">
2740
2967
  <Section class="'o-funnel-colors pt-0'" title.translate="Funnel colors">
2741
2968
  <t t-foreach="getFunnelColorItems()" t-as="item" t-key="item_index">
@@ -2786,7 +3013,7 @@
2786
3013
  </Section>
2787
3014
  </t>
2788
3015
  </SeriesWithAxisDesignEditor>
2789
- <SidePanelCollapsible collapsedAtInit="true" title.translate="Axes">
3016
+ <SidePanelCollapsible isInitiallyCollapsed="true" title.translate="Axes">
2790
3017
  <t t-set-slot="content">
2791
3018
  <AxisDesignEditor
2792
3019
  axesList="axesList"
@@ -2820,7 +3047,7 @@
2820
3047
  </t>
2821
3048
  </GeneralDesignEditor>
2822
3049
  <SeriesWithAxisDesignEditor t-props="props"/>
2823
- <SidePanelCollapsible collapsedAtInit="true" title.translate="Axes">
3050
+ <SidePanelCollapsible isInitiallyCollapsed="true" title.translate="Axes">
2824
3051
  <t t-set-slot="content">
2825
3052
  <AxisDesignEditor
2826
3053
  axesList="axesList"
@@ -3149,104 +3376,108 @@
3149
3376
  <path stroke="#eb6d00" fill="#ffe1c8" d="M21.5,35.5 h5 l-2.5,7 l-2.5,-7 h1"/>
3150
3377
  </svg>
3151
3378
  </t>
3152
-
3153
- <t t-name="o-spreadsheet.ChartTitle">
3154
- <t t-set="placeholder">Add a title</t>
3155
- <t t-set="title">
3156
- <t t-if="props.name" t-esc="props.name"/>
3157
- <t t-else="">Title</t>
3158
- </t>
3159
- <Section class="'o-chart-title'" title="title.toString()">
3160
- <input
3161
- type="text"
3162
- class="o-input"
3163
- t-att-value="props.title"
3164
- t-on-change="updateTitle"
3165
- t-att-placeholder="placeholder"
3379
+ <t t-name="o-spreadsheet-ChartPreview.SUNBURST_CHART">
3380
+ <svg viewBox="0 0 48 48" class="o-chart-preview" xmlns="http://www.w3.org/2000/svg">
3381
+ <path
3382
+ fill="#ffe1c8"
3383
+ stroke="#eb6d00"
3384
+ d="M24,12 v8A4,4,0,1,0,27.46,26 L41.32, 34 A20,20,0,0,1,8.679,36.856 L14.807,31.713 A12,12,0,0,1,24,12 M34.4,30 A12,12,0,0,1,14.807,31.713"
3166
3385
  />
3167
- <div class="o-chart-title-designer position-relative d-flex align-items-center">
3168
- <span
3169
- class="o-menu-item-button o-hoverable-button"
3170
- title="Bold"
3171
- t-att-class="{active: props.style.bold}"
3172
- t-on-click="(ev) => this.props.toggleBold()">
3173
- <span>
3174
- <t t-call="o-spreadsheet-Icon.BOLD"/>
3175
- </span>
3176
- </span>
3177
- <span
3178
- class="o-menu-item-button o-hoverable-button"
3179
- title="Italic"
3180
- t-att-class="{active: props.style.italic}"
3181
- t-on-click="(ev) => this.props.toggleItalic()">
3182
- <span>
3183
- <t t-call="o-spreadsheet-Icon.ITALIC"/>
3184
- </span>
3185
- </span>
3186
- <div class="o-divider"/>
3187
- <span
3188
- class="o-menu-item-button o-hoverable-button"
3189
- title="Horizontal alignment"
3190
- t-on-click="(ev) => this.toggleDropdownTool('horizontalChartAlignTool', ev)">
3191
- <span>
3192
- <t t-if="props.style.align === 'center'" t-call="o-spreadsheet-Icon.ALIGN_CENTER"/>
3193
- <t t-elif="props.style.align === 'right'" t-call="o-spreadsheet-Icon.ALIGN_RIGHT"/>
3194
- <t t-else="" t-call="o-spreadsheet-Icon.ALIGN_LEFT"/>
3195
- </span>
3196
- <t t-call="o-spreadsheet-Icon.CARET_DOWN"/>
3197
- </span>
3386
+ <path
3387
+ fill="#c4e4ff"
3388
+ stroke="#0074d9"
3389
+ d="M24,20 v-16 A20 20, 0, 0, 1, 41.32, 34 L27.46,26 A4,4,0,0,0,24,20 M24,12 A12,12,0,0,1,34.4,30 M33.193,16.287 L39.321,11.144 M36,24 L44,24"
3390
+ />
3391
+ </svg>
3392
+ </t>
3393
+ <t t-name="o-spreadsheet-ChartPreview.TREE_MAP_CHART">
3394
+ <svg viewBox="0 0 48 48" class="o-chart-preview" xmlns="http://www.w3.org/2000/svg">
3395
+ <path fill="#444" d="M2,4 h44 v5 h-44"/>
3396
+ <path fill="#444" d="M2,10 h28 v5 h-28"/>
3397
+ <path fill="#444" d="M31,10 h15 v5 h-15"/>
3398
+ <path fill="#0074d9" d="M2,16 h28 v14 h-28"/>
3399
+ <path fill="#c4e4ff" d="M3,17 h26 v12 h-26"/>
3400
+ <path fill="#0074d9" d="M2,31 h15 v12 h-15"/>
3401
+ <path fill="#c4e4ff" d="M3,32 h13 v10 h-13"/>
3402
+ <path fill="#0074d9" d="M18,31 h12 v12 h-12"/>
3403
+ <path fill="#c4e4ff" d="M19,32 h10 v10 h-10"/>
3404
+ <path fill="#eb6d00" d="M31,16 h15 v27 h-15"/>
3405
+ <path fill="#ffe1c8" d="M32,17 h13 v25 h-13"/>
3406
+ </svg>
3407
+ </t>
3408
+
3409
+ <t t-name="o-spreadsheet.TextStyler">
3410
+ <div
3411
+ class="o-chart-title-designer position-relative d-flex align-items-center"
3412
+ t-att-class="props.class">
3413
+ <ActionButton action="boldButtonAction" class="'o-hoverable-button'"/>
3414
+ <ActionButton action="italicButtonAction" class="'o-hoverable-button'"/>
3415
+ <div class="o-divider" t-if="props.hasHorizontalAlign || props.hasVerticalAlign"/>
3416
+ <div class="o-dropdown position-relative" t-if="props.hasHorizontalAlign">
3417
+ <ActionButton
3418
+ action="horizontalAlignButtonAction"
3419
+ hasTriangleDownIcon="true"
3420
+ t-on-click="(ev) => this.toggleDropdownTool('horizontalAlignTool', ev)"
3421
+ class="'o-hoverable-button'"
3422
+ />
3198
3423
  <div
3199
3424
  class="o-dropdown-content position-absolute top-100 start-0 bg-white"
3200
- t-if="state.activeTool === 'horizontalChartAlignTool'"
3425
+ t-if="state.activeTool === 'horizontalAlignTool'"
3426
+ t-att-style="dropdownStyle"
3201
3427
  t-on-click.stop="">
3202
3428
  <div class="o-dropdown-line d-flex">
3203
- <span
3204
- class="o-menu-item-button o-hoverable-button"
3205
- t-att-class="{active: props.style.align === 'left'}"
3206
- title="Left"
3207
- t-on-click="(ev) => this.updateAlignment('left')">
3208
- <span>
3209
- <t t-call="o-spreadsheet-Icon.ALIGN_LEFT"/>
3210
- </span>
3211
- </span>
3212
- <span
3213
- class="o-menu-item-button o-hoverable-button"
3214
- t-att-class="{active: props.style.align === 'center'}"
3215
- title="Center"
3216
- t-on-click="(ev) => this.updateAlignment('center')">
3217
- <span>
3218
- <t t-call="o-spreadsheet-Icon.ALIGN_CENTER"/>
3219
- </span>
3220
- </span>
3221
- <span
3222
- class="o-menu-item-button o-hoverable-button"
3223
- t-att-class="{active: props.style.align === 'right'}"
3224
- title="Right"
3225
- t-on-click="(ev) => this.updateAlignment('right')">
3226
- <span>
3227
- <t t-call="o-spreadsheet-Icon.ALIGN_RIGHT"/>
3228
- </span>
3229
- </span>
3429
+ <t t-foreach="horizontalAlignActions" t-as="action" t-key="action_index">
3430
+ <ActionButton action="action" class="'o-hoverable-button'"/>
3431
+ </t>
3230
3432
  </div>
3231
3433
  </div>
3232
- <div class="o-divider"/>
3233
- <FontSizeEditor
3234
- currentFontSize="props.style.fontSize"
3235
- onFontSizeChanged.bind="this.updateFontSize"
3434
+ </div>
3435
+ <div class="o-dropdown position-relative" t-if="props.hasVerticalAlign">
3436
+ <ActionButton
3437
+ action="verticalAlignButtonAction"
3438
+ hasTriangleDownIcon="true"
3439
+ t-on-click="(ev) => this.toggleDropdownTool('verticalAlignTool', ev)"
3236
3440
  class="'o-hoverable-button'"
3237
3441
  />
3238
- <div class="o-divider"/>
3239
- <ColorPickerWidget
3240
- currentColor="props.style.color"
3241
- toggleColorPicker="(ev) => this.toggleDropdownTool('fillChartColorTool', ev)"
3242
- showColorPicker="state.activeTool === 'fillChartColorTool'"
3243
- onColorPicked.bind="onColorPicked"
3244
- title="fill_color"
3245
- icon="'o-spreadsheet-Icon.TEXT_COLOR'"
3246
- class="'o-hoverable-button o-menu-item-button'"
3247
- />
3442
+ <div
3443
+ class="o-dropdown-content position-absolute top-100 start-0 bg-white"
3444
+ t-if="state.activeTool === 'verticalAlignTool'"
3445
+ t-att-style="dropdownStyle"
3446
+ t-on-click.stop="">
3447
+ <div class="o-dropdown-line d-flex">
3448
+ <t t-foreach="verticalAlignActions" t-as="action" t-key="action_index">
3449
+ <ActionButton action="action" class="'o-hoverable-button'"/>
3450
+ </t>
3451
+ </div>
3452
+ </div>
3248
3453
  </div>
3249
- </Section>
3454
+ <div class="o-divider"/>
3455
+ <FontSizeEditor
3456
+ currentFontSize="currentFontSize"
3457
+ onFontSizeChanged.bind="this.updateFontSize"
3458
+ class="'o-hoverable-button'"
3459
+ />
3460
+ <div class="o-divider"/>
3461
+ <ColorPickerWidget
3462
+ currentColor="props.style.color ?? props.defaultStyle?.color"
3463
+ toggleColorPicker="(ev) => this.toggleDropdownTool('fillChartColorTool', ev)"
3464
+ showColorPicker="state.activeTool === 'fillChartColorTool'"
3465
+ onColorPicked.bind="onTextColorChange"
3466
+ title.translate="Text color"
3467
+ icon="'o-spreadsheet-Icon.TEXT_COLOR'"
3468
+ class="'o-hoverable-button o-menu-item-button'"
3469
+ />
3470
+ <ColorPickerWidget
3471
+ t-if="props.hasBackgroundColor"
3472
+ currentColor="props.style.fillColor || props.defaultStyle?.fillColor"
3473
+ toggleColorPicker="(ev) => this.toggleDropdownTool('fillcolorTool', ev)"
3474
+ showColorPicker="state.activeTool === 'fillcolorTool'"
3475
+ onColorPicked.bind="onFillColorChange"
3476
+ title.translate="Fill color"
3477
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3478
+ class="'o-hoverable-button o-menu-item-button'"
3479
+ />
3480
+ </div>
3250
3481
  </t>
3251
3482
 
3252
3483
  <t t-name="o-spreadsheet-SeriesWithAxisDesignEditor">
@@ -3341,13 +3572,13 @@
3341
3572
  </t>
3342
3573
 
3343
3574
  <t t-name="o-spreadsheet-SeriesDesignEditor">
3344
- <SidePanelCollapsible collapsedAtInit="true" title.translate="Data Series">
3575
+ <SidePanelCollapsible isInitiallyCollapsed="true" title.translate="Data Series">
3345
3576
  <t t-set-slot="content">
3346
3577
  <Section class="'pt-0 pb-0'">
3347
3578
  <select
3348
3579
  class="o-input data-series-selector"
3349
3580
  t-model="state.label"
3350
- t-on-change="(ev) => this.updateSerieEditor(ev)">
3581
+ t-on-change="(ev) => this.updateEditedSeries(ev)">
3351
3582
  <t t-foreach="getDataSeries()" t-as="serie" t-key="serie_index">
3352
3583
  <option
3353
3584
  t-att-value="serie"
@@ -3360,7 +3591,7 @@
3360
3591
  <div class="d-flex align-items-center">
3361
3592
  <span class="o-section-title mb-0 pe-2">Series color</span>
3362
3593
  <RoundColorPicker
3363
- currentColor="getDataSerieColor()"
3594
+ currentColor="getDataSeriesColor()"
3364
3595
  onColorPicked.bind="updateDataSeriesColor"
3365
3596
  />
3366
3597
  </div>
@@ -3369,7 +3600,7 @@
3369
3600
  <input
3370
3601
  class="o-input o-serie-label-editor"
3371
3602
  type="text"
3372
- t-att-value="getDataSerieLabel()"
3603
+ t-att-value="getDataSeriesLabel()"
3373
3604
  t-on-change="(ev) => this.updateDataSeriesLabel(ev)"
3374
3605
  />
3375
3606
  </Section>
@@ -3438,7 +3669,7 @@
3438
3669
 
3439
3670
  <t t-name="o-spreadsheet-GeneralDesignEditor">
3440
3671
  <t t-set="chart_title">Chart title</t>
3441
- <SidePanelCollapsible collapsedAtInit="false" title.translate="General">
3672
+ <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="General">
3442
3673
  <t t-set-slot="content">
3443
3674
  <Section class="'o-chart-background-color pt-0 pb-0'" title.translate="Background color">
3444
3675
  <RoundColorPicker
@@ -3450,12 +3681,9 @@
3450
3681
  title="title.text"
3451
3682
  updateTitle.bind="updateTitle"
3452
3683
  name="chart_title"
3453
- toggleItalic.bind="toggleItalicChartTitle"
3454
- toggleBold.bind="toggleBoldChartTitle"
3455
- updateAlignment.bind="updateChartTitleAlignment"
3456
- updateColor.bind="updateChartTitleColor"
3457
- style="titleStyle"
3458
- onFontSizeChanged.bind="updateChartTitleFontSize"
3684
+ updateStyle.bind="updateChartTitleStyle"
3685
+ style="title"
3686
+ defaultStyle="{align: 'left', fontSize: this.props.defaultChartTitleFontSize}"
3459
3687
  />
3460
3688
  <t t-slot="general-extension"/>
3461
3689
  </t>
@@ -3483,6 +3711,29 @@
3483
3711
  </Section>
3484
3712
  </t>
3485
3713
 
3714
+ <t t-name="o-spreadsheet.ChartTitle">
3715
+ <t t-set="placeholder">Add a title</t>
3716
+ <t t-set="title">
3717
+ <t t-if="props.name" t-esc="props.name"/>
3718
+ <t t-else="">Title</t>
3719
+ </t>
3720
+ <Section class="'o-chart-title'" title="title.toString()">
3721
+ <input
3722
+ type="text"
3723
+ class="o-input"
3724
+ t-att-value="props.title"
3725
+ t-on-change="updateTitle"
3726
+ t-att-placeholder="placeholder"
3727
+ />
3728
+ <TextStyler
3729
+ style="props.style"
3730
+ updateStyle="props.updateStyle"
3731
+ defaultStyle="props.defaultStyle"
3732
+ hasHorizontalAlign="true"
3733
+ />
3734
+ </Section>
3735
+ </t>
3736
+
3486
3737
  <t t-name="o-spreadsheet-AxisDesignEditor">
3487
3738
  <t t-set="editor_label">Axis title</t>
3488
3739
  <Section class="'py-0'">
@@ -3495,13 +3746,10 @@
3495
3746
  <ChartTitle
3496
3747
  title="this.getAxisTitle()"
3497
3748
  updateTitle.bind="updateAxisTitle"
3749
+ updateStyle.bind="updateAxisTitleStyle"
3498
3750
  name="editor_label"
3499
- toggleItalic.bind="toggleItalicAxisTitle"
3500
- toggleBold.bind="toggleBoldAxisTitle"
3501
- updateAlignment.bind="updateAxisTitleAlignment"
3502
- updateColor.bind="updateAxisTitleColor"
3503
3751
  style="axisTitleStyle"
3504
- onFontSizeChanged.bind="updateAxisTitleFontSize"
3752
+ defaultStyle="{align: 'center', color: '', fontSize: defaultFontSize}"
3505
3753
  />
3506
3754
  </t>
3507
3755
 
@@ -3645,6 +3893,7 @@
3645
3893
  t-att-style="menuStyle"
3646
3894
  t-on-scroll="onScroll"
3647
3895
  t-on-wheel.stop=""
3896
+ t-on-pointerdown.prevent=""
3648
3897
  t-on-click.stop=""
3649
3898
  t-on-mouseover="onMouseOverMainMenu"
3650
3899
  t-on-contextmenu.prevent="">
@@ -3697,7 +3946,7 @@
3697
3946
  <Menu
3698
3947
  t-if="subMenu.isOpen"
3699
3948
  t-key="subMenu.parentMenu.id"
3700
- position="subMenuPosition"
3949
+ anchorRect="subMenuAnchorRect"
3701
3950
  menuItems="subMenu.menuItems"
3702
3951
  depth="props.depth + 1"
3703
3952
  maxHeight="props.maxHeight"
@@ -3714,8 +3963,7 @@
3714
3963
  <div
3715
3964
  class="o-link-editor"
3716
3965
  t-on-click.stop="() => this.menu.isOpen=false"
3717
- t-on-keydown="onKeyDown"
3718
- t-ref="linkEditor">
3966
+ t-on-keydown="onKeyDown">
3719
3967
  <div class="o-section">
3720
3968
  <div class="o-section-title">Text</div>
3721
3969
  <div class="d-flex">
@@ -3752,14 +4000,18 @@
3752
4000
  <button t-if="link.url" t-on-click="removeLink" class="o-remove-url o-button-icon">
3753
4001
 
3754
4002
  </button>
3755
- <button t-if="!link.url" t-on-click.stop="openMenu" class="o-special-link o-button-icon">
4003
+ <button
4004
+ t-if="!link.url"
4005
+ t-on-click.stop="openMenu"
4006
+ class="o-special-link o-button-icon"
4007
+ t-ref="linkEditorMenuButton">
3756
4008
  <t t-call="o-spreadsheet-Icon.LIST"/>
3757
4009
  </button>
3758
4010
  </div>
3759
4011
  </div>
3760
4012
  <Menu
3761
4013
  t-if="menu.isOpen"
3762
- position="menuPosition"
4014
+ anchorRect="menuButtonRect"
3763
4015
  menuItems="menuItems"
3764
4016
  onMenuClicked="(ev) => this.onSpecialLink(ev)"
3765
4017
  onClose="() => this.menu.isOpen=false"
@@ -4835,7 +5087,7 @@
4835
5087
  <div class="o-highlight" t-ref="highlight">
4836
5088
  <t t-foreach="['n', 's', 'w', 'e']" t-as="orientation" t-key="orientation">
4837
5089
  <Border
4838
- onMoveHighlight="(x, y) => this.onMoveHighlight(x,y)"
5090
+ onMoveHighlight.bind="this.onMoveHighlight"
4839
5091
  isMoving='highlightState.shiftingMode === "isMoving"'
4840
5092
  orientation="orientation"
4841
5093
  zone="props.zone"
@@ -4843,7 +5095,7 @@
4843
5095
  </t>
4844
5096
  <t t-foreach="['nw', 'ne', 'sw', 'se']" t-as="orientation" t-key="orientation">
4845
5097
  <Corner
4846
- onResizeHighlight="(isLeft, isTop) => this.onResizeHighlight(isLeft, isTop)"
5098
+ onResizeHighlight.bind="onResizeHighlight"
4847
5099
  isResizing='highlightState.shiftingMode === "isResizing"'
4848
5100
  orientation="orientation"
4849
5101
  zone="props.zone"
@@ -4959,7 +5211,7 @@
4959
5211
 
4960
5212
  <t t-name="o-spreadsheet-RowResizer">
4961
5213
  <div
4962
- class="o-row-resizer overflow-hidden"
5214
+ class="o-row-resizer"
4963
5215
  t-on-pointermove.self="onMouseMove"
4964
5216
  t-on-mouseleave="onMouseLeave"
4965
5217
  t-on-pointerdown.self.prevent="select"
@@ -5002,7 +5254,7 @@
5002
5254
 
5003
5255
  <t t-name="o-spreadsheet-ColResizer">
5004
5256
  <div
5005
- class="o-col-resizer d-flex overflow-hidden"
5257
+ class="o-col-resizer d-flex"
5006
5258
  t-on-pointermove.self="onMouseMove"
5007
5259
  t-on-mouseleave="onMouseLeave"
5008
5260
  t-on-pointerdown.self.prevent="select"
@@ -5107,7 +5359,7 @@
5107
5359
  <Menu
5108
5360
  t-if="menu.isOpen"
5109
5361
  menuItems="menu.menuItems"
5110
- position="menu.position"
5362
+ anchorRect="menu.anchorRect"
5111
5363
  onClose.bind="this.closeMenu"
5112
5364
  />
5113
5365
  </div>
@@ -5155,6 +5407,9 @@
5155
5407
  </t>
5156
5408
 
5157
5409
  <t t-name="o-spreadsheet-GridOverlay">
5410
+ <div class="position-absolute" t-att-style="style">
5411
+ <FiguresContainer onFigureDeleted="props.onFigureDeleted"/>
5412
+ </div>
5158
5413
  <div
5159
5414
  t-ref="gridOverlay"
5160
5415
  class="o-grid-overlay overflow-hidden"
@@ -5163,7 +5418,6 @@
5163
5418
  t-on-pointerdown="onMouseDown"
5164
5419
  t-on-dblclick.self="onDoubleClick"
5165
5420
  t-on-contextmenu.stop.prevent="onContextMenu">
5166
- <FiguresContainer onFigureDeleted="props.onFigureDeleted"/>
5167
5421
  <DataValidationOverlay/>
5168
5422
  <FilterIconsOverlay/>
5169
5423
  <GridAddRowsFooter
@@ -5171,6 +5425,7 @@
5171
5425
  t-key="env.model.getters.getActiveSheetId()"
5172
5426
  focusGrid="props.onFigureDeleted"
5173
5427
  />
5428
+ <t t-slot="default"/>
5174
5429
  </div>
5175
5430
  </t>
5176
5431
 
@@ -5222,7 +5477,6 @@
5222
5477
  onCellClicked.bind="onCellClicked"
5223
5478
  onCellDoubleClicked.bind="onCellDoubleClicked"
5224
5479
  onCellRightClicked.bind="onCellRightClicked"
5225
- onCellHovered.bind="onCellHovered"
5226
5480
  onGridResized.bind="onGridResized"
5227
5481
  onGridMoved.bind="moveCanvas"
5228
5482
  gridOverlayDimensions="gridOverlayDimensions"
@@ -5264,7 +5518,7 @@
5264
5518
  <Menu
5265
5519
  t-if="menuState.isOpen"
5266
5520
  menuItems="menuState.menuItems"
5267
- position="menuState.position"
5521
+ anchorRect="menuState.anchorRect"
5268
5522
  onClose="() => this.closeMenu()"
5269
5523
  />
5270
5524
  <t t-foreach="staticTables" t-as="table" t-key="table.id">
@@ -5425,13 +5679,13 @@
5425
5679
  <div
5426
5680
  class="o-figure-viewport-inverse w-0 h-0 overflow-visible position-absolute"
5427
5681
  t-att-style="container.inverseViewportStyle">
5428
- <t t-foreach="container.figures" t-as="figure" t-key="figure.id">
5682
+ <t t-foreach="container.figures" t-as="figureUI" t-key="figureUI.id">
5429
5683
  <FigureComponent
5430
5684
  onFigureDeleted="this.props.onFigureDeleted"
5431
- figure="figure"
5432
- style="getFigureStyle(figure)"
5433
- onMouseDown="(ev) => this.startDraggingFigure(figure, ev)"
5434
- onClickAnchor="(dirX, dirY, ev) => this.startResize(figure, dirX, dirY, ev)"
5685
+ figureUI="figureUI"
5686
+ style="getFigureStyle(figureUI)"
5687
+ onMouseDown="(ev) => this.startDraggingFigure(figureUI, ev)"
5688
+ onClickAnchor="(dirX, dirY, ev) => this.startResize(figureUI, dirX, dirY, ev)"
5435
5689
  />
5436
5690
  </t>
5437
5691
  </div>
@@ -5458,8 +5712,8 @@
5458
5712
  <div class="o-chart-container w-100 h-100" t-on-dblclick="onDoubleClick">
5459
5713
  <t
5460
5714
  t-component="chartComponent"
5461
- figure="this.props.figure"
5462
- t-key="this.props.figure.id + '-' + chartType"
5715
+ figureUI="this.props.figureUI"
5716
+ t-key="this.props.figureUI.id"
5463
5717
  />
5464
5718
  </div>
5465
5719
  </t>
@@ -5472,15 +5726,15 @@
5472
5726
  t-on-contextmenu.prevent.stop="(ev) => !env.model.getters.isReadonly() and this.onContextMenu(ev)"
5473
5727
  t-ref="figure"
5474
5728
  t-att-style="props.style"
5475
- t-att-data-id="props.figure.id"
5729
+ t-att-data-id="props.figureUI.id"
5476
5730
  tabindex="0"
5477
5731
  t-on-keydown="(ev) => this.onKeyDown(ev)"
5478
5732
  t-on-keyup.stop="">
5479
5733
  <t
5480
- t-component="figureRegistry.get(props.figure.tag).Component"
5481
- t-key="props.figure.id"
5734
+ t-component="figureRegistry.get(props.figureUI.tag).Component"
5735
+ t-key="props.figureUI.id"
5482
5736
  onFigureDeleted="props.onFigureDeleted"
5483
- figure="props.figure"
5737
+ figureUI="props.figureUI"
5484
5738
  />
5485
5739
  <div class="o-figure-menu position-absolute m-2" t-if="!env.isDashboard()">
5486
5740
  <div
@@ -5493,7 +5747,7 @@
5493
5747
  </div>
5494
5748
  <Menu
5495
5749
  t-if="menuState.isOpen"
5496
- position="menuState.position"
5750
+ anchorRect="menuState.anchorRect"
5497
5751
  menuItems="menuState.menuItems"
5498
5752
  onClose="() => this.menuState.isOpen=false"
5499
5753
  />
@@ -5619,31 +5873,30 @@
5619
5873
  </t>
5620
5874
 
5621
5875
  <t t-name="o-spreadsheet-SpreadsheetDashboard">
5622
- <div class="o-grid o-two-columns" tabindex="-1" t-on-wheel="onMouseWheel">
5876
+ <div class="o-grid o-two-columns" t-ref="dashboard" tabindex="-1" t-on-wheel="onMouseWheel">
5623
5877
  <div class="mx-auto h-100 position-relative" t-ref="grid" t-att-style="gridContainer">
5624
5878
  <GridOverlay
5625
- onCellHovered.bind="onCellHovered"
5626
5879
  onGridResized.bind="onGridResized"
5627
5880
  onGridMoved.bind="moveCanvas"
5628
- gridOverlayDimensions="gridOverlayDimensions"
5629
- />
5881
+ gridOverlayDimensions="gridOverlayDimensions">
5882
+ <div
5883
+ t-foreach="getClickableCells()"
5884
+ t-as="clickableCell"
5885
+ t-key="clickableCell_index"
5886
+ class="o-dashboard-clickable-cell"
5887
+ t-att-title="clickableCell.title"
5888
+ t-on-click="(ev) => this.selectClickableCell(ev, clickableCell)"
5889
+ t-on-auxclick="(ev) => this.selectClickableCell(ev, clickableCell)"
5890
+ t-on-contextmenu.prevent=""
5891
+ t-att-style="getCellClickableStyle(clickableCell.coordinates)"
5892
+ />
5893
+ </GridOverlay>
5630
5894
  <canvas t-ref="canvas"/>
5631
5895
  <GridPopover
5632
5896
  gridRect="getGridRect()"
5633
5897
  onMouseWheel.bind="onMouseWheel"
5634
5898
  onClosePopover.bind="onClosePopover"
5635
5899
  />
5636
- <div
5637
- t-foreach="getClickableCells()"
5638
- t-as="clickableCell"
5639
- t-key="clickableCell_index"
5640
- class="o-dashboard-clickable-cell"
5641
- t-att-title="clickableCell.title"
5642
- t-on-click="(ev) => this.selectClickableCell(ev, clickableCell)"
5643
- t-on-auxclick="(ev) => this.selectClickableCell(ev, clickableCell)"
5644
- t-on-contextmenu.prevent=""
5645
- t-att-style="getCellClickableStyle(clickableCell.coordinates)"
5646
- />
5647
5900
  </div>
5648
5901
  <VerticalScrollBar/>
5649
5902
  <HorizontalScrollBar/>
@@ -5655,6 +5908,9 @@
5655
5908
  <div class="o-topbar-composer-container w-100">
5656
5909
  <div
5657
5910
  class="o-topbar-composer position-relative bg-white user-select-text d-flex"
5911
+ t-att-class="{
5912
+ 'o-topbar-composer-readonly': env.model.getters.isReadonly(),
5913
+ }"
5658
5914
  t-on-click.stop=""
5659
5915
  t-att-style="containerStyle">
5660
5916
  <Composer
@@ -5685,6 +5941,14 @@
5685
5941
  </div>
5686
5942
  </t>
5687
5943
 
5944
+ <t t-name="o-spreadsheet-SpeechBubble">
5945
+ <t t-portal="'.o-spreadsheet'">
5946
+ <div class="o-speech-bubble position-absolute px-3" t-ref="bubble">
5947
+ <div class="o-speech-content text-truncate pb-1" t-esc="props.content"/>
5948
+ </div>
5949
+ </t>
5950
+ </t>
5951
+
5688
5952
  <t t-name="o-spreadsheet-GridComposer">
5689
5953
  <div
5690
5954
  class="o-cell-reference"
@@ -5700,14 +5964,15 @@
5700
5964
  <t t-name="o-spreadsheet-FunctionDescriptionProvider">
5701
5965
  <div class="o-formula-assistant-container user-select-none shadow">
5702
5966
  <t t-set="context" t-value="getContext()"/>
5703
- <div class="o-formula-assistant" t-if="context.functionName">
5967
+ <div class="o-formula-assistant" t-if="context.functionDescription.name">
5704
5968
  <div class="o-formula-assistant-head d-flex flex-row justify-content-between">
5705
5969
  <div>
5706
- <span t-esc="context.functionName"/>
5970
+ <span t-esc="context.functionDescription.name"/>
5707
5971
  (
5708
5972
  <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
5709
5973
  <span t-if="arg_index > '0'" t-esc="formulaArgSeparator"/>
5710
- <span t-att-class="{ 'o-formula-assistant-focus': context.argToFocus === arg_index }">
5974
+ <span
5975
+ t-att-class="{ 'o-formula-assistant-focus': context.argsToFocus.includes(arg_index) }">
5711
5976
  <span>
5712
5977
  <span t-if="arg.optional || arg.repeating || arg.default">[</span>
5713
5978
  <span t-esc="arg.name"/>
@@ -5719,13 +5984,13 @@
5719
5984
  )
5720
5985
  </div>
5721
5986
  <i
5722
- class="fa fa-caret-up px-2 align-self-start collapsed"
5723
- data-bs-toggle="collapse"
5724
- data-bs-target="#formula-assistant-details"
5987
+ class="fa fa-caret-up px-2 align-self-start"
5988
+ t-att-class="state.isCollapsed ? 'collapsed' : ''"
5989
+ t-on-click="() => this.toggle()"
5725
5990
  />
5726
5991
  </div>
5727
5992
 
5728
- <div id="formula-assistant-details" class="collapse">
5993
+ <Collapse isCollapsed="state.isCollapsed">
5729
5994
  <div class="o-formula-assistant-core pb-3 m-3">
5730
5995
  <div class="o-formula-assistant-gray">ABOUT</div>
5731
5996
  <div t-esc="context.functionDescription.description"/>
@@ -5735,8 +6000,8 @@
5735
6000
  <div
5736
6001
  class="o-formula-assistant-arg p-3 pt-0 display-flex flex-column"
5737
6002
  t-att-class="{
5738
- 'o-formula-assistant-gray': context.argToFocus >= '0',
5739
- 'o-formula-assistant-focus': context.argToFocus === arg_index,
6003
+ 'o-formula-assistant-gray': context.argsToFocus.length > 0,
6004
+ 'o-formula-assistant-focus': context.argsToFocus.includes(arg_index),
5740
6005
  }">
5741
6006
  <div>
5742
6007
  <span t-esc="arg.name"/>
@@ -5751,7 +6016,7 @@
5751
6016
  <div class="o-formula-assistant-arg-description" t-esc="arg.description"/>
5752
6017
  </div>
5753
6018
  </t>
5754
- </div>
6019
+ </Collapse>
5755
6020
  </div>
5756
6021
  </div>
5757
6022
  </t>
@@ -5788,6 +6053,7 @@
5788
6053
  t-on-mousewheel.stop=""
5789
6054
  t-on-input="onInput"
5790
6055
  t-on-pointerdown="onMousedown"
6056
+ t-on-pointerup="onMouseup"
5791
6057
  t-on-click="onClick"
5792
6058
  t-on-keyup="onKeyup"
5793
6059
  t-on-paste="onPaste"
@@ -5799,7 +6065,7 @@
5799
6065
  />
5800
6066
  </div>
5801
6067
  <div
5802
- class="o-composer-assistant-container shadow position-absolute"
6068
+ class="o-composer-assistant-container shadow position-absolute z-1"
5803
6069
  t-att-style="assistantContainerStyle"
5804
6070
  t-if="props.focus !== 'inactive' and !assistant.forcedClosed and assistantIsAvailable">
5805
6071
  <span
@@ -5818,9 +6084,8 @@
5818
6084
  t-on-pointerup.prevent.stop="">
5819
6085
  <FunctionDescriptionProvider
5820
6086
  t-if="functionDescriptionState.showDescription"
5821
- functionName="functionDescriptionState.functionName"
5822
6087
  functionDescription="functionDescriptionState.functionDescription"
5823
- argToFocus="functionDescriptionState.argToFocus"
6088
+ argsToFocus="functionDescriptionState.argsToFocus"
5824
6089
  />
5825
6090
  <div
5826
6091
  t-if="functionDescriptionState.showDescription and autoCompleteState.provider"
@@ -5835,6 +6100,11 @@
5835
6100
  />
5836
6101
  </div>
5837
6102
  </div>
6103
+ <SpeechBubble
6104
+ t-if="displaySpeechBubble"
6105
+ content="props.composerStore.hoveredContentEvaluation"
6106
+ anchorRect="composerState.hoveredRect"
6107
+ />
5838
6108
  </div>
5839
6109
  </t>
5840
6110
 
@@ -5855,7 +6125,7 @@
5855
6125
  t-foreach="htmlContent"
5856
6126
  t-as="content"
5857
6127
  t-key="content_index"
5858
- t-att-class="content.class"
6128
+ t-att-class="content.classes?.join(' ')"
5859
6129
  t-attf-style="color: {{content.color || 'inherit'}};"
5860
6130
  t-esc="content.value"
5861
6131
  />
@@ -5965,7 +6235,6 @@
5965
6235
  t-on-click.stop=""
5966
6236
  t-att-value="state.customHexColor"
5967
6237
  t-on-input="setHexColor"
5968
- maxlength="7"
5969
6238
  />
5970
6239
  <div class="o-color-preview" t-att-style="colorPreviewStyle"/>
5971
6240
  </div>
@@ -6008,7 +6277,11 @@
6008
6277
  </div>
6009
6278
  </Ripple>
6010
6279
  <Ripple>
6011
- <div class="o-sheet-item o-list-sheets me-2 p-1" t-on-click="clickListSheets">
6280
+ <div
6281
+ class="o-sheet-item o-list-sheets me-2 p-1"
6282
+ composerFocusableElement="true"
6283
+ tabindex="-1"
6284
+ t-on-click="clickListSheets">
6012
6285
  <t t-call="o-spreadsheet-Icon.LIST"/>
6013
6286
  </div>
6014
6287
  </Ripple>
@@ -6077,7 +6350,7 @@
6077
6350
 
6078
6351
  <Menu
6079
6352
  t-if="menuState.isOpen"
6080
- position="menuState.position"
6353
+ anchorRect="menuState.anchorRect"
6081
6354
  menuItems="menuState.menuItems"
6082
6355
  maxHeight="menuMaxHeight"
6083
6356
  onClose="() => this.closeMenu()"
@@ -6118,14 +6391,16 @@
6118
6391
  t-att-class="{'o-sheet-name-editable': state.isEditing }"
6119
6392
  t-ref="sheetNameSpan"
6120
6393
  t-esc="sheetName"
6121
- t-on-click="(ev) => this.onMouseEventSheetName(ev)"
6122
6394
  t-on-pointerdown="(ev) => this.onMouseEventSheetName(ev)"
6123
6395
  t-on-dblclick="() => this.onDblClick()"
6124
6396
  t-on-focusout="() => this.onFocusOut()"
6125
6397
  t-on-keydown="(ev) => this.onKeyDown(ev)"
6126
6398
  t-att-contenteditable="state.isEditing ? 'true': 'false'"
6127
6399
  />
6128
- <span class="o-sheet-icon ms-1" t-on-click.stop="(ev) => this.onIconClick(ev)">
6400
+ <span
6401
+ class="o-sheet-icon ms-1"
6402
+ tabindex="-1"
6403
+ t-on-click.stop="(ev) => this.onIconClick(ev)">
6129
6404
  <t t-call="o-spreadsheet-Icon.CARET_DOWN"/>
6130
6405
  </span>
6131
6406
  <div