Refactor "send new message" form, esp. recipients field, per Vue.js
This commit is contained in:
parent
e153e530a8
commit
86695c9dc7
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…
Reference in a new issue