renusify 2.5.1 → 3.0.0

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.
Files changed (212) hide show
  1. package/components/app/index.vue +74 -22
  2. package/components/app/toast/index.vue +76 -71
  3. package/components/app/toast/toast.vue +62 -44
  4. package/components/avatar/index.vue +208 -84
  5. package/components/button/buttonConfirm.vue +53 -26
  6. package/components/button/buttonGroup.js +0 -2
  7. package/components/button/buttonGroup.vue +310 -62
  8. package/components/button/index.vue +584 -100
  9. package/components/calendar/index.js +0 -2
  10. package/components/calendar/index.vue +326 -262
  11. package/components/calendar/month.vue +64 -55
  12. package/components/calendar/year.vue +30 -25
  13. package/components/card/index.vue +139 -59
  14. package/components/codeEditor/highlightCss.vue +38 -39
  15. package/components/codeEditor/highlightHtml.vue +64 -64
  16. package/components/codeEditor/highlightJs.vue +37 -38
  17. package/components/codeEditor/index.vue +129 -79
  18. package/components/codeEditor/run.vue +225 -39
  19. package/components/codeEditor/useCodeFormatter.js +150 -0
  20. package/components/confirm/index.vue +140 -81
  21. package/components/container/col.vue +5 -4
  22. package/components/container/divider.vue +28 -19
  23. package/components/container/index.vue +34 -15
  24. package/components/container/row.vue +26 -9
  25. package/components/container/spacer.vue +2 -4
  26. package/components/container/style.scss +3 -0
  27. package/components/content/index.vue +49 -32
  28. package/components/cropper/index.vue +401 -244
  29. package/components/float/index.vue +542 -415
  30. package/components/form/addressInput/index.vue +184 -109
  31. package/components/form/camInput/index.vue +370 -244
  32. package/components/form/checkInput/index.vue +138 -71
  33. package/components/form/checkboxInput/index.vue +87 -47
  34. package/components/form/colorInput/Alpha.vue +81 -83
  35. package/components/form/colorInput/Hue.vue +91 -68
  36. package/components/form/colorInput/Preview.vue +43 -47
  37. package/components/form/colorInput/Saturation.vue +101 -86
  38. package/components/form/colorInput/index.vue +72 -40
  39. package/components/form/colorInput/picker.vue +111 -106
  40. package/components/form/colorInput/useColor.js +153 -0
  41. package/components/form/dateInput/index.vue +691 -356
  42. package/components/form/dateInput/month.vue +63 -54
  43. package/components/form/dateInput/year.vue +35 -25
  44. package/components/form/fileInput/index.js +0 -1
  45. package/components/form/fileInput/index.vue +263 -106
  46. package/components/form/fileInput/single.vue +323 -164
  47. package/components/form/groupInput/index.vue +199 -101
  48. package/components/form/index.vue +189 -83
  49. package/components/form/input/index.vue +416 -377
  50. package/components/form/jsonInput/JsonView.vue +54 -56
  51. package/components/form/jsonInput/index.vue +247 -165
  52. package/components/form/maskInput/index.vue +252 -132
  53. package/components/form/numberInput/index.js +0 -1
  54. package/components/form/numberInput/index.vue +226 -117
  55. package/components/form/passwordInput/index.js +2 -1
  56. package/components/form/passwordInput/index.vue +269 -102
  57. package/components/form/radioInput/index.vue +143 -72
  58. package/components/form/rangeInput/index.vue +280 -167
  59. package/components/form/ratingInput/index.vue +57 -57
  60. package/components/form/selectInput/index.js +1 -3
  61. package/components/form/selectInput/index.vue +584 -296
  62. package/components/form/switchInput/index.vue +73 -59
  63. package/components/form/telInput/index.js +0 -1
  64. package/components/form/telInput/index.vue +238 -135
  65. package/components/form/textArea/index.vue +72 -35
  66. package/components/form/textEditor/index.vue +739 -0
  67. package/components/form/{text-editor → textEditor}/style.scss +8 -16
  68. package/components/form/textInput/index.vue +54 -32
  69. package/components/form/timeInput/index.vue +83 -56
  70. package/components/form/timeInput/range.vue +116 -95
  71. package/components/form/timeInput/timepicker.vue +382 -449
  72. package/components/form/uniqueInput/index.vue +105 -48
  73. package/components/form/unitInput/index.vue +139 -84
  74. package/components/formCreator/index.js +0 -1
  75. package/components/formCreator/index.vue +314 -148
  76. package/components/highlight/index.vue +41 -25
  77. package/components/highlight/style.scss +2 -2
  78. package/components/highlight/{mixin.js → useHighlight.js} +181 -160
  79. package/components/icon/index.vue +79 -33
  80. package/components/img/index.vue +249 -147
  81. package/components/img/preview.vue +180 -198
  82. package/components/img/svgImg.vue +42 -39
  83. package/components/index.js +5 -20
  84. package/components/infinite/index.js +1 -2
  85. package/components/infinite/index.vue +248 -66
  86. package/components/map/index.vue +428 -261
  87. package/components/map/route.vue +794 -487
  88. package/components/map/select.vue +118 -58
  89. package/components/menu/index.vue +201 -91
  90. package/components/meta/meta.js +26 -3
  91. package/components/modal/index.vue +383 -158
  92. package/components/notify/index.vue +204 -86
  93. package/components/notify/notification.vue +38 -55
  94. package/components/progress/circle.vue +189 -70
  95. package/components/progress/line.vue +266 -46
  96. package/components/searchBox/index.js +1 -3
  97. package/components/searchBox/index.vue +194 -101
  98. package/components/skeleton/index.vue +45 -20
  99. package/components/slider/index.vue +318 -156
  100. package/components/swiper/index.vue +254 -106
  101. package/components/table/crud/footer.vue +77 -53
  102. package/components/table/crud/header.vue +71 -72
  103. package/components/table/crud/index.vue +631 -401
  104. package/components/table/index.vue +721 -278
  105. package/components/timeAgo/index.vue +145 -96
  106. package/components/tour/index.vue +338 -235
  107. package/components/tree/index.vue +235 -89
  108. package/components/tree/tree-element.vue +107 -106
  109. package/directive/animate/index.js +77 -0
  110. package/directive/clickOutSide/index.js +98 -0
  111. package/directive/drag/index.js +153 -0
  112. package/directive/index.js +11 -13
  113. package/directive/intersect/index.js +263 -0
  114. package/directive/mask/index.js +67 -0
  115. package/directive/parallax/index.js +78 -0
  116. package/directive/ripple/index.js +14 -0
  117. package/directive/scroll/index.js +244 -0
  118. package/directive/sortable/index.js +274 -0
  119. package/directive/title/index.js +75 -0
  120. package/directive/touch/index.js +268 -0
  121. package/index.js +10 -8
  122. package/package.json +5 -2
  123. package/plugins/validation/Validate.js +88 -79
  124. package/scripts/generate-docs.mjs +226 -0
  125. package/scripts/menu.mjs +240 -0
  126. package/scripts/parser.mjs +1086 -0
  127. package/style/_index.scss +7 -0
  128. package/style/app.scss +13 -65
  129. package/style/colors.scss +5 -22
  130. package/style/functions/index.scss +8 -0
  131. package/style/mixins/index.scss +17 -5
  132. package/style/variables/base.scss +154 -175
  133. package/style/variables/color.scss +0 -12
  134. package/style/variables/utilities.scss +0 -180
  135. package/tools/helper.js +0 -8
  136. package/tools/icons.js +6 -1
  137. package/tools/root.js +71 -0
  138. package/components/app/style.scss +0 -41
  139. package/components/app/toast/style.scss +0 -20
  140. package/components/avatar/style.scss +0 -32
  141. package/components/bar/bottomNav.js +0 -1
  142. package/components/bar/bottomNav.vue +0 -28
  143. package/components/bar/bottomNavigationCircle.js +0 -2
  144. package/components/bar/bottomNavigationCircle.vue +0 -99
  145. package/components/bar/scss/bottomNav.scss +0 -67
  146. package/components/bar/scss/toolbar.scss +0 -174
  147. package/components/bar/toolbar/index.js +0 -8
  148. package/components/bar/toolbar/index.vue +0 -35
  149. package/components/bar/toolbar/laptop.vue +0 -33
  150. package/components/bar/toolbar/menuChilds.vue +0 -41
  151. package/components/bar/toolbar/menuLaptop.vue +0 -41
  152. package/components/bar/toolbar/menuMob.vue +0 -39
  153. package/components/bar/toolbar/mixin.js +0 -43
  154. package/components/bar/toolbar/mobile.vue +0 -34
  155. package/components/breadcrumb/bredcrumbItem.vue +0 -39
  156. package/components/breadcrumb/index.js +0 -3
  157. package/components/breadcrumb/index.vue +0 -71
  158. package/components/breadcrumb/style.scss +0 -51
  159. package/components/button/style.scss +0 -411
  160. package/components/card/style.scss +0 -86
  161. package/components/chart/chart.js +0 -1
  162. package/components/chart/chart.vue +0 -69
  163. package/components/chart/worldMap.js +0 -2
  164. package/components/chart/worldMap.vue +0 -1112
  165. package/components/chat/MessageList.vue +0 -163
  166. package/components/chat/chatInput.vue +0 -150
  167. package/components/chat/chatMsg.vue +0 -276
  168. package/components/chat/index.js +0 -11
  169. package/components/chat/index.vue +0 -113
  170. package/components/chip/index.js +0 -3
  171. package/components/chip/index.vue +0 -77
  172. package/components/chip/style.scss +0 -199
  173. package/components/codeEditor/mixin.js +0 -145
  174. package/components/countdown/index.js +0 -1
  175. package/components/countdown/index.vue +0 -105
  176. package/components/form/colorInput/mixin.js +0 -132
  177. package/components/form/fileInput/file.js +0 -148
  178. package/components/form/telInput/assets/flags.png +0 -0
  179. package/components/form/telInput/assets/flags@2x.png +0 -0
  180. package/components/form/text-editor/index.vue +0 -710
  181. package/components/icon/style.scss +0 -17
  182. package/components/infinite/div.js +0 -6
  183. package/components/infinite/div.vue +0 -193
  184. package/components/infinite/page.js +0 -3
  185. package/components/infinite/page.vue +0 -105
  186. package/components/list/index.js +0 -3
  187. package/components/list/index.vue +0 -122
  188. package/components/list/style.scss +0 -66
  189. package/components/message/index.js +0 -4
  190. package/components/message/index.vue +0 -40
  191. package/components/modal/style.scss +0 -146
  192. package/components/nestable/NestableItem.vue +0 -307
  193. package/components/nestable/editable.js +0 -44
  194. package/components/nestable/index.js +0 -1
  195. package/components/nestable/index.vue +0 -226
  196. package/components/nestable/methods.js +0 -416
  197. package/components/progress/style.scss +0 -229
  198. package/components/table/style.scss +0 -338
  199. package/components/tabs/index.js +0 -3
  200. package/components/tabs/index.vue +0 -151
  201. package/components/timeline/index.js +0 -6
  202. package/components/timeline/index.vue +0 -76
  203. package/directive/resize/index.js +0 -30
  204. package/directive/skeleton/index.js +0 -27
  205. package/directive/skeleton/style.scss +0 -37
  206. package/plugins/request/Request.js +0 -68
  207. package/style/animation.scss +0 -94
  208. package/style/style.scss +0 -8
  209. package/tools/rootable.js +0 -75
  210. /package/components/form/{text-editor → textEditor}/index.js +0 -0
  211. /package/components/form/{text-editor → textEditor}/preview.js +0 -0
  212. /package/components/form/{text-editor → textEditor}/preview.vue +0 -0
@@ -1,216 +1,375 @@
1
1
  <template>
2
- <div ref="uploader" class="image-card elevation-lg br-md">
2
+ <div ref="uploader" class="image-card br-md">
3
3
  <div class="file-holder text-center">
4
- <div class="image-canvas" v-if="file||modelValue">
5
- <r-btn icon class="image-close color-white">
4
+ <div v-if="file || modelValue" class="image-canvas">
5
+ <r-btn class="image-close color-white" icon size="xs">
6
6
  <r-icon @click.prevent="fileDelete()" class="color-error-text" v-html="$r.icons.delete"></r-icon>
7
7
  </r-btn>
8
8
  <r-progress-circle
9
- :indeterminate=false
10
- :modelValue="uploadPercentage"
9
+ :indeterminate="false"
10
+ :model-value="uploadPercentage"
11
11
  :width="2"
12
12
  class="image-progress"
13
13
  size="50"
14
14
  >
15
15
  {{ `% ${uploadPercentage}` }}
16
16
  </r-progress-circle>
17
- <r-btn :href="fileLink" class="image-copy" icon target="_blank">
18
- <r-icon v-html="$r.icons.eye"></r-icon>
17
+ <r-btn :href="fileLink" class="image-copy color-white" icon size="xs" target="_blank">
18
+ <r-icon class="color-black-text" v-html="$r.icons.eye"></r-icon>
19
19
  </r-btn>
20
- <img v-if="isImg()" :class="`image ${imageStatus} `" :src="getUrl(file)">
20
+ <img v-if="isImg" :class="`image ${imageStatus} `" :src="getUrl(file)">
21
21
  <r-icon v-else
22
22
  class="file" width="100" height="100" v-html="$r.icons.file"
23
23
  :class="{'color-one-text':uploadPercentage===100}"
24
24
  ></r-icon>
25
25
  </div>
26
26
  <div class="file-meta pa-1" v-if="meta && uploadPercentage===100">
27
- <r-text-input :label="$t(m,'renusify')" v-model="metaList[m]" @update:model-value="emit"
28
- v-for="(m,k) in meta" :key="k"
29
- :rules="metaRequired?['required']:[]"></r-text-input>
27
+ <r-text-input
28
+ v-for="(m,k) in meta"
29
+ :key="k"
30
+ v-model="metaList[m]"
31
+ :label="$t(m,'renusify')"
32
+ :rules="metaRequired?['required']:[]"
33
+ @update:model-value="emitFileLink"
34
+ ></r-text-input>
30
35
  </div>
31
36
  </div>
32
- <r-icon @click.prevent.stop="pickFile"
33
- class="cursor-pointer w-full h-full d-flex h-center v-center color-one-text" width="100" height="100"
34
- v-html="$r.icons.plus"
35
- v-if="showAdd"></r-icon>
36
- <input :accept="accept"
37
- @change="addFile()"
38
- ref="file"
39
- style="display: none"
40
- type="file"
41
- v-if="showFile"
37
+
38
+ <r-icon
39
+ v-if="showAdd"
40
+ class="pick-icon cursor-pointer d-flex h-center v-center color-one-text"
41
+ height="100"
42
+ width="100"
43
+ v-html="$r.icons.plus"
44
+ @click.prevent.stop="pickFile"
45
+ ></r-icon>
46
+ <input
47
+ v-if="showFile"
48
+ ref="fileInput"
49
+ :accept="accept"
50
+ style="display: none"
51
+ type="file"
52
+ @change="addFile"
42
53
  >
43
- <r-modal v-model="showCrop" maxWidth="300px">
44
- <r-cropper v-if="wPH&&file" :imgSrc="file" :selectImg="false" :w-p-h="wPH" get-blob showCropped
45
- @cropped="file=$event,checkSave()"></r-cropper>
54
+ <r-modal v-model="showCrop" max-width="300px" no-close-btn>
55
+ <r-cropper
56
+ v-if="wPH && file"
57
+ :img-src="file"
58
+ :select-img="false"
59
+ :w-p-h="wPH || 1"
60
+ get-blob
61
+ show-cropped
62
+ @cropped="handleCropped"
63
+ ></r-cropper>
46
64
  </r-modal>
47
65
  </div>
48
66
  </template>
49
67
 
50
- <script>
51
- import file from "./file.js";
52
-
53
- export default {
54
- name: 'inputFile',
55
- mixins: [file],
56
- props: {
57
- accept: {
58
- default: '*',
59
- type: String
60
- },
61
- wPH: [Number, String, Array],
62
- maxFileSize: Number,
63
- uploadLink: {
64
- type: String,
65
- required: true
66
- },
67
- modelValue: {
68
- default: null,
69
- type: [String, Object]
70
- },
71
- meta: {
72
- type: Array,
73
- default: null
74
- },
75
- metaRequired: Boolean
68
+ <script setup>
69
+ import {ref, computed, watch, onMounted, nextTick, inject} from 'vue'
70
+
71
+ const props = defineProps({
72
+ accept: {
73
+ default: '*',
74
+ type: String
76
75
  },
77
- emits: ['file-link', 'select'],
78
- data() {
79
- return {
80
- showAdd: true,
81
- showFile: true,
82
- showCrop: false,
83
- metaList: {}
84
- }
76
+ wPH: [Number, String, Array],
77
+ maxFileSize: Number,
78
+ uploadLink: {
79
+ type: String,
80
+ required: true
85
81
  },
86
- created() {
87
- this.setValue()
82
+ modelValue: {
83
+ default: null,
84
+ type: [String, Object]
88
85
  },
89
- methods: {
90
- setValue() {
91
- if (this.modelValue) {
92
- this.fileLink = this.$helper.fix_url(this.meta ? this.modelValue['url'] : this.modelValue)
93
- this.metaList = this.meta ? this.modelValue['meta'] : {}
94
- this.showAdd = false
95
- this.imageStatus = 'finished'
96
- this.uploadPercentage = 100
97
- this.emit()
98
- }
99
- },
100
- getUrl(value) {
101
- if (this.modelValue) {
102
- return this.fileLink
103
- } else {
104
- return URL.createObjectURL(value)
105
- }
106
- },
107
- isImg() {
108
- let is = false
109
- let image = this.accept.split('/')
110
- is = image[0] === 'image'
111
- if (!is) {
112
- const p = this.fileLink.split('.')
113
- is = ['jpg', 'jpeg', 'png', 'gif', 'svg'].includes(p[p.length - 1])
114
- }
115
- return is
116
- },
117
- emit() {
118
- if (this.meta) {
119
- this.$emit('file-link', {'url': this.fileLink, 'meta': this.metaList})
120
- } else {
121
- this.$emit('file-link', this.fileLink)
122
- }
123
- this.$emit('select', true)
124
- }
86
+ meta: {
87
+ type: Array,
88
+ default: null
89
+ },
90
+ metaRequired: Boolean,
91
+ headers: Object
92
+ })
93
+
94
+ const emit = defineEmits(['file-link', 'select', 'delete', 'update:modelValue'])
95
+
96
+ // Refs
97
+ const uploader = ref(null)
98
+ const fileInput = ref(null)
99
+ const showAdd = ref(true)
100
+ const showFile = ref(true)
101
+ const showCrop = ref(false)
102
+ const metaList = ref({})
103
+ const imageStatus = ref('inProgress')
104
+ const fileLink = ref('')
105
+ const file = ref(null)
106
+ const file_type = ref(null)
107
+ const uploadPercentage = ref(0)
108
+ const $axios = inject('axios')
109
+ let CancelTokenSource = null
125
110
 
111
+ // Computed properties
112
+ const isImg = computed(() => {
113
+ if (!fileLink.value) return false
114
+ const p = fileLink.value.split('.')
115
+ const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'tiff']
116
+ const extension = p[p.length - 1].toLowerCase()
117
+ return imageExtensions.includes(extension)
118
+ })
119
+
120
+ // Methods
121
+ const createCancelToken = () => {
122
+ if ($axios?.CancelToken) {
123
+ CancelTokenSource = $axios.CancelToken.source()
126
124
  }
127
125
  }
128
- </script>
129
126
 
130
- <style lang="scss">
131
- @use "../../../style/variables/base";
127
+ const addFile = () => {
128
+ if (!fileInput.value?.files?.[0]) return
132
129
 
133
- .#{base.$prefix}file-uploader {
134
- .image-card {
135
- position: relative;
136
- width: auto;
137
- min-width: 150px;
138
- min-height: 200px;
130
+ createCancelToken()
131
+ file.value = fileInput.value.files[0]
132
+ file_type.value = file.value.type
139
133
 
140
- background-color: white;
134
+ const imgs = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/bmp', 'image/tiff']
141
135
 
136
+ if (props.wPH === undefined || !imgs.includes(file_type.value)) {
137
+ checkSave()
138
+ } else {
139
+ showCrop.value = true
140
+ }
142
141
 
143
- .file-meta {
144
- width: 250px;
145
- }
142
+ showAdd.value = false
143
+ }
146
144
 
147
- .fails {
148
- -webkit-filter: grayscale(100%);
149
- filter: grayscale(100%);
150
- }
145
+ const pickFile = () => {
146
+ fileInput.value?.click()
147
+ }
151
148
 
152
- .inProgress {
153
- -webkit-filter: blur(2px);
154
- filter: blur(2px);
155
- }
149
+ const fileDelete = async () => {
150
+ if (CancelTokenSource) {
151
+ CancelTokenSource.cancel()
152
+ }
156
153
 
157
- .finished {
158
- -webkit-filter: blur(0px);
159
- filter: blur(0px);
160
- }
154
+ try {
155
+ await deleteImage()
156
+ showFile.value = false
157
+ await nextTick(() => {
158
+ showFile.value = true
159
+ })
161
160
 
162
- .file {
163
- left: 0;
164
- right: 0;
165
- position: absolute;
166
- top: 0;
167
- bottom: 0;
168
- }
161
+ file.value = null
162
+ metaList.value = {}
163
+ uploadPercentage.value = 0
164
+ showAdd.value = true
169
165
 
170
- .image {
171
- width: auto;
172
- min-width: 150px;
173
- height: 200px;
174
- z-index: -2;
175
- opacity: 0.8;
176
- max-width: 100%;
177
- }
166
+ emit('delete', true)
167
+ emit('file-link', null)
168
+ } catch (error) {
169
+ console.error('Delete error:', error)
170
+ }
171
+ }
178
172
 
179
- .icon-100 {
180
- width: 100px;
181
- height: 100px;
182
- }
173
+ const checkSave = () => {
174
+ if (!file.value) return
183
175
 
184
- .image-canvas {
185
- width: auto;
186
- min-width: 150px;
187
- height: 200px;
188
- position: relative;
189
- background-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
176
+ // Check file size
177
+ if (props.maxFileSize && file.value.size > props.maxFileSize) {
178
+ if (CancelTokenSource) {
179
+ CancelTokenSource.cancel()
190
180
  }
181
+ console.error('max file size must be:', props.maxFileSize)
182
+ console.error('current file size is:', file.value.size)
191
183
 
192
- .image-close {
193
- cursor: pointer;
194
- position: absolute;
195
- left: 5px;
196
- top: 5px;
197
- z-index: 1;
184
+ // Using $toast via window or global property
185
+ if (window.$toast || inject('$toast')) {
186
+ const toast = window.$toast || inject('$toast')
187
+ const t = window.$t || inject('$t')
188
+ toast(t(['max_allow_size', [props.maxFileSize / 1024]], 'renusify'))
198
189
  }
190
+ return
191
+ }
199
192
 
200
- .image-progress {
201
- z-index: 1;
202
- position: absolute;
203
- right: 5px;
204
- top: 5px;
205
- color: white;
193
+ const imgs = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/bmp', 'image/tiff']
194
+
195
+ // Check image aspect ratio if needed
196
+ if (props.wPH !== undefined && imgs.includes(file_type.value)) {
197
+ const img = new Image()
198
+ const objectUrl = URL.createObjectURL(file.value)
199
+
200
+ // Calculate allowed aspect ratios
201
+ const allowedWPH = calculateAllowedWPH(props.wPH)
202
+
203
+ img.onload = function () {
204
+ const currentWPH = parseFloat((this.width / this.height).toFixed(4))
205
+
206
+ if (!allowedWPH.includes(currentWPH)) {
207
+ if (CancelTokenSource) {
208
+ CancelTokenSource.cancel()
209
+ }
210
+
211
+ // Using $toast via window or global property
212
+ if (window.$toast || inject('$toast')) {
213
+ const toast = window.$toast || inject('$toast')
214
+ const t = window.$t || inject('$t')
215
+ toast(t(['image_w_p_h', [props.wPH]], 'renusify'))
216
+ }
217
+
218
+ console.error('width per height must be:', props.wPH, allowedWPH)
219
+ console.error('current width per height is:', currentWPH)
220
+ }
221
+
222
+ URL.revokeObjectURL(objectUrl)
223
+ saveImage()
206
224
  }
207
225
 
208
- .image-copy {
209
- z-index: 1;
210
- position: absolute;
211
- left: 5px;
212
- bottom: 5px;
226
+ img.src = objectUrl
227
+ return
228
+ }
229
+
230
+ saveImage()
231
+ }
232
+
233
+ const calculateAllowedWPH = (wphInput) => {
234
+ const wphArray = []
235
+
236
+ if (Array.isArray(wphInput)) {
237
+ wphInput.forEach((item) => {
238
+ const strItem = item.toString()
239
+ if (strItem.includes('/')) {
240
+ const parts = strItem.split('/')
241
+ if (parts.length === 2) {
242
+ wphArray.push(parseFloat(parts[0]) / parseFloat(parts[1]))
243
+ } else {
244
+ wphArray.push(parseFloat(strItem))
245
+ }
246
+ } else {
247
+ wphArray.push(parseFloat(strItem))
248
+ }
249
+ })
250
+ } else {
251
+ const strItem = wphInput.toString()
252
+ if (strItem.includes('/')) {
253
+ const parts = strItem.split('/')
254
+ if (parts.length === 2) {
255
+ wphArray.push(parseFloat((parseFloat(parts[0]) / parseFloat(parts[1])).toFixed(4)))
256
+ } else {
257
+ wphArray.push(parseFloat(strItem))
258
+ }
259
+ } else {
260
+ wphArray.push(parseFloat(strItem))
213
261
  }
214
262
  }
263
+
264
+ return wphArray
265
+ }
266
+
267
+ const saveImage = async () => {
268
+ if (!file.value) return
269
+
270
+ imageStatus.value = 'inProgress'
271
+
272
+ const formData = new FormData()
273
+ formData.append('file', file.value, file.value.name)
274
+
275
+ let headers = props.headers || {}
276
+ headers['Content-Type'] = 'multipart/form-data'
277
+
278
+ let link = props.uploadLink
279
+ if (props.maxFileSize) {
280
+ const separator = link.includes('?') ? '&' : '?'
281
+ link += `${separator}max_size=${props.maxFileSize}`
282
+ }
283
+
284
+ try {
285
+ const response = await $axios.post(link, formData, {
286
+ headers,
287
+ onUploadProgress: (progressEvent) => {
288
+ if (progressEvent.total) {
289
+ uploadPercentage.value = Math.min(
290
+ parseInt(Math.floor((progressEvent.loaded * 100) / progressEvent.total)),
291
+ 98
292
+ )
293
+ }
294
+ },
295
+ cancelToken: CancelTokenSource?.token
296
+ })
297
+
298
+ fileLink.value = response.data.link
299
+ uploadPercentage.value = 100
300
+ emitFileLink()
301
+ imageStatus.value = 'finished'
302
+ } catch (error) {
303
+ imageStatus.value = 'fails'
304
+ uploadPercentage.value = 0
305
+ console.error('Upload error:', error)
306
+ }
215
307
  }
216
- </style>
308
+
309
+ const deleteImage = async () => {
310
+ if (!fileLink.value) return
311
+
312
+ try {
313
+ const response = await $axios.delete(props.uploadLink, {
314
+ data: {link: fileLink.value},
315
+ headers: props.headers
316
+ })
317
+ return response
318
+ } catch (error) {
319
+ console.error('Delete request error:', error)
320
+ throw error
321
+ }
322
+ }
323
+
324
+ const handleCropped = (croppedFile) => {
325
+ file.value = croppedFile
326
+ showCrop.value = false
327
+ checkSave()
328
+ }
329
+
330
+ const setValue = (value) => {
331
+ if (value) {
332
+ const fixUrl = window.$helper?.fix_url || ((url) => url)
333
+ fileLink.value = props.meta ? fixUrl(value['url']) : fixUrl(value)
334
+ metaList.value = props.meta ? value['meta'] : {}
335
+ showAdd.value = false
336
+ imageStatus.value = 'finished'
337
+ uploadPercentage.value = 100
338
+ emitFileLink()
339
+ }
340
+ }
341
+
342
+ const getUrl = (value) => {
343
+ if (props.modelValue) {
344
+ return fileLink.value
345
+ } else if (value) {
346
+ return URL.createObjectURL(value)
347
+ }
348
+ return ''
349
+ }
350
+
351
+ const emitFileLink = () => {
352
+ if (props.meta) {
353
+ emit('file-link', {'url': fileLink.value, 'meta': metaList.value})
354
+ } else {
355
+ emit('file-link', fileLink.value)
356
+ }
357
+ emit('select', true)
358
+ }
359
+
360
+ // Watch for modelValue changes
361
+ watch(() => props.modelValue, (newVal) => {
362
+ setValue(newVal)
363
+ }, {immediate: true})
364
+
365
+ // Initialize
366
+ onMounted(() => {
367
+ createCancelToken()
368
+ })
369
+
370
+ // Expose methods if needed
371
+ defineExpose({
372
+ fileDelete,
373
+ pickFile
374
+ })
375
+ </script>