diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs new file mode 100644 index 0000000000..334124a4e5 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -0,0 +1,16 @@ +using System.IO; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; + +namespace Umbraco.Core.Configuration.Grid +{ + class GridConfig : IGridConfig + { + public GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug) + { + EditorsConfig = new GridEditorsConfig(logger, runtimeCache, appPlugins, configFolder, isDebug); + } + + public IGridEditorsConfig EditorsConfig { get; private set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs new file mode 100644 index 0000000000..389c620637 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json.Linq; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Manifest; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Core.Configuration.Grid +{ + class GridEditorsConfig : IGridEditorsConfig + { + private readonly ILogger _logger; + private readonly IRuntimeCacheProvider _runtimeCache; + private readonly DirectoryInfo _appPlugins; + private readonly DirectoryInfo _configFolder; + private readonly bool _isDebug; + + public GridEditorsConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug) + { + _logger = logger; + _runtimeCache = runtimeCache; + _appPlugins = appPlugins; + _configFolder = configFolder; + _isDebug = isDebug; + } + + public IEnumerable Editors + { + get + { + Func> getResult = () => + { + var editors = new List(); + var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js"); + if (File.Exists(gridConfig)) + { + try + { + var arr = JArray.Parse(File.ReadAllText(gridConfig)); + //ensure the contents parse correctly to objects + var parsed = ManifestParser.GetGridEditors(arr); + editors.AddRange(parsed); + } + catch (Exception ex) + { + _logger.Error("Could not parse the contents of grid.editors.config.js into a JSON array", ex); + } + } + + var parser = new ManifestParser(_appPlugins, _runtimeCache); + var builder = new ManifestBuilder(_runtimeCache, parser); + foreach (var gridEditor in builder.GridEditors) + { + //no duplicates! (based on alias) + if (editors.Contains(gridEditor) == false) + { + editors.Add(gridEditor); + } + } + return editors; + }; + + //cache the result if debugging is disabled + var result = _isDebug + ? getResult() + : _runtimeCache.GetCacheItem>( + typeof(GridEditorsConfig) + "Editors", + () => getResult(), + TimeSpan.FromMinutes(10)); + + return result; + } + + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/IGridConfig.cs b/src/Umbraco.Core/Configuration/Grid/IGridConfig.cs new file mode 100644 index 0000000000..a1170c136e --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/IGridConfig.cs @@ -0,0 +1,14 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Umbraco.Core.Configuration.Grid +{ + public interface IGridConfig + { + + IGridEditorsConfig EditorsConfig { get; } + + } +} diff --git a/src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs b/src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs new file mode 100644 index 0000000000..0e64811068 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; + +namespace Umbraco.Core.Configuration.Grid +{ + public interface IGridEditorConfig + { + string Name { get; } + string Alias { get; } + string View { get; } + string Render { get; } + IDictionary Config { get; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs new file mode 100644 index 0000000000..64fb1a831f --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Configuration.Grid +{ + public interface IGridEditorsConfig + { + IEnumerable Editors { get; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoConfig.cs b/src/Umbraco.Core/Configuration/UmbracoConfig.cs index cb82582c7e..8881c5fb2e 100644 --- a/src/Umbraco.Core/Configuration/UmbracoConfig.cs +++ b/src/Umbraco.Core/Configuration/UmbracoConfig.cs @@ -2,10 +2,13 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Configuration; +using System.IO; using System.Linq; using System.Threading; +using Umbraco.Core.Cache; using Umbraco.Core.Configuration.BaseRest; using Umbraco.Core.Configuration.Dashboard; +using Umbraco.Core.Configuration.Grid; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; @@ -67,6 +70,7 @@ namespace Umbraco.Core.Configuration private IDashboardSection _dashboardSection; private IUmbracoSettingsSection _umbracoSettings; private IBaseRestSection _baseRestExtensions; + private IGridConfig _gridConfig; /// /// Gets the IDashboardSection @@ -140,6 +144,28 @@ namespace Umbraco.Core.Configuration return _baseRestExtensions; } + /// + /// Only for testing + /// + /// + public void SetGridConfig(IGridConfig value) + { + _gridConfig = value; + } + + /// + /// Gets the IGridConfig + /// + public IGridConfig GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug) + { + if (_gridConfig == null) + { + _gridConfig = new GridConfig(logger, runtimeCache, appPlugins, configFolder, isDebug); + } + + return _gridConfig; + } + //TODO: Add other configurations here ! } } \ No newline at end of file diff --git a/src/Umbraco.Core/PropertyEditors/GridEditor.cs b/src/Umbraco.Core/PropertyEditors/GridEditor.cs index 2fd24a2e99..61ea94e7dd 100644 --- a/src/Umbraco.Core/PropertyEditors/GridEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/GridEditor.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; using Newtonsoft.Json; +using Umbraco.Core.Configuration.Grid; namespace Umbraco.Core.PropertyEditors { - internal class GridEditor + internal class GridEditor : IGridEditorConfig { public GridEditor() { diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs new file mode 100644 index 0000000000..cfcf194246 --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs @@ -0,0 +1,112 @@ +using System; +using System.IO; +using System.Linq; +using System.Web; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Grid; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Core.PropertyEditors.ValueConverters +{ + [DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter + [PropertyValueType(typeof(JToken))] + [PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)] + public class GridValueConverter : JsonValueConverter + { + public override bool IsConverter(PublishedPropertyType propertyType) + { + return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.GridAlias); + } + + public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) + { + if (source == null) return null; + var sourceString = source.ToString(); + + if (sourceString.DetectIsJson()) + { + try + { + var obj = JsonConvert.DeserializeObject(sourceString); + + //so we have the grid json... we need to merge in the grid's configuration values with the values + // we've saved in the database so that when the front end gets this value, it is up-to-date. + + //TODO: Change all singleton access to use ctor injection in v8!!! + //TODO: That would mean that property value converters would need to be request lifespan, hrm.... + var gridConfig = UmbracoConfig.For.GridConfig( + ApplicationContext.Current.ProfilingLogger.Logger, + ApplicationContext.Current.ApplicationCache.RuntimeCache, + new DirectoryInfo(HttpContext.Current.Server.MapPath(SystemDirectories.AppPlugins)), + new DirectoryInfo(HttpContext.Current.Server.MapPath(SystemDirectories.Config)), + HttpContext.Current.IsDebuggingEnabled); + + var sections = GetArray(obj, "sections"); + foreach (var section in sections.Cast()) + { + var rows = GetArray(section, "rows"); + foreach (var row in rows.Cast()) + { + var areas = GetArray(row, "areas"); + foreach (var area in areas.Cast()) + { + var controls = GetArray(area, "controls"); + foreach (var control in controls.Cast()) + { + var editor = control.Value("editor"); + if (editor != null) + { + var alias = editor.Value("alias"); + if (alias.IsNullOrWhiteSpace() == false) + { + //find the alias in config + var found = gridConfig.EditorsConfig.Editors.FirstOrDefault(x => x.Alias == alias); + if (found != null) + { + //add/replace the editor value with the one from config + + var serialized = new JObject(); + serialized["name"] = found.Name; + serialized["alias"] = found.Alias; + serialized["view"] = found.View; + serialized["render"] = found.Render; + serialized["config"] = JObject.FromObject(found.Config); + + control["editor"] = serialized; + } + } + } + } + } + } + } + + return obj; + } + catch (Exception ex) + { + LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); + } + } + + //it's not json, just return the string + return sourceString; + } + + private JArray GetArray(JObject obj, string propertyName) + { + JToken token; + if (obj.TryGetValue(propertyName, out token)) + { + var asArray = token as JArray; + return asArray ?? new JArray(); + } + return new JArray(); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 881f757eaf..ead0e5d1e2 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -204,6 +204,11 @@ + + + + + @@ -403,6 +408,7 @@ + diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 96b56f58ca..c25d0e50c0 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -163,48 +163,14 @@ namespace Umbraco.Web.Editors [HttpGet] public JsonNetResult GetGridConfig() { - Func> getResult = () => - { - var editors = new List(); - var gridConfig = Server.MapPath("~/Config/grid.editors.config.js"); - if (System.IO.File.Exists(gridConfig)) - { - try - { - var arr = JArray.Parse(System.IO.File.ReadAllText(gridConfig)); - //ensure the contents parse correctly to objects - var parsed = ManifestParser.GetGridEditors(arr); - editors.AddRange(parsed); - } - catch (Exception ex) - { - LogHelper.Error("Could not parse the contents of grid.editors.config.js into a JSON array", ex); - } - } + var gridConfig = UmbracoConfig.For.GridConfig( + Logger, + ApplicationContext.ApplicationCache.RuntimeCache, + new DirectoryInfo(Server.MapPath(SystemDirectories.AppPlugins)), + new DirectoryInfo(Server.MapPath(SystemDirectories.Config)), + HttpContext.IsDebuggingEnabled); - var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins")); - var parser = new ManifestParser(plugins, ApplicationContext.ApplicationCache.RuntimeCache); - var builder = new ManifestBuilder(ApplicationContext.ApplicationCache.RuntimeCache, parser); - foreach (var gridEditor in builder.GridEditors) - { - //no duplicates! (based on alias) - if (editors.Contains(gridEditor) == false) - { - editors.Add(gridEditor); - } - } - return editors; - }; - - //cache the result if debugging is disabled - var result = HttpContext.IsDebuggingEnabled - ? getResult() - : ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem>( - typeof(BackOfficeController) + "GetGridConfig", - () => getResult(), - new TimeSpan(0, 10, 0)); - - return new JsonNetResult { Data = result, Formatting = Formatting.Indented }; + return new JsonNetResult { Data = gridConfig.EditorsConfig.Editors, Formatting = Formatting.Indented }; } /// diff --git a/src/Umbraco.Web/GridTemplateExtensions.cs b/src/Umbraco.Web/GridTemplateExtensions.cs index e4af759c88..ca75552e51 100644 --- a/src/Umbraco.Web/GridTemplateExtensions.cs +++ b/src/Umbraco.Web/GridTemplateExtensions.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedProperty property, string framework = "bootstrap3") { var asString = property.Value as string; - if (asString.IsNullOrWhiteSpace()) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); var view = "Grid/" + framework; return html.Partial(view, property.Value); @@ -56,7 +56,7 @@ namespace Umbraco.Web public static MvcHtmlString GetGridHtml(this IPublishedProperty property, HtmlHelper html, string framework = "bootstrap3") { var asString = property.Value as string; - if (asString.IsNullOrWhiteSpace()) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); var view = "Grid/" + framework; return html.Partial(view, property.Value); @@ -91,7 +91,7 @@ namespace Umbraco.Web public static MvcHtmlString GetGridHtml(this IPublishedProperty property, string framework = "bootstrap3") { var asString = property.Value as string; - if (asString.IsNullOrWhiteSpace()) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); var htmlHelper = CreateHtmlHelper(property.Value); return htmlHelper.GetGridHtml(property, framework); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs index 9d3b50f2d9..a0368db769 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } catch (Exception ex) { - LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); + LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); } } @@ -95,7 +95,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } catch (Exception ex) { - LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); + LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); } }