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
0
Merge Requests
0
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
Jérome Perrin
gitlab-ce
Commits
6963442d
Commit
6963442d
authored
May 17, 2017
by
Phil Hughes
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'issue-edit-inline' into issue-edit-inline-confidential
[ci skip]
parents
2a934741
4fcff0bf
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
398 additions
and
6 deletions
+398
-6
app/assets/javascripts/dropzone_input.js
app/assets/javascripts/dropzone_input.js
+2
-1
app/assets/javascripts/issue_show/components/app.vue
app/assets/javascripts/issue_show/components/app.vue
+12
-1
app/assets/javascripts/issue_show/components/description.vue
app/assets/javascripts/issue_show/components/description.vue
+5
-2
app/assets/javascripts/issue_show/components/fields/description.vue
.../javascripts/issue_show/components/fields/description.vue
+47
-0
app/assets/javascripts/issue_show/components/form.vue
app/assets/javascripts/issue_show/components/form.vue
+14
-0
app/assets/javascripts/issue_show/index.js
app/assets/javascripts/issue_show/index.js
+6
-0
app/assets/javascripts/issue_show/stores/index.js
app/assets/javascripts/issue_show/stores/index.js
+1
-0
app/assets/javascripts/vue_shared/components/markdown/field.vue
...sets/javascripts/vue_shared/components/markdown/field.vue
+107
-0
app/assets/javascripts/vue_shared/components/markdown/header.vue
...ets/javascripts/vue_shared/components/markdown/header.vue
+101
-0
app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
...ts/javascripts/vue_shared/components/markdown/toolbar.vue
+33
-0
app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
...scripts/vue_shared/components/markdown/toolbar_button.vue
+58
-0
app/assets/javascripts/vue_shared/mixins/tooltip.js
app/assets/javascripts/vue_shared/mixins/tooltip.js
+10
-2
app/views/projects/issues/show.html.haml
app/views/projects/issues/show.html.haml
+2
-0
No files found.
app/assets/javascripts/dropzone_input.js
View file @
6963442d
...
@@ -142,7 +142,8 @@ window.DropzoneInput = (function() {
...
@@ -142,7 +142,8 @@ window.DropzoneInput = (function() {
$
(
child
).
val
(
beforeSelection
+
formattedText
+
afterSelection
);
$
(
child
).
val
(
beforeSelection
+
formattedText
+
afterSelection
);
textarea
.
setSelectionRange
(
caretStart
+
formattedText
.
length
,
caretEnd
+
formattedText
.
length
);
textarea
.
setSelectionRange
(
caretStart
+
formattedText
.
length
,
caretEnd
+
formattedText
.
length
);
textarea
.
style
.
height
=
`
${
textarea
.
scrollHeight
}
px`
;
textarea
.
style
.
height
=
`
${
textarea
.
scrollHeight
}
px`
;
return
form_textarea
.
trigger
(
"
input
"
);
form_textarea
.
trigger
(
"
input
"
);
form_textarea
.
get
(
0
).
dispatchEvent
(
new
Event
(
'
input
'
));
};
};
getFilename
=
function
(
e
)
{
getFilename
=
function
(
e
)
{
var
value
;
var
value
;
...
...
app/assets/javascripts/issue_show/components/app.vue
View file @
6963442d
...
@@ -45,6 +45,14 @@ export default {
...
@@ -45,6 +45,14 @@ export default {
type
:
Boolean
,
type
:
Boolean
,
required
:
true
,
required
:
true
,
},
},
markdownPreviewUrl
:
{
type
:
String
,
required
:
true
,
},
markdownDocs
:
{
type
:
String
,
required
:
true
,
},
},
},
data
()
{
data
()
{
const
store
=
new
Store
({
const
store
=
new
Store
({
...
@@ -75,6 +83,7 @@ export default {
...
@@ -75,6 +83,7 @@ export default {
this
.
store
.
formState
=
{
this
.
store
.
formState
=
{
title
:
this
.
state
.
titleText
,
title
:
this
.
state
.
titleText
,
confidential
:
this
.
isConfidential
,
confidential
:
this
.
isConfidential
,
description
:
this
.
state
.
descriptionText
,
};
};
},
},
closeForm
()
{
closeForm
()
{
...
@@ -155,7 +164,9 @@ export default {
...
@@ -155,7 +164,9 @@ export default {
<form-component
<form-component
v-if=
"canUpdate && showForm"
v-if=
"canUpdate && showForm"
:form-state=
"formState"
:form-state=
"formState"
:can-destroy=
"canDestroy"
/>
:can-destroy=
"canDestroy"
:markdown-docs=
"markdownDocs"
:markdown-preview-url=
"markdownPreviewUrl"
/>
<div
v-else
>
<div
v-else
>
<title-component
<title-component
:issuable-ref=
"issuableRef"
:issuable-ref=
"issuableRef"
...
...
app/assets/javascripts/issue_show/components/description.vue
View file @
6963442d
...
@@ -18,11 +18,13 @@
...
@@ -18,11 +18,13 @@
},
},
updatedAt
:
{
updatedAt
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
false
,
default
:
''
,
},
},
taskStatus
:
{
taskStatus
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
false
,
default
:
''
,
},
},
},
},
data
()
{
data
()
{
...
@@ -83,6 +85,7 @@
...
@@ -83,6 +85,7 @@
<
template
>
<
template
>
<div
<div
v-if=
"descriptionHtml"
class=
"description"
class=
"description"
:class=
"
{
:class=
"
{
'js-task-list-container': canUpdate
'js-task-list-container': canUpdate
...
...
app/assets/javascripts/issue_show/components/fields/description.vue
0 → 100644
View file @
6963442d
<
script
>
/* global Flash */
import
markdownField
from
'
../../../vue_shared/components/markdown/field.vue
'
;
export
default
{
props
:
{
formState
:
{
type
:
Object
,
required
:
true
,
},
markdownPreviewUrl
:
{
type
:
String
,
required
:
true
,
},
markdownDocs
:
{
type
:
String
,
required
:
true
,
},
},
components
:
{
markdownField
,
},
};
</
script
>
<
template
>
<div
class=
"common-note-form"
>
<label
class=
"sr-only"
for=
"issue-description"
>
Description
</label>
<markdown-field
:markdown-preview-url=
"markdownPreviewUrl"
:markdown-docs=
"markdownDocs"
>
<textarea
id=
"issue-description"
class=
"note-textarea js-gfm-input js-autosize markdown-area"
data-supports-slash-commands=
"false"
aria-label=
"Description"
v-model=
"formState.description"
ref=
"textatea"
slot=
"textarea"
>
</textarea>
</markdown-field>
</div>
</
template
>
app/assets/javascripts/issue_show/components/form.vue
View file @
6963442d
<
script
>
<
script
>
import
titleField
from
'
./fields/title.vue
'
;
import
titleField
from
'
./fields/title.vue
'
;
import
descriptionField
from
'
./fields/description.vue
'
;
import
editActions
from
'
./edit_actions.vue
'
;
import
editActions
from
'
./edit_actions.vue
'
;
import
confidentialCheckbox
from
'
./fields/confidential_checkbox.vue
'
;
import
confidentialCheckbox
from
'
./fields/confidential_checkbox.vue
'
;
...
@@ -13,9 +14,18 @@
...
@@ -13,9 +14,18 @@
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
markdownPreviewUrl
:
{
type
:
String
,
required
:
true
,
},
markdownDocs
:
{
type
:
String
,
required
:
true
,
},
},
},
components
:
{
components
:
{
titleField
,
titleField
,
descriptionField
,
editActions
,
editActions
,
confidentialCheckbox
,
confidentialCheckbox
,
},
},
...
@@ -28,6 +38,10 @@
...
@@ -28,6 +38,10 @@
:form-state=
"formState"
/>
:form-state=
"formState"
/>
<confidential-checkbox
<confidential-checkbox
:form-state=
"formState"
/>
:form-state=
"formState"
/>
<description-field
:form-state=
"formState"
:markdown-preview-url=
"markdownPreviewUrl"
:markdown-docs=
"markdownDocs"
/>
<edit-actions
<edit-actions
:can-destroy=
"canDestroy"
/>
:can-destroy=
"canDestroy"
/>
</form>
</form>
...
...
app/assets/javascripts/issue_show/index.js
View file @
6963442d
...
@@ -26,6 +26,8 @@ document.addEventListener('DOMContentLoaded', () => {
...
@@ -26,6 +26,8 @@ document.addEventListener('DOMContentLoaded', () => {
endpoint
,
endpoint
,
issuableRef
,
issuableRef
,
isConfidential
,
isConfidential
,
markdownPreviewUrl
,
markdownDocs
,
}
=
issuableElement
.
dataset
;
}
=
issuableElement
.
dataset
;
return
{
return
{
...
@@ -37,6 +39,8 @@ document.addEventListener('DOMContentLoaded', () => {
...
@@ -37,6 +39,8 @@ document.addEventListener('DOMContentLoaded', () => {
initialDescriptionHtml
:
issuableDescriptionElement
?
issuableDescriptionElement
.
innerHTML
:
''
,
initialDescriptionHtml
:
issuableDescriptionElement
?
issuableDescriptionElement
.
innerHTML
:
''
,
initialDescriptionText
:
issuableDescriptionTextarea
?
issuableDescriptionTextarea
.
textContent
:
''
,
initialDescriptionText
:
issuableDescriptionTextarea
?
issuableDescriptionTextarea
.
textContent
:
''
,
isConfidential
:
gl
.
utils
.
convertPermissionToBoolean
(
isConfidential
),
isConfidential
:
gl
.
utils
.
convertPermissionToBoolean
(
isConfidential
),
markdownPreviewUrl
,
markdownDocs
,
};
};
},
},
render
(
createElement
)
{
render
(
createElement
)
{
...
@@ -50,6 +54,8 @@ document.addEventListener('DOMContentLoaded', () => {
...
@@ -50,6 +54,8 @@ document.addEventListener('DOMContentLoaded', () => {
initialDescriptionHtml
:
this
.
initialDescriptionHtml
,
initialDescriptionHtml
:
this
.
initialDescriptionHtml
,
initialDescriptionText
:
this
.
initialDescriptionText
,
initialDescriptionText
:
this
.
initialDescriptionText
,
isConfidential
:
this
.
isConfidential
,
isConfidential
:
this
.
isConfidential
,
markdownPreviewUrl
:
this
.
markdownPreviewUrl
,
markdownDocs
:
this
.
markdownDocs
,
},
},
});
});
},
},
...
...
app/assets/javascripts/issue_show/stores/index.js
View file @
6963442d
...
@@ -15,6 +15,7 @@ export default class Store {
...
@@ -15,6 +15,7 @@ export default class Store {
this
.
formState
=
{
this
.
formState
=
{
title
:
''
,
title
:
''
,
confidential
:
false
,
confidential
:
false
,
description
:
''
,
};
};
}
}
...
...
app/assets/javascripts/vue_shared/components/markdown/field.vue
0 → 100644
View file @
6963442d
<
script
>
/* global Flash */
import
markdownHeader
from
'
./header.vue
'
;
import
markdownToolbar
from
'
./toolbar.vue
'
;
export
default
{
props
:
{
markdownPreviewUrl
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
markdownDocs
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
markdownPreview
:
''
,
markdownPreviewLoading
:
false
,
previewMarkdown
:
false
,
};
},
components
:
{
markdownHeader
,
markdownToolbar
,
},
methods
:
{
toggleMarkdownPreview
()
{
this
.
previewMarkdown
=
!
this
.
previewMarkdown
;
if
(
!
this
.
previewMarkdown
)
{
this
.
markdownPreview
=
''
;
}
else
{
this
.
markdownPreviewLoading
=
true
;
this
.
$http
.
post
(
this
.
markdownPreviewUrl
,
{
/*
Can't use `$refs` as the component is technically in the parent component
so we access the VNode & then get the element
*/
text
:
this
.
$slots
.
textarea
[
0
].
elm
.
value
,
},
)
.
then
((
res
)
=>
{
const
data
=
res
.
json
();
this
.
markdownPreviewLoading
=
false
;
this
.
markdownPreview
=
data
.
body
;
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
[
'
markdown-preview
'
]).
renderGFM
();
});
})
.
catch
(()
=>
new
Flash
(
'
Error loading markdown preview
'
));
}
},
},
mounted
()
{
/*
GLForm class handles all the toolbar buttons
*/
return
new
gl
.
GLForm
(
$
(
this
.
$refs
[
'
gl-form
'
]));
},
};
</
script
>
<
template
>
<div
class=
"md-area prepend-top-default append-bottom-default"
ref=
"gl-form"
>
<markdown-header
:preview-markdown=
"previewMarkdown"
@
toggle-markdown=
"toggleMarkdownPreview"
/>
<div
class=
"md-write-holder"
v-show=
"!previewMarkdown"
>
<div
class=
"zen-backdrop"
>
<slot
name=
"textarea"
></slot>
<a
class=
"zen-control zen-control-leave js-zen-leave"
href=
"#"
aria-label=
"Enter zen mode"
>
<i
class=
"fa fa-compress"
aria-hidden=
"true"
>
</i>
</a>
<markdown-toolbar
:markdown-docs=
"markdownDocs"
/>
</div>
</div>
<div
class=
"md md-preview-holder md-preview"
v-show=
"previewMarkdown"
>
<div
ref=
"markdown-preview"
v-html=
"markdownPreview"
>
</div>
<span
v-if=
"markdownPreviewLoading"
>
Loading...
</span>
</div>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/markdown/header.vue
0 → 100644
View file @
6963442d
<
script
>
import
tooltipMixin
from
'
../../mixins/tooltip
'
;
import
toolbarButton
from
'
./toolbar_button.vue
'
;
export
default
{
mixins
:
[
tooltipMixin
,
],
props
:
{
previewMarkdown
:
{
type
:
Boolean
,
required
:
true
,
},
},
components
:
{
toolbarButton
,
},
methods
:
{
toggleMarkdownPreview
(
e
)
{
e
.
target
.
blur
();
this
.
$emit
(
'
toggle-markdown
'
);
},
},
};
</
script
>
<
template
>
<div
class=
"md-header"
>
<ul
class=
"nav-links clearfix"
>
<li
:class=
"
{ active: !previewMarkdown }">
<a
href=
"#md-write-holder"
tabindex=
"-1"
@
click.prevent=
"toggleMarkdownPreview($event)"
>
Write
</a>
</li>
<li
:class=
"
{ active: previewMarkdown }">
<a
href=
"#md-preview-holder"
tabindex=
"-1"
@
click.prevent=
"toggleMarkdownPreview($event)"
>
Preview
</a>
</li>
<li
class=
"pull-right"
>
<div
class=
"toolbar-group"
>
<toolbar-button
tag=
"**"
button-title=
"Add bold text"
icon=
"bold"
/>
<toolbar-button
tag=
"*"
button-title=
"Add italic text"
icon=
"italic"
/>
<toolbar-button
tag=
"> "
:prepend=
"true"
button-title=
"Insert a quote"
icon=
"quote-right"
/>
<toolbar-button
tag=
"`"
tag-block=
"```"
button-title=
"Insert code"
icon=
"code"
/>
<toolbar-button
tag=
"* "
:prepend=
"true"
button-title=
"Add a bullet list"
icon=
"list-ul"
/>
<toolbar-button
tag=
"1. "
:prepend=
"true"
button-title=
"Add a numbered list"
icon=
"list-ol"
/>
<toolbar-button
tag=
"* [ ] "
:prepend=
"true"
button-title=
"Add a task list"
icon=
"check-square-o"
/>
</div>
<div
class=
"toolbar-group"
>
<button
aria-label=
"Go full screen"
class=
"toolbar-btn js-zen-enter"
data-container=
"body"
tabindex=
"-1"
title=
"Go full screen"
type=
"button"
ref=
"tooltip"
>
<i
aria-hidden=
"true"
class=
"fa fa-arrows-alt fa-fw"
>
</i>
</button>
</div>
</li>
</ul>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
0 → 100644
View file @
6963442d
<
script
>
export
default
{
props
:
{
markdownDocs
:
{
type
:
String
,
required
:
true
,
},
},
};
</
script
>
<
template
>
<div
class=
"comment-toolbar clearfix"
>
<div
class=
"toolbar-text"
>
<a
:href=
"markdownDocs"
target=
"_blank"
tabindex=
"-1"
>
Markdown is supported
</a>
</div>
<button
class=
"toolbar-button markdown-selector"
type=
"button"
tabindex=
"-1"
>
<i
class=
"fa fa-file-image-o toolbar-button-icon"
aria-hidden=
"true"
>
</i>
Attach a file
</button>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
0 → 100644
View file @
6963442d
<
script
>
import
tooltipMixin
from
'
../../mixins/tooltip
'
;
export
default
{
mixins
:
[
tooltipMixin
,
],
props
:
{
buttonTitle
:
{
type
:
String
,
required
:
true
,
},
icon
:
{
type
:
String
,
required
:
true
,
},
tag
:
{
type
:
String
,
required
:
true
,
},
tagBlock
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
prepend
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
iconClass
()
{
return
`fa-
${
this
.
icon
}
`
;
},
},
};
</
script
>
<
template
>
<button
type=
"button"
class=
"toolbar-btn js-md hidden-xs"
tabindex=
"-1"
ref=
"tooltip"
data-container=
"body"
:data-md-tag=
"tag"
:data-md-block=
"tagBlock"
:data-md-prepend=
"prepend"
:title=
"buttonTitle"
:aria-label=
"buttonTitle"
>
<i
aria-hidden=
"true"
class=
"fa fa-fw"
:class=
"iconClass"
>
</i>
</button>
</
template
>
app/assets/javascripts/vue_shared/mixins/tooltip.js
View file @
6963442d
export
default
{
export
default
{
mounted
()
{
mounted
()
{
$
(
this
.
$refs
.
tooltip
).
tooltip
();
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
.
tooltip
).
tooltip
();
});
},
},
updated
()
{
updated
()
{
$
(
this
.
$refs
.
tooltip
).
tooltip
(
'
fixTitle
'
);
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
.
tooltip
).
tooltip
(
'
fixTitle
'
);
});
},
beforeDestroy
()
{
$
(
this
.
$refs
.
tooltip
).
tooltip
(
'
destroy
'
);
},
},
};
};
app/views/projects/issues/show.html.haml
View file @
6963442d
...
@@ -56,6 +56,8 @@
...
@@ -56,6 +56,8 @@
"can-destroy"
=>
can?
(
current_user
,
:destroy_issue
,
@issue
).
to_s
,
"can-destroy"
=>
can?
(
current_user
,
:destroy_issue
,
@issue
).
to_s
,
"issuable-ref"
=>
@issue
.
to_reference
,
"issuable-ref"
=>
@issue
.
to_reference
,
"is-confidential"
=>
@issue
.
confidential
.
to_s
,
"is-confidential"
=>
@issue
.
confidential
.
to_s
,
"markdown-preview-url"
=>
preview_markdown_path
(
@project
),
"markdown-docs"
=>
help_page_path
(
'user/markdown'
),
}
}
}
}
%h2
.title
=
markdown_field
(
@issue
,
:title
)
%h2
.title
=
markdown_field
(
@issue
,
:title
)
-
if
@issue
.
description
.
present?
-
if
@issue
.
description
.
present?
...
...
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