Merge pull request #862 from taigaio/astagi-feature/urlcustomfield
New custom field type: URLstable
commit
d557355e3b
|
@ -4,7 +4,7 @@
|
||||||
## 2.0.0 ??? (unreleased)
|
## 2.0.0 ??? (unreleased)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- ...
|
- Ability to create url custom fields. (thanks to [@astagi](https://github.com/astagi)).
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
- Lots of small and not so small bugfixes.
|
- Lots of small and not so small bugfixes.
|
||||||
|
|
|
@ -510,16 +510,6 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
|
||||||
|
|
||||||
$httpProvider.interceptors.push("versionCheckHttpIntercept")
|
$httpProvider.interceptors.push("versionCheckHttpIntercept")
|
||||||
|
|
||||||
window.checksley.updateValidators({
|
|
||||||
linewidth: (val, width) ->
|
|
||||||
lines = taiga.nl2br(val).split("<br />")
|
|
||||||
|
|
||||||
valid = _.every lines, (line) ->
|
|
||||||
line.length < width
|
|
||||||
|
|
||||||
return valid
|
|
||||||
})
|
|
||||||
|
|
||||||
$compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false)
|
$compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false)
|
||||||
|
|
||||||
if localStorage.userInfo
|
if localStorage.userInfo
|
||||||
|
@ -577,6 +567,8 @@ i18nInit = (lang, $translate) ->
|
||||||
maxcheck: $translate.instant("COMMON.FORM_ERRORS.MAX_CHECK")
|
maxcheck: $translate.instant("COMMON.FORM_ERRORS.MAX_CHECK")
|
||||||
rangecheck: $translate.instant("COMMON.FORM_ERRORS.RANGE_CHECK")
|
rangecheck: $translate.instant("COMMON.FORM_ERRORS.RANGE_CHECK")
|
||||||
equalto: $translate.instant("COMMON.FORM_ERRORS.EQUAL_TO")
|
equalto: $translate.instant("COMMON.FORM_ERRORS.EQUAL_TO")
|
||||||
|
linewidth: $translate.instant("COMMON.FORM_ERRORS.LINEWIDTH") # Extra validator
|
||||||
|
pikaday: $translate.instant("COMMON.FORM_ERRORS.PIKADAY") # Extra validator
|
||||||
}
|
}
|
||||||
checksley.updateMessages('default', messages)
|
checksley.updateMessages('default', messages)
|
||||||
|
|
||||||
|
@ -584,6 +576,21 @@ i18nInit = (lang, $translate) ->
|
||||||
init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $navUrls, appMetaService, projectService, loaderService, navigationBarService) ->
|
init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $navUrls, appMetaService, projectService, loaderService, navigationBarService) ->
|
||||||
$log.debug("Initialize application")
|
$log.debug("Initialize application")
|
||||||
|
|
||||||
|
# Checksley - Extra validators
|
||||||
|
validators = {
|
||||||
|
linewidth: (val, width) ->
|
||||||
|
lines = taiga.nl2br(val).split("<br />")
|
||||||
|
|
||||||
|
valid = _.every lines, (line) ->
|
||||||
|
line.length < width
|
||||||
|
|
||||||
|
return valid
|
||||||
|
pikaday: (val) ->
|
||||||
|
prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT")
|
||||||
|
return moment(val, prettyDate).isValid()
|
||||||
|
}
|
||||||
|
checksley.updateValidators(validators)
|
||||||
|
|
||||||
# Taiga Plugins
|
# Taiga Plugins
|
||||||
$rootscope.contribPlugins = @.taigaContribPlugins
|
$rootscope.contribPlugins = @.taigaContribPlugins
|
||||||
$rootscope.adminPlugins = _.filter(@.taigaContribPlugins, {"type": "admin"})
|
$rootscope.adminPlugins = _.filter(@.taigaContribPlugins, {"type": "admin"})
|
||||||
|
|
|
@ -381,6 +381,7 @@ module.directive("tgColorSelection", ColorSelectionDirective)
|
||||||
TEXT_TYPE = "text"
|
TEXT_TYPE = "text"
|
||||||
MULTILINE_TYPE = "multiline"
|
MULTILINE_TYPE = "multiline"
|
||||||
DATE_TYPE = "date"
|
DATE_TYPE = "date"
|
||||||
|
URL_TYPE = "url"
|
||||||
|
|
||||||
|
|
||||||
TYPE_CHOICES = [
|
TYPE_CHOICES = [
|
||||||
|
@ -395,6 +396,10 @@ TYPE_CHOICES = [
|
||||||
{
|
{
|
||||||
key: DATE_TYPE,
|
key: DATE_TYPE,
|
||||||
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: URL_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -555,7 +560,6 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
|
|
||||||
$el.on "click", ".js-add-custom-field-button", (event) ->
|
$el.on "click", ".js-add-custom-field-button", (event) ->
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
showCreateForm()
|
showCreateForm()
|
||||||
|
|
||||||
$el.on "click", ".js-create-custom-field-button", debounce 2000, (event) ->
|
$el.on "click", ".js-create-custom-field-button", debounce 2000, (event) ->
|
||||||
|
@ -567,7 +571,6 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
|
|
||||||
$el.on "click", ".js-cancel-new-custom-field-button", (event) ->
|
$el.on "click", ".js-cancel-new-custom-field-button", (event) ->
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
cancelCreate()
|
cancelCreate()
|
||||||
|
|
||||||
$el.on "keyup", ".js-new-custom-field input", (event) ->
|
$el.on "keyup", ".js-new-custom-field input", (event) ->
|
||||||
|
|
|
@ -234,26 +234,6 @@ ProjectUrl = ($navurls) ->
|
||||||
module.factory("$projectUrl", ["$tgNavUrls", ProjectUrl])
|
module.factory("$projectUrl", ["$tgNavUrls", ProjectUrl])
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
## Limite line size in a text area
|
|
||||||
#############################################################################
|
|
||||||
|
|
||||||
LimitLineLengthDirective = () ->
|
|
||||||
link = ($scope, $el, $attrs) ->
|
|
||||||
maxColsPerLine = parseInt($el.attr("cols"))
|
|
||||||
$el.on "keyup", (event) ->
|
|
||||||
code = event.keyCode
|
|
||||||
lines = $el.val().split("\n")
|
|
||||||
|
|
||||||
_.each lines, (line, index) ->
|
|
||||||
lines[index] = line.substring(0, maxColsPerLine - 2)
|
|
||||||
|
|
||||||
$el.val(lines.join("\n"))
|
|
||||||
|
|
||||||
return {link:link}
|
|
||||||
|
|
||||||
module.directive("tgLimitLineLength", LimitLineLengthDirective)
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Queue Q promises
|
## Queue Q promises
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
|
@ -34,6 +34,7 @@ module = angular.module("taigaCommon")
|
||||||
TEXT_TYPE = "text"
|
TEXT_TYPE = "text"
|
||||||
MULTILINE_TYPE = "multiline"
|
MULTILINE_TYPE = "multiline"
|
||||||
DATE_TYPE = "date"
|
DATE_TYPE = "date"
|
||||||
|
URL_TYPE = "url"
|
||||||
|
|
||||||
|
|
||||||
TYPE_CHOICES = [
|
TYPE_CHOICES = [
|
||||||
|
@ -48,6 +49,10 @@ TYPE_CHOICES = [
|
||||||
{
|
{
|
||||||
key: DATE_TYPE,
|
key: DATE_TYPE,
|
||||||
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: URL_TYPE,
|
||||||
|
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -100,6 +105,7 @@ class CustomAttributesValuesController extends taiga.Controller
|
||||||
|
|
||||||
CustomAttributesValuesDirective = ($templates, $storage) ->
|
CustomAttributesValuesDirective = ($templates, $storage) ->
|
||||||
template = $templates.get("custom-attributes/custom-attributes-values.html", true)
|
template = $templates.get("custom-attributes/custom-attributes-values.html", true)
|
||||||
|
|
||||||
collapsedHash = (type) ->
|
collapsedHash = (type) ->
|
||||||
return generateHash(["custom-attributes-collapsed", type])
|
return generateHash(["custom-attributes-collapsed", type])
|
||||||
|
|
||||||
|
@ -198,12 +204,14 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
submit = debounce 2000, (event) =>
|
submit = debounce 2000, (event) =>
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
attributeValue.value = $el.find("input[name=value], textarea[name='value']").val()
|
form = $el.find("form").checksley()
|
||||||
|
return if not form.validate()
|
||||||
|
|
||||||
|
input = $el.find("input[name=value], textarea[name='value']")
|
||||||
|
attributeValue.value = input.val()
|
||||||
if attributeValue.type is DATE_TYPE
|
if attributeValue.type is DATE_TYPE
|
||||||
if moment(attributeValue.value, prettyDate).isValid()
|
if moment(attributeValue.value, prettyDate).isValid()
|
||||||
attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD")
|
attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD")
|
||||||
else
|
|
||||||
attributeValue.value = ""
|
|
||||||
|
|
||||||
$scope.$apply ->
|
$scope.$apply ->
|
||||||
$ctrl.updateAttributeValue(attributeValue).then ->
|
$ctrl.updateAttributeValue(attributeValue).then ->
|
||||||
|
@ -217,6 +225,10 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
render(attributeValue)
|
render(attributeValue)
|
||||||
|
|
||||||
## Actions (on view mode)
|
## Actions (on view mode)
|
||||||
|
|
||||||
|
$el.on "click", ".js-value-view-mode span a", (event) ->
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
$el.on "click", ".js-value-view-mode", ->
|
$el.on "click", ".js-value-view-mode", ->
|
||||||
return if not isEditable()
|
return if not isEditable()
|
||||||
return if $selectedText.get().length
|
return if $selectedText.get().length
|
||||||
|
|
|
@ -65,7 +65,9 @@
|
||||||
"MIN_CHECK": "You must select at least %s choices.",
|
"MIN_CHECK": "You must select at least %s choices.",
|
||||||
"MAX_CHECK": "You must select %s choices or less.",
|
"MAX_CHECK": "You must select %s choices or less.",
|
||||||
"RANGE_CHECK": "You must select between %s and %s choices.",
|
"RANGE_CHECK": "You must select between %s and %s choices.",
|
||||||
"EQUAL_TO": "This value should be the same."
|
"EQUAL_TO": "This value should be the same.",
|
||||||
|
"LINEWIDTH": "One or some lines are too long. They should have %s characters or less.",
|
||||||
|
"PIKADAY": "Invalid date format, use DD MMM YYYY (like 23 Mar 1984)"
|
||||||
},
|
},
|
||||||
"PICKERDATE": {
|
"PICKERDATE": {
|
||||||
"FORMAT": "DD MMM YYYY",
|
"FORMAT": "DD MMM YYYY",
|
||||||
|
@ -494,7 +496,8 @@
|
||||||
"ISSUE_ADD": "Add a custom field in issues",
|
"ISSUE_ADD": "Add a custom field in issues",
|
||||||
"FIELD_TYPE_TEXT": "Text",
|
"FIELD_TYPE_TEXT": "Text",
|
||||||
"FIELD_TYPE_MULTI": "Multi-line",
|
"FIELD_TYPE_MULTI": "Multi-line",
|
||||||
"FIELD_TYPE_DATE": "Date"
|
"FIELD_TYPE_DATE": "Date",
|
||||||
|
"FIELD_TYPE_URL": "Url"
|
||||||
},
|
},
|
||||||
"PROJECT_VALUES": {
|
"PROJECT_VALUES": {
|
||||||
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
||||||
|
|
|
@ -14,7 +14,9 @@ form.custom-field-single.editable
|
||||||
<% } else if (type=="multiline") { %>
|
<% } else if (type=="multiline") { %>
|
||||||
textarea#custom-field-value(name="value") <%- value %>
|
textarea#custom-field-value(name="value") <%- value %>
|
||||||
<% } else if (type=="date") { %>
|
<% } else if (type=="date") { %>
|
||||||
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>")
|
||||||
|
<% } else if (type=="url") { %>
|
||||||
|
input#custom-field-value(name="value", type="url", data-type="url", value!="<%- value %>")
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
|
@ -9,7 +9,12 @@ div.custom-field-single
|
||||||
|
|
||||||
div.custom-field-value.js-value-view-mode
|
div.custom-field-value.js-value-view-mode
|
||||||
span
|
span
|
||||||
|
<% if (type=="url") { %>
|
||||||
|
a(href!="<%- value %>")
|
||||||
|
<%- value %>
|
||||||
|
<% } else { %>
|
||||||
<%- value %>
|
<%- value %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% if (isEditable) { %>
|
<% if (isEditable) { %>
|
||||||
div.custom-field-options
|
div.custom-field-options
|
||||||
|
|
|
@ -32,6 +32,7 @@ section.custom-fields-table.basic-table
|
||||||
span(ng-switch-default, translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT")
|
span(ng-switch-default, translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT")
|
||||||
span(ng-switch-when="multiline", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI")
|
span(ng-switch-when="multiline", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI")
|
||||||
span(ng-switch-when="date", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE")
|
span(ng-switch-when="date", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE")
|
||||||
|
span(ng-switch-when="url", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL")
|
||||||
div.custom-options
|
div.custom-options
|
||||||
div.custom-options-wrapper
|
div.custom-options-wrapper
|
||||||
a.js-edit-custom-field-button.icon.icon-edit(
|
a.js-edit-custom-field-button.icon.icon-edit(
|
||||||
|
|
|
@ -3,6 +3,17 @@ a.close(href="", title="{{'COMMON.CLOSE' | translate}}")
|
||||||
form
|
form
|
||||||
h2.title(translate="COMMON.NEW_BULK")
|
h2.title(translate="COMMON.NEW_BULK")
|
||||||
fieldset
|
fieldset
|
||||||
textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="new.bulk", data-required="true", data-linewidth="200")
|
textarea(
|
||||||
|
cols="200"
|
||||||
|
wrap="off"
|
||||||
|
ng-model="new.bulk"
|
||||||
|
data-required="true"
|
||||||
|
data-linewidth="200"
|
||||||
|
ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE")
|
button.button-green.submit-button(
|
||||||
|
type="submit"
|
||||||
|
title="{{'COMMON.SAVE' | translate}}"
|
||||||
|
translate="COMMON.SAVE"
|
||||||
|
)
|
||||||
|
|
|
@ -3,6 +3,17 @@ a.close(href="", title="{{'COMMON.CLOSE' | translate}}")
|
||||||
form
|
form
|
||||||
h2.title(translate="COMMON.NEW_BULK")
|
h2.title(translate="COMMON.NEW_BULK")
|
||||||
fieldset
|
fieldset
|
||||||
textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="form.data", data-required="true")
|
textarea(
|
||||||
|
cols="200"
|
||||||
|
wrap="off"
|
||||||
|
ng-model="form.data"
|
||||||
|
data-required="true"
|
||||||
|
data-linewidth="200"
|
||||||
|
ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE")
|
button.button-green.submit-button(
|
||||||
|
type="submit"
|
||||||
|
title="{{'COMMON.SAVE' | translate}}"
|
||||||
|
translate="COMMON.SAVE"
|
||||||
|
)
|
||||||
|
|
|
@ -3,6 +3,17 @@ a.close(href="", title="{{'COMMON.CLOSE' | translate}}")
|
||||||
form
|
form
|
||||||
h2.title(translate="COMMON.NEW_BULK")
|
h2.title(translate="COMMON.NEW_BULK")
|
||||||
fieldset
|
fieldset
|
||||||
textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="new.bulk", data-required="true", data-linewidth="200")
|
textarea(
|
||||||
|
cols="200"
|
||||||
|
wrap="off"
|
||||||
|
ng-model="new.bulk"
|
||||||
|
data-required="true"
|
||||||
|
data-linewidth="200"
|
||||||
|
ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE")
|
button.button-green.submit-button(
|
||||||
|
type="submit",
|
||||||
|
title="{{'COMMON.SAVE' | translate}}",
|
||||||
|
translate="COMMON.SAVE"
|
||||||
|
)
|
||||||
|
|
|
@ -8,6 +8,7 @@ fieldset {
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
input[type="url"],
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="date"],
|
input[type="date"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
|
|
@ -78,6 +78,7 @@ a {
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
input[type="url"],
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="date"],
|
input[type="date"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
|
|
@ -73,6 +73,7 @@ a {
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
input[type="url"],
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="date"],
|
input[type="date"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
|
|
@ -55,6 +55,7 @@ a {
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
input[type="url"],
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="date"],
|
input[type="date"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
|
|
Loading…
Reference in New Issue