Rendering a complex div on Outlook 365 - outlook-addin

I'm working on an Outlook addin for a .Net Framework project. I would like the elements like the following to display in the email body:
This div is generated by the code:
<div ng-repeat="dateGroup in timeLine.DateGroups">
<div class="circle color{{dateGroup.ColorId}}Solid whiteBorder" ng-style="{'left': dateGroup.Offset + 'px', 'top': (timeLine.CenterLineTop + 1) + 'px', 'width': timeLine.DotWidth + 'px', 'height': timeLine.DotWidth + 'px'}"></div>
<div class="labelLine colorLine{{dateGroup.ColorId}}" ng-style="{'left': dateGroup.LineOffset + 'px', 'top': dateGroup.LineTop + 'px', 'width':':1px','height' : dateGroup.Height + 'px'}"></div>
<div ng-if="dateGroup.TextDirection == 0" class="entryLabel" ng-style="{'left': dateGroup.LabelOffSet + 'px', 'top' : dateGroup.LabelTop + 'px', 'width' : '450px !important'}">
<div ng-repeat="entry in dateGroup.Entries" style="position:relative;">
{{entry.EventDate | date:'MMM d'}} : {{entry.EventName}}
</div>
</div>
<div ng-if="dateGroup.TextDirection == 1" class="entryLabel" ng-style="{'text-align':'right', 'left': dateGroup.LabelOffSet + 'px', 'top': dateGroup.LabelTop + 'px', 'width':'450px !important'}">
<div ng-repeat="entry in dateGroup.Entries" style="position:relative;">
{{entry.EventDate | date:'MMM d'}} : {{entry.EventName}} <br />
</div>
</div>
</div>
<div ng-repeat="monthlabel in timeLine.TimeLineMonthLabels">
<div ng-if="monthlabel.MonthId == 12" class="monthLabel" ng-style="{'border':'none', 'left' : monthlabel.Offset + 'px' ,'top' : timeLine.MonthLabelTop + 'px' , 'width' : timeLine.MonthSectionWidth + 'px'}">{{monthlabel.MonthLabel}}</div>
<div ng-if="monthlabel.MonthId != 12" class="monthLabel" ng-style="{'left' : monthlabel.Offset + 'px' ,'top' : timeLine.MonthLabelTop + 'px' , 'width' : timeLine.MonthSectionWidth + 'px'}">{{monthlabel.MonthLabel}}</div>
</div>
<div ng-if="timeLine.TodayLineOffset > 0" class="todayLine" ng-style="{'height': timeLine.TodayLineHeight + 'px', 'top': timeLine.TodayLineTop + 'px', 'left': timeLine.TodayLineOffset + 'px'}"></div>
<div ng-if="timeLine.TodayLineOffset > 0" class="todayLabel" ng-style="{'width': timeLine.TodayLabelWidth + 'px', 'top': timeLine.TodayLabelTop + 'px', 'left': timeLine.TodayLabelOffset + 'px'}">Today</div>
The issue that I'm having is that there are HTML and css properties that aren't supported by Outlook 365, making re-rendering this div a bit difficult on outlook. Website to image is something I'm also considering, but I haven't found an efficient way to do it yet. Your insight as to how I might be able to render this on outlook is appreciated.

The email templates should be created using table tag. Many times we will face situation where div's are not aligned properly, we can solve this by showing data in table tag.

Related

With Vue.Js How can I call data from Backend into Modal in FrontEnd

In the image below, I call the current version with the Component from the Result field, but I cannot print the cloned project to the modal on the right. If anyone has an idea on how to fix this I would be very happy.
// COMPARE ACTION
GetCompareListByProject() {
// var _projectNo = this.$route.params.name;
var _this = this;
axios
.post(
GetURL() +
"Electric/GetVersionListByProject/" +
"-" +
"/" +
this.CloneSourceProjectNo
)
.then((resp) => {
if (resp.data.Response == true) {
var revisionList = [];
var data = resp.data.Data;
for (var i = 0; i < data.length; i++) {
if (revisionList.indexOf(data[i].RevisionNo) < 0)
revisionList.push(data[i].RevisionNo);
}
_this.CloneModalList = {
Revisions: revisionList,
Data: data,
};
_this.CloneNewNumber = {
Revision: resp.data.Revision,
Version: resp.data.Version,
};
}
});
},
CompareVersion() {
axios
.post(
GetURL() +
"Electric/OpenElectricProjectById/" +
this.OpenModalSelected.Id
)
.then((resp) => {
console.log(resp.data);
this.$store.state.project.ProjectTab.filter(
(p) => p.title == "Electric"
)[0].form = resp.data.Data.InputMain[0];
this.$store.state.project.Models.Project.Transformer.Electric =
resp.data.Data.Electric;
this.$store.state.general.ProjectMessage =
"Opened Version R" +
resp.data.Data.InputMain[0].RevisionNo +
"V" +
resp.data.Data.InputMain[0].VersionNo;
this.$swal({
position: "top-end",
icon: "success",
title: "Project Opened",
showConfirmButton: false,
timer: 1500,
});
this.$store.state.general.isLoading = false;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<b-modal
size="xl modal-full"
id="modal-compare"
title="Compare Project"
ok-only
ok-variant="secondary"
ok-title="Cancel"
>
<b-card class="w-50 h-10" style="float: left">
<b-tabs class="tabList" v-model="tabIndex">
<b-tab
#click="SetTabType('Result')"
v-for="(elec, index) in $store.state.project.Models.Project
.Transformer.Electric"
:key="index"
:active="index == 0"
>
<!-- <template #title>
<span class="line-tab">|</span>
{{ GetResultPageTitle(elec, index) }}
</template> -->
<ResultParameters
:Electric="elec"
:InputMain="
$store.state.project.Models.Project.Transformer.InputMain[0]
"
style="overflow-x: auto"
>
</ResultParameters>
</b-tab>
</b-tabs>
</b-card>
<b-card class="w-50 h-10" style="float: right">
<b-form-group
class="mb-0"
label-cols-sm="12"
label-cols-xl="4"
label="Clone Project"
label-class="text-left"
>
<b-input-group>
<b-input v-model="CloneSourceProjectNo"></b-input>
<b-input-group-append>
<b-input-group-text
style="cursor: pointer"
#click="GetCompareListByProject"
><i class="fa fa-sync-alt"></i
></b-input-group-text>
</b-input-group-append>
<b-button
class="w-100 waterGreen"
style="margin-top: 5px"
#ok="CompareVersion"
:ok-disabled="CompareModalSelected == null"
>
<i class="fa fa-bars"></i> Compare
</b-button>
</b-input-group>
</b-form-group>
<div class="mt-2"></div>
<div
v-for="rev in CloneModalList.Revisions"
:key="rev"
class="tree-view"
>
<h5>R{{ rev }}</h5>
<div
class="tree-item"
v-for="vers in CloneModalList.Data.filter(
(x) => x.RevisionNo == rev
)"
:key="vers.Id"
>
<span :class="GetInput().Id == vers.Id ? 'font-weight-bold' : ''">
<i
class="fas fa-check-circle releasedVersIcon"
v-if="vers.ActiveVersion"
></i>
V{{ vers.VersionNo }} : {{ vers.Description }}
<b-radio
:value="vers"
v-model="CompareModalSelected"
style="width: 16px; float: right; margin-top: -1px"
></b-radio>
</span>
</div>
</div>
</b-card>
</b-modal>

How to chain selectors in order to get element inside with webdriverio

I have a page with list of products on it.
This is how HTML DOM looks like for one product item:
<div class="module card listing-search-card js-product-card " id="product-entry-123" data-product-id="123" data-toggle-status="open" data-out-of-stock="" data-toggle-isbundle="false" data-load-prices-async="false">
<div class="product-entry__wrapper">
<div class="card__header">
<div class="promotion">
<div class="product-entry__right promotion-card__body on-promotion--banner-offer">
</div>
<a href="/Products/p/123" tabindex="-1">
<picture>
<img class="card__image mobile-img lazyload" src="/medias/image-mobile">
<img class="card__image desktop-img lazyloaded" src="/medias/image-desktop">
</picture>
</a>
</div>
</div>
<div class="product-entry__body-actions-wrapper">
<div class="product-entry__body card__body">
<h3 class="card__title">
Schweppes
</h3>
<div class="product-entry__summary card__description-wrapper">
<div class="product-entry__summary__list">
<div class="card__detail-wrapper">
<div class="product-entry__summary__item card__description-product-detail">
33 x 24</div>
<div class="product-entry__summary__item card__description-product-code">
<span class="product-entry__code">
123</span>
</div>
</div>
<div class="container-type">
box</div>
</div>
</div>
</div>
<div class="cta-container">
<div class="card__amount-wrapper ">
<div class="card__amount">
61,83 € <span class="base-unit">HT/CHACUN</span>
<p class="sales-unit-price is-price">
<span>soit</span> 10,00 €
</span></span></p>
</div>
</div>
<div class="add-to-cart__footer add-to-cart__action">
<div class="success-overlay">Add to cart</div>
<div class="add-to-cart__action--active">
<div class="form-quantity__wrapper quantity-action quantity-action__wrapper"
data-form-quantity-id="123">
<div class="form-quantity ">
<button class="form-quantity__decrease quantity-action__decr icon-Minus disabled" type="button"
tabindex="-1" aria-label="decrement" data-form-quantity-decrement="">
</button>
<input id="product-123" class="form-quantity__input form-control quantity-action__value js-
quantity-input-typing" name="product-123" type="text" value="1" maxlength="4" data-price-
single="10.00" data-price-currency="€" data-parsley-range="[1,9999]" data-form-quantity-times="1"
data-parsley-multiplerange="1" data-parsley-type="integer" data-parsley-validation-threshold="1"
required="">
<button class="form-quantity__increase quantity-action__incr icon-Add-to-list" type="button"
tabindex="-1" aria-label="increment" data-form-quantity-increment="">
</button>
</div>
<span class="form-quantity__update" data-form-quantity-success=""></span>
</div>
<div class="add-to-cart__total">
<button class="button button--primary js-addToCart" role="button" title="Add
to cart" data-product-id-ref="123" data-modal-trigger="" data-modal-target="#add-to-cart-modal" data-
modal-before-trigger="addToCart" data-component-id="product list" tabindex="-1">
<div class="button__text">
<span class="button__text-add js-added-price">Add</span>
<span class="button__text-to-cart js-added-price">to cart</span>
</div>
<span class="button__text js-added-price mobile-only">Add</span>
</button>
</div>
</div>
</div>
<div class="add-to-template">
<button class="add-to-template--button button js-addToNewTemplate" type="button" data-modal-
trigger="" data-modal-target="#add-to-template-modal" data-modal-before-
trigger="openAddToTemplateModal" data-product-code="123">
<span>Add to list</span>
</button>
</div>
</div>
</div>
</div>
I am calling this function:
isSortedAlphabeticallyAscending($$('div.js-product-card'));
And the function implementation is:
isSortedAlphabeticallyAscending(list) {
for (let i = 0; i < (list.length - 1); i++) {
let outOfStockCurrent = list[i].getAttribute('data-out-of-stock');
let outOfStockNext = list[i + 1].getAttribute('data-out-of-stock');
let idCurrent = list[i].getAttribute('id');
let idNext = list[i + 1].getAttribute('id');
console.log("outOfStockCurrent " + outOfStockCurrent + " " + idCurrent);
console.log("outOfStockNext " + outOfStockNext + " " + idNext);
let productIdCurrent = idCurrent.split('-').pop();
let productIdNext = idNext.split('-').pop();
let currentText = list[i].$('a[href*="' + productIdCurrent + '"]').getText();
let nextText = list[i+1].$('a[href*="'+ productIdNext + '"]').getText();
console.log("currentText " + currentText);
console.log("nextText " + nextText);
if(outOfStockCurrent === "true" || outOfStockNext === "true") continue;
if (currentText > nextText) return false;
}
return true;
}
I ignore out of stock products since they are always at the bottom of the page.
But the list[i].$('a[href*="' + productIdCurrent + '"]').getText() is always returning empty text.
I would like it to get "Schweppes" text, i.e. product name.
Is there a way to chain somehow differently part with .$a[href ...] to get the text from the <a> tag inside the <div> element of the list of products using webdriverio 5?
Thanks!
The above selector list[i].$('a[href*="' + productIdCurrent + '"]').getText() targeted 2 elements.
What I needed to go one div further and find it there:
list[i].$('div.product-entry__body-actions-wrapper').$('a[href*="' + productIdCurrent + '"]').getText()
And voila, text appeared :)
Hope it will help someone with the similar issue :D

Vue.js: how to have routing across 3 columns

I am trying to set up an page resembling:
========================================================================
+ Nav + Items + Individual Item +
+---------------+---------------+--------------------------------------+
+ * Cats + List + Individual Selected +
+ * Dogs + Of + Cat +
+ + Cats + OR +
+ + OR + Dog +
+ + Dogs + +
+ + + +
+ + + +
========================================================================
Usage example: Select 'Cats' in the 'Nav' column => retrieve a list of Cats (via REST/JSON) into the 'Items' column; Select an individual Cat from the list => retrieve an individual Cat (via REST/JSON) into the "Individual Item" column.
This looks like an application of Nested Routes (https://router.vuejs.org/guide/essentials/nested-routes.html) but my google-fu must be weak and I can't find a 3-level example like this anywhere.
It is easy to arrange an either/or approach where a single right-hand column renders either "List of Items" or 'Item.'
I have tried to use named views but I get to a point where I have 3 columns but when I render an 'Item' component, then the "List of Items" column is emptied.
It may be that I need to arrange to render both "List of Items" and 'Items' column at the same time (via 'components' in my router config) BUT these are remote REST calls so this is too heavyweight to be practical. Maybe 'computed' or 'watched' properties will assist in this case?
Is there an example of this three-level navigation somewhere?
Any help appreciated.
Edit:
this is the sort of thing I thought would be needed:
<div class="row">
<div class="col-2 bg-light sidebar">
<div class="sidebar-sticky">
<h3 class="h3 pl-3">Actions</h3>
<navigation />
</div>
</div>
<div class="col-3 ml-auto bg-info px-3">
<router-view />
</div>
<div class="col-7 bg-warning px-3">
<router-view name="entity" />
</div>
</div>
...
{
path: 'persons',
component: httpVueLoader('persons.vue'),
children: [
{
path: 'person/:id',
components: {
default: httpVueLoader('persons.vue'),
entity: httpVueLoader('person.vue')
}
}
]
},

How can I bind multiple values from array in v-model for form-input on vue.js?

I need to show full address in one form-input with buttons 'Edit' and 'Delete', so it's working, but in browser console I have error for all addresses like this
'[Vue warn]: Error in event handler for "input": "TypeError: Cannot use 'in' operator to search for 'zip' in 'Country Name', 'City', 'Street Address', [object Object]"'
My vue code:
<template>
<div>
....
</div>
...
<form class="form-inline" >
<div class="form-row col-md-6" v-for="address in addressList">
<b-form-group>
<b-form-input class="form-control mb-2 mr-sm-2" id="address.id" v-model="address.countryName + ', ' + address.city + ', ' + address.streetAddress + ', ' + address.zip" />
</b-form-group>
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-secondary mb-2">Edit</button>
<button type="button" class="btn btn-secondary mb-2">Delete</button>
</div>
</div>
</form>
</b-form>
</div>
</template>
<script>
...
data() {
return {
addressList: [],
}
},
async beforeRouteEnter(to, from, next) {
next(async (c) => await c.initData());
},
methods: {
async initData() {
await this.loadAddressList();
},
async loadAddressList() {
this.addressList = await accountService.getAddressList();
},
}
}
</script>
I don't understand why I am getting this error but it's working. Is there another better solution for this? And without error?
v-model="address.countryName + ', ' + address.city + ', ' + address.streetAddress + ', ' + address.zip"
I think your problem lays with binding the v-model. How you have it, it binds/concats multiple variables which isn't the intended use for v-modal.
If you only want to display the value, you could try changing:
v-model="address.countryName + ', ' + address.city + ', ' + address.streetAddress + ', ' + address.zip"
to
:value="address.countryName + ', ' + address.city + ', ' + address.streetAddress + ', ' + address.zip"

PUG playing with index

After using SO and found a lot of answers to feed my learning process, it's time for me (and because I haven't found any answer to my problem yet) to ask for your help.
I'm learning PUG since some days, and I'm trying to use "each" iteration to create a html/css slideshow (following the project of (shit, can't find the git anymore, too much projects based on this)).
Sorry.
Here's the pug code I made:
.slideshow
each val, index in ['img-1.jpg', 'img-2.jpg', 'img-3.jpg']
input(type="radio" name="ss" id='ss-img-' + index).ss-bullet
.ss-img
img(src=val)
label(for='ss-img-' + *index*).ss-nav-prev Image précédente
label(for='ss-img-' + *index*).ss-nav-next Image suivante
(.classes are just for later styling of the buttons/bullets)
And this is what I'm trying to obtain, in html:
<div class="slideshow">
<input class="ss-bullet" type="radio" name="ss" id="ss-img-0">
<div class="ss-img"><img src="img/img-1.jpg">
<label class="ss-nav-prev" for="ss-img-2">Image précédente</label>
<label class="ss-nav-next" for="ss-img-1">Image suivante</label>
</div>
<input class="ss-bullet" type="radio" name="ss" id="ss-img-1">
<div class="ss-img"><img src="img/img-2.jpg">
<label class="ss-nav-prev" for="ss-img-0">Image précédente</label>
<label class="ss-nav-next" for="ss-img-2">Image suivante</label>
</div>
<input class="ss-bullet" type="radio" name="ss" id="ss-img-2">
<div class="ss-img"><img src="img/img-3.jpg">
<label class="ss-nav-prev" for="ss-img-1">Image précédente</label>
<label class="ss-nav-next" for="ss-img-0">Image suivante</label>
</div>
</div>
Of course as you all noticed, the missing part is in the index:
label(for='ss-img-' + *index*)
part.
Can someone please teach me how to iterate the index to complete this?
(another thing you probably noticed is that i'm still new to javascript, and french)
Thanks!
So, what you need is a simple bit of circular (wrap-around) arithmetic (see also answers to this SO question):
- var arrayLength = 3;
label(for='ss-img-' + ((index + arrayLength - 1) % arrayLength)).ss-nav-prev Image précédente
label(for='ss-img-' + ((index + 1) % arrayLength)).ss-nav-next Image suivante
So with your code added:
.slideshow
each val, index in ['img-1.jpg', 'img-2.jpg', 'img-3.jpg']
input(type="radio" name="ss" id='ss-img-' + index)
.ss-img
img(src=val)
label(for='ss-img-' + ((index + val.length - 1) % val.length)) Image précédente
label(for='ss-img-' + ((index + 1) % val.length)) Image suivante
I'm getting this:
<div class="slideshow">
<input type="radio" name="ss" id="ss-img-0">
<div class="ss-img"><img src="img-1.jpg">
<label for="ss-img-8">Image précédente</label>
<label for="ss-img-1">Image suivante</label>
</div>
<input type="radio" name="ss" id="ss-img-1">
<div class="ss-img"><img src="img-2.jpg">
<label for="ss-img-0">Image précédente</label>
<label for="ss-img-2">Image suivante</label>
</div>
<input type="radio" name="ss" id="ss-img-2">
<div class="ss-img"><img src="img-3.jpg">
<label for="ss-img-1">Image précédente</label>
<label for="ss-img-3">Image suivante</label>
</div>
</div>
(removed the classes to make it more clear)
As you can see, the first and last items are not yet looping as expected. Only the middle one is right.
(And sorry to use 'answer' instead of 'comment', I haven't found a way to write multiples lines code...)
Thanks again for helping!
Here's the final pug code for the one who wants to use it:
.slideshow
- var imgs = ['img/img-1.jpg', 'img/img-2.jpg', 'img/img-3.jpg', 'img/img-4.jpg', 'img/img-5.jpg', 'img/img-6.jpg']
each img, index in imgs
input(type="radio" name="ss" id=('ss-img-' + index) checked=(index === 0)).ss-bullet
.ss-img
img(src=img)
label(for='ss-img-' + ((index + imgs.length - 1) % imgs.length)).ss-nav-prev Image précédente
label(for='ss-img-' + ((index + 1) % imgs.length)).ss-nav-next Image suivante