@concretecms/bedrock 1.0.2 → 1.1.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.
Files changed (52) hide show
  1. package/.idea/codeStyles/Project.xml +33 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  3. package/assets/account/js/frontend/components/Avatar/Cropper.js +12 -4
  4. package/assets/bedrock/scss/_theme-grid.scss +4 -2
  5. package/assets/ckeditor/js/concrete/link.js +5 -4
  6. package/assets/ckeditor/js/concrete/styles.js +2 -2
  7. package/assets/cms/components/BoardInstanceRule.vue +16 -3
  8. package/assets/cms/components/BoardInstanceRuleList.vue +24 -7
  9. package/assets/cms/components/CompletedProcessList.vue +28 -9
  10. package/assets/cms/components/Icon.vue +16 -1
  11. package/assets/cms/components/Pagination.vue +45 -8
  12. package/assets/cms/components/customizer/ColorPageCustomizerWidget.vue +7 -0
  13. package/assets/cms/components/customizer/FontWeightPageCustomizerWidget.vue +7 -1
  14. package/assets/cms/components/customizer/ImagePageCustomizerWidget.vue +13 -3
  15. package/assets/cms/components/customizer/TextTransformPageCustomizerWidget.vue +7 -1
  16. package/assets/cms/components/customizer/ThemeCustomizer.vue +36 -15
  17. package/assets/cms/components/customizer/ThemeCustomizerPreview.vue +11 -1
  18. package/assets/cms/components/customizer/TypePageCustomizerWidget.vue +21 -6
  19. package/assets/cms/components/express/Selector.vue +21 -6
  20. package/assets/cms/components/file-manager/Chooser/ExternalFileProvider.vue +13 -2
  21. package/assets/cms/components/file-manager/Chooser/FileManager.vue +75 -72
  22. package/assets/cms/components/file-manager/Chooser/FileSets.vue +24 -9
  23. package/assets/cms/components/file-manager/Chooser/FileUpload.vue +3 -1
  24. package/assets/cms/components/file-manager/Chooser/Files.vue +57 -9
  25. package/assets/cms/components/file-manager/Chooser/FolderBookmark.vue +4 -0
  26. package/assets/cms/components/file-manager/Chooser/RecentUploads.vue +4 -0
  27. package/assets/cms/components/file-manager/Chooser/SavedSearch.vue +24 -9
  28. package/assets/cms/components/file-manager/Chooser/Search.vue +25 -9
  29. package/assets/cms/components/file-manager/Chooser.vue +82 -8
  30. package/assets/cms/components/file-manager/Uploader/UploadFromComputer.vue +3 -2
  31. package/assets/cms/components/file-manager/Uploader.vue +1 -0
  32. package/assets/cms/components/form/ConcreteFileDirectoryInput.vue +17 -4
  33. package/assets/cms/components/form/ConcreteFileInput.vue +8 -1
  34. package/assets/cms/components/gallery/GalleryEdit.vue +20 -5
  35. package/assets/cms/components/gallery/ImageDetail.vue +22 -5
  36. package/assets/cms/components/groups/Chooser.vue +17 -4
  37. package/assets/cms/components/page/Chooser/ChooserSearch.vue +15 -2
  38. package/assets/cms/components/page/PageList.vue +15 -3
  39. package/assets/cms/components/user/Chooser/Search.vue +15 -2
  40. package/assets/cms/components/user/Chooser/Users.vue +19 -5
  41. package/assets/cms/components/user/Chooser.vue +15 -2
  42. package/assets/cms/js/edit-mode/layouts.js +4 -4
  43. package/assets/cms/js/edit-mode/style-customizer/color.js +10 -3
  44. package/assets/cms/js/edit-mode/style-customizer/custom.js +1 -1
  45. package/assets/cms/js/edit-mode/style-customizer/typography.js +8 -1
  46. package/assets/cms/js/file-manager/file-manager.js +1 -8
  47. package/assets/cms/scss/_inline-toolbar.scss +10 -179
  48. package/assets/cms/scss/panels/_shared.scss +1 -1
  49. package/package.json +2 -2
  50. package/.idea/dataSources.local.xml +0 -4
  51. package/.idea/misc.xml +0 -6
  52. package/.idea/workspace.xml +0 -317
@@ -9,8 +9,8 @@
9
9
  <label class="form-label" :for="'file-' + (file.fID || file.treeNodeID)"><span v-html="file.resultsThumbnailImg"></span></label>
10
10
  <div class="ccm-image-cell-title pt-1">
11
11
  <div class="form-check form-check-inline">
12
- <input class="form-check-input" type="checkbox" v-if="multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
13
- <input class="form-check-input" type="radio" v-if="!multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
12
+ <input :disabled="!canChooseFile(file)" class="form-check-input" type="checkbox" v-if="multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
13
+ <input :disabled="!canChooseFile(file)" class="form-check-input" type="radio" v-if="!multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
14
14
  <label class="form-check-label" :for="'file-' + (file.fID || file.treeNodeID)">{{file.title}}</label>
15
15
  </div>
16
16
  </div>
@@ -24,22 +24,22 @@
24
24
  <tr>
25
25
  <th></th>
26
26
  <th></th>
27
- <th>ID</th>
27
+ <th>{{ i18n.id }}</th>
28
28
  <th :class="getSortColumnClassName('fv.fvTitle')">
29
- <a v-if="enableSort" href="#" @click.prevent="sortBy('fv.fvTitle')">Name</a>
30
- <span v-else>Name</span>
29
+ <a v-if="enableSort" href="#" @click.prevent="sortBy('fv.fvTitle')">{{ i18n.name }}</a>
30
+ <span v-else>{{ i18n.name }}</span>
31
31
  </th>
32
32
  <th :class="getSortColumnClassName(dateSortColumn)">
33
- <a v-if="enableSort" href="#" @click.prevent="sortBy(dateSortColumn)">Uploaded</a>
34
- <span v-else>Uploaded</span>
33
+ <a v-if="enableSort" href="#" @click.prevent="sortBy(dateSortColumn)">{{ i18n.uploaded }}</a>
34
+ <span v-else>{{ i18n.uploaded }}</span>
35
35
  </th>
36
36
  </tr>
37
37
  </thead>
38
38
  <tbody>
39
39
  <tr v-for="file in fileList" :key="(file.fID || file.treeNodeID) + 'list'" @click="onItemClick(file)">
40
40
  <td>
41
- <input type="checkbox" v-if="multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
42
- <input type="radio" v-if="!multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
41
+ <input type="checkbox" :disabled="!canChooseFile(file)" v-if="multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
42
+ <input type="radio" :disabled="!canChooseFile(file)" v-if="!multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
43
43
  </td>
44
44
  <td class="ccm-image-chooser-icon"><span v-html="file.resultsThumbnailImg" width="32" height="32"></span></td>
45
45
  <td>{{file.fID}}</td>
@@ -80,6 +80,11 @@ export default {
80
80
  Pagination
81
81
  },
82
82
  data: () => ({
83
+ i18n: {
84
+ id: 'ID',
85
+ name: 'Name',
86
+ uploaded: 'Uploaded'
87
+ },
83
88
  currentPage: 1,
84
89
  rows: false,
85
90
  fileList: [],
@@ -95,6 +100,9 @@ export default {
95
100
  viewIsLoading: false
96
101
  }),
97
102
  props: {
103
+ filters: {
104
+ type: Array
105
+ },
98
106
  enableSort: {
99
107
  type: Boolean,
100
108
  required: false,
@@ -166,6 +174,37 @@ export default {
166
174
  }
167
175
  },
168
176
  methods: {
177
+ canChooseFile(file) {
178
+ var canChooseFile = -1
179
+ if (this.filters) {
180
+ var fileExtension = file.extension
181
+ var fileType = file.genericType
182
+ this.filters.forEach(function(filter) {
183
+ if (filter.filter === 'extension') {
184
+ if (filter.extensions.includes(fileExtension)) {
185
+ canChooseFile = true
186
+ } else {
187
+ canChooseFile = false
188
+ }
189
+ }
190
+ if (canChooseFile !== false) {
191
+ if (filter.filter === 'type') {
192
+ if (filter.type === fileType) {
193
+ canChooseFile = true
194
+ } else {
195
+ canChooseFile = false
196
+ }
197
+ }
198
+ }
199
+ })
200
+ }
201
+
202
+ if (canChooseFile === -1) {
203
+ return true
204
+ } else {
205
+ return canChooseFile
206
+ }
207
+ },
169
208
  getFiles() {
170
209
  const my = this
171
210
  my.rows = false
@@ -235,6 +274,15 @@ export default {
235
274
  }
236
275
  }
237
276
  },
277
+ mounted: function() {
278
+ if (window.ccmi18n_filemanager) {
279
+ for (const key in this.i18n) {
280
+ if (window.ccmi18n_filemanager[key]) {
281
+ this.i18n[key] = window.ccmi18n_filemanager[key]
282
+ }
283
+ }
284
+ }
285
+ },
238
286
  watch: {
239
287
  selectedFiles(value) {
240
288
  this.$emit('update:selectedFiles', Array.isArray(value) ? value : [value])
@@ -10,6 +10,7 @@
10
10
  :routePath="routePath + activeFolder"
11
11
  :enable-pagination="true"
12
12
  :enable-sort="true"
13
+ :filters="filters"
13
14
  :multipleSelection="multipleSelection"
14
15
  @folderClick="activeFolder = $event"/>
15
16
  </div>
@@ -51,6 +52,9 @@ export default {
51
52
  multipleSelection: {
52
53
  type: Boolean,
53
54
  default: true
55
+ },
56
+ filters: {
57
+ type: Array
54
58
  }
55
59
  },
56
60
  created() {
@@ -4,6 +4,7 @@
4
4
 
5
5
  <files :selectedFiles.sync="selectedFiles"
6
6
  :resultsFormFactor="formFactor"
7
+ :filters="filters"
7
8
  routePath="/ccm/system/file/chooser/recent"
8
9
  :multipleSelection="multipleSelection"/>
9
10
  </div>
@@ -37,6 +38,9 @@ export default {
37
38
  multipleSelection: {
38
39
  type: Boolean,
39
40
  default: true
41
+ },
42
+ filters: {
43
+ type: Array
40
44
  }
41
45
  },
42
46
  watch: {
@@ -7,25 +7,26 @@
7
7
 
8
8
  <div class="form-group row row-cols-auto g-0 align-items-center justify-content-end">
9
9
  <div class="col-auto">
10
- <label for="searchPresets" class="me-2">Search Presets</label>
10
+ <label for="searchPresets" class="me-2">{{ i18n.searchPresets }}</label>
11
11
  </div>
12
12
  <div class="col-auto">
13
13
  <select id="searchPresets" class="form-select search-presets-menu" v-model="activeSearchPreset">
14
- <option value="" selected>Select a Preset</option>
14
+ <option value="" selected>{{ i18n.selectPreset }}</option>
15
15
  <option v-for="searchPreset in searchPresets" :key="searchPreset.id" :value="searchPreset.id">
16
- {{searchPreset.presetName}}
16
+ {{ searchPreset.presetName }}
17
17
  </option>
18
18
  </select>
19
19
  </div>
20
20
  </div>
21
21
  <div class="mt-3" v-show="activeSearchPreset">
22
22
  <files v-if="activeSearchPreset"
23
- :selectedFiles.sync="selectedFiles"
24
- :resultsFormFactor="formFactor"
25
- :routePath="routePath + activeSearchPreset"
26
- :enable-pagination="true"
27
- :multipleSelection="multipleSelection"
28
- @folderClick="activeFolder = $event"/>
23
+ :selectedFiles.sync="selectedFiles"
24
+ :resultsFormFactor="formFactor"
25
+ :filters="filters"
26
+ :routePath="routePath + activeSearchPreset"
27
+ :enable-pagination="true"
28
+ :multipleSelection="multipleSelection"
29
+ @folderClick="activeFolder = $event"/>
29
30
  </div>
30
31
  </div>
31
32
  </template>
@@ -48,6 +49,10 @@ export default {
48
49
  Files
49
50
  },
50
51
  data: () => ({
52
+ i18n: {
53
+ searchPresets: 'Search Presets',
54
+ selectPreset: 'Select a Preset'
55
+ },
51
56
  activeFolder: '',
52
57
  searchPresets: [],
53
58
  activeSearchPreset: '',
@@ -70,6 +75,9 @@ export default {
70
75
  multipleSelection: {
71
76
  type: Boolean,
72
77
  default: true
78
+ },
79
+ filters: {
80
+ type: Array
73
81
  }
74
82
  },
75
83
  methods: {
@@ -91,6 +99,13 @@ export default {
91
99
  }
92
100
  },
93
101
  mounted() {
102
+ if (window.ccmi18n_filemanager) {
103
+ for (const key in this.i18n) {
104
+ if (window.ccmi18n_filemanager[key]) {
105
+ this.i18n[key] = window.ccmi18n_filemanager[key]
106
+ }
107
+ }
108
+ }
94
109
  this.formFactor = this.resultsFormFactor
95
110
 
96
111
  this.fetchSearchPresets()
@@ -6,7 +6,8 @@
6
6
  <div class="col-md-4 ms-auto">
7
7
  <form @submit.prevent="search">
8
8
  <div class="ccm-header-search-form-input input-group">
9
- <input type="text" class="form-control border-end-0" placeholder="Search" autocomplete="false" v-model="searchText">
9
+ <input type="text" class="form-control border-end-0" :placeholder="i18n.search"
10
+ autocomplete="false" v-model="searchText">
10
11
  <button type="submit" class="input-group-icon">
11
12
  <svg width="16" height="16">
12
13
  <use xlink:href="#icon-search"/>
@@ -20,16 +21,17 @@
20
21
  <span class="search-icon my-4">
21
22
  <Icon icon="search" type="fas" color="#f4f4f4"/>
22
23
  </span>
23
- <p><b>Let's get some info on what you're looking for.</b></p>
24
+ <p><b>{{ i18n.initialSearchChooserTip }}</b></p>
24
25
  </div>
25
26
  <div>
26
27
  <files v-if="keywords"
27
- :selectedFiles.sync="selectedFiles"
28
- :resultsFormFactor="formFactor"
29
- :routePath="routePath + keywords"
30
- :enable-pagination="true"
31
- :enable-sort="true"
32
- :multipleSelection="multipleSelection"/>
28
+ :selectedFiles.sync="selectedFiles"
29
+ :resultsFormFactor="formFactor"
30
+ :routePath="routePath + keywords"
31
+ :enable-pagination="true"
32
+ :enable-sort="true"
33
+ :filters="filters"
34
+ :multipleSelection="multipleSelection"/>
33
35
  </div>
34
36
  </div>
35
37
  </template>
@@ -47,6 +49,10 @@ export default {
47
49
  Files
48
50
  },
49
51
  data: () => ({
52
+ i18n: {
53
+ search: 'Search',
54
+ initialSearchChooserTip: "Let's get some info on what you're looking for."
55
+ },
50
56
  searchText: '',
51
57
  keywords: '',
52
58
  selectedFiles: [],
@@ -67,10 +73,13 @@ export default {
67
73
  multipleSelection: {
68
74
  type: Boolean,
69
75
  default: true
76
+ },
77
+ filters: {
78
+ type: Array
70
79
  }
71
80
  },
72
81
  methods: {
73
- search () {
82
+ search() {
74
83
  this.keywords = this.searchText
75
84
  }
76
85
  },
@@ -83,6 +92,13 @@ export default {
83
92
  }
84
93
  },
85
94
  mounted() {
95
+ if (window.ccmi18n_filemanager) {
96
+ for (const key in this.i18n) {
97
+ if (window.ccmi18n_filemanager[key]) {
98
+ this.i18n[key] = window.ccmi18n_filemanager[key]
99
+ }
100
+ }
101
+ }
86
102
  this.formFactor = this.resultsFormFactor
87
103
  }
88
104
  }
@@ -34,6 +34,8 @@
34
34
  :selectedFiles.sync="selectedFiles"
35
35
  :resultsFormFactor.sync="resultsFormFactor"
36
36
  :filesReadyToUpload.sync="filesReadyToUpload"
37
+ :filters="filters"
38
+ @upload-complete="activateTabByKey('recent-uploads')"
37
39
  ref="c"
38
40
  />
39
41
  </transition>
@@ -41,11 +43,11 @@
41
43
  </div>
42
44
  </div>
43
45
  <div class="dialog-buttons">
44
- <button class="btn btn-secondary" data-dialog-action="cancel">Cancel</button>
46
+ <button class="btn btn-secondary" data-dialog-action="cancel">{{ i18n.cancel }}</button>
45
47
 
46
- <button type="button" v-show="isImportExternalFilesMode()" @click="importExternalFiles" :disabled="selectedFiles.length === 0" class="btn btn-primary">Import</button>
47
- <button type="button" v-show="isChooseFilesMode()" @click="chooseFiles" :disabled="selectedFiles.length === 0" class="btn btn-primary">Choose</button>
48
- <button type="button" v-show="isAddNewFilesMode()" @click="uploadFiles" :disabled="uploadReady === false" class="btn btn-primary">Upload</button>
48
+ <button type="button" v-show="isImportExternalFilesMode()" @click="importExternalFiles" :disabled="selectedFiles.length === 0" class="btn btn-primary">{{ i18n.import }}</button>
49
+ <button type="button" v-show="isChooseFilesMode()" @click="chooseFiles" :disabled="selectedFiles.length === 0" class="btn btn-primary">{{ i18n.choose }}</button>
50
+ <button type="button" v-show="isAddNewFilesMode()" @click="uploadFiles" :disabled="uploadReady === false" class="btn btn-primary">{{ i18n.upload }}</button>
49
51
  </div>
50
52
  </div>
51
53
  </template>
@@ -74,6 +76,16 @@ export default {
74
76
  },
75
77
  data() {
76
78
  return {
79
+ i18n: {
80
+ cancel: 'Cancel',
81
+ import: 'Import',
82
+ choose: 'Choose',
83
+ upload: 'Upload',
84
+ recentlyUploaded: 'Recently Uploaded',
85
+ fileManager: 'File Manager',
86
+ search: 'Search',
87
+ uploadFiles: 'Upload Files'
88
+ },
77
89
  filesReadyToUpload: 0,
78
90
  activeNavItem: null,
79
91
  resultsFormFactor: 'grid',
@@ -91,15 +103,15 @@ export default {
91
103
  default: [
92
104
  {
93
105
  key: 'recent-uploads',
94
- title: 'Recently Uploaded'
106
+ title: null // use the detault one if null
95
107
  },
96
108
  {
97
109
  key: 'file-manager',
98
- title: 'File Manager'
110
+ title: null // use the detault one if null
99
111
  },
100
112
  {
101
113
  key: 'search',
102
- title: 'Search'
114
+ title: null // use the detault one if null
103
115
  }
104
116
  ]
105
117
  },
@@ -108,13 +120,16 @@ export default {
108
120
  default: [
109
121
  {
110
122
  key: 'file-upload',
111
- title: 'Upload Files'
123
+ title: null // use the detault one if null
112
124
  }
113
125
  ]
114
126
  },
115
127
  multipleSelection: {
116
128
  type: Boolean,
117
129
  default: true
130
+ },
131
+ filters: {
132
+ type: Array
118
133
  }
119
134
  },
120
135
  created() {
@@ -122,11 +137,57 @@ export default {
122
137
  },
123
138
  mounted() {
124
139
  var my = this
140
+ if (window.ccmi18n_filemanager) {
141
+ for (const key in my.i18n) {
142
+ if (window.ccmi18n_filemanager[key]) {
143
+ my.i18n[key] = window.ccmi18n_filemanager[key]
144
+ }
145
+ }
146
+ }
147
+ this.applyLocalization()
125
148
  ConcreteEvent.subscribe('FileUploaderFilesReadyToUpload', function(e, filesReadyToUpload) {
126
149
  my.filesReadyToUpload = filesReadyToUpload
127
150
  })
128
151
  },
152
+ watch: {
153
+ choosers() {
154
+ this.applyLocalization()
155
+ },
156
+ uploaders() {
157
+ this.applyLocalization()
158
+ }
159
+ },
129
160
  methods: {
161
+ applyLocalization() {
162
+ if (this.choosers) {
163
+ for (const chooser of this.choosers) {
164
+ if (typeof chooser.title !== 'string') {
165
+ switch (chooser.key) {
166
+ case 'recent-uploads':
167
+ chooser.title = this.i18n.recentlyUploaded
168
+ break
169
+ case 'file-manager':
170
+ chooser.title = this.i18n.fileManager
171
+ break
172
+ case 'search':
173
+ chooser.title = this.i18n.search
174
+ break
175
+ }
176
+ }
177
+ }
178
+ }
179
+ if (this.uploaders) {
180
+ for (const uploader of this.uploaders) {
181
+ if (typeof uploader.title !== 'string') {
182
+ switch (uploader.key) {
183
+ case 'file-upload':
184
+ uploader.title = this.i18n.uploadFiles
185
+ break
186
+ }
187
+ }
188
+ }
189
+ }
190
+ },
130
191
  isImportExternalFilesMode() {
131
192
  return this.activeNavItem.componentKey === 'external-file-provider'
132
193
  },
@@ -136,6 +197,19 @@ export default {
136
197
  isChooseFilesMode() {
137
198
  return this.activeNavItem.componentKey !== 'file-upload' && this.activeNavItem.componentKey !== 'external-file-provider'
138
199
  },
200
+ activateTabByKey(key) {
201
+ var my = this
202
+ this.choosers.forEach(function(chooser) {
203
+ if (chooser.id === key) {
204
+ my.activateTab(chooser)
205
+ }
206
+ })
207
+ this.uploaders.forEach(function(uploader) {
208
+ if (uploader.id === key) {
209
+ my.activateTab(uploader)
210
+ }
211
+ })
212
+ },
139
213
  activateTab(item) {
140
214
  this.activeNavItem = item
141
215
 
@@ -131,7 +131,8 @@ export default {
131
131
  me.uploadedFiles.forEach(function(file) {
132
132
  fileIds.push(file.fID)
133
133
  })
134
- ConcreteEvent.publish('FileManagerSelectFile', { fID: fileIds })
134
+ // Instead of firing this event let's use uploadComplete() below to re-select the Recent Uploads tab.
135
+ // ConcreteEvent.publish('FileManagerSelectFile', { fID: fileIds })
135
136
  me.uploadedFiles = []
136
137
  }
137
138
  me.uploadComplete()
@@ -222,7 +223,7 @@ export default {
222
223
  this.dropzone.removeAllFiles(true)
223
224
  },
224
225
  uploadComplete() {
225
- this.$emit('update:uploadCompleted')
226
+ this.$emit('upload-complete')
226
227
 
227
228
  ConcreteAlert.notify({
228
229
  title: 'Complete',
@@ -2,6 +2,7 @@
2
2
  <div>
3
3
  <upload-from-computer
4
4
  :upload-directory-id="uploadDirectoryId"
5
+ @upload-complete="$emit('upload-complete')"
5
6
  @uploadProgressStateChange="isUploadInProgress = $event"/>
6
7
 
7
8
  <concrete-file-directory-input
@@ -12,7 +12,7 @@
12
12
  <button type="button"
13
13
  :class="{'btn': true, 'btn-outline-secondary': true, 'ccm-create-new-directory-button': true, 'disabled': disabled === true}"
14
14
  @click="toggleDirectoryInput" :disabled="disabled">
15
- Create New Folder
15
+ {{ i18n.createNewFolder }}
16
16
  </button>
17
17
  </div>
18
18
  <select v-else :id="directorySelectInputId" :name="inputName" class="ccm-directory-selector form-select" v-model="selectedDirectoryID" ref="directoryInput" :disabled="disabled">
@@ -24,16 +24,16 @@
24
24
  </div>
25
25
  <div v-if="showAddDirectoryButton" v-show="showAddDirectoryInput" class="ccm-new-directory-name-container">
26
26
  <div class="form-group">
27
- <label class="form-label" :for="directoryInputId">Name</label>
27
+ <label class="form-label" :for="directoryInputId">{{ i18n.name }}</label>
28
28
  <div class="input-group">
29
29
  <input type="text"
30
30
  :id="directoryInputId"
31
- placeholder="Please enter a name..." class="ccm-new-directory-name form-control"
31
+ :placeholder="i18n.specifyName" class="ccm-new-directory-name form-control"
32
32
  v-model="newDirectoryName" @keyup.enter.stop.prevent="createDirectory" :disabled="disabled">
33
33
  <button type="button"
34
34
  :class="{'btn': true, 'btn-outline-secondary': true, 'disabled': disabled === true}"
35
35
  @click.stop.prevent="createDirectory" :disabled="disabled">
36
- Add
36
+ {{ i18n.add }}
37
37
  </button>
38
38
  </div>
39
39
  </div>
@@ -46,6 +46,12 @@
46
46
  /* global CCM_DISPATCHER_FILENAME, CCM_SECURITY_TOKEN, ConcreteAjaxRequest, _ */
47
47
  export default {
48
48
  data: () => ({
49
+ i18n: {
50
+ createNewFolder: 'Create New Folder',
51
+ name: 'Name',
52
+ specifyName: 'Please enter a name...',
53
+ add: 'Add'
54
+ },
49
55
  showAddDirectoryInput: false,
50
56
  selectedDirectoryID: 0,
51
57
  directorySelectInputId: _.uniqueId('input-'),
@@ -109,6 +115,13 @@ export default {
109
115
  this.fetchDirectories()
110
116
  },
111
117
  mounted() {
118
+ if (window.ccmi18n_filemanager) {
119
+ for (const key in this.i18n) {
120
+ if (window.ccmi18n_filemanager[key]) {
121
+ this.i18n[key] = window.ccmi18n_filemanager[key]
122
+ }
123
+ }
124
+ }
112
125
  $(this.$refs.directoryInput).selectpicker()
113
126
 
114
127
  if (this.directoryId) {
@@ -52,6 +52,9 @@ export default {
52
52
  },
53
53
  chooseText: {
54
54
  type: String
55
+ },
56
+ filters: {
57
+ type: Array
55
58
  }
56
59
  },
57
60
  watch: {
@@ -84,9 +87,13 @@ export default {
84
87
  },
85
88
  openChooser: function() {
86
89
  var my = this
90
+ var options = {}
91
+ if (my.filters) {
92
+ options.filters = my.filters
93
+ }
87
94
  ConcreteFileManager.launchDialog(function(r) {
88
95
  my.loadFile(r.fID)
89
- })
96
+ }, options)
90
97
  },
91
98
  loadFile(fileId) {
92
99
  var my = this
@@ -6,14 +6,14 @@
6
6
  <a class="nav-link"
7
7
  :class="activeTab === 'image' ? 'active' : ''"
8
8
  @click="openTab('image')">
9
- Images
9
+ {{ i18n.images }}
10
10
  </a>
11
11
  </li>
12
12
  <li class="nav-item">
13
13
  <a class="nav-link"
14
14
  @click="openTab('settings')"
15
15
  :class="activeTab === 'settings' ? 'active' : ''">
16
- Settings
16
+ {{ i18n.settings }}
17
17
  </a>
18
18
  </li>
19
19
  </ul>
@@ -22,7 +22,7 @@
22
22
  <div v-show="activeTab === 'image'" id="galleryImages">
23
23
  <div class="text-end mt-4">
24
24
  <icon-button icon="plus" icon-type="fas" type="outline" class="btn btn-secondary" @click="addImage()">
25
- Add Images
25
+ {{ i18n.addImages }}
26
26
  </icon-button>
27
27
  </div>
28
28
  <div class="image-container mt-4"
@@ -51,13 +51,13 @@
51
51
  </div>
52
52
  <div v-show="activeTab === 'settings'" id="gallerySettings">
53
53
  <h3>
54
- Settings
54
+ {{ i18n.settings }}
55
55
  </h3>
56
56
 
57
57
  <div class="form-check">
58
58
  <input class="form-check-input" type="checkbox" id="includeDownloadLink" :value="1" :checked="$root.includeDownloadLink" name="includeDownloadLink">
59
59
  <label class="form-check-label" for="includeDownloadLink">
60
- Include link to download original
60
+ {{ i18n.includeOriginalDownloadLink }}
61
61
  </label>
62
62
  </div>
63
63
  </div>
@@ -143,6 +143,12 @@ export default {
143
143
  ...ImageDetail.components
144
144
  },
145
145
  data: () => ({
146
+ i18n: {
147
+ images: 'Images',
148
+ settings: 'Settings',
149
+ addImages: 'Add Images',
150
+ includeOriginalDownloadLink: 'Include link to download original'
151
+ },
146
152
  activeTab: 'image',
147
153
  activeImage: null
148
154
  }),
@@ -200,6 +206,15 @@ export default {
200
206
  })
201
207
  }
202
208
  },
209
+ mounted() {
210
+ if (window.ccmi18n_gallery) {
211
+ for (const key in this.i18n) {
212
+ if (window.ccmi18n_gallery[key]) {
213
+ this.i18n[key] = window.ccmi18n_gallery[key]
214
+ }
215
+ }
216
+ }
217
+ },
203
218
  props: {
204
219
  gallery: {
205
220
  type: Array,