diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index c9b0547a..7eaf633d 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -239,7 +239,7 @@ class MemberForm(FlaskForm): class InviteForm(FlaskForm): - emails = TextAreaField(_("People to notify")) + emails = StringField(_("People to notify"), render_kw={"class": "tag"}) submit = SubmitField(_("Send invites")) def validate_emails(form, field): diff --git a/ihatemoney/static/css/main.css b/ihatemoney/static/css/main.css index 52bd77b2..6f7aabcb 100644 --- a/ihatemoney/static/css/main.css +++ b/ihatemoney/static/css/main.css @@ -1,4 +1,5 @@ @import "bootstrap.min.css"; +@import "tagsinput.css"; @import "bootstrap-datepicker3.standalone.css"; @import "../fonts/fontfaces.css"; diff --git a/ihatemoney/static/css/tagsinput.css b/ihatemoney/static/css/tagsinput.css new file mode 100644 index 00000000..cbb28cd1 --- /dev/null +++ b/ihatemoney/static/css/tagsinput.css @@ -0,0 +1,16 @@ +.tagsinput,.tagsinput *{box-sizing:border-box} +.tagsinput{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;background:#fff;font-family:sans-serif;font-size:14px;line-height:20px;color:#556270;padding:5px 5px 0;border:1px solid #e6e6e6;border-radius:2px} +.tagsinput.focus{border-color:#ccc} +.tagsinput .tag{position:relative;background:#556270;display:block;max-width:100%;word-wrap:break-word;color:#fff;padding:5px 30px 5px 5px;border-radius:2px;margin:0 5px 5px 0} +.tagsinput .tag .tag-remove{position:absolute;background:0 0;display:block;width:30px;height:30px;top:0;right:0;cursor:pointer;text-decoration:none;text-align:center;color:#ff6b6b;line-height:30px;padding:0;border:0} +.tagsinput .tag .tag-remove:after,.tagsinput .tag .tag-remove:before{background:#ff6b6b;position:absolute;display:block;width:10px;height:2px;top:14px;left:10px;content:''} +.tagsinput .tag .tag-remove:before{-webkit-transform:rotateZ(45deg);transform:rotateZ(45deg)} +.tagsinput .tag .tag-remove:after{-webkit-transform:rotateZ(-45deg);transform:rotateZ(-45deg)} +.tagsinput div{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1} +.tagsinput div input{background:0 0;display:block;width:100%;font-size:14px;line-height:20px;padding:5px;border:0;margin:0 5px 5px 0} +.tagsinput div input.error{color:#ff6b6b} +.tagsinput div input::-ms-clear{display:none} +.tagsinput div input::-webkit-input-placeholder{color:#ccc;opacity:1} +.tagsinput div input:-moz-placeholder{color:#ccc;opacity:1} +.tagsinput div input::-moz-placeholder{color:#ccc;opacity:1} +.tagsinput div input:-ms-input-placeholder{color:#ccc;opacity:1} diff --git a/ihatemoney/static/js/tagsinput.js b/ihatemoney/static/js/tagsinput.js new file mode 100644 index 00000000..a5a4e849 --- /dev/null +++ b/ihatemoney/static/js/tagsinput.js @@ -0,0 +1,381 @@ +//Credits https://bootsnipp.com/snippets/exqd3 +/* jQuery Tags Input Revisited Plugin + * + * Copyright (c) Krzysztof Rusnarczyk + * Licensed under the MIT license */ + +(function($) { + var delimiter = []; + var inputSettings = []; + var callbacks = []; + + $.fn.addTag = function(value, options) { + options = jQuery.extend({ + focus: false, + callback: true + }, options); + + this.each(function() { + var id = $(this).attr('id'); + + var tagslist = $(this).val().split(_getDelimiter(delimiter[id])); + if (tagslist[0] === '') tagslist = []; + + value = jQuery.trim(value); + + if ((inputSettings[id].unique && $(this).tagExist(value)) || !_validateTag(value, inputSettings[id], tagslist, delimiter[id])) { + $('#' + id + '_tag').addClass('error'); + return false; + } + + $('', {class: 'tag'}).append( + $('', {class: 'tag-text'}).text(value), + $('