88 @touchstart =" startTouchDrag"
99 >
1010 <div
11- v-if =" isSelected || isDraw"
11+ v-if =" isSelected || isDraw || isInMultiSelection "
1212 class =" top-0 bottom-0 right-0 left-0 absolute border border-1.5 pointer-events-none"
1313 :class =" activeBorderClasses"
1414 />
2424 :style =" { left: (cellW / area.w * 100) + '%' }"
2525 >
2626 <span
27- v-if =" index === 0 && editable"
27+ v-if =" index === 0 && editable && !isInMultiSelection "
2828 class =" h-2.5 w-2.5 rounded-full -bottom-1 border-gray-400 bg-white shadow-md border absolute cursor-ew-resize z-10"
2929 style =" left : -4px "
3030 @mousedown.stop =" startResizeCell"
3131 />
3232 </div >
3333 </div >
3434 <div
35- v-if =" field?.type && (isSelected || isNameFocus)"
35+ v-if =" field?.type && (isSelected || isNameFocus) && !isInMultiSelection "
3636 class =" absolute bg-white rounded-t border overflow-visible whitespace-nowrap flex z-10 field-area-controls"
3737 style =" top : -25px ; height : 25px "
3838 @mousedown.stop
4848 :menu-classes =" 'dropdown-content bg-white menu menu-xs p-2 shadow rounded-box w-52 rounded-t-none -left-[1px] mt-[1px]'"
4949 :submitters =" template.submitters"
5050 @update:model-value =" save"
51- @click =" selectedAreaRef .value = area"
51+ @click =" selectedAreasRef .value = [ area] "
5252 />
5353 <FieldType
5454 v-model =" field.type"
5757 :button-classes =" 'px-1'"
5858 :menu-classes =" 'bg-white rounded-t-none'"
5959 @update:model-value =" [maybeUpdateOptions(), save()]"
60- @click =" selectedAreaRef .value = area"
60+ @click =" selectedAreasRef .value = [ area] "
6161 />
6262 <span
6363 v-if =" field.type !== 'checkbox' || field.name"
146146 @click-font =" isShowFontModal = true"
147147 @click-description =" isShowDescriptionModal = true"
148148 @click-condition =" isShowConditionsModal = true"
149- @scroll-to =" [selectedAreaRef .value = $event, $emit('scroll-to', $event)]"
149+ @scroll-to =" [selectedAreasRef .value = [ $event] , $emit('scroll-to', $event)]"
150150 />
151151 </ul >
152152 </span >
266266 ref =" defaultValueSelect"
267267 class =" bg-transparent outline-none focus:outline-none w-full"
268268 @change =" [field.default_value = $event.target.value, field.readonly = !!field.default_value?.length, save()]"
269- @focus =" selectedAreaRef .value = area"
269+ @focus =" selectedAreasRef .value = [ area] "
270270 @keydown.enter =" onDefaultValueEnter"
271271 >
272272 <option
293293 :class =" { 'cursor-text': isValueInput }"
294294 :placeholder =" withFieldPlaceholder && !isValueInput ? defaultField?.title || field.title || field.name || defaultName : (field.type === 'date' ? field.preferences?.format || t('type_value') : t('type_value'))"
295295 @blur =" onDefaultValueBlur"
296- @focus =" selectedAreaRef .value = area"
296+ @focus =" selectedAreasRef .value = [ area] "
297297 @paste.prevent =" onPaste"
298298 @keydown.enter =" onDefaultValueEnter"
299299 >{{ field.default_value }}</span >
319319 <span
320320 v-if =" field?.type && editable"
321321 class =" h-4 w-4 lg:h-2.5 lg:w-2.5 -right-1 rounded-full -bottom-1 border-gray-400 bg-white shadow-md border absolute cursor-nwse-resize"
322+ :class =" { 'z-30': isInMultiSelection }"
322323 @mousedown.stop =" startResize"
323324 @touchstart =" startTouchResize"
324325 />
@@ -398,7 +399,7 @@ export default {
398399 FieldSubmitter,
399400 IconX
400401 },
401- inject: [' template' , ' selectedAreaRef ' , ' save ' , ' t ' , ' isInlineSize ' ],
402+ inject: [' template' , ' save ' , ' t ' , ' isInlineSize ' , ' selectedAreasRef ' , ' isCmdKeyRef ' ],
402403 props: {
403404 area: {
404405 type: Object ,
@@ -463,6 +464,11 @@ export default {
463464 type: Object ,
464465 required: false ,
465466 default: null
467+ },
468+ isSelectMode: {
469+ type: Boolean ,
470+ required: false ,
471+ default: false
466472 }
467473 },
468474 emits: [' start-resize' , ' stop-resize' , ' start-drag' , ' stop-drag' , ' remove' , ' scroll-to' ],
@@ -646,7 +652,10 @@ export default {
646652 ]
647653 },
648654 isSelected () {
649- return this .selectedAreaRef .value === this .area
655+ return this .selectedAreasRef .value .includes (this .area )
656+ },
657+ isInMultiSelection () {
658+ return this .selectedAreasRef .value .length >= 2 && this .isSelected
650659 },
651660 positionStyle () {
652661 const { x , y , w , h } = this .area
@@ -683,10 +692,10 @@ export default {
683692 buildAreaOptionValue (area ) {
684693 const option = this .optionsUuidIndex [area .option_uuid ]
685694
686- return option .value || ` ${ this .t (' option' )} ${ this .field .options .indexOf (option) + 1 } `
695+ return option? .value || ` ${ this .t (' option' )} ${ this .field .options .indexOf (option) + 1 } `
687696 },
688697 maybeToggleDefaultValue () {
689- if (! this .editable ) {
698+ if (! this .editable || this . isCmdKeyRef . value ) {
690699 return
691700 }
692701
@@ -770,7 +779,7 @@ export default {
770779 }
771780 },
772781 onNameFocus (e ) {
773- this .selectedAreaRef .value = this .area
782+ this .selectedAreasRef .value = [ this .area ]
774783
775784 this .isNameFocus = true
776785 this .$refs .name .style .minWidth = this .$refs .name .clientWidth + ' px'
@@ -906,6 +915,15 @@ export default {
906915 if (e .target .id === ' mask' ) {
907916 this .area .w = e .offsetX / e .target .clientWidth - this .area .x
908917 this .area .h = e .offsetY / e .target .clientHeight - this .area .y
918+
919+ if (this .isInMultiSelection ) {
920+ this .selectedAreasRef .value .forEach ((area ) => {
921+ if (area !== this .area ) {
922+ area .w = this .area .w
923+ area .h = this .area .h
924+ }
925+ })
926+ }
909927 }
910928 },
911929 drag (e ) {
@@ -931,7 +949,7 @@ export default {
931949
932950 const rect = e .target .getBoundingClientRect ()
933951
934- this .selectedAreaRef .value = this .area
952+ this .selectedAreasRef .value = [ this .area ]
935953
936954 this .dragFrom = { x: rect .left - e .touches [0 ].clientX , y: rect .top - e .touches [0 ].clientY }
937955
@@ -980,13 +998,23 @@ export default {
980998
981999 e .preventDefault ()
9821000
1001+ if (e .metaKey || e .ctrlKey ) {
1002+ if (! this .selectedAreasRef .value .includes (this .area )) {
1003+ this .selectedAreasRef .value .push (this .area )
1004+ } else {
1005+ this .selectedAreasRef .value .splice (this .selectedAreasRef .value .indexOf (this .area ), 1 )
1006+ }
1007+
1008+ return
1009+ }
1010+
9831011 if (this .editable ) {
9841012 this .isDragged = true
9851013 }
9861014
9871015 const rect = e .target .getBoundingClientRect ()
9881016
989- this .selectedAreaRef .value = this .area
1017+ this .selectedAreasRef .value = [ this .area ]
9901018
9911019 this .dragFrom = { x: rect .left - e .clientX , y: rect .top - e .clientY }
9921020
@@ -1055,7 +1083,9 @@ export default {
10551083 this .$emit (' stop-drag' )
10561084 },
10571085 startResize () {
1058- this .selectedAreaRef .value = this .area
1086+ if (! this .selectedAreasRef .value .includes (this .area )) {
1087+ this .selectedAreasRef .value = [this .area ]
1088+ }
10591089
10601090 this .$el .getRootNode ().addEventListener (' mousemove' , this .resize )
10611091 this .$el .getRootNode ().addEventListener (' mouseup' , this .stopResize )
@@ -1071,7 +1101,9 @@ export default {
10711101 this .save ()
10721102 },
10731103 startTouchResize (e ) {
1074- this .selectedAreaRef .value = this .area
1104+ if (! this .selectedAreasRef .value .includes (this .area )) {
1105+ this .selectedAreasRef .value = [this .area ]
1106+ }
10751107
10761108 this .$refs ? .name ? .blur ()
10771109
@@ -1088,6 +1120,15 @@ export default {
10881120
10891121 this .area .w = (e .touches [0 ].clientX - rect .left ) / rect .width - this .area .x
10901122 this .area .h = (e .touches [0 ].clientY - rect .top ) / rect .height - this .area .y
1123+
1124+ if (this .isInMultiSelection ) {
1125+ this .selectedAreasRef .value .forEach ((area ) => {
1126+ if (area !== this .area ) {
1127+ area .w = this .area .w
1128+ area .h = this .area .h
1129+ }
1130+ })
1131+ }
10911132 },
10921133 stopTouchResize () {
10931134 this .$el .getRootNode ().removeEventListener (' touchmove' , this .touchResize )
0 commit comments