Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
8a23bcc9
Commit
8a23bcc9
authored
Jun 13, 2018
by
Tim Zallmann
Committed by
Phil Hughes
Jun 13, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Image Diff Viewing + Download Diff Viewing
parent
929f12b6
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
1204 additions
and
36 deletions
+1204
-36
app/assets/javascripts/ide/components/repo_editor.vue
app/assets/javascripts/ide/components/repo_editor.vue
+25
-6
app/assets/javascripts/ide/constants.js
app/assets/javascripts/ide/constants.js
+7
-0
app/assets/javascripts/ide/stores/mutations/file.js
app/assets/javascripts/ide/stores/mutations/file.js
+13
-1
app/assets/javascripts/ide/stores/utils.js
app/assets/javascripts/ide/stores/utils.js
+1
-1
app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
...red/components/content_viewer/viewers/download_viewer.vue
+4
-1
app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
...shared/components/content_viewer/viewers/image_viewer.vue
+35
-8
app/assets/javascripts/vue_shared/components/diff_viewer/constants.js
...avascripts/vue_shared/components/diff_viewer/constants.js
+12
-0
app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
...scripts/vue_shared/components/diff_viewer/diff_viewer.vue
+70
-0
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue
...d/components/diff_viewer/viewers/download_diff_viewer.vue
+69
-0
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue
...ents/diff_viewer/viewers/image_diff/onion_skin_viewer.vue
+160
-0
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue
...omponents/diff_viewer/viewers/image_diff/swipe_viewer.vue
+158
-0
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue
...mponents/diff_viewer/viewers/image_diff/two_up_viewer.vue
+41
-0
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue
...ared/components/diff_viewer/viewers/image_diff_viewer.vue
+109
-0
app/assets/javascripts/vue_shared/components/lib/utils/dom_utils.js
.../javascripts/vue_shared/components/lib/utils/dom_utils.js
+5
-0
app/assets/stylesheets/framework/files.scss
app/assets/stylesheets/framework/files.scss
+48
-0
app/assets/stylesheets/pages/diff.scss
app/assets/stylesheets/pages/diff.scss
+119
-13
app/assets/stylesheets/pages/repo.scss
app/assets/stylesheets/pages/repo.scss
+0
-1
changelogs/unreleased/tz-diff-blob-image-viewer.yml
changelogs/unreleased/tz-diff-blob-image-viewer.yml
+5
-0
spec/javascripts/fixtures/images/green_box.png
spec/javascripts/fixtures/images/green_box.png
+0
-0
spec/javascripts/fixtures/images/red_box.png
spec/javascripts/fixtures/images/red_box.png
+0
-0
spec/javascripts/ide/stores/mutations/file_spec.js
spec/javascripts/ide/stores/mutations/file_spec.js
+47
-0
spec/javascripts/test_constants.js
spec/javascripts/test_constants.js
+3
-0
spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js
...e_shared/components/content_viewer/content_viewer_spec.js
+5
-5
spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js
...pts/vue_shared/components/diff_viewer/diff_viewer_spec.js
+70
-0
spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js
.../components/diff_viewer/viewers/image_diff_viewer_spec.js
+185
-0
spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js
...scripts/vue_shared/components/lib/utils/dom_utils_spec.js
+13
-0
No files found.
app/assets/javascripts/ide/components/repo_editor.vue
View file @
8a23bcc9
...
...
@@ -2,6 +2,7 @@
import
{
mapState
,
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
flash
from
'
~/flash
'
;
import
ContentViewer
from
'
~/vue_shared/components/content_viewer/content_viewer.vue
'
;
import
DiffViewer
from
'
~/vue_shared/components/diff_viewer/diff_viewer.vue
'
;
import
{
activityBarViews
,
viewerTypes
}
from
'
../constants
'
;
import
Editor
from
'
../lib/editor
'
;
import
ExternalLink
from
'
./external_link.vue
'
;
...
...
@@ -9,6 +10,7 @@ import ExternalLink from './external_link.vue';
export
default
{
components
:
{
ContentViewer
,
DiffViewer
,
ExternalLink
,
},
props
:
{
...
...
@@ -29,9 +31,18 @@ export default {
shouldHideEditor
()
{
return
this
.
file
&&
this
.
file
.
binary
&&
!
this
.
file
.
content
;
},
showContentViewer
()
{
return
(
(
this
.
shouldHideEditor
||
this
.
file
.
viewMode
===
'
preview
'
)
&&
(
this
.
viewer
!==
viewerTypes
.
mr
||
!
this
.
file
.
mrChange
)
);
},
showDiffViewer
()
{
return
this
.
shouldHideEditor
&&
this
.
file
.
mrChange
&&
this
.
viewer
===
viewerTypes
.
mr
;
},
editTabCSS
()
{
return
{
active
:
this
.
file
.
viewMode
===
'
edit
'
,
active
:
this
.
file
.
viewMode
===
'
edit
or
'
,
};
},
previewTabCSS
()
{
...
...
@@ -53,7 +64,7 @@ export default {
if
(
this
.
currentActivityView
!==
activityBarViews
.
edit
)
{
this
.
setFileViewMode
({
file
:
this
.
file
,
viewMode
:
'
edit
'
,
viewMode
:
'
edit
or
'
,
});
}
}
...
...
@@ -62,7 +73,7 @@ export default {
if
(
this
.
currentActivityView
!==
activityBarViews
.
edit
)
{
this
.
setFileViewMode
({
file
:
this
.
file
,
viewMode
:
'
edit
'
,
viewMode
:
'
edit
or
'
,
});
}
},
...
...
@@ -197,7 +208,7 @@ export default {
<a
href=
"javascript:void(0);"
role=
"button"
@
click.prevent=
"setFileViewMode(
{ file, viewMode: 'edit' })">
@
click.prevent=
"setFileViewMode(
{ file, viewMode: 'edit
or
' })">
<template
v-if=
"viewer === $options.viewerTypes.edit"
>
{{
__
(
'
Edit
'
)
}}
</
template
>
...
...
@@ -222,7 +233,7 @@ export default {
/>
</div>
<div
v-show=
"!shouldHideEditor && file.viewMode ===
'edit
'"
v-show=
"!shouldHideEditor && file.viewMode ===
'editor
'"
ref=
"editor"
class=
"multi-file-editor-holder"
:class=
"{
...
...
@@ -231,10 +242,18 @@ export default {
>
</div>
<content-viewer
v-if=
"sho
uldHideEditor || file.viewMode === 'preview'
"
v-if=
"sho
wContentViewer
"
:content=
"file.content || file.raw"
:path=
"file.rawPath || file.path"
:file-size=
"file.size"
:project-path=
"file.projectId"
/>
<diff-viewer
v-if=
"showDiffViewer"
:diff-mode=
"file.mrChange.diffMode"
:new-path=
"file.mrChange.new_path"
:new-sha=
"currentMergeRequest.sha"
:old-path=
"file.mrChange.old_path"
:old-sha=
"currentMergeRequest.baseCommitSha"
:project-path=
"file.projectId"
/>
</div>
</template>
app/assets/javascripts/ide/constants.js
View file @
8a23bcc9
...
...
@@ -21,6 +21,13 @@ export const viewerTypes = {
diff
:
'
diff
'
,
};
export
const
diffModes
=
{
replaced
:
'
replaced
'
,
new
:
'
new
'
,
deleted
:
'
deleted
'
,
renamed
:
'
renamed
'
,
};
export
const
rightSidebarViews
=
{
pipelines
:
'
pipelines-list
'
,
jobsDetail
:
'
jobs-detail
'
,
...
...
app/assets/javascripts/ide/stores/mutations/file.js
View file @
8a23bcc9
/* eslint-disable no-param-reassign */
import
*
as
types
from
'
../mutation_types
'
;
import
{
diffModes
}
from
'
../../constants
'
;
export
default
{
[
types
.
SET_FILE_ACTIVE
](
state
,
{
path
,
active
})
{
...
...
@@ -85,8 +86,19 @@ export default {
});
},
[
types
.
SET_FILE_MERGE_REQUEST_CHANGE
](
state
,
{
file
,
mrChange
})
{
let
diffMode
=
diffModes
.
replaced
;
if
(
mrChange
.
new_file
)
{
diffMode
=
diffModes
.
new
;
}
else
if
(
mrChange
.
deleted_file
)
{
diffMode
=
diffModes
.
deleted
;
}
else
if
(
mrChange
.
renamed_file
)
{
diffMode
=
diffModes
.
renamed
;
}
Object
.
assign
(
state
.
entries
[
file
.
path
],
{
mrChange
,
mrChange
:
{
...
mrChange
,
diffMode
,
},
});
},
[
types
.
SET_FILE_VIEWMODE
](
state
,
{
file
,
viewMode
})
{
...
...
app/assets/javascripts/ide/stores/utils.js
View file @
8a23bcc9
...
...
@@ -39,7 +39,7 @@ export const dataStructure = () => ({
editorColumn
:
1
,
fileLanguage
:
''
,
eol
:
''
,
viewMode
:
'
edit
'
,
viewMode
:
'
edit
or
'
,
previewMode
:
null
,
size
:
0
,
parentPath
:
null
,
...
...
app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
View file @
8a23bcc9
...
...
@@ -32,7 +32,10 @@ export default {
<div
class=
"file-container"
>
<div
class=
"file-content"
>
<p
class=
"prepend-top-10 file-info"
>
{{
fileName
}}
(
{{
fileSizeReadable
}}
)
{{
fileName
}}
<template
v-if=
"fileSize > 0"
>
(
{{
fileSizeReadable
}}
)
</
template
>
</p>
<a
:href=
"path"
...
...
app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
View file @
8a23bcc9
<
script
>
import
_
from
'
underscore
'
;
import
{
numberToHumanSize
}
from
'
../../../../lib/utils/number_utils
'
;
export
default
{
...
...
@@ -12,6 +13,10 @@ export default {
required
:
false
,
default
:
0
,
},
renderInfo
:
{
type
:
Boolean
,
default
:
true
,
},
},
data
()
{
return
{
...
...
@@ -26,14 +31,34 @@ export default {
return
numberToHumanSize
(
this
.
fileSize
);
},
},
beforeDestroy
()
{
window
.
removeEventListener
(
'
resize
'
,
this
.
resizeThrottled
,
false
);
},
mounted
()
{
// The onImgLoad may have happened before the control was actually mounted
this
.
onImgLoad
();
this
.
resizeThrottled
=
_
.
throttle
(
this
.
onImgLoad
,
400
);
window
.
addEventListener
(
'
resize
'
,
this
.
resizeThrottled
,
false
);
},
methods
:
{
onImgLoad
()
{
const
contentImg
=
this
.
$refs
.
contentImg
;
this
.
isZoomable
=
contentImg
.
naturalWidth
>
contentImg
.
width
||
contentImg
.
naturalHeight
>
contentImg
.
height
;
this
.
width
=
contentImg
.
naturalWidth
;
this
.
height
=
contentImg
.
naturalHeight
;
if
(
contentImg
)
{
this
.
isZoomable
=
contentImg
.
naturalWidth
>
contentImg
.
width
||
contentImg
.
naturalHeight
>
contentImg
.
height
;
this
.
width
=
contentImg
.
naturalWidth
;
this
.
height
=
contentImg
.
naturalHeight
;
this
.
$emit
(
'
imgLoaded
'
,
{
width
:
this
.
width
,
height
:
this
.
height
,
renderedWidth
:
contentImg
.
clientWidth
,
renderedHeight
:
contentImg
.
clientHeight
,
});
}
},
onImgClick
()
{
if
(
this
.
isZoomable
)
this
.
isZoomed
=
!
this
.
isZoomed
;
...
...
@@ -47,20 +72,22 @@ export default {
<div
class=
"file-content image_file"
>
<img
ref=
"contentImg"
:class=
"
{ 'is
Zoomable': isZoomable, 'isZ
oomed': isZoomed }"
:class=
"
{ 'is
-zoomable': isZoomable, 'is-z
oomed': isZoomed }"
:src="path"
:alt="path"
@load="onImgLoad"
@click="onImgClick"/>
<p
class=
"file-info prepend-top-10"
>
<p
v-if=
"renderInfo"
class=
"file-info prepend-top-10"
>
<template
v-if=
"fileSize>0"
>
{{
fileSizeReadable
}}
</
template
>
<
template
v-if=
"fileSize>0 && width && height"
>
-
|
</
template
>
<
template
v-if=
"width && height"
>
{{
width
}}
x
{{
height
}}
W:
{{
width
}}
| H:
{{
height
}}
</
template
>
</p>
</div>
...
...
app/assets/javascripts/vue_shared/components/diff_viewer/constants.js
0 → 100644
View file @
8a23bcc9
export
const
diffModes
=
{
replaced
:
'
replaced
'
,
new
:
'
new
'
,
deleted
:
'
deleted
'
,
renamed
:
'
renamed
'
,
};
export
const
imageViewMode
=
{
twoup
:
'
twoup
'
,
swipe
:
'
swipe
'
,
onion
:
'
onion
'
,
};
app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
0 → 100644
View file @
8a23bcc9
<
script
>
import
{
viewerInformationForPath
}
from
'
../content_viewer/lib/viewer_utils
'
;
import
ImageDiffViewer
from
'
./viewers/image_diff_viewer.vue
'
;
import
DownloadDiffViewer
from
'
./viewers/download_diff_viewer.vue
'
;
export
default
{
props
:
{
diffMode
:
{
type
:
String
,
required
:
true
,
},
newPath
:
{
type
:
String
,
required
:
true
,
},
newSha
:
{
type
:
String
,
required
:
true
,
},
oldPath
:
{
type
:
String
,
required
:
true
,
},
oldSha
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
computed
:
{
viewer
()
{
if
(
!
this
.
newPath
)
return
null
;
const
previewInfo
=
viewerInformationForPath
(
this
.
newPath
);
if
(
!
previewInfo
)
return
DownloadDiffViewer
;
switch
(
previewInfo
.
id
)
{
case
'
image
'
:
return
ImageDiffViewer
;
default
:
return
DownloadDiffViewer
;
}
},
fullOldPath
()
{
return
`
${
gon
.
relative_url_root
}
/
${
this
.
projectPath
}
/raw/
${
this
.
oldSha
}
/
${
this
.
oldPath
}
`
;
},
fullNewPath
()
{
return
`
${
gon
.
relative_url_root
}
/
${
this
.
projectPath
}
/raw/
${
this
.
newSha
}
/
${
this
.
newPath
}
`
;
},
},
};
</
script
>
<
template
>
<div
class=
"diff-file preview-container"
v-if=
"viewer"
>
<component
:is=
"viewer"
:diff-mode=
"diffMode"
:new-path=
"fullNewPath"
:old-path=
"fullOldPath"
:project-path=
"projectPath"
/>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue
0 → 100644
View file @
8a23bcc9
<
script
>
import
DownloadViewer
from
'
../../content_viewer/viewers/download_viewer.vue
'
;
import
{
diffModes
}
from
'
../constants
'
;
export
default
{
components
:
{
DownloadViewer
,
},
props
:
{
diffMode
:
{
type
:
String
,
required
:
true
,
},
newPath
:
{
type
:
String
,
required
:
true
,
},
oldPath
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
diffModes
,
};
</
script
>
<
template
>
<div
class=
"diff-file-container"
>
<div
class=
"diff-viewer"
>
<div
v-if=
"diffMode === $options.diffModes.replaced"
class=
"two-up view row"
>
<div
class=
"col-sm-6 deleted"
>
<download-viewer
:path=
"oldPath"
:project-path=
"projectPath"
/>
</div>
<div
class=
"col-sm-6 added"
>
<download-viewer
:path=
"newPath"
:project-path=
"projectPath"
/>
</div>
</div>
<div
v-else-if=
"diffMode === $options.diffModes.new"
class=
"added"
>
<download-viewer
:path=
"newPath"
:project-path=
"projectPath"
/>
</div>
<div
v-else
class=
"deleted"
>
<download-viewer
:path=
"oldPath"
:project-path=
"projectPath"
/>
</div>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue
0 → 100644
View file @
8a23bcc9
<
script
>
import
{
pixeliseValue
}
from
'
../../../lib/utils/dom_utils
'
;
import
ImageViewer
from
'
../../../content_viewer/viewers/image_viewer.vue
'
;
export
default
{
components
:
{
ImageViewer
,
},
props
:
{
newPath
:
{
type
:
String
,
required
:
true
,
},
oldPath
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
data
()
{
return
{
onionMaxWidth
:
undefined
,
onionMaxHeight
:
undefined
,
onionOldImgInfo
:
null
,
onionNewImgInfo
:
null
,
onionDraggerPos
:
0
,
onionOpacity
:
1
,
dragging
:
false
,
};
},
computed
:
{
onionMaxPixelWidth
()
{
return
pixeliseValue
(
this
.
onionMaxWidth
);
},
onionMaxPixelHeight
()
{
return
pixeliseValue
(
this
.
onionMaxHeight
);
},
onionDraggerPixelPos
()
{
return
pixeliseValue
(
this
.
onionDraggerPos
);
},
},
beforeDestroy
()
{
document
.
body
.
removeEventListener
(
'
mouseup
'
,
this
.
stopDrag
);
this
.
$refs
.
dragger
.
removeEventListener
(
'
mousedown
'
,
this
.
startDrag
);
},
methods
:
{
dragMove
(
e
)
{
if
(
!
this
.
dragging
)
return
;
const
left
=
e
.
pageX
-
this
.
$refs
.
dragTrack
.
getBoundingClientRect
().
left
;
const
dragTrackWidth
=
this
.
$refs
.
dragTrack
.
clientWidth
-
this
.
$refs
.
dragger
.
clientWidth
||
100
;
let
leftValue
=
left
;
if
(
leftValue
<
0
)
leftValue
=
0
;
if
(
leftValue
>
dragTrackWidth
)
leftValue
=
dragTrackWidth
;
this
.
onionOpacity
=
left
/
dragTrackWidth
;
this
.
onionDraggerPos
=
leftValue
;
},
startDrag
()
{
this
.
dragging
=
true
;
document
.
body
.
style
.
userSelect
=
'
none
'
;
document
.
body
.
addEventListener
(
'
mousemove
'
,
this
.
dragMove
);
},
stopDrag
()
{
this
.
dragging
=
false
;
document
.
body
.
style
.
userSelect
=
''
;
document
.
body
.
removeEventListener
(
'
mousemove
'
,
this
.
dragMove
);
},
prepareOnionSkin
()
{
if
(
this
.
onionOldImgInfo
&&
this
.
onionNewImgInfo
)
{
this
.
onionMaxWidth
=
Math
.
max
(
this
.
onionOldImgInfo
.
renderedWidth
,
this
.
onionNewImgInfo
.
renderedWidth
,
);
this
.
onionMaxHeight
=
Math
.
max
(
this
.
onionOldImgInfo
.
renderedHeight
,
this
.
onionNewImgInfo
.
renderedHeight
,
);
this
.
onionOpacity
=
1
;
this
.
onionDraggerPos
=
this
.
$refs
.
dragTrack
.
clientWidth
-
this
.
$refs
.
dragger
.
clientWidth
||
100
;
document
.
body
.
addEventListener
(
'
mouseup
'
,
this
.
stopDrag
);
}
},
onionNewImgLoaded
(
imgInfo
)
{
this
.
onionNewImgInfo
=
imgInfo
;
this
.
prepareOnionSkin
();
},
onionOldImgLoaded
(
imgInfo
)
{
this
.
onionOldImgInfo
=
imgInfo
;
this
.
prepareOnionSkin
();
},
},
};
</
script
>
<
template
>
<div
class=
"onion-skin view"
>
<div
class=
"onion-skin-frame"
:style=
"
{
'width': onionMaxPixelWidth,
'height': onionMaxPixelHeight,
'user-select': dragging === true ? 'none' : '',
}">
<div
class=
"frame deleted"
:style=
"
{
'width': onionMaxPixelWidth,
'height': onionMaxPixelHeight,
}">
<image-viewer
key=
"onionOldImg"
:render-info=
"false"
:path=
"oldPath"
:project-path=
"projectPath"
@
imgLoaded=
"onionOldImgLoaded"
/>
</div>
<div
class=
"added frame"
ref=
"addedFrame"
:style=
"
{
'opacity': onionOpacity,
'width': onionMaxPixelWidth,
'height': onionMaxPixelHeight,
}">
<image-viewer
key=
"onionNewImg"
:render-info=
"false"
:path=
"newPath"
:project-path=
"projectPath"
@
imgLoaded=
"onionNewImgLoaded"
/>
</div>
<div
class=
"controls"
>
<div
class=
"transparent"
></div>
<div
class=
"drag-track"
ref=
"dragTrack"
@
mousedown=
"startDrag"
@
mouseup=
"stopDrag"
>
<div
class=
"dragger"
ref=
"dragger"
:style=
"
{ 'left': onionDraggerPixelPos }">
</div>
</div>
<div
class=
"opaque"
></div>
</div>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue
0 → 100644
View file @
8a23bcc9
<
script
>
import
_
from
'
underscore
'
;
import
{
pixeliseValue
}
from
'
../../../lib/utils/dom_utils
'
;
import
ImageViewer
from
'
../../../content_viewer/viewers/image_viewer.vue
'
;
export
default
{
components
:
{
ImageViewer
,
},
props
:
{
newPath
:
{
type
:
String
,
required
:
true
,
},
oldPath
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
data
()
{
return
{
dragging
:
false
,
swipeOldImgInfo
:
null
,
swipeNewImgInfo
:
null
,
swipeMaxWidth
:
undefined
,
swipeMaxHeight
:
undefined
,
swipeBarPos
:
1
,
swipeWrapWidth
:
undefined
,
};
},
computed
:
{
swipeMaxPixelWidth
()
{
return
pixeliseValue
(
this
.
swipeMaxWidth
);
},
swipeMaxPixelHeight
()
{
return
pixeliseValue
(
this
.
swipeMaxHeight
);
},
swipeWrapPixelWidth
()
{
return
pixeliseValue
(
this
.
swipeWrapWidth
);
},
swipeBarPixelPos
()
{
return
pixeliseValue
(
this
.
swipeBarPos
);
},
},
beforeDestroy
()
{
window
.
removeEventListener
(
'
resize
'
,
this
.
resizeThrottled
,
false
);
document
.
body
.
removeEventListener
(
'
mouseup
'
,
this
.
stopDrag
);
document
.
body
.
removeEventListener
(
'
mousemove
'
,
this
.
dragMove
);
},
mounted
()
{
window
.
addEventListener
(
'
resize
'
,
this
.
resize
,
false
);
},
methods
:
{
dragMove
(
e
)
{
if
(
!
this
.
dragging
)
return
;
let
leftValue
=
e
.
pageX
-
this
.
$refs
.
swipeFrame
.
getBoundingClientRect
().
left
;
const
spaceLeft
=
20
;
const
{
clientWidth
}
=
this
.
$refs
.
swipeFrame
;
if
(
leftValue
<=
0
)
{
leftValue
=
0
;
}
else
if
(
leftValue
>
clientWidth
-
spaceLeft
)
{
leftValue
=
clientWidth
-
spaceLeft
;
}
this
.
swipeWrapWidth
=
this
.
swipeMaxWidth
-
leftValue
;
this
.
swipeBarPos
=
leftValue
;
},
startDrag
()
{
this
.
dragging
=
true
;
document
.
body
.
style
.
userSelect
=
'
none
'
;
document
.
body
.
addEventListener
(
'
mousemove
'
,
this
.
dragMove
);
},
stopDrag
()
{
this
.
dragging
=
false
;
document
.
body
.
style
.
userSelect
=
''
;
document
.
body
.
removeEventListener
(
'
mousemove
'
,
this
.
dragMove
);
},
prepareSwipe
()
{
if
(
this
.
swipeOldImgInfo
&&
this
.
swipeNewImgInfo
)
{
// Add 2 for border width
this
.
swipeMaxWidth
=
Math
.
max
(
this
.
swipeOldImgInfo
.
renderedWidth
,
this
.
swipeNewImgInfo
.
renderedWidth
)
+
2
;
this
.
swipeWrapWidth
=
this
.
swipeMaxWidth
;
this
.
swipeMaxHeight
=
Math
.
max
(
this
.
swipeOldImgInfo
.
renderedHeight
,
this
.
swipeNewImgInfo
.
renderedHeight
)
+
2
;
document
.
body
.
addEventListener
(
'
mouseup
'
,
this
.
stopDrag
);
}
},
swipeNewImgLoaded
(
imgInfo
)
{
this
.
swipeNewImgInfo
=
imgInfo
;
this
.
prepareSwipe
();
},
swipeOldImgLoaded
(
imgInfo
)
{
this
.
swipeOldImgInfo
=
imgInfo
;
this
.
prepareSwipe
();
},
resize
:
_
.
throttle
(
function
throttledResize
()
{
this
.
swipeBarPos
=
0
;
},
400
),
},
};
</
script
>
<
template
>
<div
class=
"swipe view"
>
<div
class=
"swipe-frame"
ref=
"swipeFrame"
:style=
"
{
'width': swipeMaxPixelWidth,
'height': swipeMaxPixelHeight,
}">
<div
class=
"frame deleted"
>
<image-viewer
key=
"swipeOldImg"
ref=
"swipeOldImg"
:render-info=
"false"
:path=
"oldPath"
:project-path=
"projectPath"
@
imgLoaded=
"swipeOldImgLoaded"
/>
</div>
<div
class=
"swipe-wrap"
ref=
"swipeWrap"
:style=
"
{
'width': swipeWrapPixelWidth,
'height': swipeMaxPixelHeight,
}">
<div
class=
"frame added"
>
<image-viewer
key=
"swipeNewImg"
:render-info=
"false"
:path=
"newPath"
:project-path=
"projectPath"
@
imgLoaded=
"swipeNewImgLoaded"
/>
</div>
</div>
<span
class=
"swipe-bar"
ref=
"swipeBar"
@
mousedown=
"startDrag"
@
mouseup=
"stopDrag"
:style=
"
{ 'left': swipeBarPixelPos }">
<span
class=
"top-handle"
></span>
<span
class=
"bottom-handle"
></span>
</span>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue
0 → 100644
View file @
8a23bcc9
<
script
>
import
ImageViewer
from
'
../../../content_viewer/viewers/image_viewer.vue
'
;
export
default
{
components
:
{
ImageViewer
,
},
props
:
{
newPath
:
{
type
:
String
,
required
:
true
,
},
oldPath
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
};
</
script
>
<
template
>
<div
class=
"two-up view row"
>
<div
class=
"col-sm-6 frame deleted"
>
<image-viewer
:path=
"oldPath"
:project-path=
"projectPath"
/>
</div>
<div
class=
"col-sm-6 frame added"
>
<image-viewer
:path=
"newPath"
:project-path=
"projectPath"
/>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue
0 → 100644
View file @
8a23bcc9
<
script
>
import
ImageViewer
from
'
../../content_viewer/viewers/image_viewer.vue
'
;
import
TwoUpViewer
from
'
./image_diff/two_up_viewer.vue
'
;
import
SwipeViewer
from
'
./image_diff/swipe_viewer.vue
'
;
import
OnionSkinViewer
from
'
./image_diff/onion_skin_viewer.vue
'
;
import
{
diffModes
,
imageViewMode
}
from
'
../constants
'
;
export
default
{
components
:
{
ImageViewer
,
TwoUpViewer
,
SwipeViewer
,
OnionSkinViewer
,
},
props
:
{
diffMode
:
{
type
:
String
,
required
:
true
,
},
newPath
:
{
type
:
String
,
required
:
true
,
},
oldPath
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
data
()
{
return
{
mode
:
imageViewMode
.
twoup
,
};
},
methods
:
{
changeMode
(
newMode
)
{
this
.
mode
=
newMode
;
},
},
diffModes
,
imageViewMode
,
};
</
script
>
<
template
>
<div
class=
"diff-file-container"
>
<div
class=
"diff-viewer"
v-if=
"diffMode === $options.diffModes.replaced"
>
<div
class=
"image js-replaced-image"
>
<two-up-viewer
v-if=
"mode === $options.imageViewMode.twoup"
v-bind=
"$props"
/>
<swipe-viewer
v-else-if=
"mode === $options.imageViewMode.swipe"
v-bind=
"$props"
/>
<onion-skin-viewer
v-else-if=
"mode === $options.imageViewMode.onion"
v-bind=
"$props"
/>
</div>
<div
class=
"view-modes"
>
<ul
class=
"view-modes-menu"
>
<li
:class=
"
{
active: mode === $options.imageViewMode.twoup
}"
@click="changeMode($options.imageViewMode.twoup)">
{{
s__
(
'
ImageDiffViewer|2-up
'
)
}}
</li>
<li
:class=
"
{
active: mode === $options.imageViewMode.swipe
}"
@click="changeMode($options.imageViewMode.swipe)">
{{
s__
(
'
ImageDiffViewer|Swipe
'
)
}}
</li>
<li
:class=
"
{
active: mode === $options.imageViewMode.onion
}"
@click="changeMode($options.imageViewMode.onion)">
{{
s__
(
'
ImageDiffViewer|Onion skin
'
)
}}
</li>
</ul>
</div>
<div
class=
"note-container"
></div>
</div>
<div
v-else-if=
"diffMode === $options.diffModes.new"
class=
"diff-viewer added"
>
<image-viewer
:path=
"newPath"
:project-path=
"projectPath"
/>
</div>
<div
v-else
class=
"diff-viewer deleted"
>
<image-viewer
:path=
"oldPath"
:project-path=
"projectPath"
/>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/lib/utils/dom_utils.js
0 → 100644
View file @
8a23bcc9
export
function
pixeliseValue
(
val
)
{
return
val
?
`
${
val
}
px`
:
''
;
}
export
default
{};
app/assets/stylesheets/framework/files.scss
View file @
8a23bcc9
...
...
@@ -400,3 +400,51 @@ span.idiff {
color
:
$common-gray-light
;
border
:
1px
solid
$common-gray-light
;
}
.preview-container
{
height
:
100%
;
overflow
:
auto
;
.file-container
{
background-color
:
$gray-darker
;
display
:
flex
;
height
:
100%
;
align-items
:
center
;
justify-content
:
center
;
text-align
:
center
;
.file-content
{
padding
:
$gl-padding
;
max-width
:
100%
;
max-height
:
100%
;
img
{
max-width
:
90%
;
max-height
:
70vh
;
}
.is-zoomable
{
cursor
:
pointer
;
cursor
:
zoom-in
;
&
.is-zoomed
{
cursor
:
pointer
;
cursor
:
zoom-out
;
max-width
:
none
;
max-height
:
none
;
margin-right
:
$gl-padding
;
}
}
}
.file-info
{
font-size
:
$label-font-size
;
color
:
$diff-image-info-color
;
}
}
.md-previewer
{
padding
:
$gl-padding
;
}
}
app/assets/stylesheets/pages/diff.scss
View file @
8a23bcc9
...
...
@@ -189,8 +189,22 @@
img
{
border
:
1px
solid
$white-light
;
background-image
:
linear-gradient
(
45deg
,
$border-color
25%
,
transparent
25%
,
transparent
75%
,
$border-color
75%
,
$border-color
100%
)
,
linear-gradient
(
45deg
,
$border-color
25%
,
transparent
25%
,
transparent
75%
,
$border-color
75%
,
$border-color
100%
);
background-image
:
linear-gradient
(
45deg
,
$border-color
25%
,
transparent
25%
,
transparent
75%
,
$border-color
75%
,
$border-color
100%
)
,
linear-gradient
(
45deg
,
$border-color
25%
,
transparent
25%
,
transparent
75%
,
$border-color
75%
,
$border-color
100%
);
background-size
:
10px
10px
;
background-position
:
0
0
,
5px
5px
;
max-width
:
100%
;
...
...
@@ -395,6 +409,69 @@
.line_content
{
white-space
:
pre-wrap
;
}
.diff-file-container
{
.frame.deleted
{
border
:
0
;
background-color
:
inherit
;
.image_file
img
{
border
:
1px
solid
$deleted
;
}
}
.frame.added
{
border
:
0
;
background-color
:
inherit
;
.image_file
img
{
border
:
1px
solid
$added
;
}
}
.swipe.view
,
.onion-skin.view
{
.swipe-wrap
{
top
:
0
;
right
:
0
;
}
.frame.deleted
{
top
:
0
;
right
:
0
;
}
.swipe-bar
{
top
:
0
;
.top-handle
{
top
:
-14px
;
left
:
-7px
;
}
.bottom-handle
{
bottom
:
-14px
;
left
:
-7px
;
}
}
.file-container
{
display
:
inline-block
;
.file-content
{
padding
:
0
;
img
{
max-width
:
none
;
}
}
}
}
.onion-skin.view
.controls
{
bottom
:
-25px
;
}
}
}
.file-content
.diff-file
{
...
...
@@ -536,7 +613,7 @@
margin-right
:
0
;
border-color
:
$white-light
;
cursor
:
pointer
;
transition
:
all
.1s
ease-out
;
transition
:
all
0
.1s
ease-out
;
@for
$i
from
1
through
4
{
&
:nth-child
(
#{
$i
}
)
{
...
...
@@ -563,7 +640,7 @@
height
:
24px
;
border-radius
:
50%
;
padding
:
0
;
transition
:
transform
.1s
ease-out
;
transition
:
transform
0
.1s
ease-out
;
z-index
:
100
;
.collapse-icon
{
...
...
@@ -708,11 +785,35 @@
width
:
100%
;
height
:
10px
;
background-color
:
$white-light
;
background-image
:
linear-gradient
(
45deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
)
,
linear-gradient
(
225deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
)
,
linear-gradient
(
135deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
)
,
linear-gradient
(
-45deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
);
background-position
:
5px
5px
,
0
5px
,
0
5px
,
5px
5px
;
background-image
:
linear-gradient
(
45deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
)
,
linear-gradient
(
225deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
)
,
linear-gradient
(
135deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
)
,
linear-gradient
(
-45deg
,
transparent
,
transparent
73%
,
$diff-jagged-border-gradient-color
75%
,
$white-light
80%
);
background-position
:
5px
5px
,
0
5px
,
0
5px
,
5px
5px
;
background-size
:
10px
10px
;
background-repeat
:
repeat
;
}
...
...
@@ -750,11 +851,16 @@
.frame.click-to-comment
{
position
:
relative
;
cursor
:
image-url
(
'illustrations/image_comment_light_cursor.svg'
)
$image-comment-cursor-left-offset
$image-comment-cursor-top-offset
,
auto
;
$image-comment-cursor-left-offset
$image-comment-cursor-top-offset
,
auto
;
// Retina cursor
cursor
:
-webkit-image-set
(
image-url
(
'illustrations/image_comment_light_cursor.svg'
)
1x
,
image-url
(
'illustrations/image_comment_light_cursor@2x.svg'
)
2x
)
$image-comment-cursor-left-offset
$image-comment-cursor-top-offset
,
auto
;
cursor
:
-webkit-image-set
(
image-url
(
'illustrations/image_comment_light_cursor.svg'
)
1x
,
image-url
(
'illustrations/image_comment_light_cursor@2x.svg'
)
2x
)
$image-comment-cursor-left-offset
$image-comment-cursor-top-offset
,
auto
;
.comment-indicator
{
position
:
absolute
;
...
...
@@ -840,7 +946,7 @@
.diff-notes-collapse
,
.note
,
.discussion-reply-holder
,
{
.discussion-reply-holder
{
display
:
none
;
}
...
...
app/assets/stylesheets/pages/repo.scss
View file @
8a23bcc9
...
...
@@ -335,7 +335,6 @@
img
{
max-width
:
90%
;
max-height
:
90%
;
}
.isZoomable
{
...
...
changelogs/unreleased/tz-diff-blob-image-viewer.yml
0 → 100644
View file @
8a23bcc9
---
title
:
Web IDE supports now Image + Download Diff Viewing
merge_request
:
18768
author
:
type
:
added
spec/javascripts/fixtures/images/green_box.png
0 → 100644
View file @
8a23bcc9
1.28 KB
spec/javascripts/fixtures/images/red_box.png
0 → 100644
View file @
8a23bcc9
1.27 KB
spec/javascripts/ide/stores/mutations/file_spec.js
View file @
8a23bcc9
...
...
@@ -152,6 +152,53 @@ describe('IDE store file mutations', () => {
expect
(
localFile
.
mrChange
.
diff
).
toBe
(
'
ABC
'
);
});
it
(
'
has diffMode replaced by default
'
,
()
=>
{
mutations
.
SET_FILE_MERGE_REQUEST_CHANGE
(
localState
,
{
file
:
localFile
,
mrChange
:
{
diff
:
'
ABC
'
,
},
});
expect
(
localFile
.
mrChange
.
diffMode
).
toBe
(
'
replaced
'
);
});
it
(
'
has diffMode new
'
,
()
=>
{
mutations
.
SET_FILE_MERGE_REQUEST_CHANGE
(
localState
,
{
file
:
localFile
,
mrChange
:
{
diff
:
'
ABC
'
,
new_file
:
true
,
},
});
expect
(
localFile
.
mrChange
.
diffMode
).
toBe
(
'
new
'
);
});
it
(
'
has diffMode deleted
'
,
()
=>
{
mutations
.
SET_FILE_MERGE_REQUEST_CHANGE
(
localState
,
{
file
:
localFile
,
mrChange
:
{
diff
:
'
ABC
'
,
deleted_file
:
true
,
},
});
expect
(
localFile
.
mrChange
.
diffMode
).
toBe
(
'
deleted
'
);
});
it
(
'
has diffMode renamed
'
,
()
=>
{
mutations
.
SET_FILE_MERGE_REQUEST_CHANGE
(
localState
,
{
file
:
localFile
,
mrChange
:
{
diff
:
'
ABC
'
,
renamed_file
:
true
,
},
});
expect
(
localFile
.
mrChange
.
diffMode
).
toBe
(
'
renamed
'
);
});
});
describe
(
'
DISCARD_FILE_CHANGES
'
,
()
=>
{
...
...
spec/javascripts/test_constants.js
View file @
8a23bcc9
...
...
@@ -2,3 +2,6 @@ export const FIXTURES_PATH = '/base/spec/javascripts/fixtures';
export
const
TEST_HOST
=
'
http://test.host
'
;
export
const
DUMMY_IMAGE_URL
=
`
${
FIXTURES_PATH
}
/one_white_pixel.png`
;
export
const
GREEN_BOX_IMAGE_URL
=
`
${
FIXTURES_PATH
}
/images/green_box.png`
;
export
const
RED_BOX_IMAGE_URL
=
`
${
FIXTURES_PATH
}
/images/red_box.png`
;
spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js
View file @
8a23bcc9
...
...
@@ -3,6 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
contentViewer
from
'
~/vue_shared/components/content_viewer/content_viewer.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
GREEN_BOX_IMAGE_URL
}
from
'
spec/test_constants
'
;
describe
(
'
ContentViewer
'
,
()
=>
{
let
vm
;
...
...
@@ -41,12 +42,12 @@ describe('ContentViewer', () => {
it
(
'
renders image preview
'
,
done
=>
{
createComponent
({
path
:
'
test.jpg
'
,
path
:
GREEN_BOX_IMAGE_URL
,
fileSize
:
1024
,
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
'
test.jpg
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
GREEN_BOX_IMAGE_URL
);
done
();
});
...
...
@@ -59,9 +60,8 @@ describe('ContentViewer', () => {
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.file-info
'
).
textContent
.
trim
()).
toContain
(
'
test.abc (1.00 KiB)
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.file-info
'
).
textContent
.
trim
()).
toContain
(
'
test.abc
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.file-info
'
).
textContent
.
trim
()).
toContain
(
'
(1.00 KiB)
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.btn.btn-default
'
).
textContent
.
trim
()).
toContain
(
'
Download
'
);
done
();
...
...
spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js
0 → 100644
View file @
8a23bcc9
import
Vue
from
'
vue
'
;
import
diffViewer
from
'
~/vue_shared/components/diff_viewer/diff_viewer.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
GREEN_BOX_IMAGE_URL
,
RED_BOX_IMAGE_URL
}
from
'
spec/test_constants
'
;
describe
(
'
DiffViewer
'
,
()
=>
{
let
vm
;
function
createComponent
(
props
)
{
const
DiffViewer
=
Vue
.
extend
(
diffViewer
);
vm
=
mountComponent
(
DiffViewer
,
props
);
}
afterEach
(()
=>
{
vm
.
$destroy
();
});
it
(
'
renders image diff
'
,
done
=>
{
window
.
gon
=
{
relative_url_root
:
''
,
};
createComponent
({
diffMode
:
'
replaced
'
,
newPath
:
GREEN_BOX_IMAGE_URL
,
newSha
:
'
ABC
'
,
oldPath
:
RED_BOX_IMAGE_URL
,
oldSha
:
'
DEF
'
,
projectPath
:
''
,
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.deleted .image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
`//raw/DEF/
${
RED_BOX_IMAGE_URL
}
`
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.added .image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
`//raw/ABC/
${
GREEN_BOX_IMAGE_URL
}
`
,
);
done
();
});
});
it
(
'
renders fallback download diff display
'
,
done
=>
{
createComponent
({
diffMode
:
'
replaced
'
,
newPath
:
'
test.abc
'
,
newSha
:
'
ABC
'
,
oldPath
:
'
testold.abc
'
,
oldSha
:
'
DEF
'
,
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.deleted .file-info
'
).
textContent
.
trim
()).
toContain
(
'
testold.abc
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.deleted .btn.btn-default
'
).
textContent
.
trim
()).
toContain
(
'
Download
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.added .file-info
'
).
textContent
.
trim
()).
toContain
(
'
test.abc
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.added .btn.btn-default
'
).
textContent
.
trim
()).
toContain
(
'
Download
'
,
);
done
();
});
});
});
spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js
0 → 100644
View file @
8a23bcc9
import
Vue
from
'
vue
'
;
import
imageDiffViewer
from
'
~/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
GREEN_BOX_IMAGE_URL
,
RED_BOX_IMAGE_URL
}
from
'
spec/test_constants
'
;
describe
(
'
ImageDiffViewer
'
,
()
=>
{
let
vm
;
function
createComponent
(
props
)
{
const
ImageDiffViewer
=
Vue
.
extend
(
imageDiffViewer
);
vm
=
mountComponent
(
ImageDiffViewer
,
props
);
}
const
triggerEvent
=
(
eventName
,
el
=
vm
.
$el
,
clientX
=
0
)
=>
{
const
event
=
document
.
createEvent
(
'
MouseEvents
'
);
event
.
initMouseEvent
(
eventName
,
true
,
true
,
window
,
1
,
clientX
,
0
,
clientX
,
0
,
false
,
false
,
false
,
false
,
0
,
null
,
);
el
.
dispatchEvent
(
event
);
};
const
dragSlider
=
(
sliderElement
,
dragPixel
=
20
)
=>
{
triggerEvent
(
'
mousedown
'
,
sliderElement
);
triggerEvent
(
'
mousemove
'
,
document
.
body
,
dragPixel
);
triggerEvent
(
'
mouseup
'
,
document
.
body
);
};
afterEach
(()
=>
{
vm
.
$destroy
();
});
it
(
'
renders image diff for replaced
'
,
done
=>
{
createComponent
({
diffMode
:
'
replaced
'
,
newPath
:
GREEN_BOX_IMAGE_URL
,
oldPath
:
RED_BOX_IMAGE_URL
,
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.added .image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
GREEN_BOX_IMAGE_URL
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.deleted .image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
RED_BOX_IMAGE_URL
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.view-modes-menu li.active
'
).
textContent
.
trim
()).
toBe
(
'
2-up
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.view-modes-menu li:nth-child(2)
'
).
textContent
.
trim
()).
toBe
(
'
Swipe
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.view-modes-menu li:nth-child(3)
'
).
textContent
.
trim
()).
toBe
(
'
Onion skin
'
,
);
done
();
});
});
it
(
'
renders image diff for new
'
,
done
=>
{
createComponent
({
diffMode
:
'
new
'
,
newPath
:
GREEN_BOX_IMAGE_URL
,
oldPath
:
''
,
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.added .image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
GREEN_BOX_IMAGE_URL
,
);
done
();
});
});
it
(
'
renders image diff for deleted
'
,
done
=>
{
createComponent
({
diffMode
:
'
deleted
'
,
newPath
:
''
,
oldPath
:
RED_BOX_IMAGE_URL
,
});
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.deleted .image_file img
'
).
getAttribute
(
'
src
'
)).
toBe
(
RED_BOX_IMAGE_URL
,
);
done
();
});
});
describe
(
'
swipeMode
'
,
()
=>
{
beforeEach
(
done
=>
{
createComponent
({
diffMode
:
'
replaced
'
,
newPath
:
GREEN_BOX_IMAGE_URL
,
oldPath
:
RED_BOX_IMAGE_URL
,
});
setTimeout
(()
=>
{
done
();
});
});
it
(
'
switches to Swipe Mode
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.view-modes-menu li:nth-child(2)
'
).
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.view-modes-menu li.active
'
).
textContent
.
trim
()).
toBe
(
'
Swipe
'
);
done
();
});
});
it
(
'
drag handler is working
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.view-modes-menu li:nth-child(2)
'
).
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.swipe-bar
'
).
style
.
left
).
toBe
(
'
1px
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.top-handle
'
)).
not
.
toBeNull
();
dragSlider
(
vm
.
$el
.
querySelector
(
'
.swipe-bar
'
),
40
);
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.swipe-bar
'
).
style
.
left
).
toBe
(
'
-20px
'
);
done
();
});
});
});
});
describe
(
'
onionSkin
'
,
()
=>
{
beforeEach
(
done
=>
{
createComponent
({
diffMode
:
'
replaced
'
,
newPath
:
GREEN_BOX_IMAGE_URL
,
oldPath
:
RED_BOX_IMAGE_URL
,
});
setTimeout
(()
=>
{
done
();
});
});
it
(
'
switches to Onion Skin Mode
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.view-modes-menu li:nth-child(3)
'
).
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.view-modes-menu li.active
'
).
textContent
.
trim
()).
toBe
(
'
Onion skin
'
,
);
done
();
});
});
it
(
'
has working drag handler
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.view-modes-menu li:nth-child(3)
'
).
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.dragger
'
).
style
.
left
).
toBe
(
'
100px
'
);
dragSlider
(
vm
.
$el
.
querySelector
(
'
.dragger
'
));
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.dragger
'
).
style
.
left
).
toBe
(
'
20px
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.added.frame
'
).
style
.
opacity
).
toBe
(
'
0.2
'
);
done
();
});
});
});
});
});
spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js
0 → 100644
View file @
8a23bcc9
import
*
as
domUtils
from
'
~/vue_shared/components/lib/utils/dom_utils
'
;
describe
(
'
domUtils
'
,
()
=>
{
describe
(
'
pixeliseValue
'
,
()
=>
{
it
(
'
should add px to a given Number
'
,
()
=>
{
expect
(
domUtils
.
pixeliseValue
(
12
)).
toEqual
(
'
12px
'
);
});
it
(
'
should not add px to 0
'
,
()
=>
{
expect
(
domUtils
.
pixeliseValue
(
0
)).
toEqual
(
''
);
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment