mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-08-29 02:07:36 +00:00
the whole server built html of an iMIP card is rendered through sg-compile
(Message.service.js sets part.compile for UIxMailPartICalViewer), and the user
comment and the description are emitted with escapeHTML="NO". event data from
the invitation is therefore both an angular template and raw html.
47133fdf3 closed the description against interpolation with ng-non-bindable.
this closes both paths for every remaining field:
* ng-non-bindable on the user comment, the location, the organizer common name
and the raw body shown when the calendar cannot be parsed
* the user comment and the description are read through accessors that escape
them, so the url detection and insertBR produce the only markup left in the
output
the marker sits on the leaf containers, not on md-card-content, so the buttons,
the delegation autocomplete and the attendee chips keep being compiled. url
detection still turns a bare url in a comment or a description into a link.
315 lines
14 KiB
XML
315 lines
14 KiB
XML
<?xml version="1.0" standalone="yes"?>
|
|
<!DOCTYPE div>
|
|
<div xmlns="http://www.w3.org/1999/xhtml"
|
|
xmlns:var="http://www.skyrix.com/od/binding"
|
|
xmlns:label="OGo:label"
|
|
xmlns:const="http://www.skyrix.com/od/constant"
|
|
xmlns:rsrc="OGo:url">
|
|
|
|
<!-- PARSING ERROR -->
|
|
<var:if condition="couldParseCalendar" const:negate="1">
|
|
<div>
|
|
<md-toolbar class="md-medium-tall md-warn md-hue-3">
|
|
<div class="md-toolbar-tools">
|
|
<h2>
|
|
<var:string label:value="SOGo could not parse the body of this calendar MIME part."/>
|
|
</h2>
|
|
</div>
|
|
</md-toolbar>
|
|
<md-whiteframe class="md-whiteframe-z1" layout="row" layout-align="space-between center">
|
|
<pre ng-non-bindable=""><var:string value="flatContentAsString" /></pre>
|
|
</md-whiteframe>
|
|
</div>
|
|
</var:if> <!-- if condition="couldParseCalendar" const:negate="1" -->
|
|
|
|
<!-- EVENT PROPERLY PARSED -->
|
|
<var:if condition="couldParseCalendar">
|
|
|
|
<md-card sg-imip="message" var:sg-imip-path="pathToAttachmentFromMessage">
|
|
<!-- TODO - remove unused strings
|
|
<legend>
|
|
<var:string label:value="Appointment"/>:
|
|
<strong><var:string value="inEvent.summary" /></strong>
|
|
|
|
<var:if condition="isLoggedInUserTheOrganizer">
|
|
(<var:string label:value="organized_by_you"/>)
|
|
</var:if>
|
|
<var:if condition="isLoggedInUserAnAttendee">
|
|
(<var:string label:value="you_are_an_attendee"/>)
|
|
</var:if>
|
|
</legend> -->
|
|
|
|
<!-- IMIP REQUEST -->
|
|
<md-card-content>
|
|
<var:if condition="inCalendar.method.uppercaseString" const:value="REQUEST">
|
|
<!-- sent to attendees to propose or update a meeting -->
|
|
<var:if condition="isLoggedInUserAnAttendee">
|
|
<var:if condition="hasCalendarAccess">
|
|
<div layout="row" layout-align="start center">
|
|
<var:if condition="currentUserAttendee.rsvp" const:value="true">
|
|
|
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
|
const:value="ACCEPTED" const:negate="YES">
|
|
<md-button class="md-raised md-accent" type="button" ng-click="iCalendarAction('accept')">
|
|
<var:string label:value="Accept" />
|
|
</md-button>
|
|
</var:if>
|
|
|
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
|
const:value="DECLINED" const:negate="YES">
|
|
<md-button class="md-raised md-warn" type="button" ng-click="iCalendarAction('decline')">
|
|
<var:string label:value="Decline" />
|
|
</md-button>
|
|
</var:if>
|
|
|
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
|
const:value="TENTATIVE" const:negate="YES">
|
|
<md-button class="md-raised" type="button" ng-click="iCalendarAction('tentative')">
|
|
<var:string label:value="Tentative" />
|
|
</md-button>
|
|
</var:if>
|
|
|
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
|
const:value="DELEGATED" const:negate="YES">
|
|
<md-button class="md-raised" type="button"
|
|
ng-click="delegateInvitation = true"
|
|
ng-hide="delegateInvitation == true">
|
|
<var:string label:value="Delegate ..." />
|
|
</md-button>
|
|
|
|
<div layout="row"
|
|
layout-align="start center"
|
|
ng-show="delegateInvitation == true">
|
|
<md-autocomplete
|
|
class="md-flex"
|
|
md-search-text="searchText"
|
|
md-selected-item="delegatedTo"
|
|
md-items="user in userFilter(searchText)"
|
|
var:md-min-length="minimumSearchLength"
|
|
md-no-cache="true"
|
|
md-item-text="user.$shortFormat()"
|
|
label:md-floating-label="Delegated to">
|
|
<md-item-template>
|
|
<span class="md-contact-suggestion" layout="row" layout-align="space-between center">
|
|
<span class="md-contact-name"
|
|
md-highlight-text="searchText"
|
|
md-highlight-flags="^i">{{user.$fullname()}}</span> <span class="md-contact-email"
|
|
md-highlight-text="searchText"
|
|
md-highlight-flags="^i">{{user.c_email}}</span>
|
|
</span>
|
|
</md-item-template>
|
|
</md-autocomplete>
|
|
<md-button class="md-icon-button" ng-click="delegateInvitation = false">
|
|
<md-icon>close</md-icon>
|
|
</md-button>
|
|
<md-button class="md-icon-button md-primary"
|
|
ng-click="iCalendarAction('delegate')"
|
|
ng-disabled="!delegatedTo || delegatedTo.length == 0">
|
|
<md-icon>check</md-icon>
|
|
</md-button>
|
|
</div>
|
|
</var:if>
|
|
<!-- TODO - should we re-enable this? It never
|
|
worked in v2!
|
|
<var:if condition="currentUserAttendee.partStatWithDefault"
|
|
const:value="DELEGATED">
|
|
<span id="delegateEditor">
|
|
<span class="floatLeft"><var:string label:value="Delegated to" />
|
|
<a var:href="currentUserAttendee.delegatedTo" name="delegatedToLink" id="delegatedToLink"><var:string value="currentUserAttendee.delegatedTo.rfc822Email" /></a></span>
|
|
<input name="delegatedTo" id="delegatedTo" type="text" var:value="currentUserAttendee.delegatedTo.rfc822Email" var:uid="currentUserAttendee.delegatedTo.rfc822Email" style="display: none;" />
|
|
<a href="#" class="button actionButton" id="iCalendarDelegate" style="display: none;">
|
|
<span><var:string label:value="OK" /></span></a>
|
|
</span>
|
|
</var:if>
|
|
-->
|
|
</var:if> <!-- if condition="currentUserAttendee.rsvp" const:value="true" -->
|
|
|
|
<var:if condition="isEventStoredInCalendar" const:negate="YES">
|
|
<md-button class="md-raised" type="button" ng-click="iCalendarAction('addToCalendar')">
|
|
<var:string label:value="Add to calendar" />
|
|
</md-button>
|
|
</var:if>
|
|
|
|
<md-divider><!-- divider --></md-divider>
|
|
</div>
|
|
|
|
</var:if> <!-- if condition="hasCalendarAccess" -->
|
|
|
|
<p>
|
|
<var:string label:value="Organizer" />
|
|
<a ng-non-bindable="" var:href="inEvent.organizer.email"
|
|
><var:string value="organizerDisplayName" /></a>
|
|
<var:string label:value="request_info" />
|
|
</p>
|
|
|
|
</var:if> <!-- if condition="isLoggedInUserAnAttendee" -->
|
|
|
|
<var:if condition="isLoggedInUserAnAttendee" const:negate="YES">
|
|
<p>
|
|
<var:string label:value="Organizer" />
|
|
<a ng-non-bindable="" var:href="inEvent.organizer.email">
|
|
<var:string value="organizerDisplayName" />
|
|
</a>
|
|
<var:string label:value="request_info_no_attendee" />
|
|
<var:if condition="hasCalendarAccess">
|
|
<var:if condition="isEventStoredInCalendar" const:negate="YES">
|
|
<!-- Add event to calendar even if the user is not invite -->
|
|
<div layout="row" layout-align="start center">
|
|
<md-button class="md-raised" type="button" ng-click="iCalendarAction('addToCalendar')">
|
|
<var:string label:value="Add to calendar" />
|
|
</md-button>
|
|
</div>
|
|
</var:if>
|
|
</var:if>
|
|
</p>
|
|
</var:if>
|
|
|
|
</var:if> <!-- if condition="inCalendar.method.uppercaseString"
|
|
const:value="REQUEST" -->
|
|
|
|
<!-- IMIP REPLY - sent to organizer to update the status of the
|
|
participant -->
|
|
<var:if condition="inCalendar.method.uppercaseString" const:value="REPLY">
|
|
<var:if condition="isReplySenderAnAttendee" const:negate="1">
|
|
<p>
|
|
<var:string label:value="reply_info_no_attendee" />
|
|
</p>
|
|
</var:if>
|
|
<var:if condition="isReplySenderAnAttendee">
|
|
<var:if condition="canOriginalEventBeUpdated">
|
|
<p>
|
|
<var:string label:value="Status Update" />:
|
|
<i><var:string label:value="$inReplyAttendee.partStatWithDefault" /></i>,
|
|
<var:string label:value="was" />
|
|
<i><var:string label:value="$storedReplyAttendee.partStatWithDefault"/></i>.
|
|
</p>
|
|
<br/>
|
|
<md-button class="md-raised" type="button" ng-click="iCalendarAction('updateUserStatus')">
|
|
<var:string label:value="Update status" />
|
|
</md-button>
|
|
</var:if>
|
|
</var:if>
|
|
</var:if>
|
|
|
|
<!-- IMIP CANCEL - sent to attendees to notify of the attendee
|
|
being removed or the event being deleted -->
|
|
<var:if condition="inCalendar.method.uppercaseString" const:value="CANCEL">
|
|
<p><var:string label:value="cancel_info_text" /></p>
|
|
<var:if condition="isEventStoredInCalendar">
|
|
<md-button class="md-raised" type="button" ng-click="iCalendarAction('deleteFromCalendar')">
|
|
<var:string label:value="Delete from calendar" />
|
|
</md-button>
|
|
</var:if>
|
|
</var:if>
|
|
|
|
<!-- IMIP ADD - TODO -->
|
|
<var:if condition="inCalendar.method.uppercaseString" const:value="ADD">
|
|
<p><var:string label:value="add_info_text" /></p>
|
|
</var:if>
|
|
|
|
<!-- IMIP PUBLISH - none-scheduling event sent to someone for
|
|
adding to the calendar -->
|
|
<var:if condition="inCalendar.method.uppercaseString" const:value="PUBLISH">
|
|
<p><var:string label:value="publish_info_text" /></p>
|
|
</var:if>
|
|
|
|
<var:if condition="isLoggedInUserTheOrganizer">
|
|
<!--
|
|
Possible Status:
|
|
REPLY => check whether it matches, if not suggest change, show comment
|
|
REFRESH => add button to resent iCal
|
|
COUNTER => show panel to decide on counter
|
|
-->
|
|
</var:if>
|
|
<var:if condition="isLoggedInUserTheOrganizer" const:negate="1">
|
|
<!--
|
|
Possible Status:
|
|
REQUEST => ACCEPT, TENTATIVELY, DECLINE buttons with comment field
|
|
- only show buttons for attendees
|
|
PUBLISH => just the 'add to calendar' button, rewrite organizer?
|
|
ADD / CANCEL
|
|
DECLINE-COUNTER
|
|
-->
|
|
</var:if>
|
|
|
|
<!-- the user comment is used in replies -->
|
|
<var:if condition="userComment.isNotEmpty">
|
|
<div class="pseudo-input-container">
|
|
<label class="pseudo-input-label">
|
|
<var:string label:value="Comment"/>
|
|
</label>
|
|
<div ng-non-bindable="">
|
|
<md-content>
|
|
<var:string value="userComment.stringByDetectingURLs" const:insertBR="1" const:escapeHTML="NO"/>
|
|
</md-content>
|
|
</div>
|
|
</div>
|
|
</var:if>
|
|
|
|
|
|
<!-- EVENT'S METADATA (time, organizer, attendees, etc.) -->
|
|
<var:if condition="hasOrganizer" const:value="true">
|
|
<div class="pseudo-input-container">
|
|
<label class="pseudo-input-label"><var:string label:value="Organizer"/></label>
|
|
<div ng-non-bindable="">
|
|
<var:string value="organizerDisplayName"/>
|
|
</div>
|
|
</div>
|
|
</var:if>
|
|
|
|
<div class="pseudo-input-container">
|
|
<label class="pseudo-input-label"><var:string label:value="Time"/></label>
|
|
<div>
|
|
<var:string value="formattedDateTime"/>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<var:if condition="hasLocation">
|
|
<div class="pseudo-input-container">
|
|
<label class="pseudo-input-label"><var:string label:value="Location"/></label>
|
|
<div ng-non-bindable="">
|
|
<var:string value="location"/>
|
|
</div>
|
|
</div>
|
|
</var:if>
|
|
|
|
<!-- ATTENDEES -->
|
|
<md-list ng-show="part.participants.length > 0">
|
|
<div class="pseudo-input-container">
|
|
<label class="pseudo-input-label"><var:string label:value="Attendees"/></label>
|
|
<!-- md-contact-chips don't support "readonly", so we build them using md-chips
|
|
in readonly mode and a template similar to the one of md-contact-chips -->
|
|
<md-chips class="md-contact-chips sg-readonly sg-with-secondary"
|
|
ng-model="::part.participants"
|
|
readonly="true">
|
|
<md-chip-template>
|
|
<div class="md-contact-avatar">
|
|
<sg-avatar-image sg-email="$chip.email" size="26">person</sg-avatar-image>
|
|
</div>
|
|
<div class="md-contact-name">{{$chip.name}}</div>
|
|
<md-icon class="sg-secondary" ng-class="'icon-' + $chip.partstat"><!-- partstat --></md-icon>
|
|
</md-chip-template>
|
|
</md-chips>
|
|
</div>
|
|
</md-list>
|
|
|
|
<var:if condition="eventDescription.isNotEmpty">
|
|
<div class="pseudo-input-container">
|
|
<label class="pseudo-input-label">
|
|
<var:string label:value="Description"/>
|
|
</label>
|
|
<div ng-non-bindable="">
|
|
<md-content>
|
|
<var:string value="eventDescription.stringByDetectingURLs" const:insertBR="1" const:escapeHTML="NO"/>
|
|
</md-content>
|
|
</div>
|
|
</div>
|
|
</var:if>
|
|
</md-card-content>
|
|
</md-card>
|
|
|
|
</var:if><!--if condition="couldParseCalendar" -->
|
|
|
|
</div>
|