Added autocomplete for @mentions, #USs, #tasks, #issues, and [[wikipages]] in MD textareas.
parent
57033c6e8b
commit
3b05871b0e
|
@ -9,6 +9,7 @@
|
||||||
- Make burndown chart collapsible at the backlog panel.
|
- Make burndown chart collapsible at the backlog panel.
|
||||||
- Ability to choose a theme (thanks to [@astagi](https://github.com/astagi))
|
- Ability to choose a theme (thanks to [@astagi](https://github.com/astagi))
|
||||||
- Inline viewing of image attachments (thanks to [@brettp](https://github.com/brettp)).
|
- Inline viewing of image attachments (thanks to [@brettp](https://github.com/brettp)).
|
||||||
|
- Autocomplete for usernames, user stories, tasks, issues, and wiki pages in text areas (thanks to [@brettp](https://github.com/brettp)).
|
||||||
- i18n.
|
- i18n.
|
||||||
- Add polish (pl) translation.
|
- Add polish (pl) translation.
|
||||||
- Add portuguese (Brazil) (pt_BR) translation.
|
- Add portuguese (Brazil) (pt_BR) translation.
|
||||||
|
|
|
@ -181,7 +181,11 @@ MarkitupDirective = ($rootscope, $rs, $selectedText, $template, $compile, $trans
|
||||||
onShiftEnter: {keepDefault:false, openWith:"\n\n"}
|
onShiftEnter: {keepDefault:false, openWith:"\n\n"}
|
||||||
onEnter:
|
onEnter:
|
||||||
keepDefault: false,
|
keepDefault: false,
|
||||||
replaceWith: () -> "\n"
|
replaceWith: () ->
|
||||||
|
# Allow textcomplete to intercept the enter key if the options list is displayed
|
||||||
|
# @todo There doesn't seem to be a more graceful way to do this with the textcomplete API.
|
||||||
|
if not $('.textcomplete-dropdown').is(':visible')
|
||||||
|
"\n"
|
||||||
afterInsert: (data) ->
|
afterInsert: (data) ->
|
||||||
lines = data.textarea.value.split("\n")
|
lines = data.textarea.value.split("\n")
|
||||||
# Detect if we are in this situation +- aa at the beginning if the textarea
|
# Detect if we are in this situation +- aa at the beginning if the textarea
|
||||||
|
@ -347,6 +351,104 @@ MarkitupDirective = ($rootscope, $rs, $selectedText, $template, $compile, $trans
|
||||||
element
|
element
|
||||||
.markItUpRemove()
|
.markItUpRemove()
|
||||||
.markItUp(markdownSettings)
|
.markItUp(markdownSettings)
|
||||||
|
.textcomplete([
|
||||||
|
# us, task, and issue autocomplete: #id or #<part of title>
|
||||||
|
{
|
||||||
|
cache: true
|
||||||
|
match: /(^|\s)#([a-z0-9]+)$/i,
|
||||||
|
search: (term, callback) ->
|
||||||
|
term = taiga.slugify(term)
|
||||||
|
|
||||||
|
searchTypes = ['issues', 'tasks', 'userstories']
|
||||||
|
searchProps = ['ref', 'subject']
|
||||||
|
|
||||||
|
filter = (item) =>
|
||||||
|
for prop in searchProps
|
||||||
|
if taiga.slugify(item[prop]).indexOf(term) >= 0
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
$rs.search.do($scope.projectId, term).then (res) =>
|
||||||
|
# ignore wikipages if they're the only results. can't exclude them in search
|
||||||
|
if res.count < 1 or res.count == res.wikipages.length
|
||||||
|
callback([])
|
||||||
|
|
||||||
|
else
|
||||||
|
for type in searchTypes
|
||||||
|
if res[type] and res[type].length > 0
|
||||||
|
callback(res[type].filter(filter), true)
|
||||||
|
|
||||||
|
# must signal end of lists
|
||||||
|
callback([])
|
||||||
|
|
||||||
|
replace: (res) ->
|
||||||
|
return "$1\##{res.ref} "
|
||||||
|
|
||||||
|
template: (res, term) ->
|
||||||
|
return "\##{res.ref} - #{res.subject}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# username autocomplete: @username or @<part of name>
|
||||||
|
{
|
||||||
|
cache: true
|
||||||
|
match: /(^|\s)@([a-z0-9\-\._]{2,})$/i
|
||||||
|
search: (term, callback) ->
|
||||||
|
username = taiga.slugify(term)
|
||||||
|
searchProps = ['username', 'full_name', 'full_name_display']
|
||||||
|
|
||||||
|
if $scope.project.members.length < 1
|
||||||
|
callback([])
|
||||||
|
|
||||||
|
else
|
||||||
|
callback $scope.project.members.filter (user) =>
|
||||||
|
for prop in searchProps
|
||||||
|
if taiga.slugify(user[prop]).indexOf(username) >= 0
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
replace: (user) ->
|
||||||
|
return "$1@#{user.username} "
|
||||||
|
|
||||||
|
template: (user) ->
|
||||||
|
return "#{user.username} - #{user.full_name_display}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# wiki pages autocomplete: [[slug or [[<part of slug>
|
||||||
|
# if the search function was called with the 3rd param the regex
|
||||||
|
# like the docs claim, we could combine this with the #123 search
|
||||||
|
{
|
||||||
|
cache: true
|
||||||
|
match: /(^|\s)\[\[([a-z0-9\-]+)$/i
|
||||||
|
search: (term, callback) ->
|
||||||
|
term = taiga.slugify(term)
|
||||||
|
|
||||||
|
$rs.search.do($scope.projectId, term).then (res) =>
|
||||||
|
if res.count < 1
|
||||||
|
callback([])
|
||||||
|
|
||||||
|
if res.count < 1 or not res.wikipages or res.wikipages.length <= 0
|
||||||
|
callback([])
|
||||||
|
|
||||||
|
else
|
||||||
|
callback res.wikipages.filter((page) =>
|
||||||
|
return taiga.slugify(page['slug']).indexOf(term) >= 0
|
||||||
|
), true
|
||||||
|
|
||||||
|
# must signal end of lists
|
||||||
|
callback([])
|
||||||
|
|
||||||
|
|
||||||
|
replace: (res) ->
|
||||||
|
return "$1[[#{res.slug}]]"
|
||||||
|
|
||||||
|
template: (res, term) ->
|
||||||
|
return res.slug
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{
|
||||||
|
debounce: 200
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
renderMarkItUp()
|
renderMarkItUp()
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
.dropdown-menu li:hover,
|
.dropdown-menu li:hover,
|
||||||
.dropdown-menu .active {
|
.dropdown-menu .active {
|
||||||
background-color: rgb(110, 183, 219);
|
background-color: rgb(110, 183, 219);
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textcomplete-wrapper {
|
.dropdown-menu .active > a,
|
||||||
width: 100%;
|
.dropdown-menu .active > a:hover {
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHOULD not modify */
|
/* SHOULD not modify */
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"google-diff-match-patch-js": "~1.0.0",
|
"google-diff-match-patch-js": "~1.0.0",
|
||||||
"underscore.string": "~2.3.3",
|
"underscore.string": "~2.3.3",
|
||||||
"markitup-1x": "~1.1.14",
|
"markitup-1x": "~1.1.14",
|
||||||
"jquery-textcomplete": "yuku-t/jquery-textcomplete#~0.1.1",
|
"jquery-textcomplete": "yuku-t/jquery-textcomplete#~0.7",
|
||||||
"flot-orderBars": "emmerich/flot-orderBars",
|
"flot-orderBars": "emmerich/flot-orderBars",
|
||||||
"flot-axislabels": "markrcote/flot-axislabels",
|
"flot-axislabels": "markrcote/flot-axislabels",
|
||||||
"flot.tooltip": "~0.8.4",
|
"flot.tooltip": "~0.8.4",
|
||||||
|
|
|
@ -154,7 +154,7 @@ paths.libs = [
|
||||||
paths.vendor + "jquery-flot/jquery.flot.time.js",
|
paths.vendor + "jquery-flot/jquery.flot.time.js",
|
||||||
paths.vendor + "flot-axislabels/jquery.flot.axislabels.js",
|
paths.vendor + "flot-axislabels/jquery.flot.axislabels.js",
|
||||||
paths.vendor + "flot.tooltip/js/jquery.flot.tooltip.js",
|
paths.vendor + "flot.tooltip/js/jquery.flot.tooltip.js",
|
||||||
paths.vendor + "jquery-textcomplete/jquery.textcomplete.js",
|
paths.vendor + "jquery-textcomplete/dist/jquery.textcomplete.js",
|
||||||
paths.vendor + "markitup-1x/markitup/jquery.markitup.js",
|
paths.vendor + "markitup-1x/markitup/jquery.markitup.js",
|
||||||
paths.vendor + "malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js",
|
paths.vendor + "malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js",
|
||||||
paths.vendor + "raven-js/dist/raven.js",
|
paths.vendor + "raven-js/dist/raven.js",
|
||||||
|
|
Loading…
Reference in New Issue