@odoo/o-spreadsheet 17.1.0-alpha.0 → 17.1.0-alpha.2

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.
@@ -0,0 +1,4492 @@
1
+ <!--
2
+ This file is generated by o-spreadsheet build tools. Do not edit it.
3
+ @see https://github.com/odoo/o-spreadsheet
4
+ @version 17.1.0-alpha.2
5
+ @date 2023-11-03T12:25:57.535Z
6
+ @hash 0595868
7
+ -->
8
+ <odoo>
9
+ <t t-name="o-spreadsheet-ActionButton">
10
+ <span
11
+ t-if="isVisible"
12
+ class="o-menu-item-button"
13
+ t-att-title="title"
14
+ t-att-class="{'o-disabled': !isEnabled, active: isActive}"
15
+ t-attf-class="{{props.class}}"
16
+ t-on-click="onClick">
17
+ <span t-if="iconTitle" t-att-style="buttonStyle">
18
+ <t t-call="{{iconTitle}}"/>
19
+ </span>
20
+ <t t-if="props.hasTriangleDownIcon">
21
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
22
+ </t>
23
+ </span>
24
+ </t>
25
+
26
+ <t t-name="o-spreadsheet-Ripple">
27
+ <div
28
+ class="o-ripple-container position-relative"
29
+ t-att-class="props.class"
30
+ t-on-click="onClick">
31
+ <div class="position-absolute w-100 h-100">
32
+ <t t-foreach="state.ripples" t-as="ripple" t-key="ripple.id">
33
+ <RippleEffect t-props="getRippleEffectProps(ripple.id)"/>
34
+ </t>
35
+ </div>
36
+ <div class="position-relative" t-ref="childContainer">
37
+ <t t-slot="default"/>
38
+ </div>
39
+ </div>
40
+ </t>
41
+
42
+ <t t-name="o-spreadsheet-RippleEffect">
43
+ <div
44
+ class="position-absolute"
45
+ t-att-class="{ 'overflow-hidden': !props.allowOverflow }"
46
+ t-att-style="props.style">
47
+ <div class="o-ripple position-relative pe-none" t-ref="ripple" t-att-style="rippleStyle"/>
48
+ </div>
49
+ </t>
50
+
51
+ <t t-name="o-spreadsheet-Autofill">
52
+ <div class="o-autofill" t-att-style="style"/>
53
+ <div
54
+ class="o-autofill-handler"
55
+ t-att-style="handlerStyle"
56
+ t-on-mousedown="onMouseDown"
57
+ t-on-dblclick="onDblClick"
58
+ />
59
+ <t t-set="tooltip" t-value="getTooltip()"/>
60
+ <div t-if="tooltip" class="o-autofill-nextvalue" t-att-style="styleNextValue">
61
+ <t t-component="tooltip.component" t-props="tooltip.props"/>
62
+ </div>
63
+ </t>
64
+
65
+ <t t-name="o-spreadsheet-BorderEditor">
66
+ <t t-set="border_color">Border Color</t>
67
+ <Popover t-props="popoverProps">
68
+ <div
69
+ class="d-flex o-border-selector"
70
+ t-on-click.stop=""
71
+ t-att-class="props.class ? props.class : ''">
72
+ <div class="o-border-selector-section">
73
+ <div
74
+ t-foreach="BORDER_POSITIONS"
75
+ t-as="borderPositionsRow"
76
+ t-key="borderPositionsRow"
77
+ class="d-flex o-dropdown-button o-dropdown-line">
78
+ <span
79
+ t-foreach="borderPositionsRow"
80
+ t-as="borderPosition"
81
+ t-key="borderPosition"
82
+ class="o-line-item o-hoverable-button"
83
+ t-att-class="{active:props.currentBorderPosition === borderPosition[0]}"
84
+ t-att-name="borderPosition[0]"
85
+ t-on-click.stop="() => this.setBorderPosition(borderPosition[0])">
86
+ <t t-call="{{borderPosition[1]}}"/>
87
+ </span>
88
+ </div>
89
+ </div>
90
+ <div class="o-divider"/>
91
+ <div class="o-border-selector-section">
92
+ <div
93
+ class="m-0 p-0 d-flex align-items-center justify-content-center o-with-color o-hoverable-button"
94
+ title="Border color"
95
+ t-on-click.stop="(ev) => this.toggleDropdownTool('borderColorTool')">
96
+ <ColorPickerWidget
97
+ currentColor="props.currentBorderColor"
98
+ toggleColorPicker="(ev) => this.toggleDropdownTool('borderColorTool')"
99
+ showColorPicker="state.activeTool === 'borderColorTool'"
100
+ onColorPicked="(color) => this.setBorderColor(color)"
101
+ title="border_color"
102
+ icon="props.currentBorderColor === '' ? 'o-spreadsheet-Icon.BORDER_NO_COLOR' : 'o-spreadsheet-Icon.BORDER_COLOR'"
103
+ dropdownMaxHeight="this.props.dropdownMaxHeight"
104
+ class="'o-dropdown-button o-border-picker-button'"
105
+ />
106
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
107
+ </div>
108
+ <div
109
+ class="o-border-style-tool d-flex align-items-center justify-content-center o-hoverable-button"
110
+ title="Line style"
111
+ t-ref="lineStyleButton"
112
+ t-on-click.stop="(ev) => this.toggleDropdownTool('borderTypeTool')">
113
+ <t t-call="o-spreadsheet-Icon.BORDER_TYPE"/>
114
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
115
+ <Popover
116
+ t-props="lineStylePickerPopoverProps"
117
+ t-if="state.activeTool === 'borderTypeTool'">
118
+ <div class="o-border-style-dropdown">
119
+ <t t-foreach="borderStyles" t-as="borderStyle" t-key="borderStyle">
120
+ <div
121
+ t-att-title="borderStyle"
122
+ t-on-click.stop="() => this.setBorderStyle(borderStyle)">
123
+ <div class="d-flex o-dropdown-border-type">
124
+ <div class="o-dropdown-border-check">
125
+ <t
126
+ t-if="props.currentBorderStyle === borderStyle"
127
+ t-call="o-spreadsheet-Icon.CHECK"
128
+ />
129
+ </div>
130
+ <div t-attf-class="o-style-preview o-style-{{borderStyle}}"/>
131
+ </div>
132
+ </div>
133
+ </t>
134
+ </div>
135
+ </Popover>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </Popover>
140
+ </t>
141
+
142
+ <t t-name="o-spreadsheet-BorderEditorWidget">
143
+ <div class="d-flex position-relative" title="Borders">
144
+ <span
145
+ t-ref="borderEditorButton"
146
+ t-on-click.stop="props.toggleBorderEditor"
147
+ t-att-class="props.class ? props.class : ''"
148
+ t-att-disabled="props.disabled">
149
+ <span t-att-style="iconStyle">
150
+ <t t-call="o-spreadsheet-Icon.BORDERS"/>
151
+ </span>
152
+ </span>
153
+ <BorderEditor
154
+ t-if="props.showBorderEditor"
155
+ onBorderColorPicked.bind="onBorderColorPicked"
156
+ onBorderStylePicked.bind="onBorderStylePicked"
157
+ onBorderPositionPicked.bind="onBorderPositionPicked"
158
+ currentBorderColor="state.currentColor"
159
+ currentBorderStyle="state.currentStyle"
160
+ currentBorderPosition="state.currentPosition"
161
+ maxHeight="props.dropdownMaxHeight"
162
+ anchorRect="borderEditorAnchorRect"
163
+ />
164
+ </div>
165
+ </t>
166
+
167
+ <t t-name="o-spreadsheet-BottomBar">
168
+ <div
169
+ class="o-spreadsheet-bottom-bar o-two-columns d-flex align-items-center overflow-hidden"
170
+ t-on-click="props.onClick"
171
+ t-ref="bottomBar"
172
+ t-on-contextmenu.prevent="">
173
+ <Ripple>
174
+ <div
175
+ class="o-sheet-item o-add-sheet me-2 p-1"
176
+ t-if="!env.model.getters.isReadonly()"
177
+ t-on-click="clickAddSheet">
178
+ <t t-call="o-spreadsheet-Icon.PLUS"/>
179
+ </div>
180
+ </Ripple>
181
+ <Ripple>
182
+ <div class="o-sheet-item o-list-sheets me-2 p-1" t-on-click="clickListSheets">
183
+ <t t-call="o-spreadsheet-Icon.LIST"/>
184
+ </div>
185
+ </Ripple>
186
+ <div class="o-all-sheets position-relative flex-shrink-0 d-flex h-100 me-3">
187
+ <div
188
+ class="o-bottom-bar-fade-in position-absolute h-100 w-100 pe-none"
189
+ t-if="state.isSheetListScrollableLeft"
190
+ />
191
+ <div
192
+ class="o-sheet-list d-flex w-100 overflow-hidden px-1"
193
+ t-ref="sheetList"
194
+ t-on-wheel="onWheel"
195
+ t-on-scroll="onScroll">
196
+ <t t-foreach="getVisibleSheets()" t-as="sheet" t-key="sheet.id">
197
+ <BottomBarSheet
198
+ style="getSheetStyle(sheet.id)"
199
+ sheetId="sheet.id"
200
+ openContextMenu="(registry, ev) => this.onSheetContextMenu(sheet.id, registry, ev)"
201
+ onMouseDown="(ev) => this.onSheetMouseDown(sheet.id, ev)"
202
+ />
203
+ </t>
204
+ </div>
205
+ <div
206
+ class="o-bottom-bar-fade-out position-absolute h-100 w-100 pe-none"
207
+ t-if="state.isSheetListScrollableRight"
208
+ />
209
+ </div>
210
+ <div
211
+ class="o-bottom-bar-arrows d-flex h-100 me-5 align-items-center"
212
+ t-if="state.isSheetListScrollableLeft || state.isSheetListScrollableRight">
213
+ <Ripple
214
+ ignoreClickPosition="true"
215
+ width="20"
216
+ height="20"
217
+ offsetX="1"
218
+ allowOverflow="true"
219
+ enabled="state.isSheetListScrollableLeft">
220
+ <div
221
+ class="o-bottom-bar-arrow o-bottom-bar-arrow-left d-flex align-items-center me-2"
222
+ t-att-class="{'o-disabled': !state.isSheetListScrollableLeft}"
223
+ t-on-click="onArrowLeft">
224
+ <t t-call="o-spreadsheet-Icon.CARET_LEFT"/>
225
+ </div>
226
+ </Ripple>
227
+ <Ripple
228
+ ignoreClickPosition="true"
229
+ width="20"
230
+ height="20"
231
+ offsetX="-1"
232
+ allowOverflow="true"
233
+ enabled="state.isSheetListScrollableRight">
234
+ <div
235
+ class="o-bottom-bar-arrow o-bottom-bar-arrow-right d-flex align-items-center me-4"
236
+ t-att-class="{'o-disabled': !state.isSheetListScrollableRight}"
237
+ t-on-click="onArrowRight">
238
+ <t t-call="o-spreadsheet-Icon.CARET_RIGHT"/>
239
+ </div>
240
+ </Ripple>
241
+ </div>
242
+
243
+ <BottomBarStatistic
244
+ openContextMenu="(x, y, registry) => this.openContextMenu(x, y, 'listSelectionStatistics', registry)"
245
+ closeContextMenu="() => this.closeContextMenuWithId('listSelectionStatistics')"
246
+ />
247
+
248
+ <Menu
249
+ t-if="menuState.isOpen"
250
+ position="menuState.position"
251
+ menuItems="menuState.menuItems"
252
+ maxHeight="menuMaxHeight"
253
+ onClose="() => this.closeMenu()"
254
+ menuId="menuState.menuId"
255
+ />
256
+ </div>
257
+ </t>
258
+
259
+ <t t-name="o-spreadsheet-BottomBarSheet">
260
+ <Ripple>
261
+ <div
262
+ class="o-sheet d-flex align-items-center user-select-none text-nowrap "
263
+ t-on-mousedown="(ev) => this.onMouseDown(ev)"
264
+ t-on-contextmenu.prevent="(ev) => this.onContextMenu(ev)"
265
+ t-ref="sheetDiv"
266
+ t-att-style="props.style"
267
+ t-att-title="sheetName"
268
+ t-att-data-id="props.sheetId"
269
+ t-att-class="{active: isSheetActive}">
270
+ <span
271
+ class="o-sheet-name"
272
+ t-att-class="{'o-sheet-name-editable': state.isEditing }"
273
+ t-ref="sheetNameSpan"
274
+ t-esc="sheetName"
275
+ t-on-click="(ev) => this.onClickSheetName(ev)"
276
+ t-on-dblclick="() => this.onDblClick()"
277
+ t-on-focusout="() => this.onFocusOut()"
278
+ t-on-keydown="(ev) => this.onKeyDown(ev)"
279
+ t-att-contenteditable="state.isEditing.toString()"
280
+ />
281
+ <span class="o-sheet-icon ms-1" t-on-click.stop="(ev) => this.onIconClick(ev)">
282
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
283
+ </span>
284
+ </div>
285
+ </Ripple>
286
+ </t>
287
+
288
+ <t t-name="o-spreadsheet-BottomBarStatisic">
289
+ <t t-set="selectedStatistic" t-value="getSelectedStatistic()"/>
290
+ <Ripple class="'ms-auto'" t-if="selectedStatistic !== undefined">
291
+ <div
292
+ class="o-selection-statistic text-truncate user-select-none me-4 bg-white rounded shadow"
293
+ t-on-click="listSelectionStatistics">
294
+ <t t-esc="selectedStatistic"/>
295
+ <span class="ms-2">
296
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
297
+ </span>
298
+ </div>
299
+ </Ripple>
300
+ </t>
301
+
302
+ <t t-name="o-spreadsheet-ClientTag">
303
+ <div t-if="props.active" class="o-client-tag" t-att-style="tagStyle" t-esc="props.name"/>
304
+ </t>
305
+
306
+ <t t-name="o-spreadsheet-ColorPicker">
307
+ <Popover t-props="popoverProps">
308
+ <div class="o-color-picker" t-on-click.stop="" t-att-style="colorPickerStyle">
309
+ <div class="o-color-picker-section-name">Standard</div>
310
+ <div class="colors-grid">
311
+ <div
312
+ t-foreach="COLORS"
313
+ t-as="color"
314
+ t-key="color"
315
+ class="o-color-picker-line-item"
316
+ t-att-data-color="color"
317
+ t-on-click="() => this.onColorClick(color)"
318
+ t-attf-style="background-color:{{color}};">
319
+ <div
320
+ t-if="isSameColor(props.currentColor, color)"
321
+ align="center"
322
+ t-attf-style="color:{{checkmarkColor}}">
323
+ ✓
324
+ </div>
325
+ </div>
326
+ </div>
327
+ <div class="o-separator"/>
328
+ <div
329
+ class="o-color-picker-section-name o-color-picker-toggler"
330
+ t-on-click="toggleColorPicker">
331
+ <span>Custom</span>
332
+ </div>
333
+ <div class="colors-grid o-color-picker-toggler" t-on-click.stop="toggleColorPicker">
334
+ <div class="o-color-picker-line-item o-color-picker-toggler-button">
335
+ <div class="o-color-picker-toggler-sign">
336
+ <t t-call="o-spreadsheet-Icon.PLUS"/>
337
+ </div>
338
+ </div>
339
+ <div
340
+ t-foreach="env.model.getters.getCustomColors()"
341
+ t-as="color"
342
+ t-key="color"
343
+ class="o-color-picker-line-item"
344
+ t-att-data-color="color"
345
+ t-attf-style="background-color:{{color}};"
346
+ t-on-click="() => this.onColorClick(color)">
347
+ <div
348
+ t-if="isSameColor(props.currentColor, color)"
349
+ align="center"
350
+ t-attf-style="color:{{checkmarkColor}}">
351
+ ✓
352
+ </div>
353
+ </div>
354
+ </div>
355
+ <div t-if="state.showGradient" class="o-custom-selector">
356
+ <div
357
+ class="o-gradient"
358
+ t-on-click.stop=""
359
+ t-on-mousedown="dragGradientPointer"
360
+ t-att-style="gradientHueStyle">
361
+ <div class="saturation w-100 h-100 position-absolute pe-none"/>
362
+ <div class="lightness w-100 h-100 position-absolute pe-none"/>
363
+ <div class="magnifier pe-none" t-att-style="pointerStyle"/>
364
+ </div>
365
+ <div class="o-hue-container" t-on-mousedown="dragHuePointer">
366
+ <div class="o-hue-picker" t-on-click.stop=""/>
367
+ <div class="o-hue-slider pe-none" t-att-style="sliderStyle">
368
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_UP"/>
369
+ </div>
370
+ </div>
371
+ <div class="o-custom-input-preview">
372
+ <input
373
+ type="text"
374
+ t-att-class="{'o-wrong-color': !isHexColorInputValid }"
375
+ t-on-click.stop=""
376
+ t-att-value="state.customHexColor"
377
+ t-on-input="setHexColor"
378
+ maxlength="7"
379
+ />
380
+ <div class="o-color-preview" t-att-style="colorPreviewStyle"/>
381
+ </div>
382
+ <div class="o-custom-input-buttons">
383
+ <button
384
+ class="o-add-button"
385
+ t-att-class="{'o-disabled': !state.customHexColor or !isHexColorInputValid}"
386
+ t-on-click.stop="addCustomColor">
387
+ Add
388
+ </button>
389
+ </div>
390
+ </div>
391
+ <div class="o-separator"/>
392
+ <div class="o-buttons">
393
+ <button t-on-click="resetColor" class="o-cancel">No Color</button>
394
+ </div>
395
+ </div>
396
+ </Popover>
397
+ </t>
398
+
399
+ <t t-name="o-spreadsheet-ColorPickerWidget">
400
+ <div class="o-color-picker-widget">
401
+ <span
402
+ class="o-color-picker-button"
403
+ t-ref="colorPickerButton"
404
+ t-on-click.stop="props.toggleColorPicker"
405
+ t-att-title="props.title"
406
+ t-att-class="props.class ? props.class : 'o-color-picker-button-style'"
407
+ t-att-disabled="props.disabled">
408
+ <span t-att-style="iconStyle">
409
+ <t t-call="{{props.icon}}"/>
410
+ </span>
411
+ </span>
412
+ <ColorPicker
413
+ t-if="props.showColorPicker"
414
+ anchorRect="colorPickerAnchorRect"
415
+ onColorPicked="props.onColorPicked"
416
+ currentColor="props.currentColor"
417
+ maxHeight="props.dropdownMaxHeight"
418
+ />
419
+ </div>
420
+ </t>
421
+
422
+ <t t-name="o-spreadsheet-TextValueProvider">
423
+ <div
424
+ t-att-class="{
425
+ 'o-autocomplete-dropdown':props.values.length,
426
+ 'shadow':props.values.length}">
427
+ <t t-foreach="props.values" t-as="v" t-key="v.text">
428
+ <div
429
+ class="d-flex flex-column text-start"
430
+ t-att-class="{'o-autocomplete-value-focus': props.selectedIndex === v_index}"
431
+ t-on-click="() => this.props.onValueSelected(v.text)"
432
+ t-on-mousemove="() => this.props.onValueHovered(v_index)">
433
+ <div class="o-autocomplete-value text-truncate">
434
+ <t t-set="htmlContent" t-value="props.getHtmlContent(v.text)"/>
435
+ <span
436
+ t-foreach="htmlContent"
437
+ t-as="content"
438
+ t-key="content_index"
439
+ t-att-class="content.class"
440
+ t-attf-style="color: {{content.color || 'inherit'}};"
441
+ t-esc="content.value"
442
+ />
443
+ </div>
444
+ <div
445
+ class="o-autocomplete-description text-truncate"
446
+ t-esc="v.description"
447
+ t-if="props.selectedIndex === v_index"
448
+ />
449
+ </div>
450
+ </t>
451
+ </div>
452
+ </t>
453
+
454
+ <t t-name="o-spreadsheet-Composer">
455
+ <div class="o-composer-container w-100 h-100">
456
+ <div
457
+ class="o-composer w-100 text-start"
458
+ t-att-class="{ 'text-muted': env.model.getters.isReadonly(), 'active': props.focus !== 'inactive' }"
459
+ t-att-style="props.inputStyle"
460
+ t-ref="o_composer"
461
+ tabindex="1"
462
+ t-att-contenteditable="env.model.getters.isReadonly() ? 'false' : 'true'"
463
+ spellcheck="false"
464
+ t-on-keydown="onKeydown"
465
+ t-on-mousewheel.stop=""
466
+ t-on-input="onInput"
467
+ t-on-mousedown="onMousedown"
468
+ t-on-click="onClick"
469
+ t-on-keyup="onKeyup"
470
+ t-on-paste.stop=""
471
+ t-on-compositionstart="onCompositionStart"
472
+ t-on-compositionend="onCompositionEnd"
473
+ t-on-dblclick="onDblClick"
474
+ />
475
+
476
+ <div
477
+ t-if="props.focus !== 'inactive' and (autoCompleteState.showProvider or functionDescriptionState.showDescription)"
478
+ class="o-composer-assistant"
479
+ t-att-style="assistantStyle"
480
+ t-on-mousedown.prevent.stop=""
481
+ t-on-click.prevent.stop=""
482
+ t-on-mouseup.prevent.stop="">
483
+ <TextValueProvider
484
+ t-if="autoCompleteState.showProvider"
485
+ values="autoCompleteState.values"
486
+ selectedIndex="autoCompleteState.selectedIndex"
487
+ onValueSelected.bind="this.autoComplete"
488
+ onValueHovered.bind="this.updateAutoCompleteIndex"
489
+ getHtmlContent="autoCompleteState.getHtmlContent"
490
+ />
491
+ <FunctionDescriptionProvider
492
+ t-if="functionDescriptionState.showDescription"
493
+ functionName="functionDescriptionState.functionName"
494
+ functionDescription="functionDescriptionState.functionDescription"
495
+ argToFocus="functionDescriptionState.argToFocus"
496
+ />
497
+ </div>
498
+ </div>
499
+ </t>
500
+
501
+ <t t-name="o-spreadsheet-FunctionDescriptionProvider">
502
+ <div
503
+ class="o-formula-assistant-container user-select-none shadow"
504
+ t-att-class="{
505
+ 'pe-none': assistantState.allowCellSelectionBehind,
506
+ 'pe-auto': !assistantState.allowCellSelectionBehind
507
+ }">
508
+ <t t-set="context" t-value="getContext()"/>
509
+ <div
510
+ class="o-formula-assistant bg-white"
511
+ t-if="context.functionName"
512
+ t-on-mousemove="onMouseMove"
513
+ t-att-class="{'opacity-25': assistantState.allowCellSelectionBehind}">
514
+ <div class="o-formula-assistant-head">
515
+ <span t-esc="context.functionName"/>
516
+ (
517
+ <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
518
+ <span t-if="arg_index > '0'">,&#xA0;</span>
519
+ <span t-att-class="{ 'o-formula-assistant-focus': context.argToFocus === arg_index }">
520
+ <span>
521
+ <span t-if="arg.optional || arg.repeating || arg.default">[</span>
522
+ <span t-esc="arg.name"/>
523
+ <span t-if="arg.repeating">, ...</span>
524
+ <span t-if="arg.optional || arg.repeating || arg.default">]</span>
525
+ </span>
526
+ </span>
527
+ </t>
528
+ )
529
+ </div>
530
+
531
+ <div class="o-formula-assistant-core pb-3 m-3">
532
+ <div class="o-formula-assistant-gray">ABOUT</div>
533
+ <div t-esc="context.functionDescription.description"/>
534
+ </div>
535
+
536
+ <t t-foreach="context.functionDescription.args" t-as="arg" t-key="arg.name">
537
+ <div
538
+ class="o-formula-assistant-arg p-3 pt-0 display-flex flex-column"
539
+ t-att-class="{
540
+ 'o-formula-assistant-gray': context.argToFocus >= '0',
541
+ 'o-formula-assistant-focus': context.argToFocus === arg_index,
542
+ }">
543
+ <div>
544
+ <span t-esc="arg.name"/>
545
+ <span
546
+ t-if="arg.optional || arg.repeating || arg.default ">&#xA0;- [optional]&#xA0;</span>
547
+ <span t-if="arg.default">
548
+ <span>default:&#xA0;</span>
549
+ <t t-esc="arg.defaultValue"/>
550
+ </span>
551
+ <span t-if="arg.repeating">repeatable</span>
552
+ </div>
553
+ <div class="o-formula-assistant-arg-description" t-esc="arg.description"/>
554
+ </div>
555
+ </t>
556
+ </div>
557
+ </div>
558
+ </t>
559
+
560
+ <t t-name="o-spreadsheet-GridComposer">
561
+ <div
562
+ class="o-cell-reference"
563
+ t-if="shouldDisplayCellReference"
564
+ t-att-style="cellReferenceStyle"
565
+ t-esc="cellReference"
566
+ />
567
+ <div class="o-grid-composer" t-att-style="containerStyle" t-ref="gridComposer">
568
+ <Composer
569
+ focus="props.focus"
570
+ inputStyle="composerStyle"
571
+ rect="composerState.rect"
572
+ delimitation="composerState.delimitation"
573
+ onComposerUnmounted="props.onComposerUnmounted"
574
+ onComposerContentFocused="props.onComposerContentFocused"
575
+ />
576
+ </div>
577
+ </t>
578
+
579
+ <t t-name="o-spreadsheet-TopBarComposer">
580
+ <div
581
+ class="o-topbar-composer bg-white user-select-text"
582
+ t-on-click.stop=""
583
+ t-att-style="containerStyle">
584
+ <Composer
585
+ focus="props.focus"
586
+ inputStyle="composerStyle"
587
+ onComposerContentFocused="props.onComposerContentFocused"
588
+ />
589
+ </div>
590
+ </t>
591
+
592
+ <t t-name="o-spreadsheet-SpreadsheetDashboard">
593
+ <div
594
+ class="o-grid o-two-columns"
595
+ tabindex="-1"
596
+ t-on-wheel="onMouseWheel"
597
+ t-on-click="onClosePopover">
598
+ <div class="mx-auto h-100 position-relative" t-ref="grid" t-att-style="gridContainer">
599
+ <GridOverlay
600
+ onCellHovered.bind="onCellHovered"
601
+ onGridResized.bind="onGridResized"
602
+ onGridMoved.bind="moveCanvas"
603
+ gridOverlayDimensions="gridOverlayDimensions"
604
+ />
605
+ <canvas t-ref="canvas"/>
606
+ <GridPopover
607
+ hoveredCell="hoveredCell"
608
+ gridRect="getGridRect()"
609
+ onMouseWheel.bind="onMouseWheel"
610
+ onClosePopover.bind="onClosePopover"
611
+ />
612
+ <div
613
+ t-foreach="getClickableCells()"
614
+ t-as="clickableCell"
615
+ t-key="clickableCell.tKey"
616
+ class="o-dashboard-clickable-cell"
617
+ t-on-click="() => this.selectClickableCell(clickableCell)"
618
+ t-on-contextmenu.prevent=""
619
+ t-att-style="getCellClickableStyle(clickableCell.coordinates)"
620
+ />
621
+ <FilterIconsOverlay/>
622
+ </div>
623
+ <VerticalScrollBar/>
624
+ <HorizontalScrollBar/>
625
+ <div class="o-scrollbar corner"/>
626
+ </div>
627
+ </t>
628
+
629
+ <t t-name="o-spreadsheet-DataValidationOverlay">
630
+ <t t-foreach="checkBoxCellPositions" t-as="position" t-key="'checkbox'+position_index">
631
+ <GridCellIcon cellPosition="position">
632
+ <DataValidationCheckbox cellPosition="position"/>
633
+ </GridCellIcon>
634
+ </t>
635
+
636
+ <t t-foreach="listIconsCellPositions" t-as="position" t-key="'list'+position_index">
637
+ <GridCellIcon cellPosition="position" horizontalAlign="'right'">
638
+ <DataValidationListIcon cellPosition="position"/>
639
+ </GridCellIcon>
640
+ </t>
641
+ </t>
642
+
643
+ <t t-name="o-spreadsheet-DataValidationCheckbox">
644
+ <input
645
+ type="checkbox"
646
+ class="o-dv-checkbox"
647
+ t-att-class="{'pe-none': isDisabled}"
648
+ t-on-change="onCheckboxChange"
649
+ t-att-checked="checkBoxValue"
650
+ />
651
+ </t>
652
+
653
+ <t t-name="o-spreadsheet-DataValidationListIcon">
654
+ <div
655
+ class="o-dv-list-icon d-flex align-items-center justify-content-center"
656
+ t-on-click="onClick">
657
+ <t t-call="o-spreadsheet-Icon.CARET_DOWN"/>
658
+ </div>
659
+ </t>
660
+
661
+ <t t-name="o-spreadsheet-ErrorToolTip">
662
+ <div class="o-error-tooltip">
663
+ <t t-foreach="props.errors" t-as="error" t-key="error_index">
664
+ <div class="o-error-tooltip-title fw-bold text-danger">
665
+ <t t-esc="error.title"/>
666
+ </div>
667
+ <div class="o-error-tooltip-message">
668
+ <t t-esc="error.message"/>
669
+ </div>
670
+ </t>
671
+ </div>
672
+ </t>
673
+
674
+ <t t-name="o-spreadsheet-ChartJsComponent">
675
+ <canvas class="o-figure-canvas w-100 h-100" t-att-style="canvasStyle" t-ref="graphContainer"/>
676
+ </t>
677
+
678
+ <t t-name="o-spreadsheet-ScorecardChart">
679
+ <canvas class="o-figure-canvas w-100 h-100" t-ref="chartContainer"/>
680
+ </t>
681
+
682
+ <t t-name="o-spreadsheet-FigureComponent">
683
+ <div class="o-figure-wrapper pe-auto" t-att-style="wrapperStyle">
684
+ <div
685
+ class="o-figure w-100 h-100"
686
+ t-on-mousedown.stop="(ev) => this.onMouseDown(ev)"
687
+ t-on-contextmenu.prevent.stop="(ev) => !env.model.getters.isReadonly() and this.onContextMenu(ev)"
688
+ t-ref="figure"
689
+ t-att-style="props.style"
690
+ t-att-data-id="props.figure.id"
691
+ tabindex="0"
692
+ t-on-keydown="(ev) => this.onKeyDown(ev)"
693
+ t-on-keyup.stop="">
694
+ <t
695
+ t-component="figureRegistry.get(props.figure.tag).Component"
696
+ t-key="props.figure.id"
697
+ onFigureDeleted="props.onFigureDeleted"
698
+ figure="props.figure"
699
+ />
700
+ <div class="o-figure-menu position-absolute m-2" t-if="!env.isDashboard()">
701
+ <div
702
+ class="o-figure-menu-item"
703
+ t-if="!env.model.getters.isReadonly()"
704
+ t-on-click="showMenu"
705
+ t-ref="menuButton"
706
+ t-on-contextmenu.prevent.stop="showMenu">
707
+ <t t-call="o-spreadsheet-Icon.LIST"/>
708
+ </div>
709
+ <Menu
710
+ t-if="menuState.isOpen"
711
+ position="menuState.position"
712
+ menuItems="menuState.menuItems"
713
+ onClose="() => this.menuState.isOpen=false"
714
+ />
715
+ </div>
716
+ </div>
717
+ <div class="o-figure-border w-100 h-100 position-absolute pe-none" t-att-style="borderStyle"/>
718
+ <t t-if="isSelected">
719
+ <div
720
+ class="o-fig-anchor o-top"
721
+ t-att-style="this.getResizerPosition('top')"
722
+ t-on-mousedown="(ev) => this.clickAnchor(0,-1, ev)"
723
+ />
724
+ <div
725
+ class="o-fig-anchor o-topRight"
726
+ t-att-style="this.getResizerPosition('top right')"
727
+ t-on-mousedown="(ev) => this.clickAnchor(1,-1, ev)"
728
+ />
729
+ <div
730
+ class="o-fig-anchor o-right"
731
+ t-att-style="this.getResizerPosition('right')"
732
+ t-on-mousedown="(ev) => this.clickAnchor(1,0, ev)"
733
+ />
734
+ <div
735
+ class="o-fig-anchor o-bottomRight"
736
+ t-att-style="this.getResizerPosition('bottom right')"
737
+ t-on-mousedown="(ev) => this.clickAnchor(1,1, ev)"
738
+ />
739
+ <div
740
+ class="o-fig-anchor o-bottom"
741
+ t-att-style="this.getResizerPosition('bottom')"
742
+ t-on-mousedown="(ev) => this.clickAnchor(0,1, ev)"
743
+ />
744
+ <div
745
+ class="o-fig-anchor o-bottomLeft"
746
+ t-att-style="this.getResizerPosition('bottom left')"
747
+ t-on-mousedown="(ev) => this.clickAnchor(-1,1, ev)"
748
+ />
749
+ <div
750
+ class="o-fig-anchor o-left"
751
+ t-att-style="this.getResizerPosition('left')"
752
+ t-on-mousedown="(ev) => this.clickAnchor(-1,0, ev)"
753
+ />
754
+ <div
755
+ class="o-fig-anchor o-topLeft"
756
+ t-att-style="this.getResizerPosition('top left')"
757
+ t-on-mousedown="(ev) => this.clickAnchor(-1,-1, ev)"
758
+ />
759
+ </t>
760
+ </div>
761
+ </t>
762
+
763
+ <t t-name="o-spreadsheet-ChartFigure">
764
+ <div class="o-chart-container w-100 h-100" t-on-dblclick="onDoubleClick">
765
+ <t
766
+ t-component="chartComponent"
767
+ figure="this.props.figure"
768
+ t-key="this.props.figure.id + '-' + chartType"
769
+ />
770
+ </div>
771
+ </t>
772
+
773
+ <t t-name="o-spreadsheet-FiguresContainer">
774
+ <div>
775
+ <t t-foreach="containers" t-as="container" t-key="container.type">
776
+ <div
777
+ class="o-figure-container position-absolute pe-none overflow-hidden"
778
+ t-att-style="container.style"
779
+ t-att-data-id="container.type + 'Container'">
780
+ <div
781
+ class="o-figure-viewport-inverse w-0 h-0 overflow-visible position-absolute"
782
+ t-att-style="container.inverseViewportStyle">
783
+ <t t-foreach="container.figures" t-as="figure" t-key="figure.id">
784
+ <FigureComponent
785
+ onFigureDeleted="this.props.onFigureDeleted"
786
+ figure="figure"
787
+ style="getFigureStyle(figure)"
788
+ onMouseDown="(ev) => this.startDraggingFigure(figure, ev)"
789
+ onClickAnchor="(dirX, dirY, ev) => this.startResize(figure, dirX, dirY, ev)"
790
+ />
791
+ </t>
792
+ </div>
793
+ </div>
794
+ </t>
795
+ </div>
796
+ <div
797
+ class="o-figure-container position-absolute pe-none overflow-hidden"
798
+ t-if="dnd.horizontalSnap"
799
+ t-att-style="dnd.horizontalSnap.containerStyle"
800
+ t-att-data-id="'HorizontalSnapContainer'">
801
+ <div class="o-figure-snap-line horizontal" t-att-style="dnd.horizontalSnap.lineStyle"/>
802
+ </div>
803
+ <div
804
+ class="o-figure-container position-absolute pe-none overflow-hidden"
805
+ t-if="dnd.verticalSnap"
806
+ t-att-style="dnd.verticalSnap.containerStyle"
807
+ t-att-data-id="'VerticalSnapContainer'">
808
+ <div class="o-figure-snap-line vertical" t-att-style="dnd.verticalSnap.lineStyle"/>
809
+ </div>
810
+ </t>
811
+
812
+ <t t-name="o-spreadsheet-ImageFigure">
813
+ <img t-att-src="getImagePath" class="w-100 h-100"/>
814
+ </t>
815
+
816
+ <t t-name="o-spreadsheet-FilterIcon">
817
+ <div class="o-filter-icon" t-on-click.stop="onClick">
818
+ <t t-if="isFilterActive" t-call="o-spreadsheet-Icon.FILTER_ICON_ACTIVE"/>
819
+ <t t-else="" t-call="o-spreadsheet-Icon.FILTER_ICON"/>
820
+ </div>
821
+ </t>
822
+
823
+ <t t-name="o-spreadsheet-FilterIconsOverlay">
824
+ <t
825
+ t-foreach="getFilterHeadersPositions()"
826
+ t-as="position"
827
+ t-key="'filter'+position.col + '_' + position.row">
828
+ <GridCellIcon cellPosition="position" offset="props.gridPosition" horizontalAlign="'right'">
829
+ <FilterIcon cellPosition="position"/>
830
+ </GridCellIcon>
831
+ </t>
832
+ </t>
833
+
834
+ <t t-name="o-spreadsheet-FilterMenu">
835
+ <div class="o-filter-menu d-flex flex-column bg-white" t-on-wheel.stop="">
836
+ <div t-if="!isReadonly">
837
+ <div class="o-filter-menu-item" t-on-click="() => this.sortFilterZone('ascending')">
838
+ Sort ascending (A ⟶ Z)
839
+ </div>
840
+ <div class="o-filter-menu-item" t-on-click="() => this.sortFilterZone('descending')">
841
+ Sort descending (Z ⟶ A)
842
+ </div>
843
+ </div>
844
+ <div class="o-separator" t-if="!isReadonly"/>
845
+ <div class="o-filter-menu-actions">
846
+ <div class="o-filter-menu-action-text" t-on-click="selectAll">Select all</div>
847
+ <div class="o-filter-menu-action-text" t-on-click="clearAll">Clear</div>
848
+ </div>
849
+ <div class="position-relative">
850
+ <input
851
+ class="w-100"
852
+ t-ref="filterMenuSearchBar"
853
+ type="text"
854
+ t-model="state.textFilter"
855
+ placeholder="Search..."
856
+ t-on-keydown="onKeyDown"
857
+ />
858
+ <i class="o-search-icon position-absolute">
859
+ <t t-call="o-spreadsheet-Icon.SEARCH"/>
860
+ </i>
861
+ </div>
862
+ <div
863
+ class="o-filter-menu-list d-flex flex-column rounded"
864
+ t-ref="filterValueList"
865
+ t-on-click="this.clearScrolledToValue"
866
+ t-on-scroll="this.clearScrolledToValue">
867
+ <t t-foreach="displayedValues" t-as="value" t-key="value.string">
868
+ <FilterMenuValueItem
869
+ onClick="() => this.checkValue(value)"
870
+ onMouseMove="() => this.onMouseMove(value)"
871
+ value="value.string"
872
+ isChecked="value.checked"
873
+ isSelected="value.string === state.selectedValue"
874
+ scrolledTo="value.scrolledTo"
875
+ />
876
+ </t>
877
+ <div
878
+ t-if="displayedValues.length === 0"
879
+ class="o-filter-menu-no-values d-flex align-items-center justify-content-center w-100 h-100 ">
880
+ No results
881
+ </div>
882
+ </div>
883
+ <div class="o-filter-menu-buttons d-flex justify-content-end">
884
+ <div class="o-filter-menu-button o-filter-menu-button-cancel" t-on-click="cancel">
885
+ Cancel
886
+ </div>
887
+ <div class="o-filter-menu-button o-filter-menu-button-primary" t-on-click="confirm">
888
+ Confirm
889
+ </div>
890
+ </div>
891
+ </div>
892
+ </t>
893
+
894
+ <t t-name="o-spreadsheet-FilterMenuValueItem">
895
+ <div
896
+ t-on-click="this.props.onClick"
897
+ t-on-mousemove="this.props.onMouseMove"
898
+ class="o-filter-menu-item o-filter-menu-value"
899
+ t-ref="menuValueItem"
900
+ t-att-class="{'selected': this.props.isSelected}">
901
+ <div>
902
+ <div class="o-filter-menu-value-checked">
903
+ <span t-if="this.props.isChecked">✓</span>
904
+ </div>
905
+ </div>
906
+ <div class="o-filter-menu-value-text text-truncate">
907
+ <t t-if="this.props.value === ''">(Blanks)</t>
908
+ <t t-else="" t-esc="this.props.value"/>
909
+ </div>
910
+ </div>
911
+ </t>
912
+
913
+ <t t-name="o-spreadsheet-FontSizeEditor">
914
+ <div class="o-dropdown" t-ref="FontSizeEditor">
915
+ <div
916
+ class=" o-font-size-editor d-flex align-items-center"
917
+ t-att-class="props.class"
918
+ title="Font Size"
919
+ t-on-click="this.toggleFontList">
920
+ <input
921
+ type="number"
922
+ min="1"
923
+ max="400"
924
+ class="o-font-size bg-transparent border-0"
925
+ t-on-keydown="onInputKeydown"
926
+ t-on-click.stop=""
927
+ t-on-focus.stop="onInputFocused"
928
+ t-att-value="currentFontSize"
929
+ t-on-change="setSizeFromInput"
930
+ t-ref="inputFontSize"
931
+ />
932
+ <span>
933
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
934
+ </span>
935
+ </div>
936
+ <div
937
+ class="o-dropdown-content o-text-options"
938
+ t-if="dropdown.isOpen"
939
+ t-on-click.stop=""
940
+ t-att-style="props.dropdownStyle">
941
+ <t t-foreach="fontSizes" t-as="fontSize" t-key="fontSize">
942
+ <div
943
+ t-esc="fontSize"
944
+ t-att-data-size="fontSize"
945
+ t-on-click="() => this.setSizeFromList(fontSize)"
946
+ />
947
+ </t>
948
+ </div>
949
+ </div>
950
+ </t>
951
+
952
+ <t t-name="o-spreadsheet-Grid">
953
+ <div
954
+ class="o-grid w-100 h-100"
955
+ tabindex="-1"
956
+ t-on-click="focus"
957
+ t-on-keydown="onKeydown"
958
+ t-on-wheel="onMouseWheel"
959
+ t-ref="grid">
960
+ <GridOverlay
961
+ onCellClicked.bind="onCellClicked"
962
+ onCellDoubleClicked.bind="onCellDoubleClicked"
963
+ onCellRightClicked.bind="onCellRightClicked"
964
+ onCellHovered.bind="onCellHovered"
965
+ onGridResized.bind="onGridResized"
966
+ onGridMoved.bind="moveCanvas"
967
+ gridOverlayDimensions="gridOverlayDimensions"
968
+ onFigureDeleted.bind="focus"
969
+ />
970
+ <HeadersOverlay onOpenContextMenu="(type, x, y) => this.toggleContextMenu(type, x, y)"/>
971
+
972
+ <t t-if="env.model.getters.getEditionMode() !== 'inactive'">
973
+ <GridComposer
974
+ onComposerUnmounted="() => this.focus()"
975
+ onComposerContentFocused="props.onComposerContentFocused"
976
+ focus="props.focusComposer"
977
+ gridDims="env.model.getters.getSheetViewDimensionWithHeaders()"
978
+ />
979
+ </t>
980
+ <t else="1">
981
+ <input
982
+ class="position-absolute"
983
+ style="z-index:-1000;"
984
+ t-on-input="onInput"
985
+ t-on-contextmenu="onInputContextMenu"
986
+ t-ref="hiddenInput"
987
+ />
988
+ </t>
989
+ <canvas t-ref="canvas"/>
990
+ <t
991
+ t-foreach="env.model.getters.getClientsToDisplay()"
992
+ t-as="client"
993
+ t-key="getClientPositionKey(client)">
994
+ <ClientTag
995
+ name="client.name"
996
+ color="client.color"
997
+ col="client.position.col"
998
+ row="client.position.row"
999
+ active="isCellHovered(client.position.col, client.position.row)"
1000
+ />
1001
+ </t>
1002
+ <GridPopover
1003
+ t-if="!menuState.isOpen"
1004
+ hoveredCell="hoveredCell"
1005
+ gridRect="getGridRect()"
1006
+ onMouseWheel.bind="onMouseWheel"
1007
+ onClosePopover.bind="onClosePopover"
1008
+ />
1009
+ <t t-if="env.model.getters.isGridSelectionActive()">
1010
+ <Autofill position="getAutofillPosition()" isVisible="isAutofillVisible"/>
1011
+ </t>
1012
+ <t t-foreach="env.model.getters.getHighlights()" t-as="highlight" t-key="highlight_index">
1013
+ <t t-if="highlight.sheetId === env.model.getters.getActiveSheetId()">
1014
+ <Highlight zone="highlight.zone" color="highlight.color"/>
1015
+ </t>
1016
+ </t>
1017
+ <Menu
1018
+ t-if="menuState.isOpen"
1019
+ menuItems="menuState.menuItems"
1020
+ position="menuState.position"
1021
+ onClose="() => this.closeMenu()"
1022
+ />
1023
+ <FilterIconsOverlay gridPosition="{ x: HEADER_WIDTH, y : HEADER_HEIGHT }"/>
1024
+ <VerticalScrollBar topOffset="HEADER_HEIGHT"/>
1025
+ <HorizontalScrollBar leftOffset="HEADER_WIDTH"/>
1026
+ <div class="o-scrollbar corner"/>
1027
+ </div>
1028
+ </t>
1029
+
1030
+ <t t-name="o-spreadsheet-GridAddRowsFooter">
1031
+ <div
1032
+ class="o-grid-add-rows mt-2 ms-2 w-100 d-flex position-relative align-items-center"
1033
+ t-att-style="addRowsPosition"
1034
+ t-on-mousedown.stop.prevent="">
1035
+ <button t-on-click="onConfirm" t-att-disabled="state.errorFlag" class="o-button">Add</button>
1036
+ <input
1037
+ type="text"
1038
+ class="o-grid-add-rows-input o-input mt-0 me-2"
1039
+ t-ref="inputRef"
1040
+ value="100"
1041
+ t-on-click.stop=""
1042
+ t-on-keydown.stop="onKeydown"
1043
+ t-on-mousedown.stop=""
1044
+ t-on-input.stop="onInput"
1045
+ />
1046
+ <span>more rows at the bottom</span>
1047
+ <ValidationMessages t-if="state.errorFlag" messages="errorMessages" msgType="'error'"/>
1048
+ </div>
1049
+ </t>
1050
+
1051
+ <t t-name="o-spreadsheet-GridCellIcon">
1052
+ <div
1053
+ class="o-grid-cell-icon position-absolute overflow-hidden"
1054
+ t-if="isPositionVisible(this.props.cellPosition)"
1055
+ t-att-style="iconStyle">
1056
+ <t t-slot="default"/>
1057
+ </div>
1058
+ </t>
1059
+
1060
+ <t t-name="o-spreadsheet-GridOverlay">
1061
+ <div
1062
+ t-ref="gridOverlay"
1063
+ class="o-grid-overlay overflow-hidden"
1064
+ t-att-class="{'o-paint-format-cursor': isPaintingFormat}"
1065
+ t-att-style="style"
1066
+ t-on-mousedown="onMouseDown"
1067
+ t-on-dblclick.self="onDoubleClick"
1068
+ t-on-contextmenu="onContextMenu">
1069
+ <FiguresContainer onFigureDeleted="props.onFigureDeleted"/>
1070
+ <DataValidationOverlay/>
1071
+ <GridAddRowsFooter
1072
+ t-if="!env.model.getters.isReadonly()"
1073
+ t-key="env.model.getters.getActiveSheetId()"
1074
+ focusGrid="props.onFigureDeleted"
1075
+ />
1076
+ </div>
1077
+ </t>
1078
+
1079
+ <t t-name="o-spreadsheet-GridPopover">
1080
+ <Popover
1081
+ t-if="cellPopover.isOpen"
1082
+ positioning="cellPopover.cellCorner"
1083
+ maxHeight="cellPopover.Component.size and cellPopover.Component.size.maxHeight"
1084
+ maxWidth="cellPopover.Component.size and cellPopover.Component.size.maxHidth"
1085
+ anchorRect="cellPopover.anchorRect"
1086
+ containerRect="env.getPopoverContainerRect()"
1087
+ onMouseWheel="props.onMouseWheel"
1088
+ zIndex="zIndex">
1089
+ <t
1090
+ t-component="cellPopover.Component"
1091
+ t-props="{...cellPopover.props, onClosed : () => props.onClosePopover()}"
1092
+ />
1093
+ </Popover>
1094
+ </t>
1095
+
1096
+ <t t-name="o-spreadsheet-HeaderGroup">
1097
+ <div
1098
+ class="o-header-group position-absolute"
1099
+ t-att-style="groupBoxStyle"
1100
+ t-att-data-id="props.group.start + '-' + props.group.end"
1101
+ t-on-click="toggleGroup"
1102
+ t-on-contextmenu.stop.prevent="onContextMenu">
1103
+ <div
1104
+ class="o-header-group-header position-absolute d-flex align-items-center justify-content-center overflow-hidden"
1105
+ t-att-style="groupHeaderStyle">
1106
+ <div
1107
+ class="o-group-fold-button user-select-none rounded d-flex align-items-center justify-content-center"
1108
+ t-att-style="groupButtonStyle">
1109
+ <t t-call="{{groupButtonIcon}}"/>
1110
+ </div>
1111
+ </div>
1112
+ <div
1113
+ class="o-group-border position-absolute"
1114
+ t-if="!isGroupFolded"
1115
+ t-att-style="groupBorderStyle"
1116
+ />
1117
+ </div>
1118
+ </t>
1119
+
1120
+ <t t-name="o-spreadsheet-HeaderGroupContainer">
1121
+ <div
1122
+ class="o-header-group-container d-flex w-100 h-100 overflow-hidden"
1123
+ t-att-class="{
1124
+ 'flex-column': props.dimension === 'ROW',
1125
+ 'flex-row': props.dimension === 'COL',
1126
+ }"
1127
+ t-if="props.layers.length"
1128
+ t-on-contextmenu.prevent="onContextMenu">
1129
+ <div
1130
+ class="o-header-group-frozen-pane flex-shrink-0 overflow-hidden position-relative"
1131
+ t-att-class="{
1132
+ 'o-group-rows': props.dimension === 'ROW',
1133
+ 'o-group-columns': props.dimension === 'COL',
1134
+ }"
1135
+ t-if="hasFrozenPane"
1136
+ t-att-style="frozenPaneContainerStyle">
1137
+ <t t-foreach="props.layers" t-as="layer" t-key="layer_index">
1138
+ <t t-foreach="layer" t-as="group" t-key="group.start + '-' + group.end">
1139
+ <t
1140
+ t-component="groupComponent"
1141
+ group=" group"
1142
+ layerOffset="getLayerOffset(layer_index)"
1143
+ openContextMenu.bind="openContextMenu"
1144
+ />
1145
+ </t>
1146
+ </t>
1147
+ </div>
1148
+ <div
1149
+ class="o-header-group-frozen-pane-border"
1150
+ t-att-class="{
1151
+ 'o-group-rows': props.dimension === 'ROW',
1152
+ 'o-group-columns': props.dimension === 'COL',
1153
+ }"
1154
+ t-if="hasFrozenPane"
1155
+ />
1156
+
1157
+ <div
1158
+ class="o-header-group-main-pane flex-shrink-0 position-relative h-100 w-100 overflow-hidden"
1159
+ t-att-class="{
1160
+ 'o-group-rows': hasFrozenPane and props.dimension === 'ROW',
1161
+ 'o-group-columns': hasFrozenPane and props.dimension === 'COL',
1162
+ }">
1163
+ <div
1164
+ class="o-header-group-scroll-container position-relative"
1165
+ t-att-style="scrollContainerStyle">
1166
+ <t t-foreach="props.layers" t-as="layer" t-key="layer_index">
1167
+ <t t-foreach="layer" t-as="group" t-key="group.start + '-' + group.end">
1168
+ <t
1169
+ t-component="groupComponent"
1170
+ group="group"
1171
+ layerOffset="getLayerOffset(layer_index)"
1172
+ openContextMenu.bind="openContextMenu"
1173
+ />
1174
+ </t>
1175
+ </t>
1176
+ </div>
1177
+ </div>
1178
+
1179
+ <Menu
1180
+ t-if="menu.isOpen"
1181
+ menuItems="menu.menuItems"
1182
+ position="menu.position"
1183
+ onClose.bind="this.closeMenu"
1184
+ />
1185
+ </div>
1186
+ </t>
1187
+
1188
+ <t t-name="o-spreadsheet-HeadersOverlay">
1189
+ <div class="o-overlay">
1190
+ <ColResizer onOpenContextMenu="props.onOpenContextMenu"/>
1191
+ <RowResizer onOpenContextMenu="props.onOpenContextMenu"/>
1192
+ <div class="all" t-on-mousedown.self="selectAll"/>
1193
+ </div>
1194
+ </t>
1195
+
1196
+ <t t-name="o-spreadsheet-RowResizer">
1197
+ <div
1198
+ class="o-row-resizer"
1199
+ t-on-mousemove.self="onMouseMove"
1200
+ t-on-mouseleave="onMouseLeave"
1201
+ t-on-mousedown.self.prevent="select"
1202
+ t-ref="rowResizer"
1203
+ t-on-mouseup.self="onMouseUp"
1204
+ t-on-contextmenu.self="onContextMenu"
1205
+ t-att-class="{'o-grab': state.waitingForMove, 'o-dragging': state.isMoving}">
1206
+ <div
1207
+ t-if="state.isMoving"
1208
+ class="dragging-row-line"
1209
+ t-attf-style="top:{{state.draggerLinePosition}}px;"
1210
+ />
1211
+ <div
1212
+ t-if="state.isMoving"
1213
+ class="dragging-row-shadow"
1214
+ t-attf-style="top:{{state.draggerShadowPosition}}px; height:{{state.draggerShadowThickness}}px;"
1215
+ />
1216
+ <t t-if="state.resizerIsActive">
1217
+ <div
1218
+ class="o-handle"
1219
+ t-on-mousedown="onMouseDown"
1220
+ t-on-dblclick="onDblClick"
1221
+ t-on-contextmenu.prevent=""
1222
+ t-attf-style="top:{{state.draggerLinePosition - 2}}px;">
1223
+ <div class="dragging-resizer" t-if="state.isResizing"/>
1224
+ </div>
1225
+ </t>
1226
+ <t
1227
+ t-foreach="env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId())"
1228
+ t-as="hiddenItem"
1229
+ t-key="hiddenItem_index">
1230
+ <t t-if="!hiddenItem.includes(0)">
1231
+ <div
1232
+ class="o-unhide"
1233
+ t-att-data-index="hiddenItem_index"
1234
+ t-attf-style="top:{{unhideStyleValue(hiddenItem[0]) - 17}}px;"
1235
+ t-on-click="() => this.unhide(hiddenItem)">
1236
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_UP"/>
1237
+ </div>
1238
+ </t>
1239
+ <t
1240
+ t-if="!hiddenItem.includes(env.model.getters.getNumberRows(env.model.getters.getActiveSheetId())-1)">
1241
+ <div
1242
+ class="o-unhide"
1243
+ t-att-data-index="hiddenItem_index"
1244
+ t-attf-style="top:{{unhideStyleValue(hiddenItem[0]) + 3}}px;"
1245
+ t-on-click="() => this.unhide(hiddenItem)">
1246
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
1247
+ </div>
1248
+ </t>
1249
+ </t>
1250
+ </div>
1251
+ </t>
1252
+
1253
+ <t t-name="o-spreadsheet-ColResizer">
1254
+ <div
1255
+ class="o-col-resizer"
1256
+ t-on-mousemove.self="onMouseMove"
1257
+ t-on-mouseleave="onMouseLeave"
1258
+ t-on-mousedown.self.prevent="select"
1259
+ t-ref="colResizer"
1260
+ t-on-mouseup.self="onMouseUp"
1261
+ t-on-contextmenu.self="onContextMenu"
1262
+ t-att-class="{'o-grab': state.waitingForMove, 'o-dragging': state.isMoving, }">
1263
+ <div
1264
+ t-if="state.isMoving"
1265
+ class="dragging-col-line"
1266
+ t-attf-style="left:{{state.draggerLinePosition}}px;"
1267
+ />
1268
+ <div
1269
+ t-if="state.isMoving"
1270
+ class="dragging-col-shadow"
1271
+ t-attf-style="left:{{state.draggerShadowPosition}}px; width:{{state.draggerShadowThickness}}px"
1272
+ />
1273
+ <t t-if="state.resizerIsActive">
1274
+ <div
1275
+ class="o-handle"
1276
+ t-on-mousedown="onMouseDown"
1277
+ t-on-dblclick="onDblClick"
1278
+ t-on-contextmenu.prevent=""
1279
+ t-attf-style="left:{{state.draggerLinePosition - 2}}px;">
1280
+ <div class="dragging-resizer" t-if="state.isResizing"/>
1281
+ </div>
1282
+ </t>
1283
+ <t
1284
+ t-foreach="env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId())"
1285
+ t-as="hiddenItem"
1286
+ t-key="hiddenItem_index">
1287
+ <t t-if="!hiddenItem.includes(0)">
1288
+ <div
1289
+ class="o-unhide"
1290
+ t-att-data-index="hiddenItem_index"
1291
+ t-attf-style="left:{{unhideStyleValue(hiddenItem[0]) - 17}}px; margin-right:6px;"
1292
+ t-on-click="() => this.unhide(hiddenItem)">
1293
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_LEFT"/>
1294
+ </div>
1295
+ </t>
1296
+ <t
1297
+ t-if="!hiddenItem.includes(env.model.getters.getNumberCols(env.model.getters.getActiveSheetId())-1)">
1298
+ <div
1299
+ class="o-unhide"
1300
+ t-att-data-index="hiddenItem_index"
1301
+ t-attf-style="left:{{unhideStyleValue(hiddenItem[0]) + 3}}px;"
1302
+ t-on-click="() => this.unhide(hiddenItem)">
1303
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_RIGHT"/>
1304
+ </div>
1305
+ </t>
1306
+ </t>
1307
+ </div>
1308
+ </t>
1309
+
1310
+ <t t-name="o-spreadsheet-Border">
1311
+ <div
1312
+ class="o-border"
1313
+ t-on-mousedown.prevent="onMouseDown"
1314
+ t-att-style="style"
1315
+ t-att-class="{
1316
+ 'o-moving': props.isMoving,
1317
+ 'o-border-n': props.orientation === 'n',
1318
+ 'o-border-s': props.orientation === 's',
1319
+ 'o-border-w': props.orientation === 'w',
1320
+ 'o-border-e': props.orientation === 'e',
1321
+ }"
1322
+ />
1323
+ </t>
1324
+
1325
+ <t t-name="o-spreadsheet-Corner">
1326
+ <div
1327
+ class="o-corner"
1328
+ t-on-mousedown.prevent="onMouseDown"
1329
+ t-att-style="style"
1330
+ t-att-class="{
1331
+ 'o-resizing': props.isResizing,
1332
+ 'o-corner-nw': props.orientation === 'nw',
1333
+ 'o-corner-ne': props.orientation === 'ne',
1334
+ 'o-corner-sw': props.orientation === 'sw',
1335
+ 'o-corner-se': props.orientation === 'se',
1336
+ }"
1337
+ />
1338
+ </t>
1339
+
1340
+ <t t-name="o-spreadsheet-Highlight">
1341
+ <div class="o-highlight" t-ref="highlight">
1342
+ <t t-foreach="['n', 's', 'w', 'e']" t-as="orientation" t-key="orientation">
1343
+ <Border
1344
+ onMoveHighlight="(x, y) => this.onMoveHighlight(x,y)"
1345
+ isMoving='highlightState.shiftingMode === "isMoving"'
1346
+ orientation="orientation"
1347
+ zone="props.zone"
1348
+ />
1349
+ </t>
1350
+ <t t-foreach="['nw', 'ne', 'sw', 'se']" t-as="orientation" t-key="orientation">
1351
+ <Corner
1352
+ onResizeHighlight="(isLeft, isTop) => this.onResizeHighlight(isLeft, isTop)"
1353
+ isResizing='highlightState.shiftingMode === "isResizing"'
1354
+ orientation="orientation"
1355
+ zone="props.zone"
1356
+ color="props.color"
1357
+ />
1358
+ </t>
1359
+ </div>
1360
+ </t>
1361
+
1362
+ <t t-name="o-spreadsheet-IconPicker">
1363
+ <div class="o-icon-picker">
1364
+ <t t-foreach="iconSets" t-as="iconSet" t-key="iconSet">
1365
+ <div class="o-cf-icon-line">
1366
+ <div
1367
+ class="o-icon-picker-item"
1368
+ t-on-click="() => this.onIconClick(iconSets[iconSet].good)">
1369
+ <t t-call="o-spreadsheet-Icon.{{icons[iconSets[iconSet].good].template}}"/>
1370
+ </div>
1371
+ <div
1372
+ class="o-icon-picker-item"
1373
+ t-on-click="() => this.onIconClick(iconSets[iconSet].neutral)">
1374
+ <t t-call="o-spreadsheet-Icon.{{icons[iconSets[iconSet].neutral].template}}"/>
1375
+ </div>
1376
+ <div
1377
+ class="o-icon-picker-item"
1378
+ t-on-click="() => this.onIconClick(iconSets[iconSet].bad)">
1379
+ <t t-call="o-spreadsheet-Icon.{{icons[iconSets[iconSet].bad].template}}"/>
1380
+ </div>
1381
+ </div>
1382
+ </t>
1383
+ </div>
1384
+ </t>
1385
+
1386
+ <t t-name="o-spreadsheet-Icon.CLEAR_AND_RELOAD">
1387
+ <svg class="o-icon">
1388
+ <path
1389
+ fill="currentColor"
1390
+ d="M14 15H4V3h6v3h4M4 1.5A1.5 1.5 0 0 0 2.5 3v12a1.5 1.5 0 0 0 1.4 1.5h10a1.5 1.5 0 0 0 1.5-1.5V5l-3.5-3.5
1391
+ "
1392
+ />
1393
+ </svg>
1394
+ </t>
1395
+ <t t-name="o-spreadsheet-Icon.EXPORT_XLSX">
1396
+ <svg class="o-icon">
1397
+ <path
1398
+ fill="currentColor"
1399
+ d="M0 1a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1m4-4V1H1v3m7 0V1H5v3M4 8V5H1v3m7 0V5H5v3m-3.5 2h2v4h3v-1.5l3 2.5-3 2.5V16h-5m9.5-6h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1m1.7 7 1.3-2 1.3 2h2l-2-3 2-3h-2L14 13l-1.3-2h-2l2 3-2 3"
1400
+ />
1401
+ </svg>
1402
+ </t>
1403
+ <t t-name="o-spreadsheet-Icon.OPEN_READ_ONLY">
1404
+ <svg class="o-icon">
1405
+ <path
1406
+ fill="currentColor"
1407
+ d="M13 7V5c0-2.5-2-4-4-4S5 2.5 5 5v2h-.5C3.5 7 3 7.5 3 8.5v7c0 1 .5 1.5 1.5 1.5h9c1 0 1.5-.5 1.5-1.5v-7c0-1-.5-1.5-1.5-1.5m-7-2c0-1.5 1-2.5 2.5-2.5s2.5 1 2.5 2.5v2h-5V5m1 7a1.5 1.5 0 0 1 3 0 1.5 1.5 0 0 1-3 0"
1408
+ />
1409
+ </svg>
1410
+ </t>
1411
+ <t t-name="o-spreadsheet-Icon.OPEN_DASHBOARD">
1412
+ <svg class="o-icon">
1413
+ <path
1414
+ fill="currentColor"
1415
+ d="M13 2.07A8 8 0 1 0 15.93 5L14.2 6A6 6 0 1 1 12 3.8m-2 3.47a2 2 0 1 0 .73.73l5.5-5.5-.6-.6M9.3 3.8a.6.6 0 1 1-.01-.01m1.81.51a.6.6 0 1 1-.01-.01M7.5 4.3a.6.6 0 1 1-.01-.01M5.9 5.4a.6.6 0 1 1-.01-.01M4.8 6.9a.6.6 0 1 1-.01-.01m8.71.61a.6.6 0 1 0-.01 0"
1416
+ />
1417
+ </svg>
1418
+ </t>
1419
+ <t t-name="o-spreadsheet-Icon.OPEN_READ_WRITE">
1420
+ <svg class="o-icon">
1421
+ <path
1422
+ fill="currentColor"
1423
+ d="M13 7V5a4 4 0 0 0-8 0v2h-.5C3.5 7 3 7.5 3 8.5v7c0 1 .5 1.5 1.5 1.5h9c1 0 1.5-.5 1.5-1.5v-7c0-1-.5-1.5-1.5-1.5m-7-2a2 2 0 0 1 5 0v2h-5m1 5a1.5 1.5 0 0 1 3 0 1.5 1.5 0 0 1-3 0m6 3.5h-9v-7h9"
1424
+ />
1425
+ </svg>
1426
+ </t>
1427
+ <t t-name="o-spreadsheet-Icon.IMPORT_XLSX">
1428
+ <svg class="o-icon">
1429
+ <path
1430
+ fill="currentColor"
1431
+ d="M9 10a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1m4-4v-3h-3v3m7 0v-3h-3v3m-1 4v-3h-3v3m7 0v-3h-3v3M.5 9h2v4h3v-1.5l3 2.5-3 2.5V15h-5M1 0h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1m1.7 7L4 5l1.3 2h2l-2-3 2-3h-2L4 3 2.7 1h-2l2 3-2 3"
1432
+ />
1433
+ </svg>
1434
+ </t>
1435
+ <t t-name="o-spreadsheet-Icon.UNDO">
1436
+ <svg class="o-icon">
1437
+ <path
1438
+ fill="currentColor"
1439
+ d="M5.43 9.43 8 12H1V5l2.96 2.958A8.29 8.29 0 0 1 9.32 6c3.46 0 6.42 2.11 7.68 5l-2 1c-.94-2.39-3.13-3.92-5.68-4a6.57 6.57 0 0 0-3.89 1.43"
1440
+ />
1441
+ </svg>
1442
+ </t>
1443
+ <t t-name="o-spreadsheet-Icon.REDO">
1444
+ <svg class="o-icon">
1445
+ <path
1446
+ fill="currentColor"
1447
+ d="M12.57 9.43 10 12h7V5l-2.96 2.96A8.29 8.29 0 0 0 8.68 6C5.22 6 2.26 8.11 1 11l2 1c.94-2.39 3.13-3.92 5.68-4a6.58 6.58 0 0 1 3.89 1.43"
1448
+ />
1449
+ </svg>
1450
+ </t>
1451
+ <t t-name="o-spreadsheet-Icon.COPY">
1452
+ <svg class="o-icon">
1453
+ <path
1454
+ fill="currentColor"
1455
+ d="M14.5 15.23v1.5H3a1 1 0 0 1-1-1V3.23h1.5v11a1 1 0 0 0 1 1h10m0-3.5a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h6.5a1 1 0 0 1 1 1m-9-2.5a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1H15a1 1 0 0 0 1-1v-11a1 1 0 0 0-1-1"
1456
+ />
1457
+ </svg>
1458
+ </t>
1459
+ <t t-name="o-spreadsheet-Icon.CUT">
1460
+ <svg class="o-icon">
1461
+ <path
1462
+ fill="currentColor"
1463
+ d="M3 2v2l4.5 5-1.2 1.3c-.4-.2-.8-.3-1.3-.3-1.7 0-3 1.3-3 3s1.3 3 3 3 3-1.3 3-3c0-.5-.1-.9-.3-1.3L9 10.4l1.3 1.3c-.2.4-.3.8-.3 1.3 0 1.7 1.3 3 3 3s3-1.3 3-3-1.3-3-3-3c-.5 0-.9.1-1.3.3L10.4 9 15 4.4V2h-.4L9 7.6 3.4 2H3Zm2 12.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5Zm9.5-1.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5ZM9 8.5c.3 0 .5.2.5.5s-.2.5-.5.5-.5-.2-.5-.5.2-.5.5-.5"
1464
+ />
1465
+ </svg>
1466
+ </t>
1467
+ <t t-name="o-spreadsheet-Icon.PASTE">
1468
+ <svg class="o-icon">
1469
+ <path
1470
+ fill="currentColor"
1471
+ d="M14.5 2.5H11C10.7 1.6 10 1 9 1s-1.5.5-2 1.5H3.5C2.5 2.5 2 3 2 4v11c0 1 .5 1.5 1.5 1.5h11c1 0 1.5-.5 1.5-1.5V4c0-1-.5-1.5-1.5-1.5Zm-4.75.75c0 .5-.34.75-.75.75s-.75-.34-.75-.75.34-.75.75-.75.75.34.75.75ZM14.5 15h-11V4H5v2.5h8V4h1.5v11"
1472
+ />
1473
+ </svg>
1474
+ </t>
1475
+ <t t-name="o-spreadsheet-Icon.FIND_AND_REPLACE">
1476
+ <svg class="o-icon">
1477
+ <path
1478
+ fill="currentColor"
1479
+ d="M10.75 11.25c-1 .75-2.25 1.25-3.5 1.25-3 0-5.5-2.5-5.5-5.5s2.5-5.5 5.5-5.5 5.5 2.5 5.5 5.5c0 1.25-.5 2.5-1.25 3.5l.25.25h.75l4 4-1.5 1.5-4-4v-.75l-.25-.25ZM7.25 11c2.25 0 4-1.75 4-4s-1.75-4-4-4-4 1.75-4 4 1.75 4 4 4"
1480
+ />
1481
+ </svg>
1482
+ </t>
1483
+ <t t-name="o-spreadsheet-Icon.DELETE">
1484
+ <svg class="o-icon">
1485
+ <path
1486
+ fill="currentColor"
1487
+ d="M12 1.75v-1H6v1H1.5v2h1v12a1.5 1.5 0 0 0 1.5 1.5h10a1.5 1.5 0 0 0 1.5-1.5v-12h1v-2M4 15.75v-12h10v12Zm2-10.5h2v9H6Zm4 0h2v9h-2"
1488
+ />
1489
+ </svg>
1490
+ </t>
1491
+ <t t-name="o-spreadsheet-Icon.CLEAR">
1492
+ <svg class="o-icon">
1493
+ <path
1494
+ fill="currentColor"
1495
+ d="M1.5 15a.75.75 0 0 0 0 1.5h15a.75.75 0 0 0 0-1.5M5.3 12.75c.1.1.3.2.5.2h4c.2 0 .4-.1.5-.2l5.5-5.5c.2-.3.2-.6 0-.8l-4.4-4.4c-.3-.2-.6-.2-.8 0l-4.8 4.8c-2.7 2.9-3.1 2.8-2.4 4M7 7.25l3.6 3.6-1 1-3.6.1-1.8-1.9"
1496
+ />
1497
+ </svg>
1498
+ </t>
1499
+ <t t-name="o-spreadsheet-Icon.FREEZE">
1500
+ <svg class="o-icon">
1501
+ <path
1502
+ fill="currentColor"
1503
+ d="M.5 17.5h16a1 1 0 0 0 1-1v-15a1 1 0 0 0-1-1h-15a1 1 0 0 0-1 1v15a1 1 0 0 0 1 1m9-10.5v4.5H6V7m0 9v-3.5h4.5V16M5 16H3.5L5 14.5M5 13l-3 3v-1.5l3-3M2 13v-2l3-3v2m-3-.5v-2l3-3v2M2 6V4l2-2h1v1m11 13h-4.5v-3.5H16m0-1h-4.5V7H16m0-5v4h-4.5V2m-1 4H6V2h4.5"
1504
+ />
1505
+ </svg>
1506
+ </t>
1507
+ <t t-name="o-spreadsheet-Icon.UNFREEZE">
1508
+ <svg class="o-icon">
1509
+ <path
1510
+ fill="currentColor"
1511
+ d="M.5 17.5h16a1 1 0 0 0 1-1v-15a1 1 0 0 0-1-1h-15a1 1 0 0 0-1 1v15a1 1 0 0 0 1 1M5 6H2V2h3m0 9.5H2V7h3m0 9H2v-3.5h3M10.5 7v4.5H6V7m0 9v-3.5h4.5V16m5.5 0h-4.5v-3.5H16m0-1h-4.5V7H16m0-5v4h-4.5V2m-1 4H6V2h4.5"
1512
+ />
1513
+ </svg>
1514
+ </t>
1515
+ <t t-name="o-spreadsheet-Icon.SHOW_HIDE_GRID">
1516
+ <svg class="o-icon">
1517
+ <path
1518
+ fill="currentColor"
1519
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v7H11V7H7v4s-.5 0-1.5 1h-1v5h-3a1.5 1.5 0 0 1-1-1M6 6V2H2v4m9 0V2H7v4m9 0V2h-4v4m-6 5V7H2v4m14-2V7h-4v2m-7.5 6.5V12H2v3.5 M14 10.5c1 0 1 .5 1 1-1.5 2.5-3.5 4.5-5 6.5-.5 0-1-.5-1-1-1-.5-1.5-1-2.5-2 0 0-.5-.5 0-1 1.5-2 4-3 7-3m-1 1.5C13.5 12 4 14 10 16c0 0-1.5-2 2.5-3.5m5 1.5c.5.5.5 1 .5 1-1.5 2-3.5 3-6 2.5.5-.5.5-1 1-1s5.5-1 2-3.5l1-1"
1520
+ />
1521
+ </svg>
1522
+ </t>
1523
+ <t t-name="o-spreadsheet-Icon.SHOW_HIDE_FORMULA">
1524
+ <svg class="o-icon">
1525
+ <path
1526
+ fill="currentColor"
1527
+ d="M7 14.25q-.25.75-.75 1.25T5 16q-.75 0-1.5-.5Q3 15 3 14.25q0-.5.25-.75t.75-.25q.25 0 .25.75v.5H5q.5 0 .5-.5l1.25-6.5H5V6h2l.5-2.25q.25-.75.75-1.25T9.5 2q1 0 1.5.5t.5 1q0 .5-.25.75t-.5.25q-.5 0-.75-.25t-.25-.5V3H9.5q-.25 0-.5.5L8.5 6H10v1.5H8.25m1.25 1H15v1h-4l2 2-2 2h4v1H9V14l2.5-2.5L9 9"
1528
+ />
1529
+ </svg>
1530
+ </t>
1531
+ <t t-name="o-spreadsheet-Icon.HIDE_ROW">
1532
+ <svg class="o-icon">
1533
+ <path
1534
+ fill="currentColor"
1535
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2H2v3.5h14V2H2v9h14V7H2v9h14v-3.5H2M1 12l4-5h2l-4 5m2 0 4-5h2l-4 5m2 0 4-5h2l-4 5m2 0 4-5v4"
1536
+ />
1537
+ </svg>
1538
+ </t>
1539
+ <t t-name="o-spreadsheet-Icon.HIDE_COL">
1540
+ <svg class="o-icon">
1541
+ <path
1542
+ fill="currentColor"
1543
+ d="M16 .5A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2A1.5 1.5 0 0 1 2 .5h14V2h-3.5v14H16V2H7v14h4V2H2v14h3.5V2M6 1l5 4v2L6 3m0 2 5 4v2L6 7m0 2 5 4v2l-5-4m0 2 5 4H"
1544
+ />
1545
+ </svg>
1546
+ </t>
1547
+ <t t-name="o-spreadsheet-Icon.INSERT_ROW">
1548
+ <svg class="o-icon">
1549
+ <path
1550
+ fill="currentColor"
1551
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2H2v3.5h14V2H2v9h14V7H2v9h14v-3.5H2"
1552
+ />
1553
+ </svg>
1554
+ </t>
1555
+ <t t-name="o-spreadsheet-Icon.INSERT_ROW_BEFORE">
1556
+ <svg class="o-icon">
1557
+ <path
1558
+ fill="currentColor"
1559
+ d="M3.5 14.5A1.5 1.5 0 0 0 5 16h10a1.5 1.5 0 0 0 1.5-1.5v-7h-3V5h3V1.5A1.5 1.5 0 0 0 15 0H5a1.5 1.5 0 0 0-1.5 1.5v2h-3V9h3M15 12.5v2H5v-2M15 9v2H5V9m10-7.5v2H5v-2M12 5v2.5H2V5"
1560
+ />
1561
+ </svg>
1562
+ </t>
1563
+ <t t-name="o-spreadsheet-Icon.INSERT_ROW_AFTER">
1564
+ <svg class="o-icon">
1565
+ <path
1566
+ fill="currentColor"
1567
+ d="M3.5 1.5A1.5 1.5 0 0 1 5 0h10a1.5 1.5 0 0 1 1.5 1.5v7h-3V11h3v3.5A1.5 1.5 0 0 1 15 16H5a1.5 1.5 0 0 1-1.5-1.5v-2h-3V7h3M15 3.5v-2H5v2M15 7V5H5v2m10 7.5v-2H5v2m7-3.5V8.5H2V11"
1568
+ />
1569
+ </svg>
1570
+ </t>
1571
+ <t t-name="o-spreadsheet-Icon.INSERT_COL">
1572
+ <svg class="o-icon">
1573
+ <path
1574
+ fill="currentColor"
1575
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2H2v14h3.5V2H2h5v14h4V2H2h10.5v14H16V2H2"
1576
+ />
1577
+ </svg>
1578
+ </t>
1579
+ <t t-name="o-spreadsheet-Icon.INSERT_COL_AFTER">
1580
+ <svg class="o-icon">
1581
+ <path
1582
+ fill="currentColor"
1583
+ d="M2.5 3A1.5 1.5 0 0 0 1 4.5v10A1.5 1.5 0 0 0 2.5 16h7v-3H12v3h3.5a1.5 1.5 0 0 0 1.5-1.5v-10A1.5 1.5 0 0 0 15.5 3h-2V0H8v3M4.5 14.5h-2v-10h2m3.5 10H6v-10h2m7.5 10h-2v-10h2m-3.5 7H9.5v-10H12"
1584
+ />
1585
+ </svg>
1586
+ </t>
1587
+ <t t-name="o-spreadsheet-Icon.INSERT_COL_BEFORE">
1588
+ <svg class="o-icon">
1589
+ <path
1590
+ fill="currentColor"
1591
+ d="M15.5 3A1.5 1.5 0 0 1 17 4.5v10a1.5 1.5 0 0 1-1.5 1.5h-7v-3H6v3H2.5A1.5 1.5 0 0 1 1 14.5v-10A1.5 1.5 0 0 1 2.5 3h2V0H10v3m3.5 11.5h2v-10h-2m-3.5 10h2v-10h-2m-7.5 10h2v-10h-2m3.5 7h2.5v-10H6"
1592
+ />
1593
+ </svg>
1594
+ </t>
1595
+ <t t-name="o-spreadsheet-Icon.INSERT_CELL">
1596
+ <svg class="o-icon">
1597
+ <path
1598
+ fill="currentColor"
1599
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2H2v14h14V2H2"
1600
+ />
1601
+ </svg>
1602
+ </t>
1603
+ <t t-name="o-spreadsheet-Icon.INSERT_CELL_SHIFT_DOWN">
1604
+ <svg class="o-icon">
1605
+ <path
1606
+ fill="currentColor"
1607
+ d="M5 2.5A1.5 1.5 0 0 1 6.5 1h10A1.5 1.5 0 0 1 18 2.5v13a1.5 1.5 0 0 1-1.5 1.5h-10A1.5 1.5 0 0 1 5 15.5v-5h5.25v-3H5m11.5-2v-3h-4.75v3m-1.5 0v-3H6.5v3m10 5v-3h-4.75v3m-1.5 5v-3H6.5v3m10 0v-3h-4.75v3M0 12.5l2.5 4 2.5-4H3.25v-6h-1.5v6"
1608
+ />
1609
+ </svg>
1610
+ </t>
1611
+ <t t-name="o-spreadsheet-Icon.INSERT_CELL_SHIFT_RIGHT">
1612
+ <svg class="o-icon">
1613
+ <path
1614
+ fill="currentColor"
1615
+ d="M2.5 5A1.5 1.5 0 0 0 1 6.5v10A1.5 1.5 0 0 0 2.5 18h13a1.5 1.5 0 0 0 1.5-1.5v-10A1.5 1.5 0 0 0 15.5 5h-5v5.25h-3V5m-2 11.5h-3v-4.75h3m0-1.5h-3V6.5h3m5 10h-3v-4.75h3m5-1.5h-3V6.5h3m0 10h-3v-4.75h3M12.5 0l4 2.5-4 2.5V3.25h-6v-1.5h6"
1616
+ />
1617
+ </svg>
1618
+ </t>
1619
+ <t t-name="o-spreadsheet-Icon.DELETE_CELL_SHIFT_UP">
1620
+ <svg class="o-icon">
1621
+ <path
1622
+ fill="currentColor"
1623
+ d="M5 2.5A1.5 1.5 0 0 1 6.5 1h10A1.5 1.5 0 0 1 18 2.5v13a1.5 1.5 0 0 1-1.5 1.5h-10A1.5 1.5 0 0 1 5 15.5v-5h5.25v-3H5m11.5-2v-3h-4.75v3m-1.5 0v-3H6.5v3m10 5v-3h-4.75v3m-1.5 5v-3H6.5v3m10 0v-3h-4.75v3M0 10l2.5-4L5 10H3.25v6h-1.5v-6"
1624
+ />
1625
+ </svg>
1626
+ </t>
1627
+ <t t-name="o-spreadsheet-Icon.DELETE_CELL_SHIFT_LEFT">
1628
+ <svg class="o-icon">
1629
+ <path
1630
+ fill="currentColor"
1631
+ d="M2.5 5A1.5 1.5 0 0 0 1 6.5v10A1.5 1.5 0 0 0 2.5 18h13a1.5 1.5 0 0 0 1.5-1.5v-10A1.5 1.5 0 0 0 15.5 5h-5v5.25h-3V5m-2 11.5h-3v-4.75h3m0-1.5h-3V6.5h3m5 10h-3v-4.75h3m5-1.5h-3V6.5h3m0 10h-3v-4.75h3M10 0 6 2.5 10 5V3.25h6v-1.5h-6"
1632
+ />
1633
+ </svg>
1634
+ </t>
1635
+ <t t-name="o-spreadsheet-Icon.INSERT_CHART">
1636
+ <svg class="o-icon">
1637
+ <path
1638
+ fill="currentColor"
1639
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2H2v14h14V2H2m1.5 12.5h2v-7h-2m3 7h2v-10h-2m3 10h2v-5h-2m3 5h2v-11h-2M2 14.5h14v1H2"
1640
+ />
1641
+ </svg>
1642
+ </t>
1643
+ <t t-name="o-spreadsheet-Icon.INSERT_IMAGE">
1644
+ <svg class="o-icon" fill="currentColor">
1645
+ <path
1646
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v14a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2H2v14h14V2H2m10 4.5L10 11 8.5 9.5l-2 2.5L5 10.5l-2 3h12M3.5,5a1.5,1.5,0,0,1,3,0a1.5,1.5,0,0,1,-3,0"
1647
+ />
1648
+ </svg>
1649
+ </t>
1650
+ <t t-name="o-spreadsheet-Icon.INSERT_LINK">
1651
+ <svg class="o-icon" fill="currentColor">
1652
+ <path
1653
+ d="M6.88 13.69c.19-.19.41-.28.68-.28.27 0 .51.09.72.28.43.45.43.92 0 1.4l-.84.8c-.75.75-1.63 1.12-2.64 1.12-1.04 0-1.93-.37-2.68-1.12C1.37 15.14 1 14.26 1 13.25c0-1.04.37-1.93 1.12-2.68l2.96-2.96c.93-.9 1.89-1.42 2.88-1.54.98-.12 1.84.17 2.56.86.21.21.32.45.32.72 0 .26-.1.51-.32.72-.48.43-.95.43-1.4 0-.67-.64-1.55-.41-2.67.68l-2.93 2.92c-.35.35-.52.77-.52 1.28s.17.92.52 1.24c.35.35.76.52 1.26.52.49 0 .91-.17 1.26-.52l.84-.8m9-11.48c.75.75 1.12 1.63 1.12 2.64 0 1.04-.37 1.94-1.12 2.68l-3.16 3.16c-.99.96-1.99 1.44-3 1.44-.83 0-1.57-.33-2.24-1a.913.913 0 0 1-.28-.68c0-.27.09-.5.27-.72.19-.19.43-.28.71-.28.28 0 .51.09.7.28.66.64 1.48.48 2.44-.48l3.16-3.12c.37-.37.56-.8.56-1.28 0-.51-.19-.92-.56-1.24-.32-.35-.7-.56-1.12-.62-.43-.07-.83.07-1.2.42l-1 1c-.22.19-.45.28-.72.28-.26 0-.5-.09-.68-.28-.46-.45-.46-.92 0-1.4l1-1c.72-.72 1.56-1.06 2.54-1.02.97.04 1.83.45 2.58 1.22"
1654
+ />
1655
+ </svg>
1656
+ </t>
1657
+ <t t-name="o-spreadsheet-Icon.INSERT_SHEET">
1658
+ <svg class="o-icon" fill="currentColor">
1659
+ <path
1660
+ d="M17.5 5.5V16a1.5 1.5 0 0 1-1.5 1.5H2A1.5 1.5 0 0 1 .5 16V2A1.5 1.5 0 0 1 2 .5h10.5M2 5.5h3.5V2H2m5.25 3.5h3.5V2h-3.5M2 10.75h3.5v-3.5H2m5.25 3.5h3.5v-3.5h-3.5m5.25 3.5H16v-3.5h-3.5M2 16h3.5v-3.5H2M7.25 16h3.5v-3.5h-3.5M12.5 16H16v-3.5h-3.5"
1661
+ />
1662
+ </svg>
1663
+ </t>
1664
+ <t t-name="o-spreadsheet-Icon.PAINT_FORMAT">
1665
+ <svg class="o-icon">
1666
+ <path
1667
+ fill="currentColor"
1668
+ d="M9,0 L1,0 C0.45,0 0,0.45 0,1 L0,4 C0,4.55 0.45,5 1,5 L9,5 C9.55,5 10,4.55 10,4 L10,3 L11,3 L11,6 L4,6 L4,14 L6,14 L6,8 L13,8 L13,2 L10,2 L10,1 C10,0.45 9.55,0 9,0 Z"
1669
+ transform="translate(3 2)"
1670
+ />
1671
+ </svg>
1672
+ </t>
1673
+ <t t-name="o-spreadsheet-Icon.CONDITIONAL_FORMAT">
1674
+ <svg class="o-icon">
1675
+ <path
1676
+ fill="currentColor"
1677
+ d="M12.25.5c2 0 3.5 1.5 3.5 3.5v6.5c0 .5 0 2-2 2h-2.5v4c0 .5-.5 1-1 1h-2.5c-.5 0-1-.5-1-1v-4h-2.5c-1 0-2-1-2-2V.5m12 3a1.5 1.5 0 0 0-1.5-1.5h-3v2h-1.5V2h-1v4h-2V2h-1.5v8.5h10.5m-12-3h12.5V9H2.25"
1678
+ />
1679
+ </svg>
1680
+ </t>
1681
+ <t t-name="o-spreadsheet-Icon.CLEAR_FORMAT">
1682
+ <svg class="o-icon">
1683
+ <path
1684
+ fill="currentColor"
1685
+ d="M2.12 4.05 7.28 9.2l-2.43 5.3h2.5l1.64-3.58 4.59 4.58 1.27-1.27L3.4 2.77 2.12 4.05ZM5.67 2.5l2 2h1.76l-.55 1.21 1.71 1.71 1.34-2.92h3.92v-2H5.67"
1686
+ />
1687
+ </svg>
1688
+ </t>
1689
+ <t t-name="o-spreadsheet-Icon.TRIANGLE_DOWN">
1690
+ <svg class="o-icon">
1691
+ <polygon fill="currentColor" points="0 0 4 4 8 0" transform="translate(5 7)"/>
1692
+ </svg>
1693
+ </t>
1694
+ <t t-name="o-spreadsheet-Icon.TRIANGLE_UP">
1695
+ <svg class="o-icon">
1696
+ <polygon fill="currentColor" points="4 0 0 4 8 4" transform="translate(5 7)"/>
1697
+ </svg>
1698
+ </t>
1699
+ <t t-name="o-spreadsheet-Icon.TRIANGLE_RIGHT">
1700
+ <svg class="o-icon">
1701
+ <polygon fill="currentColor" points="0 0 4 4 0 8" transform="translate(5 5)"/>
1702
+ </svg>
1703
+ </t>
1704
+ <t t-name="o-spreadsheet-Icon.TRIANGLE_LEFT">
1705
+ <svg class="o-icon">
1706
+ <polygon fill="currentColor" points="4 0 0 4 4 8" transform="translate(5 5)"/>
1707
+ </svg>
1708
+ </t>
1709
+ <t t-name="o-spreadsheet-Icon.BOLD">
1710
+ <svg class="o-icon">
1711
+ <path
1712
+ fill="currentColor"
1713
+ d="M13.5 6.5C13.5 4.57 11.93 3 10 3H4.5v12h6.25c1.79 0 3.25-1.46 3.25-3.25 0-1.3-.77-2.41-1.87-2.93.83-.58 1.37-1.44 1.37-2.32M9.5 5c.83 0 1.5.67 1.5 1.5S10.33 8 9.5 8h-2V5h2m-2 8v-3H10c.83 0 1.5.67 1.5 1.5S10.83 13 10 13H7.5"
1714
+ />
1715
+ </svg>
1716
+ </t>
1717
+ <t t-name="o-spreadsheet-Icon.ITALIC">
1718
+ <svg class="o-icon">
1719
+ <path fill="currentColor" d="M7 3v2h2.58l-3.66 8H3v2h8v-2H8.42l3.66-8H15V3"/>
1720
+ </svg>
1721
+ </t>
1722
+ <t t-name="o-spreadsheet-Icon.UNDERLINE">
1723
+ <svg class="o-icon">
1724
+ <path
1725
+ fill="currentColor"
1726
+ d="M9 15c2.76 0 5-2.24 5-5V3h-2v7c0 1.75-1.5 3-3 3s-3-1.242-3-3V3H4v7c0 2.76 2.24 5 5 5Zm-6 1v2h12v-2H3"
1727
+ />
1728
+ </svg>
1729
+ </t>
1730
+ <t t-name="o-spreadsheet-Icon.STRIKE">
1731
+ <svg class="o-icon">
1732
+ <path
1733
+ fill="currentColor"
1734
+ d="M4.89 6.06c0-.46.1-.87.3-1.25.2-.38.46-.7.84-.97s.78-.47 1.28-.62A5.71 5.71 0 0 1 8.93 3c.61 0 1.16.08 1.65.25.5.17.92.4 1.27.7.35.3.62.66.81 1.07.19.41.28.87.28 1.36h-2.26a1.85 1.85 0 0 0-.11-.64 1.26 1.26 0 0 0-.33-.51 1.53 1.53 0 0 0-.56-.33A2.42 2.42 0 0 0 8.89 4.8c-.3 0-.55.03-.77.1a1.52 1.52 0 0 0-.54.27 1.14 1.14 0 0 0-.43.9c0 .36.18.66.55.91l.06.04C8.02 7.19 8.5 7.5 9 8H6s-.79-.62-.82-.69c-.19-.36-.29-.77-.29-1.25M16 9H2v2h7.22c.14.05.3.1.41.15.28.12.5.26.65.38.16.13.26.27.32.42.06.15.08.33.08.51 0 .18-.03.34-.1.49a1.02 1.02 0 0 1-.31.39 1.6 1.6 0 0 1-.53.26 2.71 2.71 0 0 1-.76.09c-.33 0-.62-.03-.89-.1a1.8 1.8 0 0 1-.68-.31 1.45 1.45 0 0 1-.44-.56c-.11-.23-.19-.57-.19-.74H4.55c0 .25.06.69.18 1.02a3.15 3.15 0 0 0 1.22 1.6c.28.2.58.36.92.49.33.13.67.23 1.04.29.36.06.72.09 1.08.09.6 0 1.15-.07 1.64-.21a3.88 3.88 0 0 0 1.25-.59 2.69 2.69 0 0 0 .8-.95c.19-.38.28-.81.28-1.29 0-.45-.08-.86-.23-1.211a2.26 2.26 0 0 0-.13-.25L16 11V9"
1735
+ />
1736
+ </svg>
1737
+ </t>
1738
+ <t t-name="o-spreadsheet-Icon.TEXT_COLOR">
1739
+ <svg class="o-icon">
1740
+ <path
1741
+ fill="currentColor"
1742
+ d="M10 1H8L3.5 13h2l1.12-3h4.75l1.12 3h2L10 1ZM7.38 8 9 3.67 10.62 8H7.38"
1743
+ />
1744
+ </svg>
1745
+ </t>
1746
+ <t t-name="o-spreadsheet-Icon.FILL_COLOR">
1747
+ <svg class="o-icon">
1748
+ <path
1749
+ fill="currentColor"
1750
+ d="M14.5 8.87S13 10.49 13 11.49c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5c0-.99-1.5-2.62-1.5-2.62m-1.79-2.08L5.91 0 4.85 1.06l1.59 1.59-4.15 4.14a.996.996 0 0 0 0 1.41l4.5 4.5c.2.2.45.3.71.3.26 0 .51-.1.71-.29l4.5-4.5c.39-.39.39-1.03 0-1.42M4.21 7 7.5 3.71 10.79 7H4.21"
1751
+ />
1752
+ </svg>
1753
+ </t>
1754
+ <t t-name="o-spreadsheet-Icon.MERGE_CELL">
1755
+ <svg class="o-icon">
1756
+ <path
1757
+ fill="currentColor"
1758
+ d="M3 6H1V2h7v2H3v2m7-2V2h7v4h-2V4h-5m0 10h5v-2h2v4h-7v-2m-9-2h2v2h5v2H1v-4m0-4h4V6l3 3-3 3v-2H1V8m9 1 3-3v2h4v2h-4v2l-3-3"
1759
+ />
1760
+ </svg>
1761
+ </t>
1762
+ <t t-name="o-spreadsheet-Icon.ALIGN_LEFT">
1763
+ <svg class="o-icon align-left">
1764
+ <path fill="currentColor" d="M2 16h10v-2H2v2M12 6H2v2h10V6M2 2v2h14V2H2m0 10h14v-2H2v2"/>
1765
+ </svg>
1766
+ </t>
1767
+ <t t-name="o-spreadsheet-Icon.ALIGN_CENTER">
1768
+ <svg class="o-icon align-center">
1769
+ <path fill="currentColor" d="M4 14v2h10v-2H4m0-8v2h10V6H4m-2 6h14v-2H2v2M2 2v2h14V2H2"/>
1770
+ </svg>
1771
+ </t>
1772
+ <t t-name="o-spreadsheet-Icon.ALIGN_RIGHT">
1773
+ <svg class="o-icon align-right">
1774
+ <path fill="currentColor" d="M6 16h10v-2H6v2m-4-4h14v-2H2v2M2 2v2h14V2H2m4 6h10V6H6v2"/>
1775
+ </svg>
1776
+ </t>
1777
+ <t t-name="o-spreadsheet-Icon.ALIGN_TOP">
1778
+ <svg class="o-icon align-top">
1779
+ <path d="M3 2h12v2H3m2.5 5H8v7h2V9h2.5L9 5.5" fill="currentColor"/>
1780
+ </svg>
1781
+ </t>
1782
+ <t t-name="o-spreadsheet-Icon.ALIGN_MIDDLE">
1783
+ <svg class="o-icon align-middle">
1784
+ <path
1785
+ d="M12.5 3H10V0H8v3H5.5L9 6.5M5.5 15H8v3h2v-3h2.5L9 11.5M3 8v2h12V8"
1786
+ fill="currentColor"
1787
+ />
1788
+ </svg>
1789
+ </t>
1790
+ <t t-name="o-spreadsheet-Icon.ALIGN_BOTTOM">
1791
+ <svg class="o-icon align-bottom">
1792
+ <path d="M5.5 9H8V2h2v7h2.5L9 12.5M3 14v2h12v-2" fill="currentColor"/>
1793
+ </svg>
1794
+ </t>
1795
+ <t t-name="o-spreadsheet-Icon.WRAPPING_OVERFLOW">
1796
+ <svg class="o-icon wrapping-overflow">
1797
+ <path d="M13 8H6v2h7v2l3-3-3-3M2 2h2v14H2M9 2h2v4H9m0 6h2v4H9" fill="currentColor"/>
1798
+ </svg>
1799
+ </t>
1800
+ <t t-name="o-spreadsheet-Icon.WRAPPING_WRAP">
1801
+ <svg class="o-icon wrapping-wrap">
1802
+ <path
1803
+ fill="currentColor"
1804
+ d="M6 5v2h3.75c.75 0 1.5.67 1.5 1.5 0 .75-.75 1.5-1.5 1.5H8V8l-3 3 3 3v-2h1.5c2 0 3.5-1.5 3.5-3.5S11.5 5 9.5 5M2 2h2v14H2M14 2M14,2,h2v14h-2"
1805
+ />
1806
+ </svg>
1807
+ </t>
1808
+ <t t-name="o-spreadsheet-Icon.WRAPPING_CLIP">
1809
+ <svg class="o-icon wrapping-clip">
1810
+ <path fill="currentColor" d="M2 2h2v14H2M14 2h2v14h-2v-6H6V8h8"/>
1811
+ </svg>
1812
+ </t>
1813
+ <t t-name="o-spreadsheet-Icon.BORDERS">
1814
+ <svg class="o-icon">
1815
+ <path
1816
+ fill="currentColor"
1817
+ d="M2 2v14h14V2H2m6 12H4v-4h4v4m0-6H4V4h4v4m6 6h-4v-4h4v4m0-6h-4V4h4v4"
1818
+ />
1819
+ </svg>
1820
+ </t>
1821
+ <t t-name="o-spreadsheet-Icon.BORDER_HV">
1822
+ <svg class="o-icon" fill="currentColor">
1823
+ <path
1824
+ d="M2 16h2v-2H2v2M4 5H2v2h2V5m1 11h2v-2H5v2m8-14h-2v2h2V2M4 2H2v2h2V2m3 0H5v2h2V2M2 13h2v-2H2v2m9 3h2v-2h-2v2m3-14v2h2V2h-2m0 5h2V5h-2v2m0 9h2v-2h-2v2m0-3h2v-2h-2v2"
1825
+ opacity=".54"
1826
+ />
1827
+ <path d="M10 2H8v6H2v2h6v6h2v-6h6V8h-6"/>
1828
+ </svg>
1829
+ </t>
1830
+ <t t-name="o-spreadsheet-Icon.BORDER_H">
1831
+ <svg class="o-icon" fill="currentColor">
1832
+ <path
1833
+ d="M8 16h2v-2H8v2M5 4h2V2H5v2m3 9h2v-2H8v2m-3 3h2v-2H5v2M2 7h2V5H2v2m0 9h2v-2H2v2M2 4h2V2H2v2m0 9h2v-2H2v2m12 0h2v-2h-2v2m0 3h2v-2h-2v2m0-9h2V5h-2v2m0-5v2h2V2h-2M8 4h2V2H8v2m3 0h2V2h-2v2M8 7h2V5H8v2m3 9h2v-2h-2v2"
1834
+ opacity=".54"
1835
+ />
1836
+ <path d="M2 10h14V8H2"/>
1837
+ </svg>
1838
+ </t>
1839
+ <t t-name="o-spreadsheet-Icon.BORDER_V">
1840
+ <svg class="o-icon" fill="currentColor">
1841
+ <path
1842
+ d="M5 16h2v-2H5v2M2 7h2V5H2v2m0-3h2V2H2v2m3 6h2V8H5v2m0-6h2V2H5v2M2 16h2v-2H2v2m0-6h2V8H2v2m0 3h2v-2H2v2M14 2v2h2V2h-2m0 8h2V8h-2v2m0 6h2v-2h-2v2m0-9h2V5h-2v2m0 6h2v-2h-2v2m-3 3h2v-2h-2v2m0-6h2V8h-2v2m0-6h2V2h-2v2"
1843
+ opacity=".54"
1844
+ />
1845
+ <path d="M8 16h2V2H8"/>
1846
+ </svg>
1847
+ </t>
1848
+ <t t-name="o-spreadsheet-Icon.BORDER_EXTERNAL">
1849
+ <svg class="o-icon" fill="currentColor">
1850
+ <path d="M10 5H8v2h2V5m3 3h-2v2h2V8m-3 0H8v2h2V8m0 3H8v2h2v-2M7 8H5v2h2V8" opacity=".54"/>
1851
+ <path d="M2 2h14v14H2V2m12 12V4H4v10h10"/>
1852
+ </svg>
1853
+ </t>
1854
+ <t t-name="o-spreadsheet-Icon.BORDER_LEFT">
1855
+ <svg class="o-icon" fill="currentColor">
1856
+ <path
1857
+ d="M8 10h2V8H8v2m0-3h2V5H8v2m0 6h2v-2H8v2m0 3h2v-2H8v2m-3 0h2v-2H5v2M5 4h2V2H5v2m0 6h2V8H5v2m9 6h2v-2h-2v2m0-6h2V8h-2v2m0 3h2v-2h-2v2m0-6h2V5h-2v2M8 4h2V2H8v2m6-2v2h2V2h-2m-3 14h2v-2h-2v2m0-6h2V8h-2v2m0-6h2V2h-2v2"
1858
+ opacity=".54"
1859
+ />
1860
+ <path d="M2 16h2V2H2"/>
1861
+ </svg>
1862
+ </t>
1863
+ <t t-name="o-spreadsheet-Icon.BORDER_TOP">
1864
+ <svg class="o-icon" fill="currentColor">
1865
+ <path
1866
+ d="M5 10h2V8H5v2m-3 6h2v-2H2v2m6 0h2v-2H8v2m0-3h2v-2H8v2m-3 3h2v-2H5v2m-3-3h2v-2H2v2m6-3h2V8H8v2M2 7h2V5H2v2m0 3h2V8H2v2m12 0h2V8h-2v2m0 3h2v-2h-2v2m0-6h2V5h-2v2M8 7h2V5H8v2m3 9h2v-2h-2v2m0-6h2V8h-2v2m3 6h2v-2h-2v2"
1867
+ opacity=".54"
1868
+ />
1869
+ <path d="M2 2v2h14V2"/>
1870
+ </svg>
1871
+ </t>
1872
+ <t t-name="o-spreadsheet-Icon.BORDER_RIGHT">
1873
+ <svg class="o-icon" fill="currentColor">
1874
+ <path
1875
+ d="M2 4h2V2H2v2m3 0h2V2H5v2m0 6h2V8H5v2m0 6h2v-2H5v2M2 7h2V5H2v2m0 3h2V8H2v2m0 6h2v-2H2v2m0-3h2v-2H2v2m9-3h2V8h-2v2m-3 6h2v-2H8v2m3 0h2v-2h-2v2M8 4h2V2H8v2m3 0h2V2h-2v2m-3 9h2v-2H8v2m0-6h2V5H8v2m0 3h2V8H8v2"
1876
+ opacity=".54"
1877
+ />
1878
+ <path d="M14 2v14h2V2"/>
1879
+ </svg>
1880
+ </t>
1881
+ <t t-name="o-spreadsheet-Icon.BORDER_BOTTOM">
1882
+ <svg class="o-icon" fill="currentColor">
1883
+ <path
1884
+ d="M7 2H5v2h2V2m3 6H8v2h2V8m0 3H8v2h2v-2m3-3h-2v2h2V8M7 8H5v2h2V8m6-6h-2v2h2V2m-3 3H8v2h2V5m0-3H8v2h2V2m-6 9H2v2h2v-2m10 2h2v-2h-2v2m0-6h2V5h-2v2m0 3h2V8h-2v2m0-8v2h2V2h-2M4 2H2v2h2V2m0 3H2v2h2V5m0 3H2v2h2V8"
1885
+ opacity=".54"
1886
+ />
1887
+ <path d="M2 16h14v-2H2"/>
1888
+ </svg>
1889
+ </t>
1890
+ <t t-name="o-spreadsheet-Icon.BORDER_CLEAR">
1891
+ <svg class="o-icon">
1892
+ <path
1893
+ fill="currentColor"
1894
+ d="M8 16h2v-2H8v2m-3-6h2V8H5v2m0-6h2V2H5v2m3 9h2v-2H8v2m-3 3h2v-2H5v2M2 7h2V5H2v2m0 9h2v-2H2v2M2 4h2V2H2v2m0 6h2V8H2v2m6 0h2V8H8v2m-6 3h2v-2H2v2m12 0h2v-2h-2v2m0 3h2v-2h-2v2m0-6h2V8h-2v2m0-3h2V5h-2v2m0-5v2h2V2h-2M8 4h2V2H8v2m3 0h2V2h-2v2M8 7h2V5H8v2m3 9h2v-2h-2v2m0-6h2V8h-2v2"
1895
+ opacity=".54"
1896
+ />
1897
+ </svg>
1898
+ </t>
1899
+ <t t-name="o-spreadsheet-Icon.BORDER_TYPE">
1900
+ <svg class="o-icon">
1901
+ <g fill="currentColor" transform="translate(2 2)">
1902
+ <polygon points="0 0 0 2 14 2 14 0"/>
1903
+ <polygon points="0 6 0 8 5 8 5 6"/>
1904
+ <polygon points="9 6 9 8 14 8 14 6"/>
1905
+ <polygon points="0 12 0 14 2 14 2 12"/>
1906
+ <polygon points="4 12 4 14 6 14 6 12"/>
1907
+ <polygon points="8 12 8 14 10 14 10 12"/>
1908
+ <polygon points="12 12 12 14 14 14 14 12"/>
1909
+ </g>
1910
+ </svg>
1911
+ </t>
1912
+ <t t-name="o-spreadsheet-Icon.BORDER_COLOR">
1913
+ <svg class="o-icon">
1914
+ <g fill="currentColor" transform="translate(4 2)">
1915
+ <polygon points="0 12 0 9 7 2 10 5 3 12"/>
1916
+ <polygon points="8 1 9 0 12 3 11 4"/>
1917
+ </g>
1918
+ </svg>
1919
+ </t>
1920
+ <t t-name="o-spreadsheet-Icon.BORDER_NO_COLOR">
1921
+ <svg class="o-icon">
1922
+ <g fill="currentColor">
1923
+ <polygon points="4 12 4 9 11 2 14 5 7 12"/>
1924
+ <polygon points="12 1 13 0 16 3 15 4"/>
1925
+ </g>
1926
+ <g>
1927
+ <rect x="0" y="14" width="18" height="4" stroke="black" fill="none"/>
1928
+ </g>
1929
+ </svg>
1930
+ </t>
1931
+
1932
+ <t t-name="o-spreadsheet-Icon.PLUS">
1933
+ <svg class="o-icon plus" viewBox="0 0 18 18">
1934
+ <path fill="currentColor" d="M8 0h2v8h8v2h-8v8H8v-8H0V8h8"/>
1935
+ </svg>
1936
+ </t>
1937
+ <t t-name="o-spreadsheet-Icon.MINUS">
1938
+ <svg class="o-icon minus" viewBox="0 0 18 18">
1939
+ <path fill="currentColor" d="M0 8h18v2H0z"/>
1940
+ </svg>
1941
+ </t>
1942
+ <t t-name="o-spreadsheet-Icon.LIST">
1943
+ <svg class="o-icon" viewBox="0 0 384 384">
1944
+ <rect x="0" y="277.333" width="384" height="42.667" fill="currentColor"/>
1945
+ <rect x="0" y="170.667" width="384" height="42.667" fill="currentColor"/>
1946
+ <rect x="0" y="64" width="384" height="42.667" fill="currentColor"/>
1947
+ </svg>
1948
+ </t>
1949
+
1950
+ <t t-name="o-spreadsheet-Icon.EDIT">
1951
+ <svg class="o-icon" viewBox="0 0 576 512">
1952
+ <path
1953
+ fill="currentColor"
1954
+ d="M402.6 83.2l90.2 90.2c3.8 3.8 3.8 10 0 13.8L274.4 405.6l-92.8 10.3c-12.4 1.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8 83.2c3.8-3.8 10-3.8 13.8 0zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2 0l-35.4 35.4c-3.8 3.8-3.8 10 0 13.8l90.2 90.2c3.8 3.8 10 3.8 13.8 0l35.4-35.4c15.2-15.3 15.2-40 0-55.2zM384 346.2V448H64V128h229.8c3.2 0 6.2-1.3 8.5-3.5l40-40c7.6-7.6 2.2-20.5-8.5-20.5H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V306.2c0-10.7-12.9-16-20.5-8.5l-40 40c-2.2 2.3-3.5 5.3-3.5 8.5z"
1955
+ />
1956
+ </svg>
1957
+ </t>
1958
+ <t t-name="o-spreadsheet-Icon.UNLINK">
1959
+ <svg class="o-icon" viewBox="0 0 512 512">
1960
+ <path
1961
+ fill="currentColor"
1962
+ d="M304.083 405.907c4.686 4.686 4.686 12.284 0 16.971l-44.674 44.674c-59.263 59.262-155.693 59.266-214.961 0-59.264-59.265-59.264-155.696 0-214.96l44.675-44.675c4.686-4.686 12.284-4.686 16.971 0l39.598 39.598c4.686 4.686 4.686 12.284 0 16.971l-44.675 44.674c-28.072 28.073-28.072 73.75 0 101.823 28.072 28.072 73.75 28.073 101.824 0l44.674-44.674c4.686-4.686 12.284-4.686 16.971 0l39.597 39.598zm-56.568-260.216c4.686 4.686 12.284 4.686 16.971 0l44.674-44.674c28.072-28.075 73.75-28.073 101.824 0 28.072 28.073 28.072 73.75 0 101.823l-44.675 44.674c-4.686 4.686-4.686 12.284 0 16.971l39.598 39.598c4.686 4.686 12.284 4.686 16.971 0l44.675-44.675c59.265-59.265 59.265-155.695 0-214.96-59.266-59.264-155.695-59.264-214.961 0l-44.674 44.674c-4.686 4.686-4.686 12.284 0 16.971l39.597 39.598zm234.828 359.28l22.627-22.627c9.373-9.373 9.373-24.569 0-33.941L63.598 7.029c-9.373-9.373-24.569-9.373-33.941 0L7.029 29.657c-9.373 9.373-9.373 24.569 0 33.941l441.373 441.373c9.373 9.372 24.569 9.372 33.941 0z"
1963
+ />
1964
+ </svg>
1965
+ </t>
1966
+ /** Font Awesome by Dave Gandy
1967
+ * http://fontawesome.io/
1968
+ * https://fontawesome.com/license
1969
+ */
1970
+ <t t-name="o-spreadsheet-Icon.CARET_UP">
1971
+ <svg class="caret-up" viewBox="0 0 320 512">
1972
+ <path
1973
+ fill="currentColor"
1974
+ d="M288.662 352H31.338c-17.818 0-26.741-21.543-14.142-34.142l128.662-128.662c7.81-7.81 20.474-7.81 28.284 0l128.662 128.662c12.6 12.599 3.676 34.142-14.142 34.142z"
1975
+ />
1976
+ </svg>
1977
+ </t>
1978
+ <t t-name="o-spreadsheet-Icon.CARET_DOWN">
1979
+ <svg class="caret-down" viewBox="0 0 320 512">
1980
+ <path
1981
+ fill="currentColor"
1982
+ d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"
1983
+ />
1984
+ </svg>
1985
+ </t>
1986
+ <t t-name="o-spreadsheet-Icon.CARET_RIGHT">
1987
+ <svg class="o-icon caret-right" viewBox="0 0 192 512">
1988
+ <path
1989
+ d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"
1990
+ />
1991
+ </svg>
1992
+ </t>
1993
+ <t t-name="o-spreadsheet-Icon.CARET_LEFT">
1994
+ <svg class="o-icon caret-left" viewBox="0 0 192 512">
1995
+ <path
1996
+ d="M192 127.338v257.324c0 17.818-21.543 26.741-34.142 14.142L29.196 270.142c-7.81-7.81-7.81-20.474 0-28.284l128.662-128.662c12.599-12.6 34.142-3.676 34.142 14.142z"
1997
+ />
1998
+ </svg>
1999
+ </t>
2000
+
2001
+ <t t-name="o-spreadsheet-Icon.TRASH">
2002
+ <svg class="o-cf-icon trash" viewBox="0 0 448 512">
2003
+ <path
2004
+ fill="currentColor"
2005
+ d="M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z"
2006
+ />
2007
+ </svg>
2008
+ </t>
2009
+ <t t-name="o-spreadsheet-Icon.REFRESH">
2010
+ <svg class="o-cf-icon refresh" viewBox="0 0 512 512">
2011
+ <path
2012
+ fill="currentColor"
2013
+ d="M440.65 12.57l4 82.77A247.16 247.16 0 0 0 255.83 8C134.73 8 33.91 94.92 12.29 209.82A12 12 0 0 0 24.09 224h49.05a12 12 0 0 0 11.67-9.26 175.91 175.91 0 0 1 317-56.94l-101.46-4.86a12 12 0 0 0-12.57 12v47.41a12 12 0 0 0 12 12H500a12 12 0 0 0 12-12V12a12 12 0 0 0-12-12h-47.37a12 12 0 0 0-11.98 12.57zM255.83 432a175.61 175.61 0 0 1-146-77.8l101.8 4.87a12 12 0 0 0 12.57-12v-47.4a12 12 0 0 0-12-12H12a12 12 0 0 0-12 12V500a12 12 0 0 0 12 12h47.35a12 12 0 0 0 12-12.6l-4.15-82.57A247.17 247.17 0 0 0 255.83 504c121.11 0 221.93-86.92 243.55-201.82a12 12 0 0 0-11.8-14.18h-49.05a12 12 0 0 0-11.67 9.26A175.86 175.86 0 0 1 255.83 432z"
2014
+ />
2015
+ </svg>
2016
+ </t>
2017
+
2018
+ <t t-name="o-spreadsheet-Icon.ARROW_DOWN">
2019
+ <svg
2020
+ class="o-cf-icon arrow-down"
2021
+ width="10"
2022
+ height="10"
2023
+ focusable="false"
2024
+ viewBox="0 0 448 512">
2025
+ <path
2026
+ fill="#DC6965"
2027
+ t-att-style="color"
2028
+ d="M413.1 222.5l22.2 22.2c9.4 9.4 9.4 24.6 0 33.9L241 473c-9.4 9.4-24.6 9.4-33.9 0L12.7 278.6c-9.4-9.4-9.4-24.6 0-33.9l22.2-22.2c9.5-9.5 25-9.3 34.3.4L184 343.4V56c0-13.3 10.7-24 24-24h32c13.3 0 24 10.7 24 24v287.4l114.8-120.5c9.3-9.8 24.8-10 34.3-.4z"
2029
+ />
2030
+ </svg>
2031
+ </t>
2032
+ <t t-name="o-spreadsheet-Icon.ARROW_UP">
2033
+ <svg class="o-cf-icon arrow-up" width="10" height="10" focusable="false" viewBox="0 0 448 512">
2034
+ <path
2035
+ fill="#00A04A"
2036
+ t-att-style="color"
2037
+ d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"
2038
+ />
2039
+ </svg>
2040
+ </t>
2041
+ <t t-name="o-spreadsheet-Icon.ARROW_RIGHT">
2042
+ <svg
2043
+ class="o-cf-icon arrow-right"
2044
+ width="10"
2045
+ height="10"
2046
+ focusable="false"
2047
+ viewBox="0 0 448 512">
2048
+ <path
2049
+ fill="#F0AD4E"
2050
+ d="M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z"
2051
+ />
2052
+ </svg>
2053
+ </t>
2054
+
2055
+ <t t-name="o-spreadsheet-Icon.SMILE">
2056
+ <svg class="o-cf-icon smile" width="10" height="10" focusable="false" viewBox="0 0 496 512">
2057
+ <path
2058
+ fill="#00A04A"
2059
+ d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm4 72.6c-20.8 25-51.5 39.4-84 39.4s-63.2-14.3-84-39.4c-8.5-10.2-23.7-11.5-33.8-3.1-10.2 8.5-11.5 23.6-3.1 33.8 30 36 74.1 56.6 120.9 56.6s90.9-20.6 120.9-56.6c8.5-10.2 7.1-25.3-3.1-33.8-10.1-8.4-25.3-7.1-33.8 3.1z"
2060
+ />
2061
+ </svg>
2062
+ </t>
2063
+ <t t-name="o-spreadsheet-Icon.MEH">
2064
+ <svg class="o-cf-icon meh" width="10" height="10" focusable="false" viewBox="0 0 496 512">
2065
+ <path
2066
+ fill="#F0AD4E"
2067
+ d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm8 144H160c-13.2 0-24 10.8-24 24s10.8 24 24 24h176c13.2 0 24-10.8 24-24s-10.8-24-24-24z"
2068
+ />
2069
+ </svg>
2070
+ </t>
2071
+ <t t-name="o-spreadsheet-Icon.FROWN">
2072
+ <svg class="o-cf-icon frown" width="10" height="10" focusable="false" viewBox="0 0 496 512">
2073
+ <path
2074
+ fill="#DC6965"
2075
+ d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm-80 128c-40.2 0-78 17.7-103.8 48.6-8.5 10.2-7.1 25.3 3.1 33.8 10.2 8.4 25.3 7.1 33.8-3.1 16.6-19.9 41-31.4 66.9-31.4s50.3 11.4 66.9 31.4c8.1 9.7 23.1 11.9 33.8 3.1 10.2-8.5 11.5-23.6 3.1-33.8C326 321.7 288.2 304 248 304z"
2076
+ />
2077
+ </svg>
2078
+ </t>
2079
+
2080
+ <t t-name="o-spreadsheet-Icon.GREEN_DOT">
2081
+ <svg class="o-cf-icon green-dot" width="10" height="10" focusable="false" viewBox="0 0 512 512">
2082
+ <path
2083
+ fill="#00A04A"
2084
+ d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"
2085
+ />
2086
+ </svg>
2087
+ </t>
2088
+ <t t-name="o-spreadsheet-Icon.YELLOW_DOT">
2089
+ <svg
2090
+ class="o-cf-icon yellow-dot"
2091
+ width="10"
2092
+ height="10"
2093
+ focusable="false"
2094
+ viewBox="0 0 512 512">
2095
+ <path
2096
+ fill="#F0AD4E"
2097
+ d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"
2098
+ />
2099
+ </svg>
2100
+ </t>
2101
+ <t t-name="o-spreadsheet-Icon.RED_DOT">
2102
+ <svg class="o-cf-icon red-dot" width="10" height="10" focusable="false" viewBox="0 0 512 512">
2103
+ <path
2104
+ fill="#DC6965"
2105
+ d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"
2106
+ />
2107
+ </svg>
2108
+ </t>
2109
+ <t t-name="o-spreadsheet-Icon.SORT_RANGE">
2110
+ <svg class="o-icon">
2111
+ <path
2112
+ fill="currentColor"
2113
+ d="M9 3.5h8v2H9M9 8h6v2H9m0 2.5h3v2H9M6 6l1-1-3-3-3 3 1 1 1-1v8l-1-1-1 1 3 3 3-3-1-1-1 1V5"
2114
+ />
2115
+ </svg>
2116
+ </t>
2117
+ <t t-name="o-spreadsheet-Icon.SORT_ASCENDING">
2118
+ <svg class="o-icon" fill="currentColor">
2119
+ <path d="m3 13-1-1-1 1 3 3 3-3-1-1-1 1V0H3"/>
2120
+ <text x="9" y="7" class="small-text">A</text>
2121
+ <text x="9.3" y="15" class="small-text">Z</text>
2122
+ </svg>
2123
+ </t>
2124
+ <t t-name="o-spreadsheet-Icon.SORT_DESCENDING">
2125
+ <svg class="o-icon" fill="currentColor">
2126
+ <path d="m3 13.9-1-1-1 1 3 3 3-3-1-1-1 1V.9H3"/>
2127
+ <text x="9.3" y="7.9" class="small-text">Z</text>
2128
+ <text x="9" y="15.9" class="small-text">A</text>
2129
+ </svg>
2130
+ </t>
2131
+ <t t-name="o-spreadsheet-Icon.DATA_CLEANUP">
2132
+ <svg class="o-icon" fill="currentColor">
2133
+ <path
2134
+ d="m13.6 6.4-2.1-2.1c-.4-.4-1-.4-1.4 0l-8.8 8.9c-.4.4-.4 1 0 1.4l2.1 2.1c.4.4 1 .4 1.4 0l8.8-8.9c.4-.4.4-1 0-1.4M8 8.5 10.5 6l1.4 1.4-2.5 2.5m3-7 1.8.8.8 1.8.8-1.8 1.8-.8-1.8-.8L14.9.4l-.8 1.8M3.5 4l1.7.7.8 1.8.8-1.8 1.8-.8-1.8-.8-.8-1.8-.8 1.8zm13.5 7.7-1.8-.8-.8-1.8-.8 1.8-1.8.8 1.8.8.8 1.8.7-1.8"
2135
+ />
2136
+ </svg>
2137
+ </t>
2138
+ <t t-name="o-spreadsheet-Icon.FILTER_ICON">
2139
+ <svg
2140
+ class="o-cf-icon filter-icon"
2141
+ width="10"
2142
+ height="10"
2143
+ focusable="false"
2144
+ viewBox="0 0 850 850">
2145
+ <path
2146
+ fill="currentColor"
2147
+ d="M 339.667 681 L 510.333 681 L 510.333 595.667 L 339.667 595.667 L 339.667 681 Z M 41 169 L 41 254.333 L 809 254.333 L 809 169 L 41 169 Z M 169 467.667 L 681 467.667 L 681 382.333 L 169 382.333 L 169 467.667 Z"
2148
+ />
2149
+ </svg>
2150
+ </t>
2151
+ <t t-name="o-spreadsheet-Icon.FILTER_ICON_ACTIVE">
2152
+ <svg
2153
+ class="o-cf-icon filter-icon-active"
2154
+ width="10"
2155
+ height="10"
2156
+ focusable="false"
2157
+ viewBox="0 0 512 512">
2158
+ <path
2159
+ fill="currentColor"
2160
+ d="M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z"
2161
+ />
2162
+ </svg>
2163
+ </t>
2164
+ <t t-name="o-spreadsheet-Icon.FILTER_ICON_INACTIVE">
2165
+ <svg
2166
+ class="o-cf-icon filter-icon-inactive"
2167
+ width="10"
2168
+ height="10"
2169
+ focusable="false"
2170
+ viewBox="0 0 512 512">
2171
+ <path
2172
+ fill="currentColor"
2173
+ d="M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z"
2174
+ />
2175
+ </svg>
2176
+ </t>
2177
+ <t t-name="o-spreadsheet-Icon.MENU_FILTER_ICON">
2178
+ <svg class="o-icon">
2179
+ <path
2180
+ fill="currentColor"
2181
+ d="M16.6.5H1.29C.59.5.23 1.35.73 1.85l6.1 6.1v6.8c0 .26.13.5.34.65l2.64 1.85a.79.79 0 0 0 1.25-.65V7.96l6.1-6.1A.79.79 0 0 0 16.6.51"
2182
+ />
2183
+ </svg>
2184
+ </t>
2185
+ <t t-name="o-spreadsheet-Icon.SEARCH">
2186
+ <svg class="search-icon" width="10" height="10" focusable="false" viewBox="0 0 512 512">
2187
+ <path
2188
+ fill="currentColor"
2189
+ d="M500.3 443.7l-119.7-119.7c27.22-40.41 40.65-90.9 33.46-144.7C401.8 87.79 326.8 13.32 235.2 1.723C99.01-15.51-15.51 99.01 1.724 235.2c11.6 91.64 86.08 166.7 177.6 178.9c53.8 7.189 104.3-6.236 144.7-33.46l119.7 119.7c15.62 15.62 40.95 15.62 56.57 0C515.9 484.7 515.9 459.3 500.3 443.7zM79.1 208c0-70.58 57.42-128 128-128s128 57.42 128 128c0 70.58-57.42 128-128 128S79.1 278.6 79.1 208z"
2190
+ />
2191
+ </svg>
2192
+ </t>
2193
+ <t t-name="o-spreadsheet-Icon.CHECK">
2194
+ <svg class="o-icon" viewBox="0 0 24 24">
2195
+ <path
2196
+ fill="currentColor"
2197
+ d="M18.707 7.293a1 1 0 0 1 0 1.414L11.414 16a2 2 0 0 1-2.828 0l-3.293-3.293a1 1 0 1 1 1.414-1.414L10 14.586l7.293-7.293a1 1 0 0 1 1.414 0z"
2198
+ />
2199
+ </svg>
2200
+ </t>
2201
+ <t t-name="o-spreadsheet-Icon.PERCENT">
2202
+ <span class="o-text-icon">%</span>
2203
+ </t>
2204
+ <t t-name="o-spreadsheet-Icon.DECRASE_DECIMAL">
2205
+ <span class="o-text-icon">.0</span>
2206
+ </t>
2207
+ <t t-name="o-spreadsheet-Icon.INCREASE_DECIMAL">
2208
+ <span class="o-text-icon">.00</span>
2209
+ </t>
2210
+ <t t-name="o-spreadsheet-Icon.NUMBER_FORMATS">
2211
+ <svg class="o-icon" fill="currentColor">
2212
+ <path
2213
+ d="M0 6h2v8h2V4H0m9 0H5v2h4v2H6.5A1.5 1.5 0 0 0 5 9.5V14h6v-2H7v-2h2.5A1.5 1.5 0 0 0 11 8.5v-3A1.5 1.5 0 0 0 9.5 4M12 4v2h4v2h-2v2h2v2h-4v2h4.5a1.5 1.5 0 0 0 1.5-1.5v-2A1.5 1.5 0 0 0 16.5 9 1.5 1.5 0 0 0 18 7.5v-2A1.5 1.5 0 0 0 16.5 4"
2214
+ />
2215
+ </svg>
2216
+ </t>
2217
+ <t t-name="o-spreadsheet-Icon.FONT_SIZE">
2218
+ <svg class="o-icon" fill="currentColor">
2219
+ <text x="2" y="15" class="small-text">A</text>
2220
+ <text x="6" y="15" class="heavy-text">A</text>
2221
+ </svg>
2222
+ </t>
2223
+ <t t-name="o-spreadsheet-Icon.TRIANGLE_EXCLAMATION">
2224
+ <svg class="o-icon" viewBox="0 0 512 512">
2225
+ <path
2226
+ fill="currentColor"
2227
+ d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"
2228
+ />
2229
+ </svg>
2230
+ </t>
2231
+ <t t-name="o-spreadsheet-Icon.SPLIT_TEXT">
2232
+ <svg class="o-icon">
2233
+ <path
2234
+ fill="currentColor"
2235
+ d="M14 6v2h-4v2h4v2l3-3m-9 1V8H4V6L1 9l3 3v-2m3.5-6.5h3V7H12V3.5h3V2H3v1.5h3V7h1.5m3 7.5h-3V11H6v3.5H3V16h12v-1.5h-3V11h-1.5"
2236
+ />
2237
+ </svg>
2238
+ </t>
2239
+ <t t-name="o-spreadsheet-Icon.ERROR">
2240
+ <svg class="error-icon" width="14" height="14" viewBox="0 0 512 512">
2241
+ <path
2242
+ fill="currentColor"
2243
+ d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
2244
+ />
2245
+ </svg>
2246
+ </t>
2247
+ <t t-name="o-spreadsheet-Icon.DISPLAY_HEADER">
2248
+ <svg class="o-icon" width="18" height="18">
2249
+ <path
2250
+ fill="currentColor"
2251
+ d="M.75.5h16.5v17H.75m1.5-12H.75V7h1.5v1.5H.75V10h1.5v1.5H.75V13h1.5v1.5H.75V16h1.5v1.5h1.5V16h1.5v1.5h1.5V16h1.5v1.5h1.5V16h1.5v1.5h1.5V16h1.5v1.5h1.5V16h1.5v-1.5h-1.5V13h1.5v-1.5h-1.5V10h1.5V8.5h-1.5V7h1.5V5.5M2.75 2.25v1.5h2v-1.5m2.5 0v1.5h7v-1.5"
2252
+ />
2253
+ </svg>
2254
+ </t>
2255
+ <t t-name="o-spreadsheet-Icon.COG">
2256
+ <svg fill="currentColor" viewBox="0 0 16 16">
2257
+ <path
2258
+ d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492zM5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0z"
2259
+ />
2260
+ <path
2261
+ d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52l-.094-.319zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115l.094-.319z"
2262
+ />
2263
+ </svg>
2264
+ </t>
2265
+ <t t-name="o-spreadsheet-Icon.PLUS_IN_BOX">
2266
+ <svg
2267
+ class="o-icon"
2268
+ width="18"
2269
+ height="18"
2270
+ style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5">
2271
+ <path stroke="currentColor" d="M1.5,1.5h15v15h-15v-15M9,5v8M5,9h8"/>
2272
+ </svg>
2273
+ </t>
2274
+ <t t-name="o-spreadsheet-Icon.GROUP_ROWS">
2275
+ <svg class="o-icon" width="18" height="18">
2276
+ <path
2277
+ fill="currentColor"
2278
+ d="M6 2.5A1.5 1.5 0 0 1 7.5 1H16a1.5 1.5 0 0 1 1.5 1.5V15a1.5 1.5 0 0 1-1.5 1.5H7.5A1.5 1.5 0 0 1 6 15M7.5 2.5v2H16v-2M7.5 6v2H16V6M7.5 9.5v2H16v-2M7.5 13v2H16v-2M2 5.75V13h3v-1.5H3.5V5.75h1.25V3l-1 1v.75H3M.25 1.25v4.5h4.5v-4.5m-3.5 1h2.5v2.5h-2.5"
2279
+ />
2280
+ </svg>
2281
+ </t>
2282
+ <t t-name="o-spreadsheet-Icon.UNGROUP_ROWS">
2283
+ <svg class="o-icon" width="18" height="18">
2284
+ <path
2285
+ fill="currentColor"
2286
+ d="M6 2.5A1.5 1.5 0 0 1 7.5 1H16a1.5 1.5 0 0 1 1.5 1.5V15a1.5 1.5 0 0 1-1.5 1.5H7.5A1.5 1.5 0 0 1 6 15M7.5 2.5v2H16v-2M7.5 6v2H16V6M7.5 9.5v2H16v-2M7.5 13v2H16v-2M2 5.75V13h3v-1.5H3.5V5.75M0 5.25.75 6l2-2 2 2 .75-.75-2-2 2-2L4.75.5l-2 2-2-2-.75.75 2 2"
2287
+ />
2288
+ </svg>
2289
+ </t>
2290
+ <t t-name="o-spreadsheet-Icon.GROUP_COLUMNS">
2291
+ <svg class="o-icon" width="18" height="18">
2292
+ <path
2293
+ fill="currentColor"
2294
+ d="M2.75 6a1.5 1.5 0 0 0-1.5 1.5V16a1.5 1.5 0 0 0 1.5 1.5h12.5a1.5 1.5 0 0 0 1.5-1.5V7.5a1.5 1.5 0 0 0-1.5-1.5M2.75 7.5h2V16h-2m3.5-8.5h2V16h-2m3.5-8.5h2V16h-2m3.5-8.5h2V16h-2M6 2h7.25v3h-1.5V3.5H6v1.25H3.25l1-1H5V3M1.5.25H6v4.5H1.5m1-3.5v2.5H5v-2.5"
2295
+ />
2296
+ </svg>
2297
+ </t>
2298
+ <t t-name="o-spreadsheet-Icon.UNGROUP_COLUMNS">
2299
+ <svg class="o-icon" width="18" height="18">
2300
+ <path
2301
+ fill="currentColor"
2302
+ d="M2.75 6a1.5 1.5 0 0 0-1.5 1.5V16a1.5 1.5 0 0 0 1.5 1.5h12.5a1.5 1.5 0 0 0 1.5-1.5V7.5a1.5 1.5 0 0 0-1.5-1.5M2.75 7.5h2V16h-2m3.5-8.5h2V16h-2m3.5-8.5h2V16h-2m3.5-8.5h2V16h-2M6 2h7.25v3h-1.5V3.5H6M5.5 0l.75.75-2 2 2 2-.75.75-2-2-2 2-.75-.75 2-2-2-2L1.5 0l2 2"
2303
+ />
2304
+ </svg>
2305
+ </t>
2306
+ <t t-name="o-spreadsheet-Icon.DATA_VALIDATION">
2307
+ <svg class="o-icon">
2308
+ <path
2309
+ fill="currentColor"
2310
+ d="M.5 2A1.5 1.5 0 0 1 2 .5h14A1.5 1.5 0 0 1 17.5 2v7H11V7H7v4s-.5 0-1.5 1h-1v5h-3a1.5 1.5 0 0 1-1-1M6 6V2H2v4m9 0V2H7v4m9 0V2h-4v4m-6 5V7H2v4m14-2V7h-4v2m-7.5 6.5V12H2v3.5"
2311
+ />
2312
+ <path
2313
+ stroke="currentColor"
2314
+ style="fill:none; stroke-linecap:round; stroke-width:1.5"
2315
+ d="M8,13 l3 3 l6 -5"
2316
+ />
2317
+ </svg>
2318
+ </t>
2319
+ <t t-name="o-spreadsheet-Icon.THIN_DRAG_HANDLE">
2320
+ <svg class="o-icon" viewBox="0 0 4 16" fill="currentColor">
2321
+ <circle cx="2" cy="3.5" r="1"/>
2322
+ <circle cx="2" cy="6.5" r="1"/>
2323
+ <circle cx="2" cy="9.5" r="1"/>
2324
+ <circle cx="2" cy="12.5" r="1"/>
2325
+ </svg>
2326
+ </t>
2327
+
2328
+ <t t-name="o-spreadsheet-LinkDisplay">
2329
+ <div class="o-link-tool d-flex align-items-center">
2330
+ <!-- t-key to prevent owl from re-using the previous img element when the link changes.
2331
+ The wrong/previous image would be displayed while the new one loads -->
2332
+ <img
2333
+ t-if="link.isExternal"
2334
+ t-key="link.url"
2335
+ t-attf-src="https://www.google.com/s2/favicons?sz=16&amp;domain={{link.url}}"
2336
+ />
2337
+ <a
2338
+ t-if="link.isExternal"
2339
+ class="o-link"
2340
+ t-att-href="link.url"
2341
+ target="_blank"
2342
+ t-on-click.prevent="openLink"
2343
+ t-att-title="link.url">
2344
+ <t t-esc="getUrlRepresentation(link)"/>
2345
+ </a>
2346
+ <a
2347
+ t-else=""
2348
+ class="o-link"
2349
+ t-on-click.prevent="openLink"
2350
+ t-att-title="getUrlRepresentation(link)">
2351
+ <t t-esc="getUrlRepresentation(link)"/>
2352
+ </a>
2353
+ <span
2354
+ t-if="!env.model.getters.isReadonly()"
2355
+ class="o-link-icon o-unlink"
2356
+ t-on-click="unlink"
2357
+ title="Remove link">
2358
+ <t t-call="o-spreadsheet-Icon.UNLINK"/>
2359
+ </span>
2360
+ <span
2361
+ t-if="!env.model.getters.isReadonly()"
2362
+ class="o-link-icon o-edit-link"
2363
+ t-on-click="edit"
2364
+ title="Edit link">
2365
+ <t t-call="o-spreadsheet-Icon.EDIT"/>
2366
+ </span>
2367
+ </div>
2368
+ </t>
2369
+
2370
+ <t t-name="o-spreadsheet-LinkEditor">
2371
+ <div
2372
+ class="o-link-editor"
2373
+ t-on-click.stop="() => this.menu.isOpen=false"
2374
+ t-on-keydown="onKeyDown"
2375
+ t-ref="linkEditor">
2376
+ <div class="o-section">
2377
+ <div class="o-section-title">Text</div>
2378
+ <div class="d-flex">
2379
+ <input type="text" title="Link label" class="o-input flex-grow-1" t-model="link.label"/>
2380
+ </div>
2381
+
2382
+ <div class="o-section-title mt-3">Link</div>
2383
+ <div class="o-link-url">
2384
+ <t t-if="link.isUrlEditable">
2385
+ <input type="text" title="Link URL" t-ref="urlInput" t-model="link.url"/>
2386
+ </t>
2387
+ <t t-else="">
2388
+ <input
2389
+ type="text"
2390
+ title="Link URL"
2391
+ t-att-value="getUrlRepresentation(link)"
2392
+ disabled="1"
2393
+ />
2394
+ </t>
2395
+ <button t-if="link.url" t-on-click="removeLink" class="o-remove-url">✖</button>
2396
+ <button t-if="!link.url" t-on-click.stop="openMenu" class="o-special-link">
2397
+ <t t-call="o-spreadsheet-Icon.LIST"/>
2398
+ </button>
2399
+ </div>
2400
+ </div>
2401
+ <Menu
2402
+ t-if="menu.isOpen"
2403
+ position="menuPosition"
2404
+ menuItems="menuItems"
2405
+ onMenuClicked="(ev) => this.onSpecialLink(ev)"
2406
+ onClose="() => this.menu.isOpen=false"
2407
+ />
2408
+ <div class="o-buttons">
2409
+ <button t-on-click="cancel" class="o-button o-cancel">Cancel</button>
2410
+ <button t-on-click="save" class="o-button o-save" t-att-disabled="!link.url">
2411
+ Confirm
2412
+ </button>
2413
+ </div>
2414
+ </div>
2415
+ </t>
2416
+
2417
+ <t t-name="o-spreadsheet-Menu">
2418
+ <Popover t-if="menuItemsAndSeparators.length" t-props="popoverProps">
2419
+ <div
2420
+ t-ref="menu"
2421
+ class="o-menu"
2422
+ t-on-scroll="onScroll"
2423
+ t-on-wheel.stop=""
2424
+ t-on-click.stop=""
2425
+ t-on-contextmenu.prevent="">
2426
+ <t t-foreach="menuItemsAndSeparators" t-as="menuItem" t-key="menuItem_index">
2427
+ <div t-if="menuItem === 'separator'" class="o-separator"/>
2428
+ <t t-else="">
2429
+ <t t-set="isMenuRoot" t-value="isRoot(menuItem)"/>
2430
+ <t t-set="isMenuEnabled" t-value="isEnabled(menuItem)"/>
2431
+ <div
2432
+ t-att-title="getName(menuItem)"
2433
+ t-att-data-name="menuItem.id"
2434
+ t-on-click="(ev) => this.onClickMenu(menuItem, menuItem_index, ev)"
2435
+ t-on-mouseover="(ev) => this.onMouseOver(menuItem, menuItem_index, ev)"
2436
+ class="o-menu-item"
2437
+ t-att-class="{ 'o-menu-root': isMenuRoot, 'disabled': !isMenuEnabled, 'o-menu-item-active': isParentMenu(subMenu, menuItem)}"
2438
+ t-att-style="getColor(menuItem)">
2439
+ <div class="d-flex w-100">
2440
+ <div t-if="childrenHaveIcon" class="o-menu-item-icon align-middle">
2441
+ <t t-if="getIconName(menuItem)" t-call="{{getIconName(menuItem)}}"/>
2442
+ </div>
2443
+ <div class="o-menu-item-name align-middle text-truncate" t-esc="getName(menuItem)"/>
2444
+ <t t-set="description" t-value="menuItem.description(env)"/>
2445
+ <div
2446
+ t-if="description"
2447
+ class="o-menu-item-description ms-auto text-truncate"
2448
+ t-esc="description"
2449
+ />
2450
+ <div
2451
+ t-if="isMenuRoot"
2452
+ class="o-menu-item-root align-middle ms-auto"
2453
+ t-call="o-spreadsheet-Icon.TRIANGLE_RIGHT"
2454
+ />
2455
+ </div>
2456
+ </div>
2457
+ </t>
2458
+ </t>
2459
+ </div>
2460
+ <Menu
2461
+ t-if="subMenu.isOpen"
2462
+ position="subMenuPosition"
2463
+ menuItems="subMenu.menuItems"
2464
+ depth="props.depth + 1"
2465
+ maxHeight="props.maxHeight"
2466
+ onMenuClicked="props.onMenuClicked"
2467
+ onClose="() => this.close()"
2468
+ menuId="props.menuId"
2469
+ />
2470
+ </Popover>
2471
+ </t>
2472
+
2473
+ <t t-name="o-spreadsheet-PaintFormatButton">
2474
+ <span
2475
+ class="o-menu-item-button"
2476
+ title="Paint Format"
2477
+ t-att-class="{active: isActive}"
2478
+ t-attf-class="{{props.class}}"
2479
+ t-on-click="togglePaintFormat"
2480
+ t-on-dblclick="onDblClick">
2481
+ <span>
2482
+ <t t-call="o-spreadsheet-Icon.PAINT_FORMAT"/>
2483
+ </span>
2484
+ </span>
2485
+ </t>
2486
+
2487
+ <t t-name="o-spreadsheet-Popover">
2488
+ <t t-portal="'.o-spreadsheet'">
2489
+ <div
2490
+ class="o-popover"
2491
+ t-ref="popover"
2492
+ t-on-wheel="props.onMouseWheel"
2493
+ t-att-style="popoverStyle"
2494
+ t-on-click.stop="">
2495
+ <t t-slot="default"/>
2496
+ </div>
2497
+ </t>
2498
+ </t>
2499
+
2500
+ <t t-name="o-spreadsheet-ScrollBar">
2501
+ <div class="o-scrollbar" t-on-scroll="onScroll" t-ref="scrollbar" t-att-style="positionCss">
2502
+ <div t-att-style="sizeCss"/>
2503
+ </div>
2504
+ </t>
2505
+
2506
+ <t t-name="o-spreadsheet-SelectionInput">
2507
+ <div class="o-selection">
2508
+ <div
2509
+ t-foreach="ranges"
2510
+ t-as="range"
2511
+ t-key="range.id"
2512
+ class="o-selection-input d-flex flex-row"
2513
+ t-att-class="props.class">
2514
+ <div class="position-relative w-100">
2515
+ <input
2516
+ type="text"
2517
+ spellcheck="false"
2518
+ t-on-input="(ev) => this.onInputChanged(range.id, ev)"
2519
+ t-on-focus="() => this.focus(range.id)"
2520
+ t-on-keydown="onKeydown"
2521
+ t-att-value="range.xc"
2522
+ t-att-style="getColor(range)"
2523
+ class="w-100"
2524
+ t-att-class="{
2525
+ 'o-focused' : range.isFocused,
2526
+ 'o-required': props.required,
2527
+ 'o-optional': !props.required,
2528
+ 'o-invalid border-danger position-relative': isInvalid || !range.isValidRange,
2529
+ 'text-decoration-underline': range.isFocused and state.mode === 'select-range'
2530
+ }"
2531
+ t-ref="{{range.isFocused ? 'focusedInput' : 'unfocusedInput' + range_index}}"
2532
+ />
2533
+ <span
2534
+ t-if="isInvalid || !range.isValidRange"
2535
+ class="error-icon text-danger position-absolute d-flex align-items-center"
2536
+ title="This range is invalid">
2537
+ <t t-call="o-spreadsheet-Icon.ERROR"/>
2538
+ </span>
2539
+ </div>
2540
+ <button
2541
+ class="o-btn border-0 bg-transparent fw-bold o-remove-selection"
2542
+ t-if="ranges.length > 1"
2543
+ t-on-click="() => this.removeInput(range.id)">
2544
+ ✕
2545
+ </button>
2546
+ </div>
2547
+
2548
+ <div class="o-selection-input d-flex flex-row">
2549
+ <button
2550
+ class="o-btn-action bg-transparent fw-bold o-add-selection"
2551
+ t-if="canAddRange"
2552
+ t-on-click="addEmptyInput">
2553
+ Add range
2554
+ </button>
2555
+ <button
2556
+ class="o-btn-action bg-transparent fw-bold o-selection-ko"
2557
+ t-if="isResettable"
2558
+ t-on-click="reset">
2559
+ Reset
2560
+ </button>
2561
+ <button
2562
+ class="o-btn-action bg-transparent fw-bold o-selection-ok"
2563
+ t-if="isConfirmable"
2564
+ t-on-click="confirm">
2565
+ Confirm
2566
+ </button>
2567
+ </div>
2568
+ </div>
2569
+ </t>
2570
+
2571
+ <t t-name="o-spreadsheet-BarConfigPanel">
2572
+ <div>
2573
+ <div class="o-section pt-0">
2574
+ <label class="o-checkbox">
2575
+ <input
2576
+ type="checkbox"
2577
+ name="stacked"
2578
+ t-att-checked="props.definition.stacked"
2579
+ t-on-change="onUpdateStacked"
2580
+ class="align-middle"
2581
+ />
2582
+ Stacked barchart
2583
+ </label>
2584
+ </div>
2585
+ <div class="o-section o-data-series">
2586
+ <div class="o-section-title">Data Series</div>
2587
+ <SelectionInput
2588
+ ranges="() => this.getDataSeriesRanges()"
2589
+ required="true"
2590
+ onSelectionChanged="(ranges) => this.onDataSeriesRangesChanged(ranges)"
2591
+ onSelectionConfirmed="() => this.onDataSeriesConfirmed()"
2592
+ />
2593
+ </div>
2594
+ <div class="o-section o-data-labels">
2595
+ <div class="o-section-title">Categories / Labels</div>
2596
+ <SelectionInput
2597
+ ranges="() => [this.getLabelRange()]"
2598
+ isInvalid="isLabelInvalid"
2599
+ hasSingleRange="true"
2600
+ onSelectionChanged="(ranges) => this.onLabelRangeChanged(ranges)"
2601
+ onSelectionConfirmed="() => this.onLabelRangeConfirmed()"
2602
+ />
2603
+ <label class="o-checkbox">
2604
+ <input
2605
+ type="checkbox"
2606
+ name="aggregated"
2607
+ t-att-checked="props.definition.aggregated"
2608
+ t-on-change="onUpdateAggregated"
2609
+ class="align-middle"
2610
+ />
2611
+ Aggregate
2612
+ </label>
2613
+ </div>
2614
+ <div class="o-section o-use-row-as-headers" t-if="calculateHeaderPosition()">
2615
+ <label class="o-checkbox">
2616
+ <input
2617
+ type="checkbox"
2618
+ t-att-checked="props.definition.dataSetsHaveTitle"
2619
+ t-on-change="onUpdateDataSetsHaveTitle"
2620
+ class="align-middle"
2621
+ />
2622
+ <span>
2623
+ Use row
2624
+ <t t-esc="calculateHeaderPosition()"/>
2625
+ as headers
2626
+ </span>
2627
+ </label>
2628
+ </div>
2629
+
2630
+ <div class="o-section" t-if="errorMessages.length">
2631
+ <ValidationMessages messages="errorMessages" msgType="'error'"/>
2632
+ </div>
2633
+ </div>
2634
+ </t>
2635
+
2636
+ <t t-name="o-spreadsheet-BarChartDesignPanel">
2637
+ <t t-set="background_color">Background Color</t>
2638
+ <div>
2639
+ <div class="o-section o-chart-background-color">
2640
+ <div class="o-section-title">Background color</div>
2641
+ <div class="d-flex align-items-center">
2642
+ <span class="pe-1">Select a color...</span>
2643
+ <ColorPickerWidget
2644
+ currentColor="props.definition.background"
2645
+ toggleColorPicker="() => this.toggleColorPicker()"
2646
+ showColorPicker="state.fillColorTool"
2647
+ onColorPicked="(color) => this.updateBackgroundColor(color)"
2648
+ title="background_color"
2649
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
2650
+ />
2651
+ </div>
2652
+ </div>
2653
+ <div class="o-section o-chart-title">
2654
+ <div class="o-section-title">Title</div>
2655
+ <input
2656
+ type="text"
2657
+ t-model="state.title"
2658
+ t-on-change="updateTitle"
2659
+ class="o-input o-optional"
2660
+ placeholder="New Chart"
2661
+ />
2662
+ </div>
2663
+ <div class="o-section">
2664
+ <div class="o-section-title">Vertical axis position</div>
2665
+ <select
2666
+ t-att-value="props.definition.verticalAxisPosition"
2667
+ class="o-input o-type-selector"
2668
+ t-on-change="(ev) => this.updateSelect('verticalAxisPosition', ev)">
2669
+ <option value="left">Left</option>
2670
+ <option value="right">Right</option>
2671
+ </select>
2672
+ </div>
2673
+ <div class="o-section">
2674
+ <div class="o-section-title">Legend position</div>
2675
+ <select
2676
+ t-att-value="props.definition.legendPosition"
2677
+ class="o-input o-type-selector"
2678
+ t-on-change="(ev) => this.updateSelect('legendPosition', ev)">
2679
+ <option value="none">None</option>
2680
+ <option value="top">Top</option>
2681
+ <option value="bottom">Bottom</option>
2682
+ <option value="left">Left</option>
2683
+ <option value="right">Right</option>
2684
+ </select>
2685
+ </div>
2686
+ </div>
2687
+ </t>
2688
+
2689
+ <t t-name="o-spreadsheet-GaugeChartConfigPanel">
2690
+ <div>
2691
+ <div class="o-section o-data-series">
2692
+ <div class="o-section-title">Data range</div>
2693
+ <SelectionInput
2694
+ ranges="() => [this.getDataRange()]"
2695
+ isInvalid="isDataRangeInvalid"
2696
+ hasSingleRange="true"
2697
+ required="true"
2698
+ onSelectionChanged="(ranges) => this.onDataRangeChanged(ranges)"
2699
+ onSelectionConfirmed="() => this.updateDataRange()"
2700
+ />
2701
+ </div>
2702
+
2703
+ <div class="o-section" t-if="configurationErrorMessages.length">
2704
+ <ValidationMessages messages="configurationErrorMessages" msgType="'error'"/>
2705
+ </div>
2706
+ </div>
2707
+ </t>
2708
+
2709
+ <t t-name="o-spreadsheet-GaugeChartDesignPanel">
2710
+ <t t-set="background_color">Background Color</t>
2711
+ <div>
2712
+ <div class="o-section o-chart-background-color">
2713
+ <div class="o-section-title">Background color</div>
2714
+ <div class="d-flex align-items-center">
2715
+ <span class="pe-1">Select a color...</span>
2716
+ <ColorPickerWidget
2717
+ currentColor="props.definition.background"
2718
+ toggleColorPicker="() => this.toggleMenu('backgroundColor', ev)"
2719
+ showColorPicker="state.openedMenu === 'backgroundColor'"
2720
+ onColorPicked="(color) => this.updateBackgroundColor(color)"
2721
+ title="background_color"
2722
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
2723
+ />
2724
+ </div>
2725
+ </div>
2726
+
2727
+ <div class="o-section o-chart-title">
2728
+ <div class="o-section-title">Title</div>
2729
+ <input
2730
+ type="text"
2731
+ t-model="state.title"
2732
+ t-on-change="updateTitle"
2733
+ class="o-input o-optional"
2734
+ placeholder="New Chart"
2735
+ />
2736
+ </div>
2737
+
2738
+ <div class="o-section">
2739
+ <div class="o-section-title">Range</div>
2740
+ <div class="o-subsection-left">
2741
+ <input
2742
+ type="text"
2743
+ t-model="state.sectionRule.rangeMin"
2744
+ t-on-change="() => this.updateSectionRule(state.sectionRule)"
2745
+ t-on-input="() => this.canUpdateSectionRule(state.sectionRule)"
2746
+ class="o-input o-data-range-min"
2747
+ t-att-class="{ 'o-invalid': isRangeMinInvalid() }"
2748
+ />
2749
+ </div>
2750
+ <div class="o-subsection-right">
2751
+ <input
2752
+ type="text"
2753
+ t-model="state.sectionRule.rangeMax"
2754
+ t-on-change="() => this.updateSectionRule(state.sectionRule)"
2755
+ t-on-input="() => this.canUpdateSectionRule(state.sectionRule)"
2756
+ class="o-input o-data-range-max"
2757
+ t-att-class="{ 'o-invalid': isRangeMaxInvalid() }"
2758
+ />
2759
+ </div>
2760
+ </div>
2761
+
2762
+ <div class="o-section">
2763
+ <div class="o-section-title">Thresholds</div>
2764
+ <t t-call="o-spreadsheet-GaugeChartColorSectionTemplate">
2765
+ <t t-set="sectionRule" t-value="state.sectionRule"/>
2766
+ </t>
2767
+ </div>
2768
+
2769
+ <div class="o-section" t-if="designErrorMessages.length">
2770
+ <ValidationMessages messages="designErrorMessages" msgType="'error'"/>
2771
+ </div>
2772
+ </div>
2773
+ </t>
2774
+
2775
+ <t t-name="o-spreadsheet-GaugeChartColorSectionTemplate">
2776
+ <div class="o-gauge-color-set">
2777
+ <table>
2778
+ <tr>
2779
+ <th class="o-gauge-color-set-colorPicker"/>
2780
+ <th class="o-gauge-color-set-text"/>
2781
+ <th class="o-gauge-color-set-value">Value</th>
2782
+ <th class="o-gauge-color-set-type">Type</th>
2783
+ </tr>
2784
+
2785
+ <t t-call="o-spreadsheet-GaugeChartColorSectionTemplateRow">
2786
+ <t t-set="sectionColor" t-value="sectionRule.colors.lowerColor"/>
2787
+ <t t-set="sectionType" t-value="'lowerColor'"/>
2788
+ <t t-set="inflectionPoint" t-value="sectionRule.lowerInflectionPoint"/>
2789
+ <t t-set="isInvalid" t-value="isLowerInflectionPointInvalid"/>
2790
+ <t t-set="inflectionPointName" t-value="'lowerInflectionPoint'"/>
2791
+ </t>
2792
+
2793
+ <t t-call="o-spreadsheet-GaugeChartColorSectionTemplateRow">
2794
+ <t t-set="sectionColor" t-value="sectionRule.colors.middleColor"/>
2795
+ <t t-set="sectionType" t-value="'middleColor'"/>
2796
+ <t t-set="inflectionPoint" t-value="sectionRule.upperInflectionPoint"/>
2797
+ <t t-set="isInvalid" t-value="isUpperInflectionPointInvalid"/>
2798
+ <t t-set="inflectionPointName" t-value="'upperInflectionPoint'"/>
2799
+ </t>
2800
+
2801
+ <tr>
2802
+ <td>
2803
+ <ColorPickerWidget
2804
+ currentColor="sectionRule.colors.upperColor"
2805
+ toggleColorPicker="(ev) => this.toggleMenu('sectionColor-upperColor', ev)"
2806
+ showColorPicker="state.openedMenu === 'sectionColor-upperColor'"
2807
+ onColorPicked="(color) => this.updateSectionColor('upperColor', color)"
2808
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
2809
+ />
2810
+ </td>
2811
+ <td>Else</td>
2812
+ <td/>
2813
+ <td/>
2814
+ <td/>
2815
+ </tr>
2816
+ </table>
2817
+ </div>
2818
+ </t>
2819
+
2820
+ <t t-name="o-spreadsheet-GaugeChartColorSectionTemplateRow">
2821
+ <tr>
2822
+ <td>
2823
+ <ColorPickerWidget
2824
+ currentColor="sectionColor"
2825
+ toggleColorPicker="(ev) => this.toggleMenu('sectionColor-'+sectionType, ev)"
2826
+ showColorPicker="state.openedMenu === 'sectionColor-'+sectionType"
2827
+ onColorPicked="(color) => this.updateSectionColor(sectionType, color)"
2828
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
2829
+ />
2830
+ </td>
2831
+ <td>When value is below</td>
2832
+ <td>
2833
+ <input
2834
+ type="text"
2835
+ class="o-input"
2836
+ t-model="inflectionPoint.value"
2837
+ t-on-input="() => this.canUpdateSectionRule(state.sectionRule)"
2838
+ t-on-change="() => this.updateSectionRule(state.sectionRule)"
2839
+ t-attf-class="o-input-{{inflectionPointName}}"
2840
+ t-att-class="{ 'o-invalid': isInvalid }"
2841
+ />
2842
+ </td>
2843
+ <td>
2844
+ <select
2845
+ class="o-input"
2846
+ name="valueType"
2847
+ t-model="inflectionPoint.type"
2848
+ t-on-change="(ev) => this.updateSectionRule(state.sectionRule)">
2849
+ <option value="number">Number</option>
2850
+ <option value="percentage">Percentage</option>
2851
+ </select>
2852
+ </td>
2853
+ </tr>
2854
+ </t>
2855
+
2856
+ <t t-name="o-spreadsheet-LineBarPieConfigPanel">
2857
+ <div>
2858
+ <div class="o-section o-data-series">
2859
+ <div class="o-section-title">Data Series</div>
2860
+ <SelectionInput
2861
+ ranges="() => this.getDataSeriesRanges()"
2862
+ required="true"
2863
+ onSelectionChanged="(ranges) => this.onDataSeriesRangesChanged(ranges)"
2864
+ onSelectionConfirmed="() => this.onDataSeriesConfirmed()"
2865
+ />
2866
+ </div>
2867
+ <div class="o-section o-data-labels">
2868
+ <div class="o-section-title">Categories / Labels</div>
2869
+ <SelectionInput
2870
+ ranges="() => [this.getLabelRange()]"
2871
+ isInvalid="isLabelInvalid"
2872
+ hasSingleRange="true"
2873
+ onSelectionChanged="(ranges) => this.onLabelRangeChanged(ranges)"
2874
+ onSelectionConfirmed="() => this.onLabelRangeConfirmed()"
2875
+ />
2876
+ <label class="o-checkbox">
2877
+ <input
2878
+ type="checkbox"
2879
+ name="aggregated"
2880
+ t-att-checked="props.definition.aggregated"
2881
+ t-on-change="onUpdateAggregated"
2882
+ class="align-middle"
2883
+ />
2884
+ Aggregate
2885
+ </label>
2886
+ </div>
2887
+ <div class="o-section o-use-row-as-headers" t-if="calculateHeaderPosition()">
2888
+ <label class="o-checkbox">
2889
+ <input
2890
+ type="checkbox"
2891
+ t-att-checked="props.definition.dataSetsHaveTitle"
2892
+ t-on-change="onUpdateDataSetsHaveTitle"
2893
+ class="align-middle"
2894
+ />
2895
+ <span>
2896
+ Use row
2897
+ <t t-esc="calculateHeaderPosition()"/>
2898
+ as headers
2899
+ </span>
2900
+ </label>
2901
+ </div>
2902
+
2903
+ <div class="o-section" t-if="errorMessages.length">
2904
+ <ValidationMessages messages="errorMessages" msgType="'error'"/>
2905
+ </div>
2906
+ </div>
2907
+ </t>
2908
+
2909
+ <t t-name="o-spreadsheet-LineBarPieDesignPanel">
2910
+ <t t-set="background_color">Background Color</t>
2911
+ <div>
2912
+ <div class="o-section o-chart-background-color">
2913
+ <div class="o-section-title">Background color</div>
2914
+ <div class="d-flex align-items-center">
2915
+ <span class="pe-1">Select a color...</span>
2916
+ <ColorPickerWidget
2917
+ currentColor="props.definition.background"
2918
+ toggleColorPicker="() => this.toggleColorPicker()"
2919
+ showColorPicker="state.fillColorTool"
2920
+ onColorPicked="(color) => this.updateBackgroundColor(color)"
2921
+ title="background_color"
2922
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
2923
+ />
2924
+ </div>
2925
+ </div>
2926
+ <div class="o-section o-chart-title">
2927
+ <div class="o-section-title">Title</div>
2928
+ <input
2929
+ type="text"
2930
+ t-model="state.title"
2931
+ t-on-change="updateTitle"
2932
+ class="o-input o-optional"
2933
+ placeholder="New Chart"
2934
+ />
2935
+ </div>
2936
+ <div class="o-section">
2937
+ <div class="o-section-title">Legend position</div>
2938
+ <select
2939
+ t-att-value="props.definition.legendPosition"
2940
+ class="o-input o-type-selector"
2941
+ t-on-change="(ev) => this.updateSelect('legendPosition', ev)">
2942
+ <option value="none">None</option>
2943
+ <option value="top">Top</option>
2944
+ <option value="bottom">Bottom</option>
2945
+ <option value="left">Left</option>
2946
+ <option value="right">Right</option>
2947
+ </select>
2948
+ </div>
2949
+ </div>
2950
+ </t>
2951
+
2952
+ <t t-name="o-spreadsheet-LineConfigPanel">
2953
+ <div>
2954
+ <div class="o-section pt-0">
2955
+ <label class="o-checkbox">
2956
+ <input
2957
+ type="checkbox"
2958
+ name="stacked"
2959
+ t-att-checked="props.definition.stacked"
2960
+ t-on-change="onUpdateStacked"
2961
+ class="align-middle"
2962
+ />
2963
+ Stacked linechart
2964
+ </label>
2965
+ <label class="o-checkbox">
2966
+ <input
2967
+ type="checkbox"
2968
+ name="cumulative"
2969
+ t-att-checked="props.definition.cumulative"
2970
+ t-on-change="onUpdateCumulative"
2971
+ class="align-middle"
2972
+ />
2973
+ Cumulative data
2974
+ </label>
2975
+ </div>
2976
+ <div class="o-section o-data-series">
2977
+ <div class="o-section-title">Data Series</div>
2978
+ <SelectionInput
2979
+ ranges="() => this.getDataSeriesRanges()"
2980
+ required="true"
2981
+ onSelectionChanged="(ranges) => this.onDataSeriesRangesChanged(ranges)"
2982
+ onSelectionConfirmed="() => this.onDataSeriesConfirmed()"
2983
+ />
2984
+ </div>
2985
+ <div class="o-section o-data-labels">
2986
+ <div class="o-section-title">Categories / Labels</div>
2987
+ <SelectionInput
2988
+ ranges="() => [this.getLabelRange()]"
2989
+ isInvalid="isLabelInvalid"
2990
+ hasSingleRange="true"
2991
+ onSelectionChanged="(ranges) => this.onLabelRangeChanged(ranges)"
2992
+ onSelectionConfirmed="() => this.onLabelRangeConfirmed()"
2993
+ />
2994
+ <label class="o-checkbox">
2995
+ <input
2996
+ type="checkbox"
2997
+ name="aggregated"
2998
+ t-att-checked="props.definition.aggregated"
2999
+ t-on-change="onUpdateAggregated"
3000
+ class="align-middle"
3001
+ />
3002
+ Aggregate
3003
+ </label>
3004
+ <label t-if="canTreatLabelsAsText" class="o-checkbox">
3005
+ <input
3006
+ type="checkbox"
3007
+ name="labelsAsText"
3008
+ t-att-checked="props.definition.labelsAsText"
3009
+ t-on-change="onUpdateLabelsAsText"
3010
+ />
3011
+ Treat labels as text
3012
+ </label>
3013
+ </div>
3014
+ <div class="o-section o-use-row-as-headers" t-if="calculateHeaderPosition()">
3015
+ <label>
3016
+ <input
3017
+ type="checkbox"
3018
+ t-att-checked="props.definition.dataSetsHaveTitle"
3019
+ t-on-change="onUpdateDataSetsHaveTitle"
3020
+ class="align-middle"
3021
+ />
3022
+ <span>
3023
+ Use row
3024
+ <t t-esc="calculateHeaderPosition()"/>
3025
+ as headers
3026
+ </span>
3027
+ </label>
3028
+ </div>
3029
+
3030
+ <div class="o-section" t-if="errorMessages.length">
3031
+ <ValidationMessages messages="errorMessages" msgType="'error'"/>
3032
+ </div>
3033
+ </div>
3034
+ </t>
3035
+
3036
+ <t t-name="o-spreadsheet-LineChartDesignPanel">
3037
+ <t t-set="background_color">Background Color</t>
3038
+ <div>
3039
+ <div class="o-section o-chart-background-color">
3040
+ <div class="o-section-title">Background color</div>
3041
+ <div class="d-flex align-items-center">
3042
+ <span class="pe-1">Select a color...</span>
3043
+ <ColorPickerWidget
3044
+ currentColor="props.definition.background"
3045
+ toggleColorPicker="() => this.toggleColorPicker()"
3046
+ showColorPicker="state.fillColorTool"
3047
+ onColorPicked="(color) => this.updateBackgroundColor(color)"
3048
+ title="background_color"
3049
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3050
+ />
3051
+ </div>
3052
+ </div>
3053
+ <div class="o-section o-chart-title">
3054
+ <div class="o-section-title">Title</div>
3055
+ <input
3056
+ type="text"
3057
+ t-model="state.title"
3058
+ t-on-change="updateTitle"
3059
+ class="o-input o-optional"
3060
+ placeholder="New Chart"
3061
+ />
3062
+ </div>
3063
+ <div class="o-section">
3064
+ <div class="o-section-title">Vertical axis position</div>
3065
+ <select
3066
+ t-att-value="props.definition.verticalAxisPosition"
3067
+ class="o-input o-type-selector"
3068
+ t-on-change="(ev) => this.updateSelect('verticalAxisPosition', ev)">
3069
+ <option value="left">Left</option>
3070
+ <option value="right">Right</option>
3071
+ </select>
3072
+ </div>
3073
+ <div class="o-section">
3074
+ <div class="o-section-title">Legend position</div>
3075
+ <select
3076
+ t-att-value="props.definition.legendPosition"
3077
+ class="o-input o-type-selector"
3078
+ t-on-change="(ev) => this.updateSelect('legendPosition', ev)">
3079
+ <option value="none">None</option>
3080
+ <option value="top">Top</option>
3081
+ <option value="bottom">Bottom</option>
3082
+ <option value="left">Left</option>
3083
+ <option value="right">Right</option>
3084
+ </select>
3085
+ </div>
3086
+ </div>
3087
+ </t>
3088
+
3089
+ <t t-name="o-spreadsheet-ChartPanel">
3090
+ <div class="o-chart">
3091
+ <div class="o-panel">
3092
+ <div
3093
+ class="o-panel-element o-panel-configuration"
3094
+ t-att-class="state.panel !== 'configuration' ? 'inactive' : ''"
3095
+ t-on-click="() => this.activatePanel('configuration')">
3096
+ <i class="fa fa-sliders"/>
3097
+ Configuration
3098
+ </div>
3099
+ <div
3100
+ class="o-panel-element o-panel-design"
3101
+ t-att-class="state.panel !== 'design' ? 'inactive' : ''"
3102
+ t-on-click="() => this.activatePanel('design')">
3103
+ <i class="fa fa-paint-brush"/>
3104
+ Design
3105
+ </div>
3106
+ </div>
3107
+
3108
+ <t t-set="definition" t-value="getChartDefinition()"/>
3109
+ <t t-if="state.panel === 'configuration'">
3110
+ <div class="o-section">
3111
+ <div class="o-section-title">Chart type</div>
3112
+ <t t-set="types" t-value="chartTypes"/>
3113
+ <select
3114
+ class="o-input o-type-selector"
3115
+ t-on-change="(ev) => this.onTypeChange(ev.target.value)">
3116
+ <option
3117
+ t-foreach="chartTypes"
3118
+ t-as="type"
3119
+ t-key="type"
3120
+ t-att-value="type"
3121
+ t-esc="types[type]"
3122
+ t-att-selected="definition.type === type"
3123
+ />
3124
+ </select>
3125
+ </div>
3126
+ <t
3127
+ t-component="chartPanel.configuration"
3128
+ definition="definition"
3129
+ figureId="figureId"
3130
+ updateChart.bind="updateChart"
3131
+ canUpdateChart.bind="canUpdateChart"
3132
+ t-key="figureId + definition.type"
3133
+ />
3134
+ </t>
3135
+ <t t-else="">
3136
+ <t
3137
+ t-component="chartPanel.design"
3138
+ definition="definition"
3139
+ figureId="figureId"
3140
+ updateChart.bind="updateChart"
3141
+ canUpdateChart.bind="canUpdateChart"
3142
+ t-key="figureId + definition.type"
3143
+ />
3144
+ </t>
3145
+ </div>
3146
+ </t>
3147
+
3148
+ <t t-name="o-spreadsheet-ScorecardChartConfigPanel">
3149
+ <div>
3150
+ <div class="o-section o-data-series">
3151
+ <div class="o-section-title">Key value</div>
3152
+ <SelectionInput
3153
+ ranges="() => [this.getKeyValueRange()]"
3154
+ isInvalid="isKeyValueInvalid"
3155
+ hasSingleRange="true"
3156
+ required="true"
3157
+ onSelectionChanged="(ranges) => this.onKeyValueRangeChanged(ranges)"
3158
+ onSelectionConfirmed="() => this.updateKeyValueRange()"
3159
+ />
3160
+ </div>
3161
+ <div class="o-section o-data-labels">
3162
+ <div class="o-section-title">Baseline configuration</div>
3163
+ <div class="o-section-subtitle">Baseline value</div>
3164
+ <SelectionInput
3165
+ ranges="() => [this.getBaselineRange()]"
3166
+ isInvalid="isBaselineInvalid"
3167
+ hasSingleRange="true"
3168
+ onSelectionChanged="(ranges) => this.onBaselineRangeChanged(ranges)"
3169
+ onSelectionConfirmed="() => this.updateBaselineRange()"
3170
+ />
3171
+ <div class="o-section-subtitle">Baseline format</div>
3172
+ <select
3173
+ t-att-value="props.definition.baselineMode"
3174
+ class="o-input o-type-selector o-optional"
3175
+ t-on-change="(ev) => this.updateBaselineMode(ev)">
3176
+ <option value="text">Absolute value</option>
3177
+ <option value="difference">Value change from key value</option>
3178
+ <option value="percentage">Percentage change from key value</option>
3179
+ </select>
3180
+ </div>
3181
+
3182
+ <div class="o-section" t-if="errorMessages.length">
3183
+ <ValidationMessages messages="errorMessages" msgType="'error'"/>
3184
+ </div>
3185
+ </div>
3186
+ </t>
3187
+
3188
+ <t t-name="o-spreadsheet-ScorecardChartDesignPanel">
3189
+ <t t-set="background_color">Background Color</t>
3190
+ <t t-set="color_up">Color Up</t>
3191
+ <t t-set="color_down">Color Down</t>
3192
+ <div>
3193
+ <div class="o-section o-chart-background-color">
3194
+ <div class="o-section-title">Background color</div>
3195
+ <div class="d-flex align-items-center">
3196
+ <span class="pe-1">Select a color...</span>
3197
+ <ColorPickerWidget
3198
+ currentColor="props.definition.background"
3199
+ toggleColorPicker="() => this.toggleColorPicker('backgroundColor')"
3200
+ showColorPicker="state.openedColorPicker === 'backgroundColor'"
3201
+ onColorPicked="(color) => this.setColor(color, 'backgroundColor')"
3202
+ title="background_color"
3203
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3204
+ />
3205
+ </div>
3206
+ </div>
3207
+
3208
+ <div class="o-section o-chart-title">
3209
+ <div class="o-section-title">Title</div>
3210
+ <input
3211
+ type="text"
3212
+ t-model="state.title"
3213
+ t-on-change="updateTitle"
3214
+ class="o-input o-optional"
3215
+ placeholder="New Chart"
3216
+ />
3217
+ </div>
3218
+ <div class="o-section">
3219
+ <div class="o-section-title">Baseline description</div>
3220
+ <input
3221
+ type="text"
3222
+ t-att-value="translate(props.definition.baselineDescr)"
3223
+ t-on-change="updateBaselineDescr"
3224
+ class="o-input o-optional"
3225
+ />
3226
+ </div>
3227
+ </div>
3228
+ <div class="o-section o-chart-baseline-color">
3229
+ <div class="o-section-title">Baseline color</div>
3230
+ <div class="d-flex align-items-center">
3231
+ <span class="pe-1">Color on value increase</span>
3232
+ <ColorPickerWidget
3233
+ currentColor="props.definition.baselineColorUp"
3234
+ toggleColorPicker="() => this.toggleColorPicker('baselineColorUp')"
3235
+ showColorPicker="state.openedColorPicker === 'baselineColorUp'"
3236
+ onColorPicked="(color) => this.setColor(color, 'baselineColorUp')"
3237
+ title="color_up"
3238
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3239
+ />
3240
+ </div>
3241
+ <div class="d-flex align-items-center">
3242
+ <span class="pe-1">Color on value decrease</span>
3243
+ <ColorPickerWidget
3244
+ currentColor="props.definition.baselineColorDown"
3245
+ toggleColorPicker="() => this.toggleColorPicker('baselineColorDown')"
3246
+ showColorPicker="state.openedColorPicker === 'baselineColorDown'"
3247
+ onColorPicked="(color) => this.setColor(color, 'baselineColorDown')"
3248
+ title="color_down"
3249
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3250
+ />
3251
+ </div>
3252
+ </div>
3253
+ </t>
3254
+
3255
+ <t t-name="o-spreadsheet-CellIsRuleEditorPreview">
3256
+ <div
3257
+ class="o-cf-preview-line"
3258
+ t-attf-style="font-weight:{{currentStyle.bold ?'bold':'normal'}};
3259
+ text-decoration:{{getTextDecoration(currentStyle)}};
3260
+ font-style:{{currentStyle.italic?'italic':'normal'}};
3261
+ color:{{currentStyle.textColor || '#000'}};
3262
+ border-radius: 4px;
3263
+ background-color:{{currentStyle.fillColor}};">
3264
+ <t t-if="previewText" t-esc="previewText"/>
3265
+ <t t-else="">Preview text</t>
3266
+ </div>
3267
+ </t>
3268
+
3269
+ <t t-name="o-spreadsheet-CellIsRuleEditor">
3270
+ <t t-set="fill_color">Fill Color</t>
3271
+ <t t-set="text_color">Text Color</t>
3272
+ <div class="o-cf-cell-is-rule">
3273
+ <div class="o-section-subtitle">Format cells if...</div>
3274
+ <select t-model="rule.operator" class="o-input o-cell-is-operator">
3275
+ <t t-foreach="Object.keys(cellIsOperators)" t-as="op" t-key="op_index">
3276
+ <option t-att-value="op" t-esc="cellIsOperators[op]"/>
3277
+ </t>
3278
+ </select>
3279
+ <t t-if="rule.operator !== 'IsEmpty' and rule.operator !== 'IsNotEmpty'">
3280
+ <input
3281
+ type="text"
3282
+ placeholder="Value or formula"
3283
+ t-model="rule.values[0]"
3284
+ t-att-class="{ 'o-invalid': isValue1Invalid }"
3285
+ class="o-input o-cell-is-value o-required"
3286
+ t-on-keydown="(ev) => this.onKeydown(ev)"
3287
+ />
3288
+ <t t-if="rule.operator === 'Between' || rule.operator === 'NotBetween'">
3289
+ <input
3290
+ type="text"
3291
+ placeholder="and value or formula"
3292
+ t-model="rule.values[1]"
3293
+ t-att-class="{ 'o-invalid': isValue2Invalid }"
3294
+ class="o-input o-cell-is-value o-required"
3295
+ t-on-keydown="(ev) => this.onKeydown(ev)"
3296
+ />
3297
+ </t>
3298
+ </t>
3299
+ <div class="o-section-subtitle">Formatting style</div>
3300
+
3301
+ <t t-call="o-spreadsheet-CellIsRuleEditorPreview">
3302
+ <t t-set="currentStyle" t-value="rule.style"/>
3303
+ </t>
3304
+ <div class="o-sidePanel-tools">
3305
+ <div
3306
+ class="o-tool"
3307
+ title="Bold"
3308
+ t-att-class="{active:rule.style.bold}"
3309
+ t-on-click="() => this.toggleStyle('bold')">
3310
+ <t t-call="o-spreadsheet-Icon.BOLD"/>
3311
+ </div>
3312
+ <div
3313
+ class="o-tool"
3314
+ title="Italic"
3315
+ t-att-class="{active:rule.style.italic}"
3316
+ t-on-click="() => this.toggleStyle('italic')">
3317
+ <t t-call="o-spreadsheet-Icon.ITALIC"/>
3318
+ </div>
3319
+ <div
3320
+ class="o-tool"
3321
+ title="Underline"
3322
+ t-att-class="{active:rule.style.underline}"
3323
+ t-on-click="(ev) => this.toggleStyle('underline', ev)">
3324
+ <t t-call="o-spreadsheet-Icon.UNDERLINE"/>
3325
+ </div>
3326
+ <div
3327
+ class="o-tool"
3328
+ title="Strikethrough"
3329
+ t-att-class="{active:rule.style.strikethrough}"
3330
+ t-on-click="(ev) => this.toggleStyle('strikethrough', ev)">
3331
+ <t t-call="o-spreadsheet-Icon.STRIKE"/>
3332
+ </div>
3333
+ <ColorPickerWidget
3334
+ currentColor="rule.style.textColor || '#000000'"
3335
+ toggleColorPicker="(ev) => this.toggleMenu('cellIsRule-textColor', ev)"
3336
+ showColorPicker="state.openedMenu === 'cellIsRule-textColor'"
3337
+ onColorPicked="(color) => this.setColor('textColor', color)"
3338
+ title="text_color"
3339
+ icon="'o-spreadsheet-Icon.TEXT_COLOR'"
3340
+ class="'o-tool'"
3341
+ />
3342
+ <div class="o-divider"/>
3343
+ <ColorPickerWidget
3344
+ currentColor="rule.style.fillColor"
3345
+ toggleColorPicker="(ev) => this.toggleMenu('cellIsRule-fillColor', ev)"
3346
+ showColorPicker="state.openedMenu === 'cellIsRule-fillColor'"
3347
+ onColorPicked="(color) => this.setColor('fillColor', color)"
3348
+ title="fill_color"
3349
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3350
+ class="'o-tool'"
3351
+ />
3352
+ </div>
3353
+ </div>
3354
+ </t>
3355
+
3356
+ <t t-name="o-spreadsheet-ConditionalFormattingEditor">
3357
+ <div class="o-cf-ruleEditor">
3358
+ <div class="o-section o-cf-range">
3359
+ <div class="o-section-title">Apply to range</div>
3360
+ <div class="o-selection-cf">
3361
+ <SelectionInput
3362
+ ranges="() => state.currentCF.ranges"
3363
+ class="'o-range'"
3364
+ isInvalid="isRangeValid"
3365
+ onSelectionChanged="(ranges) => this.onRangesChanged(ranges)"
3366
+ required="true"
3367
+ />
3368
+ </div>
3369
+ <div class="o-section-title">Format rules</div>
3370
+ <div class="o_field_radio o_horizontal o_field_widget o-cf-type-selector">
3371
+ <div
3372
+ class="custom-control form-check o_cf_radio_item"
3373
+ t-on-click="() => this.changeRuleType('CellIsRule')">
3374
+ <input
3375
+ class="form-check-input o_radio_input"
3376
+ t-att-checked="state.currentCFType === 'CellIsRule'"
3377
+ type="radio"
3378
+ id="cellIsRule"
3379
+ name="ruleType"
3380
+ value="CellIsRule"
3381
+ />
3382
+ <label for="cellIsRule" class="form-check-label o_form_label">Single color</label>
3383
+ </div>
3384
+ <div
3385
+ class="custom-control form-check o_cf_radio_item"
3386
+ t-on-click="() => this.changeRuleType('ColorScaleRule')">
3387
+ <input
3388
+ class="form-check-input o_radio_input"
3389
+ t-att-checked="state.currentCFType === 'ColorScaleRule'"
3390
+ type="radio"
3391
+ id="colorScaleRule"
3392
+ name="ruleType"
3393
+ value="ColorScaleRule"
3394
+ />
3395
+ <label for="colorScaleRule" class="form-check-label o_form_label">Color scale</label>
3396
+ </div>
3397
+
3398
+ <div
3399
+ class="custom-control form-check o_cf_radio_item"
3400
+ t-on-click="() => this.changeRuleType('IconSetRule')">
3401
+ <input
3402
+ class="form-check-input o_radio_input"
3403
+ t-att-checked="state.currentCFType === 'IconSetRule'"
3404
+ type="radio"
3405
+ id="iconSetRule"
3406
+ name="ruleType"
3407
+ value="IconSetRule"
3408
+ />
3409
+ <label for="iconSetRule" class="form-check-label o_form_label">Icon set</label>
3410
+ </div>
3411
+ </div>
3412
+ </div>
3413
+ <div class="o-section o-cf-editor">
3414
+ <t t-if="state.currentCFType === 'CellIsRule'" t-call="o-spreadsheet-CellIsRuleEditor">
3415
+ <t t-set="rule" t-value="state.rules.cellIs"/>
3416
+ </t>
3417
+ <t
3418
+ t-if="state.currentCFType === 'ColorScaleRule'"
3419
+ t-call="o-spreadsheet-ColorScaleRuleEditor">
3420
+ <t t-set="rule" t-value="state.rules.colorScale"/>
3421
+ </t>
3422
+ <t t-if="state.currentCFType === 'IconSetRule'" t-call="o-spreadsheet-IconSetEditor">
3423
+ <t t-set="rule" t-value="state.rules.iconSet"/>
3424
+ </t>
3425
+ <div class="o-sidePanelButtons">
3426
+ <button t-on-click="props.onExitEdition" class="o-button o-cf-cancel">Cancel</button>
3427
+ <button t-on-click="saveConditionalFormat" class="o-button primary o-cf-save">
3428
+ Save
3429
+ </button>
3430
+ </div>
3431
+ </div>
3432
+ <div class="o-section">
3433
+ <div class="o-cf-error" t-foreach="state.errors || []" t-as="error" t-key="error_index">
3434
+ <t t-esc="errorMessage(error)"/>
3435
+ </div>
3436
+ </div>
3437
+ </div>
3438
+ </t>
3439
+
3440
+ <t t-name="o-spreadsheet-ColorScaleRuleEditorPreview">
3441
+ <div class="o-cf-preview-gradient" t-attf-style="{{getPreviewGradient()}}">Preview text</div>
3442
+ </t>
3443
+
3444
+ <t t-name="o-spreadsheet-ColorScaleRuleEditorThreshold">
3445
+ <t t-set="fill_color">Fill Color</t>
3446
+ <div t-attf-class="o-threshold o-threshold-{{thresholdType}}">
3447
+ <t t-if="thresholdType === 'midpoint'">
3448
+ <t t-set="type" t-value="threshold and threshold.type"/>
3449
+ <select
3450
+ class="o-input"
3451
+ name="valueType"
3452
+ t-on-change="onMidpointChange"
3453
+ t-on-click="closeMenus">
3454
+ <option value="none" t-att-selected="threshold === undefined">None</option>
3455
+ <option value="number" t-att-selected="type === 'number'">FixedNumber</option>
3456
+ <option value="percentage" t-att-selected="type === 'percentage'">Percentage</option>
3457
+ <option value="percentile" t-att-selected="type === 'percentile'">Percentile</option>
3458
+ <option value="formula" t-att-selected="type === 'formula'">Formula</option>
3459
+ </select>
3460
+ </t>
3461
+ <t t-else="">
3462
+ <select class="o-input" name="valueType" t-model="threshold.type" t-on-click="closeMenus">
3463
+ <option value="value">Cell values</option>
3464
+ <option value="number">Number</option>
3465
+ <option value="percentage">Percentage</option>
3466
+ <option value="percentile">Percentile</option>
3467
+ <option value="formula">Formula</option>
3468
+ </select>
3469
+ </t>
3470
+ <input
3471
+ type="text"
3472
+ class="o-input o-threshold-value o-required"
3473
+ t-model="rule[thresholdType].value"
3474
+ t-att-class="{ 'o-invalid': isValueInvalid(thresholdType) }"
3475
+ t-if="threshold !== undefined and threshold.type !== 'value'"
3476
+ />
3477
+ <input type="text" class="o-input o-threshold-value" t-else="" disabled="1"/>
3478
+ <ColorPickerWidget
3479
+ currentColor="getThresholdColor(threshold)"
3480
+ toggleColorPicker="(ev) => this.toggleMenu('colorScale-'+thresholdType+'Color', ev)"
3481
+ showColorPicker="state.openedMenu === 'colorScale-'+thresholdType+'Color'"
3482
+ onColorPicked="(color) => this.setColorScaleColor(thresholdType, color)"
3483
+ title="fill_color"
3484
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
3485
+ disabled="threshold === undefined"
3486
+ />
3487
+ </div>
3488
+ </t>
3489
+
3490
+ <t t-name="o-spreadsheet-ColorScaleRuleEditor">
3491
+ <div class="o-cf-color-scale-editor">
3492
+ <div class="o-section-subtitle">Preview</div>
3493
+ <t t-call="o-spreadsheet-ColorScaleRuleEditorPreview"/>
3494
+ <div class="o-section-subtitle">Minpoint</div>
3495
+ <t t-call="o-spreadsheet-ColorScaleRuleEditorThreshold">
3496
+ <t t-set="threshold" t-value="rule.minimum"/>
3497
+ <t t-set="thresholdType" t-value="'minimum'"/>
3498
+ </t>
3499
+ <div class="o-section-subtitle">MidPoint</div>
3500
+ <t t-call="o-spreadsheet-ColorScaleRuleEditorThreshold">
3501
+ <t t-set="threshold" t-value="rule.midpoint"/>
3502
+ <t t-set="thresholdType" t-value="'midpoint'"/>
3503
+ </t>
3504
+ <div class="o-section-subtitle">MaxPoint</div>
3505
+ <t t-call="o-spreadsheet-ColorScaleRuleEditorThreshold">
3506
+ <t t-set="threshold" t-value="rule.maximum"/>
3507
+ <t t-set="thresholdType" t-value="'maximum'"/>
3508
+ </t>
3509
+ </div>
3510
+ </t>
3511
+
3512
+ <t t-name="o-spreadsheet-IconSets">
3513
+ <div>
3514
+ <div class="o-section-subtitle">Icons</div>
3515
+ <div class="o-cf-iconsets">
3516
+ <div
3517
+ class="o-cf-iconset"
3518
+ t-foreach="['arrows', 'smiley', 'dots']"
3519
+ t-as="iconSet"
3520
+ t-key="iconSet"
3521
+ t-on-click="(ev) => this.setIconSet(iconSet, ev)">
3522
+ <div class="o-cf-icon">
3523
+ <t t-call="o-spreadsheet-Icon.{{icons[iconSets[iconSet].good].template}}"/>
3524
+ </div>
3525
+ <div class="o-cf-icon">
3526
+ <t t-call="o-spreadsheet-Icon.{{icons[iconSets[iconSet].neutral].template}}"/>
3527
+ </div>
3528
+ <div class="o-cf-icon">
3529
+ <t t-call="o-spreadsheet-Icon.{{icons[iconSets[iconSet].bad].template}}"/>
3530
+ </div>
3531
+ </div>
3532
+ </div>
3533
+ </div>
3534
+ </t>
3535
+
3536
+ <t t-name="o-spreadsheet-IconSetInflexionPointRow">
3537
+ <tr>
3538
+ <td>
3539
+ <div t-on-click.stop="(ev) => this.toggleMenu('iconSet-'+icon+'Icon', ev)">
3540
+ <div class="o-cf-icon-button">
3541
+ <t t-call="o-spreadsheet-Icon.{{icons[iconValue].template}}"/>
3542
+ </div>
3543
+ </div>
3544
+ <IconPicker
3545
+ t-if="state.openedMenu === 'iconSet-'+icon+'Icon'"
3546
+ onIconPicked="(i) => this.setIcon(icon, i)"
3547
+ />
3548
+ </td>
3549
+ <td>When value is</td>
3550
+ <td>
3551
+ <select class="o-input" name="valueType" t-model="inflectionPointValue.operator">
3552
+ <option value="gt">
3553
+ <span>&#62;</span>
3554
+ </option>
3555
+ <option value="ge">
3556
+ <span>&#8805;</span>
3557
+ </option>
3558
+ </select>
3559
+ </td>
3560
+ <td>
3561
+ <input
3562
+ type="text"
3563
+ class="o-input"
3564
+ t-att-class="{ 'o-invalid': isInflectionPointInvalid(inflectionPoint) }"
3565
+ t-model="rule[inflectionPoint].value"
3566
+ />
3567
+ </td>
3568
+ <td>
3569
+ <select class="o-input" name="valueType" t-model="inflectionPointValue.type">
3570
+ <option value="number">Number</option>
3571
+ <option value="percentage">Percentage</option>
3572
+ <option value="percentile">Percentile</option>
3573
+ <option value="formula">Formula</option>
3574
+ </select>
3575
+ </td>
3576
+ </tr>
3577
+ </t>
3578
+
3579
+ <t t-name="o-spreadsheet-IconSetInflexionPoints">
3580
+ <div class="o-inflection">
3581
+ <table>
3582
+ <tr>
3583
+ <th class="o-cf-iconset-icons"/>
3584
+ <th class="o-cf-iconset-text"/>
3585
+ <th class="o-cf-iconset-operator"/>
3586
+ <th class="o-cf-iconset-value">Value</th>
3587
+ <th class="o-cf-iconset-type">Type</th>
3588
+ </tr>
3589
+ <t t-call="o-spreadsheet-IconSetInflexionPointRow">
3590
+ <t t-set="iconValue" t-value="rule.icons.upper"/>
3591
+ <t t-set="icon" t-value="'upper'"/>
3592
+ <t t-set="inflectionPointValue" t-value="rule.upperInflectionPoint"/>
3593
+ <t t-set="inflectionPoint" t-value="'upperInflectionPoint'"/>
3594
+ </t>
3595
+ <t t-call="o-spreadsheet-IconSetInflexionPointRow">
3596
+ <t t-set="iconValue" t-value="rule.icons.middle"/>
3597
+ <t t-set="icon" t-value="'middle'"/>
3598
+ <t t-set="inflectionPointValue" t-value="rule.lowerInflectionPoint"/>
3599
+ <t t-set="inflectionPoint" t-value="'lowerInflectionPoint'"/>
3600
+ </t>
3601
+ <tr>
3602
+ <td>
3603
+ <div t-on-click.stop="(ev) => this.toggleMenu('iconSet-lowerIcon', ev)">
3604
+ <div class="o-cf-icon-button">
3605
+ <t t-call="o-spreadsheet-Icon.{{icons[rule.icons.lower].template}}"/>
3606
+ </div>
3607
+ </div>
3608
+ <IconPicker
3609
+ t-if="state.openedMenu === 'iconSet-lowerIcon'"
3610
+ onIconPicked="(icon) => this.setIcon('lower', icon)"
3611
+ />
3612
+ </td>
3613
+ <td>Else</td>
3614
+ <td/>
3615
+ <td/>
3616
+ <td/>
3617
+ </tr>
3618
+ </table>
3619
+ </div>
3620
+ </t>
3621
+ <t t-name="o-spreadsheet-IconSetEditor">
3622
+ <div class="o-cf-iconset-rule">
3623
+ <t t-call="o-spreadsheet-IconSets"/>
3624
+ <t t-call="o-spreadsheet-IconSetInflexionPoints"/>
3625
+ <div class="btn btn-link o_refresh_measures o-cf-iconset-reverse" t-on-click="reverseIcons">
3626
+ <div class="me-1 d-inline-block">
3627
+ <t t-call="o-spreadsheet-Icon.REFRESH"/>
3628
+ </div>
3629
+ Reverse icons
3630
+ </div>
3631
+ </div>
3632
+ </t>
3633
+
3634
+ <t t-name="o-spreadsheet-ConditionalFormatPreviewList">
3635
+ <div class="o-cf-preview-list h-100 overflow-auto" t-ref="cfList">
3636
+ <t t-foreach="props.conditionalFormats" t-as="cf" t-key="cf.id">
3637
+ <t t-call="o-spreadsheet-ConditionalFormattingPanelPreview"/>
3638
+ </t>
3639
+ <div
3640
+ class="btn btn-link o-sidePanel-btn-link o-cf-add float-end"
3641
+ t-on-click.prevent.stop="props.onAddConditionalFormat">
3642
+ + Add another rule
3643
+ </div>
3644
+ </div>
3645
+ </t>
3646
+
3647
+ <t t-name="o-spreadsheet-ConditionalFormattingPanelPreview">
3648
+ <div
3649
+ class="o-cf-preview d-flex position-relative"
3650
+ t-att-class="{ 'o-cf-dragging': dragAndDrop.draggedItemId === cf.id }"
3651
+ t-att-style="getPreviewDivStyle(cf)"
3652
+ t-att-data-id="cf.id"
3653
+ t-on-click="(ev) => props.onPreviewClick(cf)"
3654
+ t-on-mousedown="(ev) => this.onMouseDown(cf, ev)">
3655
+ <div class="position-relative h-100 w-100 d-flex align-items-center">
3656
+ <div class="o-cf-drag-handle h-100 position-absolute d-flex align-items-center text-muted">
3657
+ <t t-call="o-spreadsheet-Icon.THIN_DRAG_HANDLE"/>
3658
+ </div>
3659
+ <t t-if="cf.rule.type==='IconSetRule'">
3660
+ <div class="o-cf-preview-icon d-flex justify-content-around align-items-center me-2">
3661
+ <t t-call="o-spreadsheet-Icon.{{icons[cf.rule.icons.upper].template}}"/>
3662
+ <t t-call="o-spreadsheet-Icon.{{icons[cf.rule.icons.middle].template}}"/>
3663
+ <t t-call="o-spreadsheet-Icon.{{icons[cf.rule.icons.lower].template}}"/>
3664
+ </div>
3665
+ </t>
3666
+ <t t-else="">
3667
+ <div
3668
+ t-att-style="getPreviewImageStyle(cf.rule)"
3669
+ class="o-cf-preview-icon d-flex justify-content-around align-items-center me-2">
3670
+ 123
3671
+ </div>
3672
+ </t>
3673
+ <div class="o-cf-preview-description">
3674
+ <div class="o-cf-preview-ruletype">
3675
+ <div class="o-cf-preview-description-rule text-truncate">
3676
+ <t t-esc="getDescription(cf)"/>
3677
+ </div>
3678
+ </div>
3679
+ <div class="o-cf-preview-range text-truncate" t-esc="cf.ranges"/>
3680
+ </div>
3681
+ <div class="o-cf-delete">
3682
+ <div
3683
+ class="o-cf-delete-button text-muted"
3684
+ t-on-click.stop="(ev) => this.deleteConditionalFormat(cf, ev)"
3685
+ title="Remove rule">
3686
+ <t t-call="o-spreadsheet-Icon.TRASH"/>
3687
+ </div>
3688
+ </div>
3689
+ </div>
3690
+ </div>
3691
+ </t>
3692
+
3693
+ <t t-name="o-spreadsheet-ConditionalFormattingPanel">
3694
+ <div class="o-cf h-100">
3695
+ <t t-if="state.mode === 'list'">
3696
+ <ConditionalFormatPreviewList
3697
+ conditionalFormats="conditionalFormats"
3698
+ onPreviewClick.bind="editConditionalFormat"
3699
+ onAddConditionalFormat.bind="addConditionalFormat"
3700
+ />
3701
+ </t>
3702
+ <t t-if="state.mode === 'edit'">
3703
+ <ConditionalFormattingEditor editedCf="state.editedCf" onExitEdition.bind="switchToList"/>
3704
+ </t>
3705
+ </div>
3706
+ </t>
3707
+
3708
+ <t t-name="o-spreadsheet-CustomCurrencyPanel">
3709
+ <div class="o-custom-currency">
3710
+ <div class="o-section" t-if="availableCurrencies.length > 1">
3711
+ <div class="o-section-title">Currency</div>
3712
+ <select
3713
+ class="o-input o-available-currencies"
3714
+ t-on-change="(ev) => this.updateSelectCurrency(ev)">
3715
+ <t t-foreach="availableCurrencies" t-as="currency" t-key="currency_index">
3716
+ <option
3717
+ t-att-value="currency_index"
3718
+ t-esc="currencyDisplayName(currency)"
3719
+ t-att-selected="currency_index === state.selectedCurrencyIndex"
3720
+ />
3721
+ </t>
3722
+ </select>
3723
+ </div>
3724
+ <div class="o-section">
3725
+ <div class="o-subsection-left">
3726
+ <div class="o-section-title">Code</div>
3727
+ <input
3728
+ type="text"
3729
+ class="o-input"
3730
+ t-model="state.currencyCode"
3731
+ t-on-input="(ev) => this.updateCode(ev)"
3732
+ />
3733
+ </div>
3734
+ <div class="o-subsection-right">
3735
+ <div class="o-section-title">Symbol</div>
3736
+ <input
3737
+ type="text"
3738
+ class="o-input"
3739
+ t-model="state.currencySymbol"
3740
+ t-on-input="(ev) => this.updateSymbol(ev)"
3741
+ />
3742
+ </div>
3743
+ </div>
3744
+ <div class="o-section">
3745
+ <div class="o-section-title">Format</div>
3746
+ <select
3747
+ class="o-input o-format-proposals"
3748
+ t-on-change="(ev) => this.updateSelectFormat(ev)"
3749
+ t-att-disabled="!formatProposals.length">
3750
+ <t t-foreach="formatProposals" t-as="proposal" t-key="proposal_index">
3751
+ <option
3752
+ t-att-value="proposal_index"
3753
+ t-esc="proposal.example"
3754
+ t-att-selected="proposal_index === state.selectedFormatIndex"
3755
+ />
3756
+ </t>
3757
+ </select>
3758
+ </div>
3759
+ <div class="o-sidePanelButtons">
3760
+ <button
3761
+ class="o-button"
3762
+ t-on-click="() => this.apply()"
3763
+ t-att-disabled="!formatProposals.length || isSameFormat">
3764
+ Apply
3765
+ </button>
3766
+ </div>
3767
+ </div>
3768
+ </t>
3769
+
3770
+ <t t-name="o-spreadsheet-DataValidationPanel">
3771
+ <div class="o-data-validation">
3772
+ <t t-if="state.mode === 'list'">
3773
+ <div class="o-dv-preview-list">
3774
+ <t t-foreach="validationRules" t-as="rule" t-key="rule.id">
3775
+ <DataValidationPreview
3776
+ rule="localizeDVRule(rule)"
3777
+ onClick="() => this.onPreviewClick(rule.id)"
3778
+ />
3779
+ </t>
3780
+ </div>
3781
+ <div
3782
+ class="o-dv-add btn btn-link o-sidePanel-btn-link float-end"
3783
+ t-on-click="addDataValidationRule">
3784
+ + Add another rule
3785
+ </div>
3786
+ </t>
3787
+ <t t-else="">
3788
+ <DataValidationEditor rule="localizeDVRule(state.activeRule)" onExit.bind="onExitEditMode"/>
3789
+ </t>
3790
+ </div>
3791
+ </t>
3792
+
3793
+ <t t-name="o-spreadsheet-DataValidationDateCriterion">
3794
+ <select class="o-dv-date-value o-input mb-4" t-on-change="onDateValueChanged">
3795
+ <option
3796
+ t-foreach="dateValues"
3797
+ t-as="dateValue"
3798
+ t-key="dateValue.value"
3799
+ t-att-value="dateValue.value"
3800
+ t-esc="dateValue.title"
3801
+ t-att-selected="dateValue.value === props.criterion.dateValue"
3802
+ />
3803
+ </select>
3804
+
3805
+ <DataValidationInput
3806
+ t-if="props.criterion.dateValue === 'exactDate'"
3807
+ value="props.criterion.values[0]"
3808
+ onValueChanged.bind="onValueChanged"
3809
+ criterionType="props.criterion.type"
3810
+ />
3811
+ </t>
3812
+
3813
+ <t t-name="o-spreadsheet-DataValidationDoubleInput">
3814
+ <DataValidationInput
3815
+ value="props.criterion.values[0]"
3816
+ onValueChanged.bind="onFirstValueChanged"
3817
+ criterionType="props.criterion.type"
3818
+ />
3819
+
3820
+ <div class="o-section-subtitle ms-1 my-2">and</div>
3821
+ <DataValidationInput
3822
+ value="props.criterion.values[1]"
3823
+ onValueChanged.bind="onSecondValueChanged"
3824
+ criterionType="props.criterion.type"
3825
+ />
3826
+ </t>
3827
+
3828
+ <t t-name="o-spreadsheet-DataValidationInput">
3829
+ <div class="o-dv-input position-relative w-100">
3830
+ <input
3831
+ type="text"
3832
+ t-ref="input"
3833
+ t-on-input="onValueChanged"
3834
+ t-att-value="props.value"
3835
+ class="o-input"
3836
+ t-att-class="{
3837
+ 'o-invalid border-danger position-relative': errorMessage,
3838
+ }"
3839
+ t-att-title="errorMessage"
3840
+ t-att-placeholder="placeholder"
3841
+ t-on-keydown="props.onKeyDown"
3842
+ t-on-blur="props.onBlur"
3843
+ />
3844
+ <span
3845
+ t-if="errorMessage"
3846
+ class="error-icon text-danger position-absolute d-flex align-items-center"
3847
+ t-att-title="errorMessage">
3848
+ <t t-call="o-spreadsheet-Icon.ERROR"/>
3849
+ </span>
3850
+ </div>
3851
+ </t>
3852
+
3853
+ <t t-name="o-spreadsheet-DataValidationSingleInput">
3854
+ <DataValidationInput
3855
+ value="props.criterion.values[0]"
3856
+ onValueChanged.bind="onValueChanged"
3857
+ criterionType="props.criterion.type"
3858
+ />
3859
+ </t>
3860
+
3861
+ <t t-name="o-spreadsheet-DataValidationListCriterionForm">
3862
+ <t t-foreach="displayedValues" t-as="value" t-key="value_index">
3863
+ <div class="o-dv-list-values d-flex align-items-center">
3864
+ <DataValidationInput
3865
+ value="props.criterion.values[value_index]"
3866
+ onValueChanged="(v) => this.onValueChanged(v, value_index)"
3867
+ criterionType="props.criterion.type"
3868
+ onKeyDown="(ev) => this.onKeyDown(ev, value_index)"
3869
+ focused="value_index === state.focusedValueIndex"
3870
+ onBlur.bind="onBlurInput"
3871
+ />
3872
+ <div
3873
+ class="o-dv-list-item-delete ms-2 me-1"
3874
+ t-on-click="() => this.removeItem(value_index)">
3875
+ <t t-call="o-spreadsheet-Icon.TRASH"/>
3876
+ </div>
3877
+ </div>
3878
+ <div class="mb-2"/>
3879
+ </t>
3880
+ <button class="o-dv-list-add-value o-button mb-3" t-on-click="onAddAnotherValue">
3881
+ Add another item
3882
+ </button>
3883
+
3884
+ <div class="o-section-subtitle">Display style</div>
3885
+ <select class="o-dv-display-style o-input" t-on-change="onChangedDisplayStyle">
3886
+ <option t-att-selected="props.criterion.displayStyle === 'arrow'" value="arrow">Arrow</option>
3887
+ <option t-att-selected="props.criterion.displayStyle === 'plainText'" value="plainText">
3888
+ Plain text
3889
+ </option>
3890
+ </select>
3891
+ </t>
3892
+
3893
+ <t t-name="o-spreadsheet-DataValidationValueInRangeCriterionForm">
3894
+ <SelectionInput
3895
+ ranges="() => [props.criterion.values[0] || '']"
3896
+ onSelectionChanged="(ranges) => this.onRangeChanged(ranges[0])"
3897
+ required="true"
3898
+ hasSingleRange="true"
3899
+ />
3900
+
3901
+ <div class="o-section-subtitle">Display style</div>
3902
+ <select class="o-dv-display-style o-input" t-on-change="onChangedDisplayStyle">
3903
+ <option t-att-selected="props.criterion.displayStyle === 'arrow'" value="arrow">Arrow</option>
3904
+ <option t-att-selected="props.criterion.displayStyle === 'plainText'" value="plainText">
3905
+ Plain text
3906
+ </option>
3907
+ </select>
3908
+ </t>
3909
+
3910
+ <t t-name="o-spreadsheet-DataValidationEditor">
3911
+ <div class="o-dv-form w-100 h-100">
3912
+ <div class="o-section o-dv-range">
3913
+ <div class="o-section-title">Apply to range</div>
3914
+ <SelectionInput
3915
+ ranges="() => state.rule.ranges"
3916
+ onSelectionChanged="(ranges) => this.onRangesChanged(ranges)"
3917
+ required="true"
3918
+ />
3919
+
3920
+ <div class="o-subsection o-dv-settings">
3921
+ <div class="o-section-title">Criteria</div>
3922
+ <SelectMenu
3923
+ class="'o-dv-type o-input mb-4'"
3924
+ menuItems="dvCriterionMenuItems"
3925
+ selectedValue="selectedCriterionName"
3926
+ />
3927
+
3928
+ <t
3929
+ t-if="criterionComponent"
3930
+ t-component="criterionComponent"
3931
+ t-key="state.rule.criterion.type"
3932
+ criterion="state.rule.criterion"
3933
+ onCriterionChanged.bind="onCriterionChanged"
3934
+ />
3935
+ </div>
3936
+ </div>
3937
+
3938
+ <div class="o-section o-dv-invalid-option">
3939
+ <div class="o-section-title">If the data is invalid</div>
3940
+ <select class="o-dv-reject-input o-input" t-on-change="changeRuleIsBlocking">
3941
+ <option t-att-selected="!state.rule.isBlocking" value="false">Show a warning</option>
3942
+ <option t-att-selected="state.rule.isBlocking" value="true">Reject the input</option>
3943
+ </select>
3944
+ </div>
3945
+
3946
+ <div class="o-sidePanelButtons">
3947
+ <button t-on-click="props.onExit" class="o-dv-cancel o-button">Cancel</button>
3948
+ <button
3949
+ t-on-click="onSave"
3950
+ class="o-dv-save o-button primary"
3951
+ t-att-class="{'o-disabled': !canSave }">
3952
+ Save
3953
+ </button>
3954
+ </div>
3955
+ </div>
3956
+ </t>
3957
+
3958
+ <t t-name="o-spreadsheet-DataValidationPreview">
3959
+ <div class="o-dv-preview p-3" t-on-click="props.onClick">
3960
+ <div class="d-flex justify-content-between">
3961
+ <div class="o-dv-container d-flex flex-column">
3962
+ <div class="o-dv-preview-description fw-bold text-truncate" t-esc="descriptionString"/>
3963
+ <div class="o-dv-preview-ranges text-truncate" t-esc="rangesString"/>
3964
+ </div>
3965
+ <div
3966
+ class="o-dv-preview-delete d-flex align-items-center text-muted px-3"
3967
+ t-on-click.stop="deleteDataValidation">
3968
+ <t t-call="o-spreadsheet-Icon.TRASH"/>
3969
+ </div>
3970
+ </div>
3971
+ </div>
3972
+ </t>
3973
+
3974
+ <t t-name="o-spreadsheet-FindAndReplacePanel">
3975
+ <div class="o-find-and-replace">
3976
+ <div class="o-section">
3977
+ <div class="o-section-title">Search</div>
3978
+ <div class="o-input-search-container">
3979
+ <input
3980
+ type="text"
3981
+ t-ref="searchInput"
3982
+ class="o-input o-input-with-count"
3983
+ t-on-input="onInput"
3984
+ t-on-keydown="onKeydownSearch"
3985
+ />
3986
+ <div class="o-input-count" t-if="hasSearchResult">
3987
+ <t t-esc="env.model.getters.getCurrentSelectedMatchIndex()+1"/>
3988
+ /
3989
+ <t t-esc="env.model.getters.getSearchMatches().length"/>
3990
+ </div>
3991
+ <div t-elif="!pendingSearch and state.toSearch !== ''" class="o-input-count">0 / 0</div>
3992
+ </div>
3993
+ <div>
3994
+ <!-- TODO: go through this css, the group misses a padding and could profit from BootStrap -->
3995
+ <label class="o-checkbox mt-1">
3996
+ <input
3997
+ t-model="state.searchOptions.matchCase"
3998
+ t-on-change="updateSearch"
3999
+ type="checkbox"
4000
+ />
4001
+ <span>Match case</span>
4002
+ </label>
4003
+ <label class="o-checkbox">
4004
+ <input
4005
+ t-model="state.searchOptions.exactMatch"
4006
+ t-on-change="updateSearch"
4007
+ type="checkbox"
4008
+ />
4009
+ <span>Match entire cell content</span>
4010
+ </label>
4011
+ <label class="o-checkbox">
4012
+ <input
4013
+ t-model="state.searchOptions.searchFormulas"
4014
+ t-on-change="searchFormulas"
4015
+ type="checkbox"
4016
+ />
4017
+ <span>Search in formulas</span>
4018
+ </label>
4019
+ </div>
4020
+ </div>
4021
+ <div class="o-sidePanelButtons">
4022
+ <button
4023
+ t-att-disabled="!hasSearchResult"
4024
+ t-on-click="onSelectPreviousCell"
4025
+ class="o-button">
4026
+ Previous
4027
+ </button>
4028
+ <button t-att-disabled="!hasSearchResult" t-on-click="onSelectNextCell" class="o-button">
4029
+ Next
4030
+ </button>
4031
+ </div>
4032
+ <div class="o-section" t-if="!env.model.getters.isReadonly()">
4033
+ <div class="o-section-title">Replace</div>
4034
+ <div class="o-input-search-container">
4035
+ <input
4036
+ type="text"
4037
+ class="o-input o-input-without-count"
4038
+ t-model="state.replaceWith"
4039
+ t-on-keydown="onKeydownReplace"
4040
+ />
4041
+ </div>
4042
+ </div>
4043
+
4044
+ <div class="o-sidePanelButtons" t-if="!env.model.getters.isReadonly()">
4045
+ <button
4046
+ t-att-disabled="env.model.getters.getCurrentSelectedMatchIndex() === null"
4047
+ t-on-click="replace"
4048
+ class="o-button">
4049
+ Replace
4050
+ </button>
4051
+ <button
4052
+ t-att-disabled="env.model.getters.getCurrentSelectedMatchIndex() === null"
4053
+ t-on-click="replaceAll"
4054
+ class="o-button">
4055
+ Replace all
4056
+ </button>
4057
+ </div>
4058
+ </div>
4059
+ </t>
4060
+
4061
+ <t t-name="o-spreadsheet-MoreFormatsPanel">
4062
+ <div class="o-more-formats-panel">
4063
+ <div
4064
+ t-foreach="dateFormatsActions"
4065
+ t-as="action"
4066
+ t-key="action.name(env)"
4067
+ t-att-data-name="action.name(env)"
4068
+ t-on-click="() => action.execute(env)"
4069
+ class="w-100 d-flex align-items-center border-bottom format-preview">
4070
+ <span class="ms-3 check-icon">
4071
+ <t t-if="action.isActive(env)" t-call="o-spreadsheet-Icon.CHECK"/>
4072
+ </span>
4073
+ <span t-out="action.description(env)"/>
4074
+ </div>
4075
+ </div>
4076
+ </t>
4077
+
4078
+ <t t-name="o-spreadsheet-RemoveDuplicatesPanel">
4079
+ <div class="o-remove-duplicates">
4080
+ <div class="o-section">
4081
+ <div class="o-section-subtitle" t-esc="selectionStatisticalInformation"/>
4082
+ <label class="o-checkbox">
4083
+ <input type="checkbox" t-att-checked="state.hasHeader" t-on-change="toggleHasHeader"/>
4084
+ Data has header row
4085
+ </label>
4086
+ </div>
4087
+
4088
+ <div class="o-section">
4089
+ <div class="o-section-title">Columns to analyze</div>
4090
+ <div class="o-checkbox-selection overflow-auto p-3 vh-50 border rounded">
4091
+ <label class="o-checkbox">
4092
+ <input
4093
+ t-att-checked="isEveryColumnSelected"
4094
+ t-on-change="toggleAllColumns"
4095
+ type="checkbox"
4096
+ />
4097
+ Select all
4098
+ </label>
4099
+
4100
+ <t t-foreach="Object.keys(state.columns)" t-as="colIndex" t-key="colIndex">
4101
+ <label class="o-checkbox">
4102
+ <input
4103
+ type="checkbox"
4104
+ t-att-checked="state.columns[colIndex]"
4105
+ t-on-change="() => this.toggleColumn(colIndex)"
4106
+ />
4107
+ <t t-esc="getColLabel(colIndex)"/>
4108
+ </label>
4109
+ </t>
4110
+ </div>
4111
+ </div>
4112
+
4113
+ <div class="o-sidePanelButtons">
4114
+ <button
4115
+ class="o-button"
4116
+ t-att-class="{'o-disabled': !canConfirm}"
4117
+ t-on-click="onRemoveDuplicates">
4118
+ Remove duplicates
4119
+ </button>
4120
+ </div>
4121
+
4122
+ <div class="o-section" t-if="errorMessages.length">
4123
+ <ValidationMessages messages="errorMessages" msgType="'error'"/>
4124
+ </div>
4125
+ </div>
4126
+ </t>
4127
+
4128
+ <t t-name="o-spreadsheet-SelectMenu">
4129
+ <select
4130
+ t-att-class="props.class"
4131
+ t-ref="select"
4132
+ t-on-mousedown.stop.prevent=""
4133
+ t-on-click="onClick">
4134
+ <option selected="true" t-esc="props.selectedValue"/>
4135
+ </select>
4136
+ <Menu
4137
+ t-if="state.isMenuOpen"
4138
+ menuItems="props.menuItems"
4139
+ position="menuPosition"
4140
+ onClose.bind="onMenuClosed"
4141
+ />
4142
+ </t>
4143
+
4144
+ <t t-name="o-spreadsheet-SettingsPanel">
4145
+ <div class="o-settings-panel">
4146
+ <div class="o-section">
4147
+ <div class="o-section-title">Locale</div>
4148
+ <select
4149
+ class="o-input o-type-selector"
4150
+ t-on-change="(ev) => this.onLocaleChange(ev.target.value)">
4151
+ <option
4152
+ t-foreach="supportedLocales"
4153
+ t-as="locale"
4154
+ t-key="locale.code"
4155
+ t-att-value="locale.code"
4156
+ t-esc="locale.name"
4157
+ t-att-selected="currentLocale.code === locale.code"
4158
+ />
4159
+ </select>
4160
+ <div class="o-locale-preview mt-2 ms-3">
4161
+ <div>
4162
+ <span class="fw-bold me-1">Number:</span>
4163
+ <span t-esc="numberFormatPreview"/>
4164
+ </div>
4165
+ <div>
4166
+ <span class="fw-bold me-1">Date:</span>
4167
+ <span t-esc="dateFormatPreview"/>
4168
+ </div>
4169
+ <div>
4170
+ <span class="fw-bold me-1">Date time:</span>
4171
+ <span t-esc="dateTimeFormatPreview"/>
4172
+ </div>
4173
+ </div>
4174
+ </div>
4175
+ </div>
4176
+ </t>
4177
+
4178
+ <t t-name="o-spreadsheet-SidePanel">
4179
+ <div class="o-sidePanel">
4180
+ <div class="o-sidePanelHeader">
4181
+ <div class="o-sidePanelTitle" t-esc="getTitle()"/>
4182
+ <div class="o-sidePanelClose" t-on-click="() => this.props.onCloseSidePanel()">✕</div>
4183
+ </div>
4184
+ <div class="o-sidePanelBody">
4185
+ <t
4186
+ t-component="state.panel.Body"
4187
+ t-props="props.panelProps"
4188
+ onCloseSidePanel="props.onCloseSidePanel"
4189
+ t-key="'Body_' + props.component"
4190
+ />
4191
+ </div>
4192
+ <div class="o-sidePanelFooter" t-if="state.panel.Footer">
4193
+ <t
4194
+ t-component="state.panel.Footer"
4195
+ t-props="props.panelProps"
4196
+ t-key="'Footer_' + props.component"
4197
+ />
4198
+ </div>
4199
+ </div>
4200
+ </t>
4201
+
4202
+ <t t-name="o-spreadsheet-SplitIntoColumnsPanel">
4203
+ <div class="o-split-to-cols-panel">
4204
+ <div class="o-section">
4205
+ <div class="o-section-title">Separator</div>
4206
+ <select
4207
+ class="o-input o-type-selector"
4208
+ t-on-change="(ev) => this.onSeparatorChange(ev.target.value)">
4209
+ <option
4210
+ t-foreach="separators"
4211
+ t-as="separator"
4212
+ t-key="separator.value"
4213
+ t-att-value="separator.value"
4214
+ t-esc="separator.name"
4215
+ t-att-selected="state.separatorValue === separator.value"
4216
+ />
4217
+ </select>
4218
+
4219
+ <input
4220
+ class="o-input o-required mt-3"
4221
+ type="text"
4222
+ t-if="state.separatorValue === 'custom'"
4223
+ t-att-value="state.customSeparator"
4224
+ t-on-input="updateCustomSeparator"
4225
+ placeholder="Add any characters or symbol"
4226
+ />
4227
+
4228
+ <label class="o-checkbox">
4229
+ <input
4230
+ type="checkbox"
4231
+ name="add columns"
4232
+ t-att-checked="state.addNewColumns"
4233
+ t-on-change="updateAddNewColumnsCheckbox"
4234
+ />
4235
+ Add new columns to avoid overwriting cells
4236
+ </label>
4237
+
4238
+ <div class="o-sidePanelButtons">
4239
+ <button
4240
+ class="o-button"
4241
+ t-att-class="{'o-disabled': isConfirmDisabled}"
4242
+ t-on-click="confirm">
4243
+ Confirm
4244
+ </button>
4245
+ </div>
4246
+
4247
+ <ValidationMessages messages="errorMessages" msgType="'error'"/>
4248
+ <ValidationMessages messages="warningMessages" msgType="'warning'"/>
4249
+ </div>
4250
+ </div>
4251
+ </t>
4252
+
4253
+ <t t-name="o-spreadsheet-Spreadsheet">
4254
+ <div
4255
+ class="o-spreadsheet"
4256
+ t-on-keydown="(ev) => !env.isDashboard() and this.onKeydown(ev)"
4257
+ t-att-style="getStyle()">
4258
+ <t t-if="env.isDashboard()">
4259
+ <SpreadsheetDashboard/>
4260
+ </t>
4261
+ <t t-else="">
4262
+ <TopBar
4263
+ onClick="() => this.focusGrid()"
4264
+ onComposerContentFocused="(selection) => this.onTopBarComposerFocused(selection)"
4265
+ focusComposer="focusTopBarComposer"
4266
+ dropdownMaxHeight="gridHeight"
4267
+ />
4268
+ <div
4269
+ class="o-grid-container"
4270
+ t-att-class="{'o-two-columns': !sidePanel.isOpen}"
4271
+ t-att-style="gridContainerStyle"
4272
+ t-on-click="this.focusGrid">
4273
+ <div class="o-top-left"/>
4274
+ <div class="o-column-groups">
4275
+ <HeaderGroupContainer layers="colLayers" dimension="'COL'"/>
4276
+ </div>
4277
+ <div class="o-row-groups">
4278
+ <HeaderGroupContainer layers="rowLayers" dimension="'ROW'"/>
4279
+ </div>
4280
+ <div class="o-group-grid overflow-hidden">
4281
+ <Grid
4282
+ sidePanelIsOpen="sidePanel.isOpen"
4283
+ focusComposer="focusGridComposer"
4284
+ exposeFocus="(focus) => this._focusGrid = focus"
4285
+ onComposerContentFocused="() => this.onGridComposerContentFocused()"
4286
+ onGridComposerCellFocused="(content, selection) => this.onGridComposerCellFocused(content, selection)"
4287
+ />
4288
+ </div>
4289
+ </div>
4290
+ <SidePanel
4291
+ t-if="sidePanel.isOpen"
4292
+ onCloseSidePanel="() => this.closeSidePanel()"
4293
+ component="sidePanel.component"
4294
+ panelProps="sidePanel.panelProps"
4295
+ />
4296
+ <BottomBar onClick="() => this.focusGrid()"/>
4297
+ </t>
4298
+ </div>
4299
+ </t>
4300
+
4301
+ <t t-name="o-spreadsheet-TopBar">
4302
+ <t t-set="text_color">Text Color</t>
4303
+ <t t-set="fill_color">Fill Color</t>
4304
+ <div
4305
+ class="o-spreadsheet-topbar o-two-columns d-flex flex-column user-select-none"
4306
+ t-on-click="props.onClick">
4307
+ <div class="o-topbar-top d-flex justify-content-between">
4308
+ <!-- Menus -->
4309
+ <div class="o-topbar-topleft d-flex">
4310
+ <t t-foreach="menus" t-as="menu" t-key="menu_index">
4311
+ <div
4312
+ t-if="menu.children.length !== 0"
4313
+ class="o-topbar-menu o-hoverable-button rounded"
4314
+ t-att-class="{'active': state.menuState.parentMenu and state.menuState.parentMenu.id === menu.id}"
4315
+ t-on-click="(ev) => this.toggleContextMenu(menu, ev)"
4316
+ t-on-mouseover="(ev) => this.onMenuMouseOver(menu, ev)"
4317
+ t-att-data-id="menu.id">
4318
+ <t t-esc="getMenuName(menu)"/>
4319
+ </div>
4320
+ </t>
4321
+ </div>
4322
+ <div class="o-topbar-topright d-flex justify-content-end">
4323
+ <div t-foreach="topbarComponents" t-as="comp" t-key="comp.id">
4324
+ <t t-component="comp.component"/>
4325
+ </div>
4326
+ </div>
4327
+ </div>
4328
+ <!-- Toolbar and Cell Content -->
4329
+ <div class="d-flex">
4330
+ <div class="o-topbar-toolbar d-flex flex-shrink-0">
4331
+ <!-- Toolbar -->
4332
+ <div
4333
+ t-if="env.model.getters.isReadonly()"
4334
+ class="o-readonly-toolbar d-flex align-items-center text-muted">
4335
+ <span>
4336
+ <i class="fa fa-eye"/>
4337
+ Readonly Access
4338
+ </span>
4339
+ </div>
4340
+ <div t-else="" class="o-toolbar-tools d-flex flex-shrink-0 ms-4">
4341
+ <ActionButton action="EDIT.undo" class="'o-hoverable-button'"/>
4342
+ <ActionButton action="EDIT.redo" class="'o-hoverable-button'"/>
4343
+ <PaintFormatButton class="'o-hoverable-button'"/>
4344
+ <ActionButton action="FORMAT.clearFormat" class="'o-hoverable-button'"/>
4345
+
4346
+ <div class="o-divider"/>
4347
+
4348
+ <ActionButton action="FORMAT.formatPercent" class="'o-hoverable-button'"/>
4349
+ <ActionButton action="FORMAT.decraseDecimalPlaces" class="'o-hoverable-button'"/>
4350
+ <ActionButton action="FORMAT.incraseDecimalPlaces" class="'o-hoverable-button'"/>
4351
+ <ActionButton
4352
+ action="formatNumberMenuItemSpec"
4353
+ onClick="(ev) => this.toggleToolbarContextMenu(formatNumberMenuItemSpec, ev)"
4354
+ hasTriangleDownIcon="true"
4355
+ class="'o-hoverable-button'"
4356
+ />
4357
+
4358
+ <div class="o-divider"/>
4359
+ <FontSizeEditor
4360
+ class="'o-hoverable-button'"
4361
+ onToggle.bind="this.onClick"
4362
+ dropdownStyle="this.dropdownStyle"
4363
+ />
4364
+ <div class="o-divider"/>
4365
+
4366
+ <ActionButton action="FORMAT.formatBold" class="'o-hoverable-button'"/>
4367
+ <ActionButton action="FORMAT.formatItalic" class="'o-hoverable-button'"/>
4368
+ <ActionButton action="FORMAT.formatStrikethrough" class="'o-hoverable-button'"/>
4369
+
4370
+ <ColorPickerWidget
4371
+ currentColor="state.textColor"
4372
+ toggleColorPicker="(ev) => this.toggleDropdownTool('textColorTool', ev)"
4373
+ showColorPicker="state.activeTool === 'textColorTool'"
4374
+ onColorPicked="(color) => this.setColor('textColor', color)"
4375
+ title="text_color"
4376
+ icon="'o-spreadsheet-Icon.TEXT_COLOR'"
4377
+ dropdownMaxHeight="this.props.dropdownMaxHeight"
4378
+ class="'o-hoverable-button o-menu-item-button'"
4379
+ />
4380
+
4381
+ <div class="o-divider"/>
4382
+
4383
+ <ColorPickerWidget
4384
+ currentColor="state.fillColor"
4385
+ toggleColorPicker="(ev) => this.toggleDropdownTool('fillColorTool', ev)"
4386
+ showColorPicker="state.activeTool === 'fillColorTool'"
4387
+ onColorPicked="(color) => this.setColor('fillColor', color)"
4388
+ title="fill_color"
4389
+ icon="'o-spreadsheet-Icon.FILL_COLOR'"
4390
+ dropdownMaxHeight="this.props.dropdownMaxHeight"
4391
+ class="'o-hoverable-button o-menu-item-button'"
4392
+ />
4393
+
4394
+ <BorderEditorWidget
4395
+ class="'o-hoverable-button o-menu-item-button'"
4396
+ toggleBorderEditor="(ev) => this.toggleDropdownTool('borderTool', ev)"
4397
+ showBorderEditor="state.activeTool === 'borderTool'"
4398
+ dropdownMaxHeight="this.props.dropdownMaxHeight"
4399
+ />
4400
+ <ActionButton action="EDIT.mergeCells" class="'o-hoverable-button'"/>
4401
+ <div class="o-divider"/>
4402
+
4403
+ <div class="o-dropdown">
4404
+ <ActionButton
4405
+ action="FORMAT.formatAlignmentHorizontal"
4406
+ hasTriangleDownIcon="true"
4407
+ t-on-click="(ev) => this.toggleDropdownTool('horizontalAlignTool', ev)"
4408
+ class="'o-hoverable-button'"
4409
+ />
4410
+ <div
4411
+ class="o-dropdown-content"
4412
+ t-if="state.activeTool === 'horizontalAlignTool'"
4413
+ t-att-style="dropdownStyle"
4414
+ t-on-click.stop="">
4415
+ <div class="o-dropdown-line">
4416
+ <ActionButton action="FORMAT.formatAlignmentLeft" class="'o-hoverable-button'"/>
4417
+ <ActionButton action="FORMAT.formatAlignmentCenter" class="'o-hoverable-button'"/>
4418
+ <ActionButton action="FORMAT.formatAlignmentRight" class="'o-hoverable-button'"/>
4419
+ </div>
4420
+ </div>
4421
+ </div>
4422
+ <div class="o-dropdown">
4423
+ <ActionButton
4424
+ action="FORMAT.formatAlignmentVertical"
4425
+ hasTriangleDownIcon="true"
4426
+ t-on-click="(ev) => this.toggleDropdownTool('verticalAlignTool', ev)"
4427
+ class="'o-hoverable-button'"
4428
+ />
4429
+ <div
4430
+ class="o-dropdown-content"
4431
+ t-att-style="dropdownStyle"
4432
+ t-if="state.activeTool === 'verticalAlignTool'"
4433
+ t-on-click.stop="">
4434
+ <div class="o-dropdown-line">
4435
+ <ActionButton action="FORMAT.formatAlignmentTop" class="'o-hoverable-button'"/>
4436
+ <ActionButton action="FORMAT.formatAlignmentMiddle" class="'o-hoverable-button'"/>
4437
+ <ActionButton action="FORMAT.formatAlignmentBottom" class="'o-hoverable-button'"/>
4438
+ </div>
4439
+ </div>
4440
+ </div>
4441
+ <div class="o-dropdown">
4442
+ <ActionButton
4443
+ action="FORMAT.formatWrapping"
4444
+ hasTriangleDownIcon="true"
4445
+ t-on-click="(ev) => this.toggleDropdownTool('textWrappingTool', ev)"
4446
+ class="'o-hoverable-button'"
4447
+ />
4448
+ <div
4449
+ class="o-dropdown-content"
4450
+ t-att-style="dropdownStyle"
4451
+ t-if="state.activeTool === 'textWrappingTool'"
4452
+ t-on-click.stop="">
4453
+ <div class="o-dropdown-line">
4454
+ <ActionButton
4455
+ action="FORMAT.formatWrappingOverflow"
4456
+ class="'o-hoverable-button'"
4457
+ />
4458
+ <ActionButton action="FORMAT.formatWrappingWrap" class="'o-hoverable-button'"/>
4459
+ <ActionButton action="FORMAT.formatWrappingClip" class="'o-hoverable-button'"/>
4460
+ </div>
4461
+ </div>
4462
+ </div>
4463
+
4464
+ <div class="o-divider"/>
4465
+
4466
+ <ActionButton action="VIEW.createRemoveFilter" class="'o-hoverable-button'"/>
4467
+ </div>
4468
+ </div>
4469
+ <TopBarComposer
4470
+ focus="props.focusComposer"
4471
+ onComposerContentFocused="props.onComposerContentFocused"
4472
+ />
4473
+ </div>
4474
+ </div>
4475
+ <Menu
4476
+ t-if="state.menuState.isOpen"
4477
+ position="state.menuState.position"
4478
+ menuItems="state.menuState.menuItems"
4479
+ onClose="() => this.closeMenus()"
4480
+ onMenuClicked="() => this.props.onClick()"
4481
+ />
4482
+ </t>
4483
+
4484
+ <t t-name="o-spreadsheet-ValidationMessages">
4485
+ <t t-foreach="props.messages" t-as="msg" t-key="msg">
4486
+ <div class="d-flex align-items-center o-side-panel-error" t-att-class="divClasses">
4487
+ <t t-call="o-spreadsheet-Icon.TRIANGLE_EXCLAMATION"/>
4488
+ <span t-esc="msg"/>
4489
+ </div>
4490
+ </t>
4491
+ </t>
4492
+ </odoo>