Tuesday, February 7, 2017

Add Custom Element, Extend Existing Element With Custom Attributes in EPiServer TinyMCE

In one of our project we had to add custom element and custom attributes in TinyMCE for angular directive. However, TinyMCE was stripping off the non-registered element and attributes during the validation

Fortunately, EPiServer provides easy way to Add and Extend TinyMCE element and attributes.

First of all we need to define below class


namespace EPiServer7App.EPiServerCore.Core.TinyMce
{
    [TinyMCEPluginNonVisual(PlugInName = "TinyMceExtendedValidElements", AlwaysEnabled = true, EditorInitConfigurationOptions = "{ custom_elements : 'uib-accordion,uib-accordion-group', extended_valid_elements: 'uib-accordion[close-others],uib-accordion-group[heading]' }")]
    public class TinyMceExtendedValidElements
    {
    }
}



Then, we need to define this EmptyHandler other wise js will throw error


using System.Web;

namespace EPiServer7App.EPiServerCore.Core.TinyMce
{
    public class EmptyFileHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
        }
    }
}


Then, we need to update the web.config location settings

 <location path="util/editor/tinymce/plugins">
    <system.webServer>
      <handlers>
        <add name="TinyMceExtendedValidElements" path="/util/editor/tinymce/plugins/TinyMceExtendedValidElements/editor_plugin.js" verb="GET" type="EPiServer7App.EPiServerCore.Core.TinyMce.EmptyFileHandler, EPiServer7App.EPiServerCore, Version=1.0.0.0, Culture=neutral" />
      </handlers>
    </system.webServer>
  </location>

Then, we will update the episerver.config file to allow TinyMCE merge of custom element.

<episerver xmlns="http://EPiServer.Configuration.EPiServerSection">
  <applicationSettings globalErrorHandling="Off" disableVersionDeletion="false" httpCacheVaryByCustom="path" httpCacheVaryByParams="id,epslanguage" httpCacheability="Public" uiEditorCssPaths="~/Static/css/editor.css" urlRebaseKind="ToRootRelative" pageUseBrowserLanguagePreferences="false" uiShowGlobalizationUserInterface="true" subscriptionHandler="EPiServer.Personalization.SubscriptionMail,EPiServer" uiMaxVersions="20" pageValidateTemplate="false" uiUrl="~/manage/CMS/" utilUrl="~/util/" pageFolderVirtualPathProvider="SitePageFiles" />
  <workflowSettings>
    <workflowHost type="EPiServer.WorkflowFoundation.AspNetWorkflowManager,EPiServer.WorkflowFoundation" />
    <externalServices>
      <externalService type="EPiServer.WorkflowFoundation.Workflows.ApprovalService,EPiServer.WorkflowFoundation" />
      <externalService type="EPiServer.WorkflowFoundation.Workflows.ReadyForTranslationService,EPiServer.WorkflowFoundation" />
      <externalService type="EPiServer.WorkflowFoundation.Workflows.RequestForFeedbackService,EPiServer.WorkflowFoundation" />
    </externalServices>
  </workflowSettings>
  <tinyMCE mergedConfigurationProperties="valid_elements, extended_valid_elements, invalid_elements, valid_child_elements" />
</episerver>


After all of the above steps TinyMCE will not strip off the custom elements and attibutes.

Friday, February 3, 2017

Creating Split Shipment, Address For Line Item in EPiServer

In one of our project I had to create multiple shipment and addresses depending on the line item type.

The story is, If user includes gift card in the cart then gift card code needs to be sent on email to differnt user. Therefore, i had to add different address to store First Name and Email and add seperate shipment for each gift voucher card.

In order to do that i had to add as many order addresses in cart and for each addresses i had to add shipment and then assign line item to shipment. I also had to add those multiple addresses to order form as well.

Adding Order Address For Each Line Item

 
 foreach (var gift in giftsLineItems)
            {
                var addressId = $"{OrderConstants.GIFT_PREFIX}{gift.LineItem.LineItemId}";
                var giftAddress = giftVoucherOrderAddresses.FirstOrDefault(o => o.Name.Equals(addressId, StringComparison.InvariantCultureIgnoreCase)) ?? _checkoutService.AddNewOrderAddress();
                giftAddress.Name = addressId;
                giftAddress.Email = giftCodeAndEmail[gift.LineItem.LineItemId].Email;
                giftAddress.FirstName = giftCodeAndEmail[gift.LineItem.LineItemId].FirstName;
                giftAddress.CountryCode = _currentMarket.GetCurrentMarket().Countries.First();
                giftAddress.CountryName = _countryManager.GetCountryByCountryCode(giftAddress.CountryCode).Name;
                giftAddress.AcceptChanges();

                /* The shipment code will be described below */
            }


Adding Shipment and Assigning Shipment to Line Item

 
/* Add/Update Shipment based on shipping address id 
 * shipping address is will be unique for each line item as it is based on line item id
 * AddShipmentLineItemShipment functions adds shipment and binds it to line item
 * giftsLineItems is just wrapper for line item giftLineItem object contains Commerce Line Item 
 */
 var shipment = orderForm.Shipments.FirstOrDefault(s => addressId.Equals(s.ShippingAddressId)) ?? orderForm.Shipments.AddNew();
 AddShipmentLineItemShipment(gift.LineItem, shipment, freeShippingEmailDefault, addressId);
 shipment.AcceptChanges();
 gift.LineItem.AcceptChanges();


Adding Shipping Method, Shipping Rate and Assigning it to Line Item

 
 private void AddShipmentLineItemShipment(LineItem lineItem, Shipment shipment, ShippingMethodDto.ShippingMethodRow shippingMethod, string addressId)
        {
            var orderForm = _cartService.GetOrderForms().First();
            var shippingRate = _checkoutService.GetShippingRate(shipment, shippingMethod.ShippingMethodId);

            shipment.ShippingMethodId = shippingMethod.ShippingMethodId;
            shipment.ShippingMethodName = shippingMethod.Name;
            shipment.ShippingAddressId = addressId;
            shipment.SubTotal = shippingRate.Money.Amount;
            shipment.ShippingSubTotal = shippingRate.Money.Amount;

            int lineItemIndex = orderForm.LineItems.IndexOf(lineItem);
            lineItem.ShippingMethodId = shippingMethod.ShippingMethodId;
            lineItem.ShippingMethodName = shippingMethod.Name;
            lineItem.ShippingAddressId = addressId;
            shipment.AddLineItemIndex(lineItemIndex);
        }



GetShippingMethod 

The above method gets the rate for shipping method. This is the function available in QuickSilver template. I have included here as well

  
  public ShippingRate GetShippingRate(Shipment shipment, Guid shippingMethodId)
        {
            var method = ShippingManager.GetShippingMethod(shippingMethodId).ShippingMethod.Single();
            return GetRate(shipment, method);
        }

        private ShippingRate GetRate(Shipment shipment, ShippingMethodDto.ShippingMethodRow shippingMethodRow)
        {
            var type = Type.GetType(shippingMethodRow.ShippingOptionRow.ClassName);
            var shippingGateway = (IShippingGateway)Activator.CreateInstance(type, _currentMarket.GetCurrentMarket());
            string message = null;
            return shippingGateway.GetRate(shippingMethodRow.ShippingMethodId, shipment, ref message);
        }