vue-intergrall-plugins 0.0.4 → 0.0.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-intergrall-plugins",
3
- "version": "0.0.4",
3
+ "version": "0.0.8",
4
4
  "description": "",
5
5
  "main": "dist/vue-intergrall-plugins.ssr.js",
6
6
  "browser": "dist/vue-intergrall-plugins.esm.js",
@@ -12,7 +12,6 @@
12
12
  ],
13
13
  "sideEffects": false,
14
14
  "scripts": {
15
- "compile:sass": "node-sass -w sass/main.scss css/style.css --output-style --style=compressed",
16
15
  "serve": "vue-cli-service serve dev/serve.js",
17
16
  "prebuild": "rimraf ./dist",
18
17
  "build": "cross-env NODE_ENV=production rollup --config build/rollup.config.js",
@@ -28,8 +27,7 @@
28
27
  "@popperjs/core": "^2.9.3",
29
28
  "core-js": "^3.16.3",
30
29
  "emoji-mart-vue": "^2.6.6",
31
- "node-sass": "^5.0.0",
32
- "rollup-plugin-sass": "^1.2.7",
30
+ "postcss": "^8.3.6",
33
31
  "vue-clickaway": "^2.2.2",
34
32
  "vue-select": "^3.12.3",
35
33
  "vue-toasted": "^1.1.28"
@@ -0,0 +1,233 @@
1
+ <template>
2
+ <span class="text-footer-actions--btn" :class="{'files-activated' : openFiles}" :title="dictionary.title_selecionar_anexo" @click="fileSettings.multiple ? openSelectFileHandler('both') : toggleFiles">
3
+ <fa-icon :icon="['fas', 'paperclip']" />
4
+ <transition name="show">
5
+ <div v-if="openFiles" class="text-footer-files-container" :class="{'horizontal' : cssStyle.outsideButtons}">
6
+ <div class="files-btn images" :class="{'margin-bottom' : cssStyle.outsideButtons}" :title="dictionary.title_anexo_img" @click="openSelectFileHandler('img')">
7
+ <fa-icon :icon="['fas', 'image']" />
8
+ </div>
9
+ <div class="files-btn docs" :title="dictionary.title_anexo_doc" @click="openSelectFileHandler('doc')">
10
+ <fa-icon :icon="['fas', 'file-alt']" />
11
+ </div>
12
+ </div>
13
+ </transition>
14
+ <div class="files-pointers d-none">
15
+ <input v-if="fileSettings.multiple" type="file" :id="`both-${textId}`" accept="image/*,application/*" multiple @change="fileUpload($event, 'both')" />
16
+ <input v-if="!fileSettings.multiple" type="file" :id="`img-${textId}`" accept="image/*" @change="fileUpload($event, 'img')" />
17
+ <input v-if="!fileSettings.multiple" type="file" :id="`doc-${textId}`" accept="application/*" @change="fileUpload($event, 'doc')" />
18
+ </div>
19
+ <transition name="fade">
20
+ <div class="text-footer-preview-container" @click.stop v-if="showFilePreview" :class="[previewContainerClass]">
21
+ <SingleFilePreview
22
+ v-if="!fileSettings.multiple"
23
+ :dictionary="dictionary"
24
+ :file="file"
25
+ :isDoc="isDoc"
26
+ :fileFormatError="fileFormatError"
27
+ :validFileFormats="validFileFormats"
28
+ :imagePreview="imagePreview"
29
+ @delete-file="deleteFile"
30
+ @open-image="openImage"
31
+ />
32
+ <MultipleFilePreview
33
+ v-else
34
+ :dictionary="dictionary"
35
+ :file="file"
36
+ :fileFormatError="fileFormatError"
37
+ :validFileFormats="validFileFormats"
38
+ @delete-file="deleteFile"
39
+ @delete-specific-file="deleteSpecificFile"
40
+ @open-image="openImage"
41
+ />
42
+ </div>
43
+ </transition>
44
+ </span>
45
+ </template>
46
+
47
+ <style>
48
+ .fade-enter-active,
49
+ .fade-leave-active {
50
+ transition: opacity 0.3s;
51
+ }
52
+ .fade-enter,
53
+ .fade-leave-to {
54
+ opacity: 0;
55
+ }
56
+ </style>
57
+
58
+ <script>
59
+ import SingleFilePreview from "./SingleFilePreview"
60
+ import MultipleFilePreview from "./MultipleFilePreview"
61
+
62
+ export default {
63
+ components: { SingleFilePreview, MultipleFilePreview },
64
+ props: {
65
+ textId: {
66
+ type: String,
67
+ required: true
68
+ },
69
+ dictionary: {
70
+ type: Object,
71
+ required: true
72
+ },
73
+ fileSettings: {
74
+ type: Object,
75
+ required: false
76
+ },
77
+ cssStyle: {
78
+ type: Object,
79
+ required: false
80
+ }
81
+ },
82
+ data() {
83
+ return {
84
+ file: [],
85
+ openFiles: false,
86
+ showFilePreview: false,
87
+ imagePreview: "",
88
+ isDoc: false,
89
+ fileFormatError: false,
90
+ validFileFormats: ""
91
+ }
92
+ },
93
+ computed: {
94
+ previewContainerClass() {
95
+ if(this.fileFormatError) return "isError"
96
+ if(this.fileSettings.multiple) return "isMultiple"
97
+ if(this.isDoc) return "isDoc"
98
+ return "isMsg"
99
+ }
100
+ },
101
+ methods: {
102
+ toggleFiles() {
103
+ this.openFiles = !this.openFiles
104
+ },
105
+ openSelectFileHandler(type) {
106
+ const fileInput = document.querySelector(`#${type}-${this.textId}`)
107
+ if(fileInput) fileInput.click()
108
+ if(!fileInput) if (!document.querySelector(".toasted.toasted-primary.error")) this.$toasted.global.defaultError()
109
+ },
110
+ isFileValid(type, fileName) {
111
+ const extensions = type === "img" ? this.fileSettings.imagesExtensions : this.fileSettings.docsExtensions
112
+ const regex = new RegExp("("+extensions+")", "i")
113
+
114
+ if(regex.test(fileName)) return true
115
+ this.showToastedValidFormats()
116
+ return false
117
+ },
118
+ showToastedValidFormats() {
119
+ if (!document.querySelector(".toasted.toasted-primary.error")) this.$toasted.global.defaultError({ msg: this.dictionary.msg_formato_invalido })
120
+ const str = {
121
+ img: this.fileSettings.imagesExtensions.split("|").join(", "),
122
+ doc: this.fileSettings.docsExtensions.split("|").join(", ")
123
+ }
124
+ if (!document.querySelector(".toasted.toasted-primary.info")) this.$toasted.global.showValidFormats({ msg: `Imagens: ${str.img} - Documentos: ${str.doc} ${this.dictionary.msg_extensoes_aceitas}` })
125
+ },
126
+ fileUpload(event, type, externalCall) {
127
+ try {
128
+ this.openFiles = false
129
+ if(this.showFilePreview) this.deleteFile()
130
+
131
+ this.file = !externalCall ? event.target.files ? event.target.files : event.dataTransfer.files : event
132
+ if(!this.file.length) {
133
+ this.file = []
134
+ return
135
+ }
136
+
137
+ this.showFilePreview = true
138
+ if(!this.fileSettings.multiple) {
139
+ this.file = this.file[0]
140
+ this.singleFileUpload(type, this.file.name)
141
+ }else {
142
+ this.multipleFileUpload()
143
+ }
144
+ }catch(e) {
145
+ console.error("Error file upload")
146
+ console.error(e)
147
+ }
148
+ },
149
+ returnFileType(file) {
150
+ const imgRegex = new RegExp("\.("+this.fileSettings.imagesExtensions+")", "i")
151
+ if(imgRegex.test(file.name)) return "img"
152
+
153
+ const docRegex = new RegExp("\.("+this.fileSettings.docsExtensions+")", "i")
154
+ if(docRegex.test(file.name)) return "doc"
155
+
156
+ return ""
157
+ },
158
+ multipleFileUpload() {
159
+ let waitForImageLoad = false
160
+ this.file = Array.from(this.file)
161
+ this.file.forEach(file => {
162
+ const fileReader = new FileReader();
163
+
164
+ const singleFileType = this.returnFileType(file)
165
+ if(!singleFileType) file.invalid = true
166
+ file.imgOrDoc = singleFileType ? singleFileType : ""
167
+
168
+ if(file.imgOrDoc === "doc") this.isDoc = true
169
+ if(file.imgOrDoc === "img") {
170
+ waitForImageLoad = true
171
+ fileReader.onload = () => file.src = fileReader.result
172
+ fileReader.onloadend = () => this.emitFileVars(true)
173
+ }
174
+
175
+ if(this.isFileValid(file.imgOrDoc, file.name)) {
176
+ if(file.imgOrDoc === "img") fileReader.readAsDataURL(file)
177
+ }else{
178
+ file.invalid = true
179
+ this.fileFormatError = true
180
+ this.validFileFormats = `${file.imgOrDoc === "img" ? this.fileSettings.imagesExtensions.split("|").join(", ") : this.fileSettings.docsExtensions.split("|").join(", ")} ${this.dictionary.msg_extensoes_aceitas}`
181
+ }
182
+ })
183
+
184
+ if(this.isDoc && !waitForImageLoad) this.emitFileVars()
185
+ },
186
+ singleFileUpload(type, fileName) {
187
+ const fileReader = new FileReader()
188
+ if(type === "img") {
189
+ fileReader.onload = () => this.imagePreview = fileReader.result
190
+ fileReader.onloadend = () => this.emitFileVars()
191
+ }
192
+
193
+ if(this.isFileValid(type, fileName)) {
194
+ if(type === "img") fileReader.readAsDataURL(this.file)
195
+ if(type === "doc") this.isDoc = true
196
+
197
+ this.fileFormatError = false
198
+ }else {
199
+ this.fileFormatError = true
200
+ this.validFileFormats = `${type === "img" ? this.fileSettings.imagesExtensions.split("|").join(", ") : this.fileSettings.docsExtensions.split("|").join(", ")} ${this.dictionary.msg_extensoes_aceitas}`
201
+ }
202
+
203
+ if(this.isDoc) this.emitFileVars()
204
+ },
205
+ emitFileVars() {
206
+ const vars = { file: this.file, isDoc: this.isDoc, showFilePreview: this.showFilePreview, imagePreview: this.imagePreview, fileFormatError: this.fileFormatError }
207
+
208
+ this.$emit("set-file-vars", vars)
209
+ this.$parent.focusTextarea()
210
+ },
211
+ deleteSpecificFile(obj) {
212
+ const { fileName } = obj
213
+ this.file = this.file.filter(file => {
214
+ return file.name != fileName
215
+ })
216
+ this.file.length ? this.emitFileVars(true) : this.deleteFile()
217
+ },
218
+ deleteFile() {
219
+ this.$emit("set-file-vars", { file: [], isDoc: false, showFilePreview: false, imagePreview: "", fileFormatError: false })
220
+
221
+ this.file = []
222
+ this.isDoc = false
223
+ this.showFilePreview = false
224
+ this.imagePreview = ""
225
+ this.fileFormatError = false
226
+ this.validFileFormats = ""
227
+ },
228
+ openImage(imagePreview) {
229
+ this.$emit("open-image", !imagePreview ? this.imagePreview : imagePreview)
230
+ }
231
+ }
232
+ }
233
+ </script>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <span class="text-footer-actions--btn" :class="{'audio-activated' : isRecording}" @click="toggleAudioRecorder">
3
+ <fa-icon :icon="['fas', 'microphone']" />
4
+ </span>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ props: {
10
+ dictionary: {
11
+ type: Object,
12
+ required: true
13
+ }
14
+ },
15
+ data() {
16
+ return {
17
+ isRecording: false,
18
+ mediaRecorder: {}
19
+ }
20
+ },
21
+ methods: {
22
+ toggleAudioRecorder() {
23
+ if(!this.mediaRecorder.state) return this.initAudioRecorder()
24
+
25
+ this.isRecording = !this.isRecording
26
+
27
+ if(this.isRecording) return this.mediaRecorder.start()
28
+ return this.mediaRecorder.stop()
29
+ },
30
+ initAudioRecorder() {
31
+ navigator.mediaDevices.getUserMedia({ audio: true })
32
+ .then(stream => {
33
+ this.mediaRecorder = new MediaRecorder(stream)
34
+ const audioChunks = []
35
+ this.mediaRecorder.ondataavailable = eventData => { audioChunks.push(eventData.data) }
36
+ this.mediaRecorder.onstop = () => {
37
+ const blob = new Blob(audioChunks, { type: "audio/mpeg" })
38
+ blob.lastModifiedDate = new Date()
39
+ blob.name = `im-audio-file-${parseInt(Math.random() * 50000)}`
40
+ const reader = new FileReader()
41
+ reader.readAsDataURL(blob)
42
+ reader.onloadend = () => {
43
+ this.$emit("set-audio", { audioFile: new File([blob], `${blob.name}.mpeg`, { type: blob.type }), audioSource: reader.result })
44
+ }
45
+ stream.getTracks().forEach(track => track.stop())
46
+ }
47
+
48
+ this.toggleAudioRecorder()
49
+ },
50
+ error => {
51
+ this.$toasted.global.defaultError({ msg: this.dictionary.msg_permitir_audio })
52
+ console.error("error audio recorder: ", error)
53
+ })
54
+ },
55
+ deleteMediaRecorder() {
56
+ this.mediaRecorder = {}
57
+ }
58
+ }
59
+ }
60
+ </script>
@@ -0,0 +1,197 @@
1
+ <template>
2
+ <div class="multiple-file-preview">
3
+ <transition-group name="fade">
4
+ <Loader v-if="loading" key="mfp-loader" />
5
+ <template v-else-if="fileFormatError">
6
+ <span @click="deleteFile" :title="dictionary.msg_cancelar_anexo" class="text-footer-exclude-file" key="mfp-exlude-file">
7
+ <fa-icon :icon="['fas', 'times-circle']" />
8
+ </span>
9
+ <div class="text-footer-invalid-format" v-if="fileFormatError" key="mfp-invalid-format">
10
+ <h3 v-text="dictionary.titulo_msg_formato_invalido"></h3>
11
+ <h4 v-text="validFileFormats"></h4>
12
+ </div>
13
+ </template>
14
+ <template v-else>
15
+ <div class="file-preview" v-for="(singleFile, index) in file" :key="index">
16
+ <p class="file-title">
17
+ <fa-icon :icon="icon(singleFile.imgOrDoc)" />
18
+ {{ singleFile.name }}
19
+ </p>
20
+ <p v-if="singleFile.invalid" class="file-title red">
21
+ {{ dictionary.titulo_msg_formato_invalido ? dictionary.titulo_msg_formato_invalido : "Arquivo invalido" }}
22
+ </p>
23
+ <div class="small-img">
24
+ <span class="img-container" v-if="singleFile.imgOrDoc === 'img'">
25
+ <img
26
+ :src="singleFile.src"
27
+ :alt="dictionary.alt_previa_img"
28
+ @click="openImage(singleFile.src)"
29
+ />
30
+ </span>
31
+ <span class="pdf" v-else-if="isPdf(singleFile.type)">
32
+ <fa-icon :icon="['fas', 'file-pdf']" />
33
+ </span>
34
+ </div>
35
+ <span @click="deleteSpecificFile(singleFile.name, index)" class="delete-file">
36
+ <fa-icon :icon="['fas', 'times-circle']" />
37
+ </span>
38
+ </div>
39
+ </template>
40
+ </transition-group>
41
+ </div>
42
+ </template>
43
+
44
+ <script>
45
+ import Loader from "../Loader/Loader"
46
+
47
+ export default {
48
+ components: { Loader },
49
+ data() {
50
+ return {
51
+ loading: true,
52
+ loadingTimeout: 0,
53
+ ignoreNextUpdate: false
54
+ }
55
+ },
56
+ mounted() {
57
+ setTimeout(() => { this.loading = false;}, 500);
58
+ },
59
+ watch: {
60
+ file() {
61
+ if(!this.ignoreNextUpdate) {
62
+ if(this.loadingTimeout) clearTimeout(this.loadingTimeout);
63
+ this.loading = true;
64
+ this.loadingTimeout = setTimeout(() => { this.loading = false; }, 500);
65
+ this.ignoreNextUpdate = true
66
+ }
67
+ this.ignoreNextUpdate = false;
68
+ }
69
+ },
70
+ props: {
71
+ dictionary: { type: Object, required: true },
72
+ file: { type: Array, required: true },
73
+ fileFormatError: { type: Boolean, required: false },
74
+ validFileFormats: { type: String, required: false, default: "" }
75
+ },
76
+ methods: {
77
+ deleteFile() {
78
+ this.$emit("delete-file");
79
+ },
80
+ deleteSpecificFile(fileName, index) {
81
+ this.ignoreNextUpdate = true;
82
+ this.$emit("delete-specific-file", { fileName, index });
83
+ },
84
+ openImage(image) {
85
+ this.$emit("open-image", image);
86
+ },
87
+ icon(imgOrDoc) {
88
+ if(!imgOrDoc) return ['fas', 'times-circle'];
89
+ return imgOrDoc == 'doc' ? ['fas', 'file-alt'] : ['fas', 'image'];
90
+ },
91
+ isPdf(type) {
92
+ return type === "application/pdf" ? true : false
93
+ }
94
+ }
95
+ }
96
+ </script>
97
+
98
+ <style>
99
+ .multiple-file-preview {
100
+ position: relative;
101
+ display: flex;
102
+ flex-direction: column;
103
+ width: 100%;
104
+ height: 100%;
105
+ max-height: 100%;
106
+ overflow-y: auto;
107
+ overflow-x: hidden;
108
+ border-top-left-radius: 5px;
109
+ border-top-right-radius: 5px;
110
+ transition: background-color 150ms;
111
+ }
112
+
113
+ .file-preview {
114
+ display: flex;
115
+ width: 100%;
116
+ align-items: center;
117
+ padding: 5px 10px;
118
+ transition: background-color 150ms;
119
+ }
120
+ .file-preview:hover {
121
+ background-color: rgba(0, 0, 0, .1)
122
+ }
123
+
124
+ .file-title {
125
+ color: #222;
126
+ display: flex;
127
+ align-items: center;
128
+ white-space: nowrap;
129
+ text-overflow: ellipsis;
130
+ overflow: hidden;
131
+ padding: 4px 10px;
132
+ background-color: rgba(255, 255, 255, 0.8);
133
+ border-radius: 30px;
134
+ }
135
+ .file-title.red {
136
+ color: #E74C3C;
137
+ margin-left:5px;
138
+ }
139
+ .file-title > svg {
140
+ margin-right: 5px
141
+ }
142
+
143
+ .small-img {
144
+ flex: 1;
145
+ margin: 0 15px;
146
+ display: flex;
147
+ justify-content: center;
148
+ align-items: center;
149
+ position: relative;
150
+ }
151
+ .small-img img {
152
+ height: 40px;
153
+ cursor: pointer;
154
+ }
155
+ .small-img .pdf {
156
+ display: flex;
157
+ justify-content: center;
158
+ align-items: center;
159
+ font-size: 30px;
160
+ color: #E74C3C;
161
+ }
162
+ .small-img .pdf svg{
163
+ z-index: 1;
164
+ }
165
+ .small-img .pdf::after {
166
+ content: "";
167
+ position: absolute;
168
+ bottom: 2px;
169
+ transform: translateY(2px);
170
+ width: 20px;
171
+ height: 20px;
172
+ background-color: #FFF;
173
+ }
174
+ .img-container {
175
+ padding: 5px;
176
+ border-radius: 2.5px;
177
+ background-color: rgba(0, 0, 0, .15);
178
+ display: flex;
179
+ justify-content: center;
180
+ align-items: center;
181
+ }
182
+
183
+ .delete-file {
184
+ display: flex;
185
+ justify-content: center;
186
+ align-items: center;
187
+ border-radius: 50%;
188
+ background-color: #FFF;
189
+ min-width: 1rem;
190
+ min-height: 1rem;
191
+ cursor: pointer;
192
+ }
193
+ .delete-file > svg {
194
+ font-size: 1rem;
195
+ color: #E74C3C;
196
+ }
197
+ </style>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <span
3
+ class="max-characters no-width"
4
+ v-if="maxCharacters"
5
+ v-text="`(${this.remainingCharacters})`"
6
+ ></span>
7
+ </template>
8
+
9
+ <script>
10
+ export default {
11
+ props: {
12
+ message: {
13
+ type: String,
14
+ required: true
15
+ },
16
+ maxCharacters: {
17
+ type: Number,
18
+ required: false
19
+ },
20
+ },
21
+ computed: {
22
+ remainingCharacters() {
23
+ if(this.message.length) return this.maxCharacters - this.message.length
24
+ return this.maxCharacters
25
+ }
26
+ }
27
+ }
28
+ </script>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <div class="single-file-preview">
3
+ <span @click="deleteFile" :title="dictionary.msg_cancelar_anexo" class="text-footer-exclude-file">
4
+ <fa-icon :icon="['fas', 'times-circle']" />
5
+ </span>
6
+ <div class="text-footer-invalid-format" v-if="fileFormatError">
7
+ <h3 v-text="dictionary.titulo_msg_formato_invalido"></h3>
8
+ <h4 v-text="validFileFormats"></h4>
9
+ </div>
10
+ <template v-else>
11
+ <h3 v-if="file.name" class="text-footer-preview-title">
12
+ <fa-icon :icon="['fas', 'file-alt']" v-if="isDoc" />
13
+ <fa-icon :icon="['fas', 'image']" v-else />
14
+ {{ file.name }}
15
+ </h3>
16
+ <div class="text-footer-image-preview" v-if="imagePreview">
17
+ <img :src="imagePreview" :alt="dictionary.alt_previa_img" @click="openImage">
18
+ </div>
19
+ </template>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+ export default {
25
+ props: {
26
+ dictionary: { type: Object, required: true },
27
+ file: { type: File, required: true },
28
+ isDoc: { type: Boolean, required: false },
29
+ fileFormatError: { type: Boolean, required: false },
30
+ validFileFormats: { type: String, required: false, default: "" },
31
+ imagePreview: { type: String, required: false }
32
+ },
33
+ methods: {
34
+ deleteFile() {
35
+ this.$emit("delete-file")
36
+ },
37
+ openImage() {
38
+ this.$emit("open-image")
39
+ }
40
+ }
41
+ }
42
+ </script>
43
+
44
+ <style>
45
+
46
+ </style>