Skip to content

Commit ed1d947

Browse files
authored
Merge pull request #1850 from nextcloud/backport/1835/stable27
2 parents 4da1f1a + 797aafd commit ed1d947

5 files changed

Lines changed: 118 additions & 9 deletions

File tree

js/viewer-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/viewer-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/services/FileList.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import { genFileInfo } from '../utils/fileUtils.js'
2828
*
2929
* @param {string} path the path relative to the user root
3030
* @param {object} [options] optional options for axios
31-
* @return {Array} the file list
3231
*/
3332
export default async function(path, options) {
3433
// getDirectoryContents doesn't accept / for root

src/services/Viewer.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ import Images from '../models/images.js'
2424
import Videos from '../models/videos.js'
2525
import Audios from '../models/audios.js'
2626

27+
/**
28+
* Handler type definition
29+
*
30+
* @typedef {object} Handler
31+
* @property {string} id unique identifier for the handler
32+
* @property {string[]} mimes list of mime types that are supported for opening
33+
* @property {object} component Vue component to render the file
34+
* @property {string} group group identifier to combine for navigating to the next/previous files
35+
* @property {?string} theme viewer modal theme (one of 'dark', 'light', 'default')
36+
* @property {boolean} canCompare Indicate support for comparing two files
37+
*/
38+
2739
/**
2840
* File info type definition
2941
*
@@ -41,12 +53,15 @@ export default class Viewer {
4153

4254
_state
4355
_mimetypes
56+
_mimetypesCompare
4457

4558
constructor() {
4659
this._mimetypes = []
60+
this._mimetypesCompare = []
4761
this._state = {}
4862
this._state.file = ''
4963
this._state.fileInfo = null
64+
this._state.compareFileInfo = null
5065
this._state.files = []
5166
this._state.enableSidebar = true
5267
this._state.el = null
@@ -71,6 +86,7 @@ export default class Viewer {
7186
*
7287
* @readonly
7388
* @memberof Viewer
89+
* @return {Handler[]}
7490
*/
7591
get availableHandlers() {
7692
return this._state.handlers
@@ -80,11 +96,14 @@ export default class Viewer {
8096
* Register a new handler
8197
*
8298
* @memberof Viewer
83-
* @param {object} handler a new unregistered handler
99+
* @param {Handler} handler a new unregistered handler
84100
*/
85101
registerHandler(handler) {
86102
this._state.handlers.push(handler)
87103
this._mimetypes.push.apply(this._mimetypes, handler.mimes)
104+
if (handler?.canCompare === true) {
105+
this._mimetypesCompare.push.apply(this._mimetypesCompare, handler.mimes)
106+
}
88107
}
89108

90109
/**
@@ -107,6 +126,16 @@ export default class Viewer {
107126
return this._state.fileInfo
108127
}
109128

129+
/**
130+
* Get the current comparison view opened file fileInfo
131+
*
132+
* @memberof Viewer
133+
* @return {?Fileinfo} the currently opened file fileInfo
134+
*/
135+
get compareFileInfo() {
136+
return this._state.compareFileInfo
137+
}
138+
110139
/**
111140
* Get the current files list
112141
*
@@ -147,6 +176,16 @@ export default class Viewer {
147176
return this._mimetypes
148177
}
149178

179+
/**
180+
* Get the supported mimetypes that can be opened side by side for comparison
181+
*
182+
* @memberof Viewer
183+
* @return {Array} list of mimetype strings that the viewer can open side by side for comparison
184+
*/
185+
get mimetypesCompare() {
186+
return this._mimetypesCompare
187+
}
188+
150189
/**
151190
* Return the method provided to fetch more results
152191
*
@@ -291,6 +330,20 @@ export default class Viewer {
291330
this.open(options)
292331
}
293332

333+
/**
334+
* Open the viewer with two files side by side
335+
*
336+
* @memberof Viewer
337+
* @param {Fileinfo} fileInfo current file
338+
* @param {Fileinfo} compareFileInfo older file to compare
339+
*/
340+
compare(fileInfo, compareFileInfo) {
341+
this.open({
342+
fileInfo,
343+
})
344+
this._state.compareFileInfo = compareFileInfo
345+
}
346+
294347
/**
295348
* Close the opened file
296349
*

src/views/Viewer.vue

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,23 @@
111111
</NcActionButton>
112112
</template>
113113

114-
<div class="viewer__content" @click.self.exact="close">
114+
<div class="viewer__content" :class="contentClass" @click.self.exact="close">
115+
<!-- COMPARE FILE -->
116+
<component :is="comparisonFile.modal"
117+
v-if="comparisonFile && !comparisonFile.failed && showComparison"
118+
:key="comparisonFile | uniqueKey"
119+
ref="comparison-content"
120+
v-bind="comparisonFile"
121+
:active="true"
122+
:can-swipe="false"
123+
:can-zoom="false"
124+
:editing="false"
125+
:is-full-screen="isFullscreen"
126+
:is-sidebar-shown="isSidebarShown"
127+
:loaded.sync="comparisonFile.loaded"
128+
class="viewer__file viewer__file--active"
129+
@error="comparisonFailed" />
130+
115131
<!-- PREVIOUS -->
116132
<component :is="previousFile.modal"
117133
v-if="previousFile && !previousFile.failed"
@@ -231,6 +247,7 @@ export default {
231247
currentIndex: 0,
232248
previousFile: {},
233249
currentFile: {},
250+
comparisonFile: null,
234251
nextFile: {},
235252
fileList: [],
236253
@@ -275,6 +292,9 @@ export default {
275292
fileInfo() {
276293
return this.Viewer.fileInfo
277294
},
295+
comparisonFileInfo() {
296+
return this.Viewer.compareFileInfo
297+
},
278298
files() {
279299
return this.Viewer.files
280300
},
@@ -340,7 +360,7 @@ export default {
340360
* @return {boolean}
341361
*/
342362
canDownload() {
343-
return canDownload()
363+
return canDownload() && !this.comparisonFile
344364
},
345365
346366
/**
@@ -354,6 +374,7 @@ export default {
354374
&& canDownload()
355375
&& this.currentFile?.permissions?.includes('W')
356376
&& this.isImage
377+
&& !this.comparisonFile
357378
},
358379
359380
modalClass() {
@@ -366,6 +387,16 @@ export default {
366387
'image--fullscreen': this.isImage && this.isFullscreenMode,
367388
}
368389
},
390+
391+
showComparison() {
392+
return !this.isMobile
393+
},
394+
395+
contentClass() {
396+
return {
397+
'viewer--split': this.comparisonFile,
398+
}
399+
},
369400
},
370401
371402
watch: {
@@ -407,6 +438,16 @@ export default {
407438
}
408439
},
409440
441+
comparisonFileInfo(fileInfo) {
442+
if (fileInfo) {
443+
logger.info('Opening viewer for comparisonFileInfo ', { fileInfo })
444+
this.compareFile(fileInfo)
445+
} else {
446+
// object is undefined, we're closing!
447+
this.cleanup()
448+
}
449+
},
450+
410451
files(fileList) {
411452
// the files list changed, let's update the current opened index
412453
const currentIndex = fileList.findIndex(file => file.basename === this.currentFile.basename)
@@ -517,7 +558,7 @@ export default {
517558
this.cancelRequestFile()
518559
519560
// do not open the same file again
520-
if (path === this.currentFile.path) {
561+
if (path === this.currentFile.path && !this.currentFile.source) {
521562
return
522563
}
523564
@@ -568,7 +609,7 @@ export default {
568609
this.cancelRequestFolder()
569610
570611
// do not open the same file info again
571-
if (fileInfo.basename === this.currentFile.basename) {
612+
if (fileInfo.basename === this.currentFile.basename && fileInfo.source !== this.currentFile.source) {
572613
return
573614
}
574615
@@ -638,6 +679,7 @@ export default {
638679
639680
// show file
640681
this.currentFile = new File(fileInfo, mime, handler.component)
682+
this.comparisonFile = null
641683
this.updatePreviousNext()
642684
643685
// if sidebar was opened before, let's update the file
@@ -657,6 +699,10 @@ export default {
657699
this.updatePreviousNext()
658700
},
659701
702+
async compareFile(fileInfo) {
703+
this.comparisonFile = new File(fileInfo, fileInfo.mime, this.components[fileInfo.mime])
704+
},
705+
660706
/**
661707
* Show sidebar if available and a file is already opened
662708
*/
@@ -872,6 +918,7 @@ export default {
872918
cleanup() {
873919
// reset all properties
874920
this.currentFile = {}
921+
this.comparisonFile = null
875922
this.currentModal = null
876923
this.fileList = []
877924
this.initiated = false
@@ -934,6 +981,10 @@ export default {
934981
/**
935982
* Failures handlers
936983
*/
984+
comparisonFailed() {
985+
this.comparisonFile.failed = true
986+
},
987+
937988
previousFailed() {
938989
this.previousFile.failed = true
939990
},
@@ -1086,6 +1137,12 @@ export default {
10861137
cursor: pointer;
10871138
}
10881139
1140+
&--split {
1141+
.viewer__file--active {
1142+
width: 50%;
1143+
}
1144+
}
1145+
10891146
:deep(.modal-wrapper) {
10901147
.modal-container {
10911148
// Ensure some space at the bottom

0 commit comments

Comments
 (0)