Refactor "send new message" form, esp. recipients field, per Vue.js
This commit is contained in:
		
							parent
							
								
									e153e530a8
								
							
						
					
					
						commit
						86695c9dc7
					
				
					 8 changed files with 274 additions and 20 deletions
				
			
		
							
								
								
									
										108
									
								
								tailbone/static/js/tailbone.buefy.message_recipients.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								tailbone/static/js/tailbone.buefy.message_recipients.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,108 @@ | ||||||
|  | 
 | ||||||
|  | const MessageRecipients = { | ||||||
|  |     template: '#message-recipients-template', | ||||||
|  | 
 | ||||||
|  |     props: { | ||||||
|  |         name: String, | ||||||
|  |         value: Array, | ||||||
|  |         possibleRecipients: Array, | ||||||
|  |         recipientDisplayMap: Object, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     data() { | ||||||
|  |         return { | ||||||
|  |             autocompleteValue: null, | ||||||
|  |             actualValue: this.value, | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     computed: { | ||||||
|  | 
 | ||||||
|  |         filteredData() { | ||||||
|  |             // this is the logic responsible for "matching" user's autocomplete
 | ||||||
|  |             // input, with possible recipients.  we return all matches as list.
 | ||||||
|  |             let filtered = [] | ||||||
|  |             if (this.autocompleteValue) { | ||||||
|  |                 let term = this.autocompleteValue.toLowerCase() | ||||||
|  |                 this.possibleRecipients.forEach(function(value, key, map) { | ||||||
|  | 
 | ||||||
|  |                     // first check to see if value is simple string, if so then
 | ||||||
|  |                     // will attempt to match it directly
 | ||||||
|  |                     if (value.toLowerCase !== undefined) { | ||||||
|  |                         if (value.toLowerCase().indexOf(term) >= 0) { | ||||||
|  |                             filtered.push({value: key, label: value}) | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                     } else { | ||||||
|  |                         // value is not a string, which means it must be a
 | ||||||
|  |                         // grouping object, which must have a name property
 | ||||||
|  |                         if (value.name.toLowerCase().indexOf(term) >= 0) { | ||||||
|  |                             filtered.push({ | ||||||
|  |                                 value: key, | ||||||
|  |                                 label: value.name, | ||||||
|  |                                 moreValues: value.uuids, | ||||||
|  |                             }) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |             } | ||||||
|  |             return filtered | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     methods: { | ||||||
|  | 
 | ||||||
|  |         addRecipient(uuid) { | ||||||
|  | 
 | ||||||
|  |             // add selected user to "actual" value
 | ||||||
|  |             if (!this.actualValue.includes(uuid)) { | ||||||
|  |                 this.actualValue.push(uuid) | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         removeRecipient(uuid) { | ||||||
|  | 
 | ||||||
|  |             // locate and remove user uuid from "actual" value
 | ||||||
|  |             for (let i = 0; i < this.actualValue.length; i++) { | ||||||
|  |                 if (this.actualValue[i] == uuid) { | ||||||
|  |                     this.actualValue.splice(i, 1) | ||||||
|  |                     break | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         selectionMade(option) { | ||||||
|  | 
 | ||||||
|  |             // apparently option can be null sometimes..?
 | ||||||
|  |             if (option) { | ||||||
|  | 
 | ||||||
|  |                 // add all newly-selected users to "actual" value
 | ||||||
|  |                 if (option.moreValues) { | ||||||
|  |                     // grouping object; add all its "contained" values
 | ||||||
|  |                     option.moreValues.forEach(function(uuid) { | ||||||
|  |                         this.addRecipient(uuid) | ||||||
|  |                     }, this) | ||||||
|  |                 } else { | ||||||
|  |                     // normal object, just add its value
 | ||||||
|  |                     this.addRecipient(option.value) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // let parent know we changed value
 | ||||||
|  |                 this.$emit('input', this.actualValue) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // clear out the *visible* autocomplete value
 | ||||||
|  |             this.$nextTick(function() { | ||||||
|  |                 this.autocompleteValue = null | ||||||
|  | 
 | ||||||
|  |                 // TODO: wtf, sometimes we have to clear this out twice?!
 | ||||||
|  |                 this.$nextTick(function() { | ||||||
|  |                     this.autocompleteValue = null | ||||||
|  |                 }) | ||||||
|  |             }) | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Vue.component('message-recipients', MessageRecipients) | ||||||
							
								
								
									
										13
									
								
								tailbone/templates/deform/message_recipients_buefy.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tailbone/templates/deform/message_recipients_buefy.pt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | <div tal:define="name name|field.name; | ||||||
|  |                  possible_recipients possible_recipients|'possibleRecipients'; | ||||||
|  |                  recipient_display_map recipient_display_map|'recipientDisplayMap';" | ||||||
|  |      tal:omit-tag=""> | ||||||
|  |   <div tal:define="vmodel vmodel|'field_model_' + name;" | ||||||
|  |        tal:omit-tag=""> | ||||||
|  |     <message-recipients name="${name}" | ||||||
|  |                         v-model="${vmodel}" | ||||||
|  |                         tal:attributes=":possible-recipients possible_recipients; | ||||||
|  |                                         :recipient-display-map recipient_display_map;"> | ||||||
|  |     </message-recipients> | ||||||
|  |   </div> | ||||||
|  | </div> | ||||||
|  | @ -4,13 +4,16 @@ | ||||||
|                   mask mask|field.widget.mask; |                   mask mask|field.widget.mask; | ||||||
|                   mask_placeholder mask_placeholder|field.widget.mask_placeholder; |                   mask_placeholder mask_placeholder|field.widget.mask_placeholder; | ||||||
|                   style style|field.widget.style; |                   style style|field.widget.style; | ||||||
|                   use_buefy use_buefy|0;" |                   use_buefy use_buefy|0; | ||||||
|  |                   placeholder placeholder|getattr(field.widget, 'placeholder', ''); | ||||||
|  |                   autocomplete autocomplete|getattr(field.widget, 'autocomplete', 'on');" | ||||||
|       tal:omit-tag=""> |       tal:omit-tag=""> | ||||||
|   <div tal:condition="not use_buefy" tal:omit-tag=""> |   <div tal:condition="not use_buefy" tal:omit-tag=""> | ||||||
|     <input type="text" name="${name}" value="${cstruct}"  |     <input type="text" name="${name}" value="${cstruct}"  | ||||||
|            tal:attributes="class string: form-control ${css_class or ''}; |            tal:attributes="class string: form-control ${css_class or ''}; | ||||||
|                            style style; |                            style style; | ||||||
|                            attributes|field.widget.attributes|{};" |                            attributes|field.widget.attributes|{};" | ||||||
|  |            autocomplete="${autocomplete}" | ||||||
|            id="${oid}"/> |            id="${oid}"/> | ||||||
|     <script tal:condition="mask" type="text/javascript"> |     <script tal:condition="mask" type="text/javascript"> | ||||||
|       deform.addCallback( |       deform.addCallback( | ||||||
|  | @ -26,7 +29,9 @@ | ||||||
|        tal:define="vmodel vmodel|'field_model_' + name;" |        tal:define="vmodel vmodel|'field_model_' + name;" | ||||||
|        tal:omit-tag=""> |        tal:omit-tag=""> | ||||||
|     <b-input name="${name}" |     <b-input name="${name}" | ||||||
|              v-model="${vmodel}"> |              v-model="${vmodel}" | ||||||
|  |              placeholder="${placeholder}" | ||||||
|  |              autocomplete="${autocomplete}"> | ||||||
|     </b-input> |     </b-input> | ||||||
|   </div> |   </div> | ||||||
| </span> | </span> | ||||||
|  |  | ||||||
|  | @ -1,8 +1,14 @@ | ||||||
| ## -*- coding: utf-8 -*- | ## -*- coding: utf-8; -*- | ||||||
| <%inherit file="/master/create.mako" /> | <%inherit file="/master/create.mako" /> | ||||||
|  | <%namespace file="/messages/recipients.mako" import="message_recipients_template" /> | ||||||
|  | 
 | ||||||
|  | <%def name="content_title()">${parent.content_title() if not use_buefy else ''}</%def> | ||||||
| 
 | 
 | ||||||
| <%def name="extra_javascript()"> | <%def name="extra_javascript()"> | ||||||
|   ${parent.extra_javascript()} |   ${parent.extra_javascript()} | ||||||
|  |   % if use_buefy: | ||||||
|  |       ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.message_recipients.js'))} | ||||||
|  |   % else: | ||||||
|   ${h.javascript_link(request.static_url('tailbone:static/js/lib/tag-it.min.js'))} |   ${h.javascript_link(request.static_url('tailbone:static/js/lib/tag-it.min.js'))} | ||||||
|   <script type="text/javascript"> |   <script type="text/javascript"> | ||||||
| 
 | 
 | ||||||
|  | @ -18,9 +24,9 @@ | ||||||
|     function validate_message_form() { |     function validate_message_form() { | ||||||
|         var form = $('#deform'); |         var form = $('#deform'); | ||||||
| 
 | 
 | ||||||
|         if (! form.find('input[name="recipients_"]').val()) { |         if (! form.find('input[name="set_recipients"]').val()) { | ||||||
|             alert("You must specify some recipient(s) for the message."); |             alert("You must specify some recipient(s) for the message."); | ||||||
|             $('.recipients_ input').data('ui-tagit').tagInput.focus(); |             $('.set_recipients input').data('ui-tagit').tagInput.focus(); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -35,7 +41,7 @@ | ||||||
| 
 | 
 | ||||||
|     $(function() { |     $(function() { | ||||||
| 
 | 
 | ||||||
|         var recipients = $('.recipients_ input'); |         var recipients = $('.set_recipients input'); | ||||||
| 
 | 
 | ||||||
|         recipients.tagit({ |         recipients.tagit({ | ||||||
| 
 | 
 | ||||||
|  | @ -81,6 +87,7 @@ | ||||||
| 
 | 
 | ||||||
|   </script> |   </script> | ||||||
|   ${self.validate_message_js()} |   ${self.validate_message_js()} | ||||||
|  |   % endif | ||||||
| </%def> | </%def> | ||||||
| 
 | 
 | ||||||
| <%def name="validate_message_js()"> | <%def name="validate_message_js()"> | ||||||
|  | @ -95,6 +102,19 @@ | ||||||
| 
 | 
 | ||||||
| <%def name="extra_styles()"> | <%def name="extra_styles()"> | ||||||
|   ${parent.extra_styles()} |   ${parent.extra_styles()} | ||||||
|  |   % if use_buefy: | ||||||
|  |       <style type="text/css"> | ||||||
|  | 
 | ||||||
|  |         .this-page-content { | ||||||
|  |           width: 100%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .this-page-content .buttons { | ||||||
|  |             margin-left: 20rem; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |       </style> | ||||||
|  |   % else: | ||||||
|   ${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.tagit.css'))} |   ${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.tagit.css'))} | ||||||
|   <style type="text/css"> |   <style type="text/css"> | ||||||
| 
 | 
 | ||||||
|  | @ -111,6 +131,7 @@ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   </style> |   </style> | ||||||
|  |   % endif | ||||||
| </%def> | </%def> | ||||||
| 
 | 
 | ||||||
| <%def name="before_tag_added()"> | <%def name="before_tag_added()"> | ||||||
|  | @ -133,4 +154,20 @@ | ||||||
|   % endif |   % endif | ||||||
| </%def> | </%def> | ||||||
| 
 | 
 | ||||||
|  | <%def name="render_this_page_template()"> | ||||||
|  |   ${parent.render_this_page_template()} | ||||||
|  |   ${message_recipients_template()} | ||||||
|  | </%def> | ||||||
|  | 
 | ||||||
|  | <%def name="modify_this_page_vars()"> | ||||||
|  |   ${parent.modify_this_page_vars()} | ||||||
|  |   <script type="text/javascript"> | ||||||
|  | 
 | ||||||
|  |     TailboneFormData.possibleRecipients = new Map(${json.dumps(available_recipients)|n}) | ||||||
|  |     TailboneFormData.recipientDisplayMap = ${json.dumps(recipient_display_map)|n} | ||||||
|  | 
 | ||||||
|  |   </script> | ||||||
|  | </%def> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ${parent.body()} | ${parent.body()} | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								tailbone/templates/messages/recipients.mako
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								tailbone/templates/messages/recipients.mako
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | ## -*- coding: utf-8; -*- | ||||||
|  | 
 | ||||||
|  | <%def name="message_recipients_template()"> | ||||||
|  |   <script type="text/x-template" id="message-recipients-template"> | ||||||
|  |     <div> | ||||||
|  | 
 | ||||||
|  |       <input type="hidden" :name="name" v-model="actualValue" /> | ||||||
|  | 
 | ||||||
|  |       <b-field grouped group-multiline> | ||||||
|  |         <div v-for="uuid in actualValue" | ||||||
|  |              :key="uuid" | ||||||
|  |              class="control"> | ||||||
|  |           <b-tag type="is-primary" | ||||||
|  |                  attached | ||||||
|  |                  aria-close-label="Remove recipient" | ||||||
|  |                  closable | ||||||
|  |                  @close="removeRecipient(uuid)"> | ||||||
|  |             {{ recipientDisplayMap[uuid] }} | ||||||
|  |           </b-tag> | ||||||
|  |         </div> | ||||||
|  |       </b-field> | ||||||
|  | 
 | ||||||
|  |       <b-autocomplete v-model="autocompleteValue" | ||||||
|  |                       placeholder="add recipient" | ||||||
|  |                       :data="filteredData" | ||||||
|  |                       field="uuid" | ||||||
|  |                       @select="selectionMade" | ||||||
|  |                       keep-first> | ||||||
|  |         <template slot-scope="props"> | ||||||
|  |           {{ props.option.label }} | ||||||
|  |         </template> | ||||||
|  |         <template slot="empty">No results found</template> | ||||||
|  |       </b-autocomplete> | ||||||
|  |     </div> | ||||||
|  |   </script> | ||||||
|  | </%def> | ||||||
|  | @ -34,6 +34,7 @@ | ||||||
|         } |         } | ||||||
|         .tailbone-message-body { |         .tailbone-message-body { | ||||||
|             margin: 1rem auto; |             margin: 1rem auto; | ||||||
|  |             min-height: 10rem; | ||||||
|         } |         } | ||||||
|         .tailbone-message-body p { |         .tailbone-message-body p { | ||||||
|             margin-bottom: 1rem; |             margin-bottom: 1rem; | ||||||
|  |  | ||||||
|  | @ -246,7 +246,7 @@ | ||||||
|               % if master: |               % if master: | ||||||
|                   % if master.listing: |                   % if master.listing: | ||||||
|                       <span>${index_title}</span> |                       <span>${index_title}</span> | ||||||
|                   % else: |                   % elif index_url: | ||||||
|                       ${h.link_to(index_title, index_url)} |                       ${h.link_to(index_title, index_url)} | ||||||
|                       % if parent_url is not Undefined: |                       % if parent_url is not Undefined: | ||||||
|                           <span>»</span> |                           <span>»</span> | ||||||
|  | @ -258,6 +258,8 @@ | ||||||
|                       % if master.viewing and grid_index: |                       % if master.viewing and grid_index: | ||||||
|                           ${grid_index_nav()} |                           ${grid_index_nav()} | ||||||
|                       % endif |                       % endif | ||||||
|  |                   % else: | ||||||
|  |                       <span>${index_title}</span> | ||||||
|                   % endif |                   % endif | ||||||
|               % elif index_title: |               % elif index_title: | ||||||
|                   <span>${index_title}</span> |                   <span>${index_title}</span> | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| ################################################################################ | ################################################################################ | ||||||
| # | # | ||||||
| #  Rattail -- Retail Software Framework | #  Rattail -- Retail Software Framework | ||||||
| #  Copyright © 2010-2018 Lance Edgar | #  Copyright © 2010-2019 Lance Edgar | ||||||
| # | # | ||||||
| #  This file is part of Rattail. | #  This file is part of Rattail. | ||||||
| # | # | ||||||
|  | @ -36,6 +36,7 @@ from deform import widget as dfwidget | ||||||
| from pyramid import httpexceptions | from pyramid import httpexceptions | ||||||
| from webhelpers2.html import tags, HTML | from webhelpers2.html import tags, HTML | ||||||
| 
 | 
 | ||||||
|  | # from tailbone import forms | ||||||
| from tailbone.db import Session | from tailbone.db import Session | ||||||
| from tailbone.views import MasterView | from tailbone.views import MasterView | ||||||
| from tailbone.util import raw_datetime | from tailbone.util import raw_datetime | ||||||
|  | @ -140,6 +141,8 @@ class MessagesView(MasterView): | ||||||
|         return six.text_type(sender) |         return six.text_type(sender) | ||||||
| 
 | 
 | ||||||
|     def render_subject_bold(self, message, field): |     def render_subject_bold(self, message, field): | ||||||
|  |         if not message.subject: | ||||||
|  |             return "" | ||||||
|         return HTML.tag('span', c=message.subject, style='font-weight: bold;') |         return HTML.tag('span', c=message.subject, style='font-weight: bold;') | ||||||
| 
 | 
 | ||||||
|     def render_recipients(self, message, column_name): |     def render_recipients(self, message, column_name): | ||||||
|  | @ -212,9 +215,12 @@ class MessagesView(MasterView): | ||||||
|         super(MessagesView, self).configure_form(f) |         super(MessagesView, self).configure_form(f) | ||||||
|         use_buefy = self.get_use_buefy() |         use_buefy = self.get_use_buefy() | ||||||
| 
 | 
 | ||||||
|         # we have custom logic to disable submit button |         f.submit_label = "Send Message" | ||||||
|         f.auto_disable = False | 
 | ||||||
|         f.auto_disable_save = False |         if not use_buefy: | ||||||
|  |             # we have custom logic to disable submit button | ||||||
|  |             f.auto_disable = False | ||||||
|  |             f.auto_disable_save = False | ||||||
| 
 | 
 | ||||||
|         # TODO: A fair amount of this still seems hacky... |         # TODO: A fair amount of this still seems hacky... | ||||||
| 
 | 
 | ||||||
|  | @ -223,22 +229,34 @@ class MessagesView(MasterView): | ||||||
| 
 | 
 | ||||||
|         f.set_type('sent', 'datetime') |         f.set_type('sent', 'datetime') | ||||||
| 
 | 
 | ||||||
|  |         # recipients | ||||||
|         f.set_renderer('recipients', self.render_recipients_full) |         f.set_renderer('recipients', self.render_recipients_full) | ||||||
|         f.set_label('recipients', "To") |         f.set_label('recipients', "To") | ||||||
| 
 | 
 | ||||||
|  |         # subject | ||||||
|         if use_buefy: |         if use_buefy: | ||||||
|             f.set_renderer('subject', self.render_subject_bold) |             f.set_renderer('subject', self.render_subject_bold) | ||||||
|  |             if self.creating: | ||||||
|  |                 f.set_widget('subject', dfwidget.TextInputWidget( | ||||||
|  |                     placeholder="please enter a subject", | ||||||
|  |                     autocomplete='off')) | ||||||
|  |                 f.set_required('subject') | ||||||
| 
 | 
 | ||||||
|  |         # body | ||||||
|         f.set_widget('body', dfwidget.TextAreaWidget(cols=50, rows=15)) |         f.set_widget('body', dfwidget.TextAreaWidget(cols=50, rows=15)) | ||||||
| 
 | 
 | ||||||
|         if self.creating: |         if self.creating: | ||||||
|             f.remove('sender', 'sent') |             f.remove('sender', 'sent') | ||||||
| 
 | 
 | ||||||
|             f.insert_after('recipients', 'recipients_') |             # recipients | ||||||
|  |             f.insert_after('recipients', 'set_recipients') | ||||||
|             f.remove('recipients') |             f.remove('recipients') | ||||||
|             f.set_node('recipients_', colander.SchemaNode(colander.Set())) |             f.set_node('set_recipients', colander.SchemaNode(colander.Set())) | ||||||
|             f.set_widget('recipients_', RecipientsWidget()) |             if use_buefy: | ||||||
|             f.set_label('recipients_', "To") |                 f.set_widget('set_recipients', RecipientsWidgetBuefy()) | ||||||
|  |             else: | ||||||
|  |                 f.set_widget('set_recipients', RecipientsWidget()) | ||||||
|  |             f.set_label('set_recipients', "To") | ||||||
| 
 | 
 | ||||||
|             if self.replying: |             if self.replying: | ||||||
|                 old_message = self.get_instance() |                 old_message = self.get_instance() | ||||||
|  | @ -259,11 +277,11 @@ class MessagesView(MasterView): | ||||||
|                     value = [r[0] for r in value] |                     value = [r[0] for r in value] | ||||||
|                     if old_message.sender is not self.request.user and old_message.sender.active: |                     if old_message.sender is not self.request.user and old_message.sender.active: | ||||||
|                         value.insert(0, old_message.sender_uuid) |                         value.insert(0, old_message.sender_uuid) | ||||||
|                     f.set_default('recipients_', ','.join(value)) |                     f.set_default('set_recipients', ','.join(value)) | ||||||
| 
 | 
 | ||||||
|                 # Just a normal reply, to sender only. |                 # Just a normal reply, to sender only. | ||||||
|                 elif self.filter_reply_recipient(old_message.sender): |                 elif self.filter_reply_recipient(old_message.sender): | ||||||
|                     f.set_default('recipients_', old_message.sender.uuid) |                     f.set_default('set_recipients', old_message.sender.uuid) | ||||||
| 
 | 
 | ||||||
|                 # TODO? |                 # TODO? | ||||||
|                 # # Set focus to message body instead of recipients, when replying. |                 # # Set focus to message body instead of recipients, when replying. | ||||||
|  | @ -281,7 +299,7 @@ class MessagesView(MasterView): | ||||||
|             if self.request.user: |             if self.request.user: | ||||||
|                 message.sender = self.request.user |                 message.sender = self.request.user | ||||||
| 
 | 
 | ||||||
|             for uuid in data['recipients_']: |             for uuid in data['set_recipients']: | ||||||
|                 user = self.Session.query(model.User).get(uuid) |                 user = self.Session.query(model.User).get(uuid) | ||||||
|                 if user: |                 if user: | ||||||
|                     message.add_recipient(user, status=self.enum.MESSAGE_STATUS_INBOX) |                     message.add_recipient(user, status=self.enum.MESSAGE_STATUS_INBOX) | ||||||
|  | @ -322,11 +340,21 @@ class MessagesView(MasterView): | ||||||
|                 return recipient |                 return recipient | ||||||
| 
 | 
 | ||||||
|     def template_kwargs_create(self, **kwargs): |     def template_kwargs_create(self, **kwargs): | ||||||
|         recips = list(self.get_available_recipients().items()) |         use_buefy = self.get_use_buefy() | ||||||
|  | 
 | ||||||
|  |         recips = self.get_available_recipients() | ||||||
|  |         if use_buefy: | ||||||
|  |             kwargs['recipient_display_map'] = recips | ||||||
|  |         recips = list(recips.items()) | ||||||
|         recips.sort(key=self.recipient_sortkey) |         recips.sort(key=self.recipient_sortkey) | ||||||
|         kwargs['available_recipients'] = recips |         kwargs['available_recipients'] = recips | ||||||
|  | 
 | ||||||
|         if self.replying: |         if self.replying: | ||||||
|             kwargs['original_message'] = self.get_instance() |             kwargs['original_message'] = self.get_instance() | ||||||
|  | 
 | ||||||
|  |         if use_buefy: | ||||||
|  |             kwargs['index_url'] = None | ||||||
|  |             kwargs['index_title'] = "New Message" | ||||||
|         return kwargs |         return kwargs | ||||||
| 
 | 
 | ||||||
|     def recipient_sortkey(self, recip): |     def recipient_sortkey(self, recip): | ||||||
|  | @ -355,7 +383,7 @@ class MessagesView(MasterView): | ||||||
|         kwargs['message'] = message |         kwargs['message'] = message | ||||||
|         kwargs['recipient'] = recipient |         kwargs['recipient'] = recipient | ||||||
| 
 | 
 | ||||||
|         if recipient.status == self.enum.MESSAGE_STATUS_ARCHIVE: |         if recipient and recipient.status == self.enum.MESSAGE_STATUS_ARCHIVE: | ||||||
|             kwargs['index_url'] = self.request.route_url('messages.archive') |             kwargs['index_url'] = self.request.route_url('messages.archive') | ||||||
| 
 | 
 | ||||||
|         return kwargs |         return kwargs | ||||||
|  | @ -514,6 +542,30 @@ class RecipientsWidget(dfwidget.TextInputWidget): | ||||||
|         return pstruct.split(',') |         return pstruct.split(',') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class RecipientsWidgetBuefy(dfwidget.Widget): | ||||||
|  |     """ | ||||||
|  |     Custom "message recipients" widget, for use with Buefy / Vue.js themes. | ||||||
|  |     """ | ||||||
|  |     template = 'message_recipients_buefy' | ||||||
|  | 
 | ||||||
|  |     def deserialize(self, field, pstruct): | ||||||
|  |         if pstruct is colander.null: | ||||||
|  |             return colander.null | ||||||
|  |         if not isinstance(pstruct, six.string_types): | ||||||
|  |             raise colander.Invalid(field.schema, "Pstruct is not a string") | ||||||
|  |         if not pstruct: | ||||||
|  |             return colander.null | ||||||
|  |         pstruct = pstruct.split(',') | ||||||
|  |         return pstruct | ||||||
|  | 
 | ||||||
|  |     def serialize(self, field, cstruct, **kw): | ||||||
|  |         if cstruct in (colander.null, None): | ||||||
|  |             cstruct = "" | ||||||
|  |         template = self.template | ||||||
|  |         values = self.get_template_values(field, cstruct, kw) | ||||||
|  |         return field.renderer(template, **values) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def includeme(config): | def includeme(config): | ||||||
| 
 | 
 | ||||||
|     config.add_tailbone_permission('messages', 'messages.list', "List/Search Messages") |     config.add_tailbone_permission('messages', 'messages.list', "List/Search Messages") | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar