uCssClassNameDropdown Property Editor for Umbraco 7
Written by @marcemarc on Monday, 25 November 2013
Ok, so I know alot of people are waiting on the popular uCssClassNameDropdown umbraco Data Type to be ported as a new fangled Property Editor in Umbraco 7 before they'll even contemplate looking at the possibility of upgrading from 4 or 6, and who can blame them ?
It's all very well having this swish responsive editing experience but how else are you going to turn your css stylesheet class names into a rich datasource for editor's to pick ? you, the dev, are going to have to type them all in as prevalues into a dropdownlist, and try and maintain them as the front enders, switch, rename and add new ones just to spite you; and for something like font-awesome that's alot of class names to type.
But hey you can read more about the existing uCssClassNameDropdown package on our (think I need to update the font-awesome icon picker to use the new version of class names in font-awesome 4.0)
So porting this to Umbraco 7, first off, I'll just concentrate on binding the regex matches from the stylesheet to a dropdown, if that's ok ?
I have paid some attention to several of Per's talks, and read Tim Geyssen's excellent blog posts on creating custom property editor's in Umbraco 7.
So I won't repeat all that here but basically:
You need a manifest
to tell umbraco all about the property editor. You configure, alias, name and how to store the data:
editor: { alias: "tooorangey.uCssClassNameDropdown",
name: "Class Name Dropdown", valueType: "JSON",
then set the path to the view file for the editor, that will be displayed when the property editor is in use:
view: "~/App_Plugins/uCssClassNameDropdown/ucssclassnamedropdowneditor.html"},
then set any prevalues, for the editor, with uCssClassNameDropdown, you need to be able to configure the path to the css file, the regex to match the class name pattern, and a basic exclusion list for when the regex is too hard to work out...
prevalues: { fields: [ { label: "PathToStylesheet", description: "Put in the relative path to the stylesheet", key: "cssPath", view: "requiredfield", validation: [ { type: "Required" } ] }, { label: "Class Name Regex", description: "put in the regex pattern that matches the class names", key: "cssRegex", view: "requiredfield", validation: [ { type: "Required" } ] }, { label: "Exclusion list", description: "comma delimited list of styles to exclude", key: "excludeList", view: "textstring" } ] }
and finally you register any javascript or css files that the editor will need to render itself on the page. For the simple dropdown version of uCssClassNameDropdown, I'll just need to register the angular controller that will be responsible for gluing everything together:
javascript: [ '~/App_Plugins/uCssClassNameDropdown/ucssclassnamedropdown.controller.js' ], css: []
The View
In uCssClassNameDropdown's case this is just a <select tag using angular's ng-options attribute to bind to a list of classnames defined in the controller and the value of select get's saved in the umbraco document type, via binding the selection of the dropdown to model.value (ng-model) and this is two way binding. so when he control loads if the value is set on the node, then the selected item is automatically displayed.
I've got a span there to write an error message to when things go wrong.
The Controller
So the controller, glues it all together, You defined the controller on the umbraco module in this file at the top:
angular.module("umbraco") .controller("tooorangey.uCssClassNameDropdownController", function ($scope) {
and then put all your controller 'actions' in here.
first I set up the classnames property as an array for the ng-options thing to loop through on the view.
$scope.classnames = [];
then create a function, to populate it.
$scope.getClassNames = function () {
Now because I'm going to be making a http request I also need to 'inject' the angular $http request functionality into the controller, which is done by adding it at the controller function after the $scope
angular.module("umbraco") .controller("tooorangey.uCssClassNameDropdownController", function ($scope, $http) {
I could have made a serverside web api call to handle the reading of the css file, applying of the regex and caching, then returning of the matched classnames, but I was interested to see if this could all be done in angular (so this may not be the most efficient way) So I'm going to make a request for the css styles sheet.
Read in the configuration properties
var cssPath = $scope.model.config.cssPath; var cssRegexPattern = $scope.model.config.cssRegex; var excludeList = $scope.model.config.excludeList;
make the http request
$http({ method: 'GET', url: cssPath, cache: true }). success(function (data, status, headers, config) { cssStylesheetContents = data; // apply regex and populate $scope.classnames property }
Now I had a hunch I didn't want to make this request every time the editor was loaded, and I noticed there was a cache: true property that could be set on the $http request eg.
$http({ method: 'GET', url: cssPath, cache: true })
hopefully that makes this not the case ?
umm that's it, added those three files to a folder called 'uCssClassNameDropdown' in the app_plugin folder and I can now create a font-awesome icon picker data type by supply cssPath as /css/font-awesome.css and regex as \.fa-(*.?):before, and then add it to my blog post doc type. so look,
I can pick a font-awesome icon now for each blog post and display it after the title... (umm for no particular reason, but it does have it's uses this sometimes honest)
The next step is to work out how to dynamically add the selected stylesheet to the control in angular, so that instead of a dropdown you can see and click on the actual icon to select it, like the usercontrol wrappers I created before in version 4.