work in progress: 'send link by email' feature
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3154 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
6ff94ad004
commit
12061a6aa3
8 changed files with 184 additions and 40 deletions
|
@ -101,8 +101,8 @@ class ConceptEditForm(EditForm, I18NView):
|
||||||
desc.height = 2
|
desc.height = 2
|
||||||
|
|
||||||
|
|
||||||
class ConceptRelationView(BaseView):
|
class BaseRelationView(BaseView):
|
||||||
""" For displaying children and resources lists, used by ConceptView.
|
""" For displaying children and resources lists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, relation, request, contextIsSecond=False):
|
def __init__(self, relation, request, contextIsSecond=False):
|
||||||
|
@ -123,6 +123,9 @@ class ConceptRelationView(BaseView):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def data(self):
|
def data(self):
|
||||||
|
return self.getData()
|
||||||
|
|
||||||
|
def getData(self):
|
||||||
return self.instance.applyTemplate()
|
return self.instance.applyTemplate()
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -176,19 +179,13 @@ class ConceptRelationView(BaseView):
|
||||||
def order(self):
|
def order(self):
|
||||||
return self.relation.order
|
return self.relation.order
|
||||||
|
|
||||||
def getActions(self, category='object', page=None, target=None):
|
|
||||||
t = IType(self.context)
|
|
||||||
actInfo = t.optionsDict.get('action.' + category, '')
|
|
||||||
actNames = [n.strip() for n in actInfo.split(',')]
|
|
||||||
if actNames:
|
|
||||||
return actions.get(category, actNames, view=self, page=page, target=target)
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
class ConceptView(BaseView):
|
class ConceptView(BaseView):
|
||||||
|
|
||||||
template = concept_macros
|
template = concept_macros
|
||||||
childViewFactory = ConceptRelationView
|
|
||||||
|
def childViewFactory(self, *args, **kw):
|
||||||
|
return ConceptRelationView(*args, **kw)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def macro(self):
|
def macro(self):
|
||||||
|
@ -354,12 +351,32 @@ class ConceptView(BaseView):
|
||||||
yield NodeView(node, self.request)
|
yield NodeView(node, self.request)
|
||||||
|
|
||||||
def getActions(self, category='object', page=None, target=None):
|
def getActions(self, category='object', page=None, target=None):
|
||||||
|
acts = []
|
||||||
t = IType(self.context)
|
t = IType(self.context)
|
||||||
actInfo = t.optionsDict.get('action.' + category, '')
|
actInfo = t.optionsDict.get('action.' + category, '')
|
||||||
actNames = [n.strip() for n in actInfo.split(',')]
|
actNames = [n.strip() for n in actInfo.split(',')]
|
||||||
if actNames:
|
if actNames:
|
||||||
return actions.get(category, actNames, view=self, page=page, target=target)
|
acts = list(actions.get(category, actNames,
|
||||||
return []
|
view=self, page=page, target=target))
|
||||||
|
if category in self.actions:
|
||||||
|
acts.extend(self.actions[category](self, page, target))
|
||||||
|
return acts
|
||||||
|
|
||||||
|
def getObjectActions(self, page=None, target=None):
|
||||||
|
acts = ['info']
|
||||||
|
acts.extend('state.' + st.statesDefinition for st in self.states)
|
||||||
|
if self.globalOptions('organize.allowSendEmail'):
|
||||||
|
acts.append('send_email')
|
||||||
|
return actions.get('object', acts, view=self, page=page, target=target)
|
||||||
|
|
||||||
|
actions = dict(object=getObjectActions)
|
||||||
|
|
||||||
|
|
||||||
|
class ConceptRelationView(ConceptView, BaseRelationView):
|
||||||
|
|
||||||
|
__init__ = BaseRelationView.__init__
|
||||||
|
|
||||||
|
getData = BaseRelationView.getData
|
||||||
|
|
||||||
|
|
||||||
class ConceptConfigureView(ConceptView):
|
class ConceptConfigureView(ConceptView):
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<metal:info define-macro="object_info"
|
<metal:info define-macro="object_info"
|
||||||
tal:define="item nocall:view/item">
|
tal:define="item nocall:view/item">
|
||||||
<table class="object_info">
|
<table class="object_info" width="400">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><h2 i18n:translate="">Object Information</h2><br /></td>
|
<td colspan="2"><h2 i18n:translate="">Object Information</h2><br /></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -23,9 +23,10 @@
|
||||||
<td><span i18n:translate="">Type</span>:</td>
|
<td><span i18n:translate="">Type</span>:</td>
|
||||||
<td tal:content="item/longTypeTitle"></td>
|
<td tal:content="item/longTypeTitle"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr tal:define="size item/context/sizeForDisplay|nothing"
|
||||||
|
tal:condition="size">
|
||||||
<td><span i18n:translate="">Size</span>:</td>
|
<td><span i18n:translate="">Size</span>:</td>
|
||||||
<td tal:content="item/context/sizeForDisplay"></td>
|
<td tal:content="size"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><span i18n:translate="">modified</span>:</td>
|
<td><span i18n:translate="">modified</span>:</td>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -38,7 +38,6 @@ from zope.event import notify
|
||||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
from zope.lifecycleevent import Attributes
|
from zope.lifecycleevent import Attributes
|
||||||
from zope.formlib.form import Form, FormFields
|
from zope.formlib.form import Form, FormFields
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.security import canAccess, canWrite, checkPermission
|
from zope.security import canAccess, canWrite, checkPermission
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
@ -50,7 +49,7 @@ from cybertools.browser.view import GenericView
|
||||||
from cybertools.stateful.interfaces import IStateful
|
from cybertools.stateful.interfaces import IStateful
|
||||||
from cybertools.typology.interfaces import IType, ITypeManager
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
from cybertools.xedit.browser import ExternalEditorView
|
from cybertools.xedit.browser import ExternalEditorView
|
||||||
from loops.browser.action import DialogAction
|
from loops.browser.action import actions, DialogAction
|
||||||
from loops.common import adapted, AdapterBase
|
from loops.common import adapted, AdapterBase
|
||||||
from loops.i18n.browser import i18n_macros
|
from loops.i18n.browser import i18n_macros
|
||||||
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
|
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
|
||||||
|
@ -438,6 +437,12 @@ class NodeView(BaseView):
|
||||||
page=self, target=target))
|
page=self, target=target))
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
def xx_getObjectActions(self, target=None):
|
||||||
|
acts = []
|
||||||
|
if self.globalOptions('organize.allowSendEmail'):
|
||||||
|
acts.append('send_email')
|
||||||
|
return actions.get('object', acts, view=self, page=self, target=target)
|
||||||
|
|
||||||
actions = dict(portlet=getPortletActions)
|
actions = dict(portlet=getPortletActions)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -704,7 +709,9 @@ class ConfigureView(NodeView):
|
||||||
|
|
||||||
class NodeAdding(Adding):
|
class NodeAdding(Adding):
|
||||||
|
|
||||||
def addingInfo(self):
|
pass
|
||||||
|
|
||||||
|
def xx_addingInfo(self):
|
||||||
info = super(NodeAdding, self).addingInfo()
|
info = super(NodeAdding, self).addingInfo()
|
||||||
#info.append({'title': 'Document',
|
#info.append({'title': 'Document',
|
||||||
# 'action': 'AddLoopsNodeDocument.html',
|
# 'action': 'AddLoopsNodeDocument.html',
|
||||||
|
|
|
@ -44,7 +44,8 @@ from cybertools.typology.interfaces import IType
|
||||||
from cybertools.xedit.browser import ExternalEditorView, fromUnicode
|
from cybertools.xedit.browser import ExternalEditorView, fromUnicode
|
||||||
from loops.browser.action import DialogAction, TargetAction
|
from loops.browser.action import DialogAction, TargetAction
|
||||||
from loops.browser.common import EditForm, BaseView
|
from loops.browser.common import EditForm, BaseView
|
||||||
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
from loops.browser.concept import BaseRelationView, ConceptRelationView
|
||||||
|
from loops.browser.concept import ConceptConfigureView
|
||||||
from loops.browser.node import NodeView, node_macros
|
from loops.browser.node import NodeView, node_macros
|
||||||
from loops.common import adapted, NameChooser
|
from loops.common import adapted, NameChooser
|
||||||
from loops.interfaces import IBaseResource, IDocument, IMediaAsset, ITextDocument
|
from loops.interfaces import IBaseResource, IDocument, IMediaAsset, ITextDocument
|
||||||
|
@ -190,8 +191,9 @@ class ResourceView(BaseView):
|
||||||
|
|
||||||
def getObjectActions(self, page=None, target=None):
|
def getObjectActions(self, page=None, target=None):
|
||||||
acts = ['info']
|
acts = ['info']
|
||||||
#acts.extend('state.' + st for st in statefulActions)
|
|
||||||
acts.extend('state.' + st.statesDefinition for st in self.states)
|
acts.extend('state.' + st.statesDefinition for st in self.states)
|
||||||
|
if self.globalOptions('organize.allowSendEmail'):
|
||||||
|
acts.append('send_email')
|
||||||
if self.xeditable:
|
if self.xeditable:
|
||||||
acts.append('external_edit')
|
acts.append('external_edit')
|
||||||
return actions.get('object', acts, view=self, page=page, target=target)
|
return actions.get('object', acts, view=self, page=page, target=target)
|
||||||
|
@ -214,10 +216,9 @@ class ResourceView(BaseView):
|
||||||
yield NodeView(node, self.request)
|
yield NodeView(node, self.request)
|
||||||
|
|
||||||
|
|
||||||
class ResourceRelationView(ResourceView, ConceptRelationView):
|
class ResourceRelationView(ResourceView, BaseRelationView):
|
||||||
|
|
||||||
def __init__(self, relation, request, contextIsSecond=False):
|
__init__ = BaseRelationView.__init__
|
||||||
ConceptRelationView.__init__(self, relation, request, contextIsSecond)
|
|
||||||
|
|
||||||
getActions = ResourceView.getActions
|
getActions = ResourceView.getActions
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ concept assigned we should get an error:
|
||||||
>>> johnC.conceptType = person
|
>>> johnC.conceptType = person
|
||||||
>>> john = IPerson(johnC)
|
>>> john = IPerson(johnC)
|
||||||
>>> john.userId = 'users.john'
|
>>> john.userId = 'users.john'
|
||||||
|
>>> john.email = 'john@loopz.org'
|
||||||
|
|
||||||
>>> marthaC = concepts['martha'] = Concept(u'Martha')
|
>>> marthaC = concepts['martha'] = Concept(u'Martha')
|
||||||
>>> marthaC.conceptType = person
|
>>> marthaC.conceptType = person
|
||||||
|
@ -377,6 +378,20 @@ Allocation of persons to tasks
|
||||||
... conceptType=predicate, predicateInterface=IAllocated)
|
... conceptType=predicate, predicateInterface=IAllocated)
|
||||||
|
|
||||||
|
|
||||||
|
Send Email to Members
|
||||||
|
=====================
|
||||||
|
|
||||||
|
>>> menu.target = event01
|
||||||
|
|
||||||
|
>>> from loops.organize.browser.party import SendEmailForm
|
||||||
|
>>> form = SendEmailForm(menu, TestRequest())
|
||||||
|
>>> form.members
|
||||||
|
[{'email': 'john@loopz.org', 'title': u'John'}]
|
||||||
|
>>> form.subject
|
||||||
|
u"loops Notification from '$site'"
|
||||||
|
>>> form.mailBody
|
||||||
|
u'\n\nEvent #1\nhttp://127.0.0.1/loops/views/menu/.target95\n\n'
|
||||||
|
|
||||||
|
|
||||||
Fin de partie
|
Fin de partie
|
||||||
=============
|
=============
|
||||||
|
|
|
@ -11,8 +11,7 @@
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
provides="zope.interface.Interface"
|
provides="zope.interface.Interface"
|
||||||
factory="loops.organize.browser.member.PersonalInfo"
|
factory="loops.organize.browser.member.PersonalInfo"
|
||||||
permission="zope.View"
|
permission="zope.View" />
|
||||||
/>
|
|
||||||
|
|
||||||
<zope:view
|
<zope:view
|
||||||
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
@ -20,22 +19,19 @@
|
||||||
zope.schema.interfaces.ITextLine"
|
zope.schema.interfaces.ITextLine"
|
||||||
provides="zope.app.form.interfaces.IDisplayWidget"
|
provides="zope.app.form.interfaces.IDisplayWidget"
|
||||||
factory="cybertools.browser.widget.SimpleListDisplayWidget"
|
factory="cybertools.browser.widget.SimpleListDisplayWidget"
|
||||||
permission="zope.Public"
|
permission="zope.Public" />
|
||||||
/>
|
|
||||||
|
|
||||||
<browser:page
|
<browser:page
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
name="register_user.html"
|
name="register_user.html"
|
||||||
class="loops.organize.browser.member.MemberRegistration"
|
class="loops.organize.browser.member.MemberRegistration"
|
||||||
permission="zope.Public"
|
permission="zope.Public" />
|
||||||
/>
|
|
||||||
|
|
||||||
<browser:page
|
<browser:page
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
name="change_password.html"
|
name="change_password.html"
|
||||||
class="loops.organize.browser.member.PasswordChange"
|
class="loops.organize.browser.member.PasswordChange"
|
||||||
permission="zope.Public"
|
permission="zope.Public" />
|
||||||
/>
|
|
||||||
|
|
||||||
<zope:adapter
|
<zope:adapter
|
||||||
name="task.html"
|
name="task.html"
|
||||||
|
@ -43,8 +39,7 @@
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
provides="zope.interface.Interface"
|
provides="zope.interface.Interface"
|
||||||
factory="loops.organize.browser.task.TaskView"
|
factory="loops.organize.browser.task.TaskView"
|
||||||
permission="zope.View"
|
permission="zope.View" />
|
||||||
/>
|
|
||||||
|
|
||||||
<zope:adapter
|
<zope:adapter
|
||||||
name="list_events.html"
|
name="list_events.html"
|
||||||
|
@ -52,15 +47,19 @@
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
provides="zope.interface.Interface"
|
provides="zope.interface.Interface"
|
||||||
factory="loops.organize.browser.event.Events"
|
factory="loops.organize.browser.event.Events"
|
||||||
permission="zope.View"
|
permission="zope.View" />
|
||||||
/>
|
|
||||||
|
|
||||||
<zope:adapter
|
<zope:adapter
|
||||||
for="cybertools.tracking.interfaces.ITrack
|
for="cybertools.tracking.interfaces.ITrack
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
provides="zope.interface.Interface"
|
provides="zope.interface.Interface"
|
||||||
factory="cybertools.tracking.browser.TrackView"
|
factory="cybertools.tracking.browser.TrackView"
|
||||||
permission="zope.View"
|
permission="zope.View" />
|
||||||
/>
|
|
||||||
|
<browser:page
|
||||||
|
name="object_send_email.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="loops.organize.browser.party.SendEmailForm"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,12 +24,19 @@ $Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope import interface, component
|
from zope import interface, component
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.dublincore.interfaces import IZopeDublinCore
|
||||||
|
|
||||||
|
from cybertools.ajax import innerHtml
|
||||||
from cybertools.browser.action import actions
|
from cybertools.browser.action import actions
|
||||||
from loops.browser.action import DialogAction
|
from loops.browser.action import DialogAction
|
||||||
|
from loops.browser.node import NodeView
|
||||||
|
from loops.common import adapted
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
|
|
||||||
|
organize_macros = ViewPageTemplateFile('view_macros.pt')
|
||||||
|
|
||||||
|
|
||||||
actions.register('createPerson', 'portlet', DialogAction,
|
actions.register('createPerson', 'portlet', DialogAction,
|
||||||
title=_(u'Create Person...'),
|
title=_(u'Create Person...'),
|
||||||
|
@ -66,3 +73,53 @@ actions.register('editAddress', 'portlet', DialogAction,
|
||||||
viewName='edit_concept.html',
|
viewName='edit_concept.html',
|
||||||
dialogName='editAddress',
|
dialogName='editAddress',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
actions.register('send_email', 'object', DialogAction,
|
||||||
|
description=_(u'Send a link to this object by email.'),
|
||||||
|
viewName='object_send_email.html',
|
||||||
|
dialogName='',
|
||||||
|
icon='cybertools.icons/email.png',
|
||||||
|
cssClass='icon-action',
|
||||||
|
prerequisites=['registerDojoTextWidget', 'registerDojoTextarea'],
|
||||||
|
addParams=dict(version='this'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SendEmailForm(NodeView):
|
||||||
|
|
||||||
|
__call__ = innerHtml
|
||||||
|
|
||||||
|
@property
|
||||||
|
def macro(self):
|
||||||
|
return organize_macros.macros['send_email']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def dialog_name(self):
|
||||||
|
return self.request.get('dialog', 'object_send_email')
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def title(self):
|
||||||
|
return self.target.title
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def targetUrl(self):
|
||||||
|
return self.getUrlForTarget(self.virtualTargetObject)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def members(self):
|
||||||
|
persons = self.conceptManager['person'].getChildren([self.typePredicate])
|
||||||
|
persons = [adapted(p) for p in persons]
|
||||||
|
return [dict(title=p.title, email=p.email) for p in persons if p.email]
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def mailBody(self):
|
||||||
|
return '\n\n%s\n%s\n\n' % (self.title, self.targetUrl)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def subject(self):
|
||||||
|
menu = self.context.getMenu()
|
||||||
|
zdc = IZopeDublinCore(menu)
|
||||||
|
zdc.languageInfo = self.languageInfo
|
||||||
|
site = zdc.title or menu.title
|
||||||
|
return _(u"loops Notification from '$site'",
|
||||||
|
mapping=dict(site=site))
|
||||||
|
|
|
@ -43,3 +43,50 @@
|
||||||
</tal:child>
|
</tal:child>
|
||||||
</div>
|
</div>
|
||||||
</metal:block>
|
</metal:block>
|
||||||
|
|
||||||
|
|
||||||
|
<metal:block define-macro="send_email">
|
||||||
|
<form method="post" id="sendEmail_form" class="dialog"
|
||||||
|
dojoType="dijit.form.Form">
|
||||||
|
<input type="hidden" name="form.action" value="create_workitem" />
|
||||||
|
<div class="heading">
|
||||||
|
<span i18n:translate="">Send Link by Email</span> -
|
||||||
|
<span tal:content="view/target/title"></span></div>
|
||||||
|
<div>
|
||||||
|
<label i18n:translate="" for="subject">Subject</label>
|
||||||
|
<div>
|
||||||
|
<input name="subject" id="subject" style="width: 60em"
|
||||||
|
dojoType="dijit.form.ValidationTextBox" required
|
||||||
|
tal:attributes="value view/subject" /></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label i18n:translate="" for="mailbody">Mail Body</label>
|
||||||
|
<div>
|
||||||
|
<textarea name="mailbody" cols="80" rows="4" id="mailbody"
|
||||||
|
dojoType="dijit.form.SimpleTextarea" style="width: 60em"
|
||||||
|
tal:content="view/mailBody"></textarea></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label i18n:translate="">Recipients</label>
|
||||||
|
<div tal:repeat="member view/members">
|
||||||
|
<input type="checkbox" checked name="recipients:list"
|
||||||
|
tal:attributes="value member/email" />
|
||||||
|
<span tal:content="member/title">Johnny</span>
|
||||||
|
(<span tal:content="member/email">Johnny</span>)
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label i18n:translate="" for="addrecipients">Additional recipients</label>
|
||||||
|
<div>
|
||||||
|
<textarea name="addrecipients" cols="80" rows="4" id="addrecipients"
|
||||||
|
dojoType="dijit.form.SimpleTextarea"
|
||||||
|
style="width: 60em"></textarea></div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<input value="Send email" type="submit"
|
||||||
|
onClick="return closeDialog(true)"
|
||||||
|
i18n:attributes="value">
|
||||||
|
<input type="button" value="Cancel"
|
||||||
|
onClick="return closeDialog(false)"
|
||||||
|
i18n:attributes="value"></div>
|
||||||
|
</form>
|
||||||
|
</metal:block>
|
||||||
|
|
Loading…
Add table
Reference in a new issue