2014-10-14 16:07:00 -07:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using Orchard.DisplayManagement ;
using Orchard.DisplayManagement.Descriptors ;
using Orchard.Environment ;
using Orchard.Environment.Extensions ;
using Orchard.Layouts.Elements ;
using Orchard.Layouts.Framework.Display ;
2015-11-19 17:39:52 +01:00
using Orchard.Layouts.Framework.Drivers ;
2014-10-14 16:07:00 -07:00
using Orchard.Layouts.Framework.Elements ;
using Orchard.Layouts.Framework.Harvesters ;
2015-11-19 17:39:52 +01:00
using Orchard.Layouts.Helpers ;
using Orchard.Layouts.Models ;
2014-10-14 16:07:00 -07:00
using Orchard.Layouts.Services ;
2015-11-19 17:39:52 +01:00
using Orchard.Layouts.Shapes ;
using Orchard.Layouts.ViewModels ;
using Orchard.Localization ;
2014-10-14 16:07:00 -07:00
using Orchard.Themes.Services ;
2015-11-19 17:39:52 +01:00
using Orchard.Tokens ;
2014-10-14 16:07:00 -07:00
using Orchard.Utility.Extensions ;
namespace Orchard.Layouts.Providers {
[OrchardFeature("Orchard.Layouts.Snippets")]
2015-08-21 23:14:37 +01:00
public class SnippetElementHarvester : Component , IElementHarvester {
2014-10-14 16:07:00 -07:00
private const string SnippetShapeSuffix = "Snippet" ;
private readonly Work < IShapeFactory > _shapeFactory ;
private readonly Work < ISiteThemeService > _siteThemeService ;
private readonly Work < IShapeTableLocator > _shapeTableLocator ;
private readonly Work < IElementFactory > _elementFactory ;
2015-11-19 17:39:52 +01:00
private readonly Work < IShapeDisplay > _shapeDisplay ;
private readonly Work < ICurrentThemeShapeBindingResolver > _currentThemeShapeBindingResolver ;
private readonly Work < ITokenizer > _tokenizer ;
2016-02-20 17:44:31 +01:00
private readonly IWorkContextAccessor _wca ;
2014-10-14 16:07:00 -07:00
public SnippetElementHarvester (
IWorkContextAccessor workContextAccessor ,
Work < IShapeFactory > shapeFactory ,
Work < ISiteThemeService > siteThemeService ,
2016-02-20 17:44:31 +01:00
Work < IShapeTableLocator > shapeTableLocator ,
2015-11-19 17:39:52 +01:00
Work < IElementFactory > elementFactory ,
Work < IShapeDisplay > shapeDisplay ,
Work < ITokenizer > tokenizer ,
Work < ICurrentThemeShapeBindingResolver > currentThemeShapeBindingResolver ) {
2014-10-14 16:07:00 -07:00
_shapeFactory = shapeFactory ;
_siteThemeService = siteThemeService ;
_shapeTableLocator = shapeTableLocator ;
_elementFactory = elementFactory ;
2015-11-19 17:39:52 +01:00
_shapeDisplay = shapeDisplay ;
_tokenizer = tokenizer ;
_currentThemeShapeBindingResolver = currentThemeShapeBindingResolver ;
2016-02-20 17:44:31 +01:00
_wca = workContextAccessor ;
2014-10-14 16:07:00 -07:00
}
public IEnumerable < ElementDescriptor > HarvestElements ( HarvestElementsContext context ) {
var currentThemeName = _siteThemeService . Value . GetCurrentThemeName ( ) ;
var shapeTable = _shapeTableLocator . Value . Lookup ( currentThemeName ) ;
2015-03-12 17:27:00 +01:00
var shapeDescriptors = shapeTable . Bindings . Where ( x = > ! String . Equals ( x . Key , "Elements_Snippet" , StringComparison . OrdinalIgnoreCase ) & & x . Key . EndsWith ( SnippetShapeSuffix , StringComparison . OrdinalIgnoreCase ) ) . ToDictionary ( x = > x . Key , x = > x . Value . ShapeDescriptor ) ;
2016-02-20 17:44:31 +01:00
var elementType = typeof ( Snippet ) ;
2015-11-19 17:39:52 +01:00
var snippetElement = ( Snippet ) _elementFactory . Value . Activate ( elementType ) ;
2014-10-14 16:07:00 -07:00
foreach ( var shapeDescriptor in shapeDescriptors ) {
var shapeType = shapeDescriptor . Value . ShapeType ;
var elementName = GetDisplayName ( shapeDescriptor . Value . BindingSource ) ;
var closureDescriptor = shapeDescriptor ;
2015-02-19 22:14:55 +01:00
yield return new ElementDescriptor ( elementType , shapeType , T ( elementName ) , T ( "An element that renders the {0} shape." , shapeType ) , snippetElement . Category ) {
2016-02-20 17:44:31 +01:00
Displaying = displayContext = > Displaying ( displayContext , closureDescriptor . Value ) ,
2015-11-19 17:39:52 +01:00
ToolboxIcon = "\uf10c" ,
2016-02-20 17:44:31 +01:00
EnableEditorDialog = HasSnippetFields ( shapeDescriptor . Value ) ,
Editor = ctx = > Editor ( DescribeSnippet ( shapeType , snippetElement ) , ctx ) ,
UpdateEditor = ctx = > UpdateEditor ( DescribeSnippet ( shapeType , snippetElement ) , ctx )
2014-10-14 16:07:00 -07:00
} ;
}
}
2015-11-19 17:39:52 +01:00
private void Editor ( SnippetDescriptor descriptor , ElementEditorContext context ) {
UpdateEditor ( descriptor , context ) ;
}
private void UpdateEditor ( SnippetDescriptor descriptor , ElementEditorContext context ) {
var viewModel = new SnippetViewModel {
Descriptor = descriptor
} ;
2016-02-20 17:44:31 +01:00
2015-11-19 17:39:52 +01:00
if ( context . Updater ! = null ) {
foreach ( var fieldDescriptor in descriptor . Fields ) {
var name = fieldDescriptor . Name ;
var result = context . ValueProvider . GetValue ( name ) ;
if ( result = = null )
continue ;
context . Element . Data [ name ] = result . AttemptedValue ;
}
}
viewModel . FieldEditors = descriptor . Fields . Select ( x = > {
var fieldEditorTemplateName = String . Format ( "Elements.Snippet.Field.{0}" , x . Type ? ? "Text" ) ;
var fieldDescriptorViewModel = new SnippetFieldViewModel {
Descriptor = x ,
Value = context . Element . Data . Get ( x . Name )
} ;
var fieldEditor = context . ShapeFactory . EditorTemplate ( TemplateName : fieldEditorTemplateName , Model : fieldDescriptorViewModel , Prefix : context . Prefix ) ;
return fieldEditor ;
} ) . ToList ( ) ;
var snippetEditorShape = context . ShapeFactory . EditorTemplate ( TemplateName : "Elements.Snippet" , Model : viewModel , Prefix : context . Prefix ) ;
snippetEditorShape . Metadata . Position = "Fields:0" ;
2016-02-20 17:44:31 +01:00
2015-11-19 17:39:52 +01:00
context . EditorResult . Add ( snippetEditorShape ) ;
}
2016-02-20 17:44:31 +01:00
private void Displaying ( ElementDisplayingContext context , ShapeDescriptor shapeDescriptor ) {
2014-10-14 16:07:00 -07:00
var shapeType = shapeDescriptor . ShapeType ;
2015-11-19 17:39:52 +01:00
var shape = ( dynamic ) _shapeFactory . Value . Create ( shapeType ) ;
shape . Element = context . Element ;
ElementShapes . AddTokenizers ( shape , _tokenizer . Value ) ;
2014-10-14 16:07:00 -07:00
context . ElementShape . Snippet = shape ;
}
private string GetDisplayName ( string bindingSource ) {
var fileName = Path . GetFileNameWithoutExtension ( bindingSource ) ;
var lastIndex = fileName . IndexOf ( SnippetShapeSuffix , StringComparison . OrdinalIgnoreCase ) ;
return fileName . Substring ( 0 , lastIndex ) . CamelFriendly ( ) ;
}
2015-11-19 17:39:52 +01:00
private SnippetDescriptor DescribeSnippet ( string shapeType , Snippet element ) {
var shape = ( dynamic ) _shapeFactory . Value . Create ( shapeType ) ;
shape . Element = element ;
return DescribeSnippet ( shape ) ;
}
private SnippetDescriptor DescribeSnippet ( dynamic shape ) {
// Execute the shape and intercept calls to the Html.SnippetField method.
var descriptor = new SnippetDescriptor ( ) ;
2016-02-20 17:44:31 +01:00
shape . DescriptorRegistrationCallback = ( Action < SnippetFieldDescriptor > ) ( fieldDescriptor = > {
2015-11-24 23:19:06 +01:00
var existingDescriptor = descriptor . Fields . SingleOrDefault ( x = > x . Name = = fieldDescriptor . Name ) ; // Not using Dictionary, as that will break rendering the view for some obscure reason.
2016-02-20 17:44:31 +01:00
2015-11-24 23:19:06 +01:00
if ( existingDescriptor = = null )
descriptor . Fields . Add ( fieldDescriptor ) ;
2015-11-19 17:39:52 +01:00
if ( fieldDescriptor . DisplayName = = null )
fieldDescriptor . DisplayName = new LocalizedString ( fieldDescriptor . Name ) ;
} ) ;
using ( _currentThemeShapeBindingResolver . Value . Enable ( ) ) {
_shapeDisplay . Value . Display ( shape ) ;
}
shape . SnippetDescriptor = descriptor ;
return descriptor ;
}
2016-02-20 17:44:31 +01:00
private bool HasSnippetFields ( ShapeDescriptor shapeDescriptor ) {
var bindingSource = shapeDescriptor . BindingSource ;
var localFileName = _wca . GetContext ( ) . HttpContext . Server . MapPath ( bindingSource ) ;
if ( ! File . Exists ( localFileName ) )
return false ;
var markup = File . ReadAllText ( localFileName ) ;
return markup . Contains ( "@Html.SnippetField" ) ;
}
2014-10-14 16:07:00 -07:00
}
}