Hi Henrik, looked at the 2.1.0 version code and it uses the content type and property name as a key to fetch the settings, so I would say it doesn't work with base types or interfaces.
Thanks, was just about to start digging into the source code.
Then this need to be a feature request since I believe I am not alone to use base classes for common properties....
Hi,
Thanks for the input. We have been thinking about this feature but we decided not to do it in the first release as we wanted some feedback first on how you want it to work.
Should it work on for every base type in the inheritance chain (override the settings on different levels)?
E.g.
abstract class MainPageData { public virtual XHtml MainBody {get;set;} } class ProductPage : MainPageData { } class VerySpecialProductPage : ProductPage { } class AndEvenMoreSpecialProductPage : VerySpecialProductPage { } // Init context.Services.Configure<TinyMceConfiguration>(config => { config.For<MainPageData>(t=>t.MainBody) .Toolbar("cut"); config.For<VerySpecialProductPage>(t=>t.MainBody) .Toolbar("cut past"); });
Or should we just fallback to the settings on the abstract base types?
And what happens if we throw interfaces in mix.
Haven't tried but I guess for now it's quite easy to use reflection, iterate based on parent or interface and set for the "leaf" type on your own?
@Magnus, would be nice if it can be done with base classes, interfaces would be a bonus but complex logic will there be in extreme cases where there is base class and interface matching.
I'll throw in another idea which could work pretty well with the current way. We could register named configurations, like first we naturally define the settings for TinyMce config and then we could call something like Register("SimpleEditorSettings", config), then we could use attribute to decorate a property like this:
[TinyMceConfig("SimpleEditorSettings")] public virtual XhtmlString SomeProperty {get;set;}
Then we could use that in base classes as the attribute would be inherited for the classes inherited from the base class. Also one could change the editor in derived class by applying a new attribute.
And logic could be something like: first check from the current type is the property decorated with attribute if yer use that, next is there a configuration with the current way of doing content type + property name key, if yes use that, next check is there attribute coming from some base class if yes use that otherwise use the default.
Something like that ;) So the closest configuration would always win, attribute on the type has highest priority, next the current way of doing and last the attribute on the base class.
PROS
CONS
Magnus I was just about to write pretty much the same as Antti, so thanks Antti for writing it so good!
I liked the way it was before with attributes and would very much have that possibility again.
If that will not be possible then I would prefere to have it that the closest setting win, so if there are one setting on a base class and then there is also another setting on the contenttype then the one on the content type wins
"if you need to change config, for some properties then you need to do a search and replace on a string to change the attribute config value and hope that you don't by mistake change a config for property that you should not have changed"
First, you can use constants instead of magic strings. But even better, as the old settings worked for TinyMCE, is to use a type instead, like this:
[TinyMceConfig(typeof(SimpleEditorSettings))] public virtual XhtmlString SomeProperty {get;set;}
But I guess there is a good reason Episerver moved away from this approach?
Yes of course constants would be used for the registered names (my sample was just to demonstrate the idea). I guess we can't use that typeof(SimpleEditorSettings) as we are not going to create new types for the different configurations?
Settings are an instance of an TinyMceSettings object. So I guess you could inherit from this class to create different types of settings and then reference them by type in an attribute somehow.
In that case it would work, maybe the question is do we want to create different types just to achieve this? I guess not a biggie if you have a couple of configurations (most likely two configurations might be what sites usually would have) but if you go crazy with the configurations then you end up creating a lot of types so that you can use typeof on a type (and most likely not adding any new functionality to type). PROS - you can use find references in VS, CONS - you need to create new types just for this.
I personally wouldn't want to create new types. Currently we can use the Clone functionality if we want to use some setting as the base for another configuration.
But ideas ideas and then let us vote on the options? ;-)
In most cases you just change the default settings, i.e. no need for an attribute, and then have one more locked down setting for introduction texts and so on. I can't imagine that one would create a lot of different settings.
Hi,
We have talked some more about this now and have a suggestion.
But first, the question about the Attributes on the DataModels.
We have a long term plan to try to get rid of the attributes that describes what the edit ui should look like from the data models. So most likely we are not going to add new attributes for this.
We think that the idea (that I posted earlier) will solve your problem in a
pretty good way and still have all the configuration in the same place.
abstract class MainPageData { public virtual XHtml MainBody {get;set;} } class ProductPage : MainPageData { } class VerySpecialProductPage : ProductPage { } class AndEvenMoreSpecialProductPage : VerySpecialProductPage { } // Init context.Services.Configure<TinyMceConfiguration>(config => { // This setting will be based on Default() config.For<MainPageData>(t=>t.MainBody) .Toolbar("cut"); // This setting will be based on Default() to make sure the API is consistent config.For<VerySpecialProductPage>(t=>t.MainBody) .Toolbar("cut past"); }); })
ProductPage would have cut
VerySpecialProductPage would have cut copy
AndEvenMoreSpecialProductPage would have cut copy
We also said that we will not create a copy of the settings configured on MainPageData
when we request the settings for MainBody on ProductPage. They will share the same settings instance, until you decide to modify it on the ProductPage.
And to be able to do this without doing a breaking change this new behavior needs to be opt-in. That means that we probably will add a
property on the TinyMceConfiguration settings that you can set to true to enable it.
e.g.
context.Services.Configure<TinyMceConfiguration>(config => { // Will be true for every TinyMceSetting config.InheritSettings = true; });
Sounds like you had it already a bit further thought ;) I think the most important part is that it is documented how the "resolving" rule goes (like you already did) and no cumbersome if this and that then do something else is added to the resolving.
Is this released next week? *wink wink*
Maybe something like this would also be nice to be able to get some own convention over configuration in place.
config.For<IContent>("*Body", someConfig)
config.For<IContent>("*Intro", someOtherConfig)
Not sure if you noticed but we have updated the api a bit to make it easier for you to do this.
https://world.episerver.com/blogs/magnus-stalberg/Dates/2018/5/tinymce-configuration-api-news/
I am implementing the new TinyMCE and in this big solution we have some abstract baseclasses where we have common properties shared with around 50 different content types.
Some of those properties were using a simple version of tiny with less functions and when I try to fix this with the technique described here:
https://world.episerver.com/documentation/developer-guides/CMS/add-ons/customizing-the-tinymce-editor-v2/
If works when I write (a content type)
config.For(x => x.TeaserBody, simplified);
But not when I write like this (a base typ)
config.For(x => x.TeaserBody, simplified);
Does anyone know if this new way of defining specific versions for different properties is suppose to work for base classes?