Add rich text field

stable
Jesús Espino 2016-11-21 13:33:35 +01:00 committed by David Barragán Merino
parent 481fef4847
commit 0937fbfcc5
10 changed files with 121 additions and 13 deletions

View File

@ -5,8 +5,9 @@
### Features
- Contact with the project: if the projects have this module enabled Taiga users can contact them.
- Velocity forecasting. Create sprints according to team velocity.
- Remove bower
- Remove bower, now use only npm packages.
- Add new wysiwyg editor (like the Medunm editor) with emojis, local storage changes, mentions...
- Add rich text custom fields (with a wysiwyg editor like descreption or comments).
### Misc
- Lots of small and not so small bugfixes.

View File

@ -406,6 +406,7 @@ module.directive("tgColorSelection", ColorSelectionDirective)
# Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py)
TEXT_TYPE = "text"
MULTILINE_TYPE = "multiline"
RICHTEXT_TYPE = "richtext"
DATE_TYPE = "date"
URL_TYPE = "url"
@ -419,6 +420,10 @@ TYPE_CHOICES = [
key: MULTILINE_TYPE,
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI"
},
{
key: RICHTEXT_TYPE,
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT"
},
{
key: DATE_TYPE,
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"

View File

@ -32,6 +32,7 @@ module = angular.module("taigaCommon")
# Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py)
TEXT_TYPE = "text"
RICHTEXT_TYPE = "url"
MULTILINE_TYPE = "multiline"
DATE_TYPE = "date"
URL_TYPE = "url"
@ -53,6 +54,10 @@ TYPE_CHOICES = [
{
key: URL_TYPE,
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL"
},
{
key: RICHTEXT_TYPE,
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT"
}
]
@ -193,6 +198,15 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
requiredEditionPerm = $attrs.requiredEditionPerm
return permissions.indexOf(requiredEditionPerm) > -1
$scope.saveCustomRichText = (markdown, callback) =>
attributeValue.value = markdown
$ctrl.updateAttributeValue(attributeValue).then ->
callback()
render(attributeValue, false)
$scope.cancelCustomRichText= () =>
render(attributeValue, false)
submit = debounce 2000, (event) =>
event.preventDefault()
@ -214,6 +228,9 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
# Bootstrap
attributeValue = $scope.$eval($attrs.tgCustomAttributeValue)
if attributeValue.value == null or attributeValue.value == undefined
attributeValue.value = ""
$scope.customAttributeValue = attributeValue
render(attributeValue)
## Actions (on view mode)

View File

@ -573,6 +573,7 @@
"ISSUE_DESCRIPTION": "Issues custom fields",
"ISSUE_ADD": "Add a custom field in issues",
"FIELD_TYPE_TEXT": "Text",
"FIELD_TYPE_RICHTEXT": "Rich text",
"FIELD_TYPE_MULTI": "Multi-line",
"FIELD_TYPE_DATE": "Date",
"FIELD_TYPE_URL": "Url"

View File

@ -0,0 +1,58 @@
###
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
# Copyright (C) 2014-2016 Jesús Espino Garcia <jespinog@gmail.com>
# Copyright (C) 2014-2016 David Barragán Merino <bameda@dbarragan.com>
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
# Copyright (C) 2014-2016 Juan Francisco Alcántara <juanfran.alcantara@kaleidos.net>
# Copyright (C) 2014-2016 Xavi Julian <xavier.julian@kaleidos.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# File: modules/components/wysiwyg/comment-edit-wysiwyg.directive.coffee
###
CustomFieldEditWysiwyg = (attachmentsFullService) ->
link = ($scope, $el, $attrs) ->
types = {
userstories: "us",
issues: "issue",
tasks: "task"
}
uploadFile = (file, cb) ->
return attachmentsFullService.addAttachment($scope.vm.projectId, $scope.vm.comment.comment.id, types[$scope.vm.comment.comment._name], file).then (result) ->
cb(result.getIn(['file', 'name']), result.getIn(['file', 'url']))
$scope.uploadFiles = (files, cb) ->
for file in files
uploadFile(file, cb)
return {
scope: true,
link: link,
template: """
<div>
<tg-wysiwyg
editonly
content='customAttributeValue.value'
on-save="saveCustomRichText(text, cb)"
on-cancel="cancelCustomRichText()"
on-upload-file='uploadFiles(files, cb)'>
</tg-wysiwyg>
</div>
"""
}
angular.module("taigaComponents")
.directive("tgCustomFieldEditWysiwyg", ["tgAttachmentsFullService", CustomFieldEditWysiwyg])

View File

@ -1,17 +1,27 @@
.diff-custom-new(
.diff-status-wrapper(
ng-if="vm.diff.new.length"
ng-repeat="newCustom in vm.diff.new"
)
span.key(translate="ACTIVITY.CREATED_CUSTOM_ATTRIBUTE")
span.diff ({{newCustom.name}})
span(ng-if="newCustom.type == 'richtext'")
p.diff(tg-bo-html="newCustom.value_diff")
span(ng-if="newCustom.type != 'richtext'")
span.diff {{newCustom.value}}
.diff-custom-new(
.diff-status-wrapper(
ng-if="vm.diff.changed.length"
ng-repeat="changeCustom in vm.diff.changed"
)
span.key(translate="ACTIVITY.UPDATED_CUSTOM_ATTRIBUTE")
span.diff ({{changeCustom.name}})
span(ng-if="changeCustom.type == 'richtext'")
p.diff(tg-bo-html="changeCustom.value_diff")
span(ng-if="changeCustom.type != 'richtext'")
span.diff {{changeCustom.changes.value[0]}}
tg-svg(
svg-icon="icon-arrow-right"

View File

@ -13,6 +13,8 @@ form.custom-field-single.editable
input#custom-field-value(name="value", type="text", value!="<%- value %>")
<% } else if (type=="multiline") { %>
textarea#custom-field-value(name="value") <%- value %>
<% } else if (type=="richtext") { %>
tg-custom-field-edit-wysiwyg()
<% } else if (type=="date") { %>
input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>")
<% } else if (type=="url") { %>
@ -21,6 +23,8 @@ form.custom-field-single.editable
input#custom-field-value(name="value", type="text", value!="<%- value %>")
<% } %>
<% if (type != "richtext") { %>
div.custom-field-options
a.js-save-description(href="", title="{{'COMMON.CUSTOM_ATTRIBUTES.SAVE' | translate}}")
tg-svg(svg-icon="icon-save")
<% } %>

View File

@ -7,12 +7,17 @@
<%- description %>
<% } %>
<% if (type=="url") { %>
.custom-field-value.js-value-view-mode
span
<% if (type=="url") { %>
a(href!="<%- value %>")
<%- value %>
<% } else if (type=="richtext") { %>
.custom-field-value.js-value-view-mode.wysiwyg
div(ng-bind-html!="\'<%- value %>\'|markdownToHTML")
<% } else { %>
.custom-field-value.js-value-view-mode
span
<%- value %>
<% } %>

View File

@ -30,6 +30,10 @@ section.custom-fields-table.basic-table
ng-switch-default
translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT"
)
span(
ng-switch-when="richtext"
translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT"
)
span(
ng-switch-when="multiline"
translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI"

View File

@ -71,6 +71,9 @@
padding: 0 1rem 0 2rem;
&.js-value-view-mode {
white-space: pre-line;
&.wysiwyg {
white-space: normal;
}
}
}
form {