Last active
May 19, 2017 18:28
-
-
Save 5up3rman/213b88cb9eb747f3ed0ca81416204395 to your computer and use it in GitHub Desktop.
Live Photo - Render the Element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collections.Specialized; | |
using System.IO; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Text; | |
using System.Web; | |
using System.Web.UI; | |
using Glass.Mapper; | |
using Glass.Mapper.Sc; | |
using Glass.Mapper.Sc.Configuration; | |
using Glass.Mapper.Sc.Web.Mvc; | |
using Paragon.Foundation.LivePhoto.Extensions; | |
using Paragon.Foundation.LivePhoto.GlassFieldObjects; | |
using Paragon.Foundation.LivePhoto.HtmlHelpers; | |
using Sitecore.Collections; | |
using Sitecore.Data; | |
using Sitecore.Data.Items; | |
using Sitecore.Pipelines; | |
using Sitecore.Pipelines.RenderField; | |
using Sitecore.Resources.Media; | |
using Sitecore.Text; | |
using Sitecore.Web; | |
using Utilities = Glass.Mapper.Utilities; | |
namespace Paragon.Foundation.LivePhoto.Mvc | |
{ | |
public class LivePhotoMvc<TK> : GlassHtmlMvc<TK> | |
{ | |
protected new IGlassHtml GlassHtml { get; private set; } | |
protected new TextWriter Output { get; private set; } | |
public LivePhotoMvc(IGlassHtml glassHtml, TextWriter output, TK model) : base(glassHtml, output, model) | |
{ | |
GlassHtml = glassHtml; | |
Output = output; | |
Model = model; | |
} | |
public HtmlString RenderLivePhoto<T>(T model, Expression<Func<T, object>> field, | |
bool isEditable = false, HtmlTextWriterTag tag = HtmlTextWriterTag.Span) | |
{ | |
var fld = field.Compile().Invoke(model) as LivePhotoGlassObject; | |
if (Glass.Mapper.Sc.GlassHtml.IsInEditingMode && isEditable) | |
{ | |
var attr = GetLivePhotoCommonAttributes(fld, tag); | |
var urlString = new UrlString(); | |
foreach (var keyValuePair in attr) | |
urlString.Parameters.Add(keyValuePair.Key, keyValuePair.Value); | |
return new HtmlString(MakeEditable(field, model, urlString.Parameters, LivePhotoAPIDataAttributes(fld), SitecoreContext.GlassContext)); | |
} | |
return RenderLivePhoto(fld, tag); | |
} | |
/// <summary> | |
/// Render out the complete Tag | |
/// </summary> | |
/// <param name="fld"></param> | |
/// <param name="tag"></param> | |
/// <returns></returns> | |
private HtmlString RenderLivePhoto(ILivePhotoGlassObject fld, HtmlTextWriterTag tag = HtmlTextWriterTag.Span) | |
{ | |
var firstPart = $"<{tag.ToString().ToLower()} {string.Join(" ", LivePhotoAPIDataAttributes(fld))} {PropertyExtensions.ConvertAttributes(GetLivePhotoCommonAttributes(fld, tag), "")} style={fld?.InlineStyle ?? $"\"\""}>"; | |
var lastPart = $"</{tag.ToString().ToLower()}>"; | |
return new HtmlString(firstPart + lastPart); | |
} | |
private string MakeEditable<T>(Expression<Func<T, object>> field, T target, object parameters, IEnumerable<string> attributes, Context context) | |
{ | |
var sb = new StringBuilder(); | |
var stringWriter = new StringWriter(sb); | |
MakeEditableLivePhoto(field, target, parameters, attributes, stringWriter, context).Dispose(); | |
stringWriter.Flush(); | |
stringWriter.Close(); | |
return sb.ToString(); | |
} | |
/// <summary> | |
/// Helps perform the Glass Editing Magic | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="field"></param> | |
/// <param name="model"></param> | |
/// <param name="parameters"></param> | |
/// <param name="dataAttributes"></param> | |
/// <param name="writer"></param> | |
/// <param name="context"></param> | |
/// <returns></returns> | |
private RenderElement MakeEditableLivePhoto<T>(Expression<Func<T, object>> field, T model, object parameters, | |
IEnumerable<string> dataAttributes, TextWriter writer, Context context) | |
{ | |
var firstPart = string.Empty; | |
var lastPart = string.Empty; | |
var attributes = new SafeDictionary<string>(); | |
try | |
{ | |
if (model == null) | |
throw new NullReferenceException("No model set"); | |
if (field == null) | |
throw new NullReferenceException("No field set"); | |
if (parameters is string) | |
attributes = WebUtil.ParseQueryString(parameters as string); | |
else if (parameters is NameValueCollection) | |
{ | |
var nameValueCollection = (NameValueCollection)parameters; | |
foreach (var key in nameValueCollection.AllKeys) | |
attributes.Add(key, nameValueCollection[key]); | |
} | |
else | |
{ | |
var propertiesCollection = PropertyExtensions.GetPropertiesCollection(parameters, true); | |
foreach (var key in propertiesCollection.AllKeys) | |
attributes.Add(key, propertiesCollection[key]); | |
} | |
// The following Utilities are using Glass Mapper. I did not decompile and 'borrow' them this time :) | |
MemberExpression memberExpression; | |
var targetObjectOfLamba = Utilities.GetTargetObjectOfLamba<T>(field, model, out memberExpression); | |
var typeConfiguration = Utilities.GetTypeConfig<T, SitecoreTypeConfiguration>(field, context, model); | |
var glassProperty = Utilities.GetGlassProperty<T, SitecoreTypeConfiguration>(field, context, model); | |
var item = typeConfiguration.ResolveItem(targetObjectOfLamba, SitecoreContext.Database); | |
using (new ContextItemSwitcher(item)) | |
{ | |
var fieldConfiguration = (SitecoreFieldConfiguration) glassProperty; | |
var renderFieldArgs = new RenderFieldArgs | |
{ | |
Item = item, | |
FieldName = fieldConfiguration.FieldId == (ID) null || fieldConfiguration.FieldId == ID.Null | |
? fieldConfiguration.FieldName : fieldConfiguration.FieldId.ToString(), | |
Parameters = attributes, | |
Before = string.Join(" ", dataAttributes), | |
DisableWebEdit = false | |
}; | |
// Running this will run the GetLivePhotoValue pipeline. | |
CorePipeline.Run("renderField", renderFieldArgs); | |
firstPart = renderFieldArgs.Result.FirstPart; | |
lastPart = renderFieldArgs.Result.LastPart; | |
} | |
} | |
catch (Exception ex) | |
{ | |
firstPart = string.Format($"<p>{ex.Message}</p><pre>{ex.StackTrace}</pre>"); | |
Sitecore.Diagnostics.Log.Error("Failed to render field", ex, typeof (IGlassHtml)); | |
} | |
return new RenderElement(writer, firstPart, lastPart); | |
} | |
/// <summary> | |
/// Set all the common, necessary data attributes | |
/// </summary> | |
/// <param name="fld"></param> | |
/// <param name="tag"></param> | |
/// <returns></returns> | |
private SafeDictionary<string> GetLivePhotoCommonAttributes(ILivePhotoGlassObject fld, HtmlTextWriterTag tag = HtmlTextWriterTag.Span) | |
{ | |
var collection = new SafeDictionary<string>(); | |
if (fld == null) | |
return collection; | |
PropertyExtensions.AddAttribute(collection, "data-photo-src", HttpUtility.HtmlEncode(GetProtectedPhotoSource(fld))); | |
PropertyExtensions.AddAttribute(collection, "data-video-src", fld.DataVideoSrc); | |
PropertyExtensions.AddAttribute(collection, "height", fld.Height.ToString()); | |
PropertyExtensions.AddAttribute(collection, "width", fld.Width.ToString()); | |
PropertyExtensions.AddAttribute(collection, "inlineStyle", fld.InlineStyle); | |
PropertyExtensions.AddAttribute(collection, "tag", tag.ToString().ToLower()); | |
return collection; | |
} | |
private IEnumerable<string> LivePhotoAPIDataAttributes(ILivePhotoGlassObject fld) | |
{ | |
if (fld == null) | |
return Enumerable.Empty<string>(); | |
// Add the API Options. They need to added to the tag without a following ="", the API takes care of that. | |
var dataAttrList = new List<string> { "data-live-photo" }; | |
if (!string.IsNullOrEmpty(fld.DataPhotoTime)) | |
dataAttrList.Add("data-photo-time"); | |
if (!string.IsNullOrEmpty(fld.DataProactivelyLoadsVideo)) | |
dataAttrList.Add("data-proactively-loads-video"); | |
if (!string.IsNullOrEmpty(fld.DataShowsNativeControls)) | |
dataAttrList.Add("data-show-native-controls"); | |
return dataAttrList; | |
} | |
/// <summary> | |
/// Sets the Dimensions and Media Protection Hash to the Image Url... or it's supposed to add the Hash | |
/// </summary> | |
/// <param name="fld"></param> | |
/// <returns></returns> | |
private string GetProtectedPhotoSource(ILivePhotoGlassObject fld) | |
{ | |
var collection = new SafeDictionary<string>(); | |
if (!collection.ContainsKey("h") && fld.Height != 0) | |
collection.Add("h", fld.Height.ToString()); | |
if (!collection.ContainsKey("w") && fld.Width != 0) | |
collection.Add("w", fld.Width.ToString()); | |
var urlBuilder = new Glass.Mapper.UrlBuilder(fld.DataPhotoSrc); | |
// Add the height and width | |
foreach (var key in collection.Keys) | |
urlBuilder.AddToQueryString(key, collection[key]); | |
return HttpUtility.HtmlEncode(ProtectMediaUrl(urlBuilder.ToString())); | |
} | |
private string ProtectMediaUrl(string url) | |
{ | |
return HashingUtils.ProtectAssetUrl(url); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment