Nibble

Archive for the 'Umbraco' Category


Seek and destroy 1.0 Release 4

SeekAndDestroyLogoThe ajax locator package I’ve been working on the last couple of freedom fridays is available as a package on our.umbraco.org today Smile

If you haven’t seen it in action make sure to check out this quick preview video.

Here is a quick overview of it’s features

Dashboard control

It features a dashboard control (in the developer section) that can install the google maps datatype, add a new property of that type to your doc type(s) and then geocode existing content based on the address you have stored. So you should be up and running in a couple of minutes (even if you don’t have any coordinates on your content documents yet).

image

Fully Customizable AJAX Locator control

By inserting the macro you have a working locator in a couple of clicks but of course it’s output is fully customizable just by updating the Partial View Macro File associated with the Macro. So you can tailor it to your needs! If you want custom google map markers check out (http://www.webiconset.com/map-icons/ and http://www.cycloloco.com/shadowmaker/shadowmaker.htm)

image

More

The locator control includes some nice features, it loads a default location based on the users IP address, you can set it in street view mode and there is also a directions mode.

Download

So the package is available for download on http://our.umbraco.org/projects/developer-tools/seek-and-destroy

If you are interested in the sourcecode that’s available on github

Please not that since this pacakge uses an UmbracoAPIController you’ll need at least Umbraco v6.1 to run this package

Extending the Umbraco Backend Using MVC 21

1 thing I wanted to do while creating Optimus for Umbraco was creating the page that is responsible for editing the bundle use the MVC framework instead of Webforms

The backoffice of Umbraco v4/v6 is still Webforms but it’s perfectly possible to plug in pages that use MVC.

The sourcecode for Optimus is available and you can use that to figure out how it’s done but I thought It would be even easier if I created a starter project for that Smile

Umbraco MVC Backoffice Pages

So I’ve just published a new project on github that does exactly that
https://github.com/TimGeyssens/UmbracoMVCBackofficePages

You might have come accros this post by Bart de Meyer http://blog.bartdemeyer.be/2013/01/using-mvc-backend-pages-in-umbraco-4-11-1/ that also talks about this subject but there is a difference in the approach I’m using since I’m not making use of a SurfaceController (since those are for frontend use) and I’m also trying to keep things seperated by working in the /App_plugins folder (~\App_Plugins\UmbracoMVCBackofficePages\ folder in this case)

Solution setup

image

The vs solution consist of 2 projects, 1 test site that just contains Umbraco and the the project where we’ll add our code and push to the test site using post build events.

The post build events (moving the assembly and the views/icons used)

xcopy "$(ProjectDir)bin\UmbracoMVCBackofficePages.*" "$(ProjectDir)..\TestSite\bin\" /Y
 
xcopy "$(ProjectDir)Icons\*.*" "$(ProjectDir)..\TestSite\App_Plugins\UmbracoMVCBackofficePages\Icons\" /Y   
 
xcopy "$(ProjectDir)Views\*.*" "$(ProjectDir)..\TestSite\App_Plugins\UmbracoMVCBackofficePages\Views\" /Y 

Step 1: Data

So first step it to create some data that we’ll be working with as this is an example I just creates a very simple Person class and another class that will return some sample data

Person class:

 public class Person
    {
        public Person(int id, string firstName, string lastName)
        {
            Id = id;
            FirstName = firstName;
            LastName = lastName;
 
        }
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
 
        public override string ToString()
        {
            return FirstName + " " + LastName;
        }
    }

 

Data class:

 public class Data
    {
        public static IEnumerable<Person> GetAll()
        {
            var data = new List<Person>();
            data.Add(new Person(1, "Jeff", "Trent"));
            data.Add(new Person(2, "Paula", "Trent"));
            data.Add(new Person(3, "Lieutenant", "Harper"));
            data.Add(new Person(4, "Colonel", "Edwards"));
            data.Add(new Person(5, "Patrolman", "Larry"));
            return data;
        }
 
        public static Person GetById(int id)
        {
 
            return GetAll().Where(p => p.Id == id).FirstOrDefault();
        }
    }


So imagine that this interacts with your datasource….

Step 2: The Tree

Next I’ll add a tree to the settings section that will list my data

 [Tree("settings", "exampleTree", "Example")]
    public class ExampleTree : BaseTree
    {
        public ExampleTree(string application)
            : base(application)
        {
        }
 
        protected override void CreateRootNode(ref XmlTreeNode rootNode)
        {
            rootNode.NodeType   = "example";
            rootNode.NodeID     = "init";
            rootNode.Menu =  new List<IAction> { ActionRefresh.Instance };
        }
 
        public override void Render(ref XmlTree tree)
        {
 
            foreach (var person in Data.GetAll())
            {
                var node = XmlTreeNode.Create(this);
                node.NodeID = person.Id.ToString();
                node.NodeType = "person";
                node.Text = person.ToString();
                node.Action = string.Format("javascript:openExamplePage({0});",
                    person.Id.ToString());
                node.Icon = "../../../App_Plugins/UmbracoMVCBackofficePages/Icons/example-icon.png";
                node.OpenIcon = "../../../App_Plugins/UmbracoMVCBackofficePages/Icons/example-icon.png";
                node.HasChildren = false;
                node.Menu = new List<IAction>();
                OnBeforeNodeRender(ref tree, ref node, EventArgs.Empty);
                if (node != null)
                {
                    tree.Add(node);
                    OnAfterNodeRender(ref tree, ref node, EventArgs.Empty);
                }
 
            }
 
        }
 
        public override void RenderJS(ref System.Text.StringBuilder Javascript)
        {
            Javascript.Append(
               @"function openExamplePage(id) {
                 UmbClientMgr.contentFrame('../App_Plugins/UmbracoMVCBackofficePages/Index?id='+id);
                }");
        }
    }

 

Important part here is the js function that will open the edit page and pass it the id (check the node action)

UmbClientMgr.contentFrame(’../App_Plugins/UmbracoMVCBackofficePages/Index?id=’+id);

Of course we’ll need to make sure ../App_Plugins/UmbracoMVCBackofficePages/Index get’s routed correctly (more in the next steps)

Step 3: Routing

Since I’m not making use of an Umbraco SurfaceController I need to take care of the routing

So my route config looks like

 public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute(
               name: "ExampleMVCBackofficePages",
               url: "App_Plugins/UmbracoMVCBackofficePages/{action}/{id}",
               defaults: new { controller = "Example", action = "Index", id = UrlParameter.Optional }
           );
        }
    }

And to make sure that is done when the application is started I have an Umbraco ApplicationEventHandler (since I’m using 6.1 +) in place

public class StartUpHandlers : ApplicationEventHandler
    {
        protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }

 

Step 4: VIew model

Pretty simple model making use of data annotations

public class PersonViewModel
    {
        public int Id { get; set; }
 
        [Display(Name = "First name:")]
        [Required]
        public string FirstName { get; set; }
 
        [Display(Name = "Last name:")]
        [Required]
        public string LastName { get; set; }
 
    }

 

Step 5: Controller

An  MVC controller inheriting from UmbracoAuthorizedController that takes care of the authentication (so you can’t access App_Plugins/UmbracoMVCBackofficePages/Index if you aren’t logged into the backoffice)

public class ExampleController : UmbracoAuthorizedController
    {
        public ActionResult Index(int id)
        {
            var p = Data.GetById(id);
 
            PersonViewModel model = new PersonViewModel();
            model.Id = p.Id;
            model.FirstName = p.FirstName;
            model.LastName = p.LastName;
 
            return View("~/App_Plugins/UmbracoMVCBackofficePages/Views/Index.cshtml", model);
        }
 
        [HttpPost]
        public ActionResult Edit(PersonViewModel person)
        {
            if (ModelState.IsValid) { }
                //do something
 
            TempData["success"] = true;
 
            return View("~/App_Plugins/UmbracoMVCBackofficePages/Views/Index.cshtml",person);
        }
    }

But notice that I do specify the view path since it won’t look in that directory by default

Step 6: View

Strongly typed view that uses the same js/css/markup as the backoffice webforms pages so it also has the same look Smile (and also shows the speech bubble when the form was submitted successfully)

@model UmbracoMVCBackofficePages.Models.PersonViewModel
 
<!doctype html>
<html>
<head>
    <title>Example editor</title>
   
    <script src="~/umbraco_client/ui/jquery.js" type="text/javascript"></script>
    <script src="~/umbraco_client/Application/NamespaceManager.js" type="text/javascript"></script>
    <script src="~/umbraco_client/Application/UmbracoApplicationActions.js" type="text/javascript"></script>
    <script src="~/umbraco_client/Application/UmbracoUtils.js" type="text/javascript"></script>
    <script src="~/umbraco_client/Application/UmbracoClientManager.js" type="text/javascript"></script>
    <script src="~/umbraco_client/ui/default.js" type="text/javascript"></script>
 
 
    <link href="~/umbraco_client/ui/default.css" rel="stylesheet" />
    <link href="~/umbraco_client/menuicon/style.css" rel="stylesheet" />
    <link href="~/umbraco_client/panel/style.css" rel="stylesheet" />
    <link href="~/umbraco_client/propertypane/style.css" rel="stylesheet" />
    <link href="~/umbraco_client/scrollingmenu/style.css" rel="stylesheet" />
    
  
 
    <style>
 
        #save {
            height: 26px;
            margin: 0;
            padding: 0;
        }
 
        #save img {
            padding: 0;
            margin: 0;
        }   
    </style>
    @if (TempData["success"] != null)
    {
        <script>
            UmbClientMgr.mainWindow().UmbSpeechBubble.ShowMessage(’save’, ‘Saved’, ’successfully saved’);
        </script>
    }
</head>
    <body>
        
        @using (Html.BeginForm("Edit", "Example"))
        {
        <div id="body_UmbracoPanel" class="panel" style="width:100%;">
            <div class="boxhead">
                <h2 id="body_UmbracoPanelLabel">Example Editor</h2>
            </div>
            <div class="boxbody">
                <div id="body_UmbracoPanel_menubackground" class="menubar_panel">
                    <span id="body_UmbracoPanel_menu">
                        <table id="body_UmbracoPanel_menu_tableContainer">
                            <tbody>
                                <tr id="body_UmbracoPanel_menu_tableContainerRow">
                                    <td id="body_UmbracoPanel_menu_tableContainerButtons">
                                        <button type="submit" id="save">
                                            <img src="~/umbraco/images/editor/save.gif" alt="Save Bundle" class="editorIcon"/>
                                        </button>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </span>
                </div>
                <div id="body_UmbracoPanel_content" class="content">
                    <div class="innerContent" id="body_UmbracoPanel_innerContent">
                        <h2 class="propertypaneTitel">Details</h2>
 
                        @Html.HiddenFor( m => m.Id)
 
                        <div class="propertypane">
                            <div>
                                <div class="propertyItem">
                                    <div class="propertyItemheader">@Html.LabelFor(m => m.FirstName)</div>
                                    <div class="propertyItemContent">
                                        @Html.EditorFor(m => m.FirstName)
                                        @Html.ValidationMessageFor(m => m.FirstName)
                                    </div>
                                </div>
 
                                <div class="propertyItem">
                                    <div class="propertyItemheader">@Html.LabelFor(m => m.LastName)</div>
                                    <div class="propertyItemContent">
                                        @Html.EditorFor(m => m.LastName)
                                         @Html.ValidationMessageFor(m => m.LastName)
                                    </div>
                                </div>
 
                                <div class="propertyPaneFooter">-</div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="boxfooter">
                <div class="statusBar">
                    <h2></h2>
                </div>
            </div>
        </div>
        }
    </body>
</html>

Result

So that are the different bits and the end result should look like

image

Again source code for this project is available at https://github.com/TimGeyssens/UmbracoMVCBackofficePages

(I’ll also do a follow up post to show you how to get create/delete working)

Introducing Optimus Lite, instantly make any Umbraco website faster! 0

OptimusLiteLogoIf you’ve been following the latest blog posts you know I’ve been working on Optimus (bundling and minification for Umbraco built on top of the web optimization framework). In the comments Dima Stefantsov pointed out that there is another nice framework out there called  Request reduce.

Request reduce

Compared to the web optimization framework request reduce creates bundles automaticity, this means it’s just a matter of installing and your site performance is immediately improved.

For full overview please check out http://requestreduce.org/ 

Of course all credits for this package goes to the Request reduce creator Matt Wrock

The only change I made was to make sure it ignores the umbraco backoffice since that had some side effects.

Demo

To see it in action check out this screenr

 

Package

Package is available on http://our.umbraco.org//projects/developer-tools/optimus-lite

Optimus 1.0 release 0

We are done with the finishing touches to the Optimus package for Umbraco and are glad to announce that the 1.0 release is available today!

If you haven’t seen it in action yet, be sure to check out this quick overview


 

What’s new?

web optimization framework 1.1.0

The web optimization framework has been updated to the latest version (1.1.0), so you can make use of the Element template strings if you want full control over the link/script tag that will be inserted (this one’s for you James South)

@Scripts.RenderFormat(“<script src=’{0}’ async></script>”,”~/bundles/jquery”)

No empty trees

You’ll only get the dynamic scripts/stylesheet tree if you have at least 1 of the providers installed

Minification

Possible to disable minification on a bundle with the bundle editor UI

image

Bundle dynamic stylesheets/scripts directly

As requested by Jeavon Leopold it’s now possible to include less/sass/typescript/coffeescript files directly in a bundle (needs to be enabled in the \App_Plugins\Optimus\config\bundles.config file)

Caching

Some code refactor has been done to speed up several parts of the core

Installer

And finally the installer now handles the necessary files updates (thanks to the package action contrib team for the helpful snippets)

Dowload

The package is available at http://our.umbraco.org//projects/developer-tools/optimus

If you are interested in the sourcecode that can be found at https://github.com/TimGeyssens/BundlingAndMinificationForTheMasses

Introducing Optimus: Resource bundling, minification and transformation for Umbraco 8

In collab with Mr Warren Buckley we are glad to announce the beta release of a new Umbraco package.

Meet Optimus

In essence Optimus is a UI layer on top of  the Asp.net Web Optimization framework for Umbraco, making it possible to create script and style bundles from within the backoffice.

Why should you bundles those resources? Well in short: bundling and minification improves request load time by reducing the number of requests to the server and reducing the size of requested assets (such as CSS and JavaScript), for a good intro check http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification

After installing Optimus you’ll end up with some new bits in the Settings section that allow you to create both script and style bundles by simply selecting the available files in the /css or /scripts folder

OptimusBundleUI

In addition to manually creating these bundles you’ll also find a new option in the edit template toolbar (for both views and masterpages) that allows you to simply select script/link tags and auto create a bundle from those (can’t get any easier).

OptimusCreateBundleUI

more than meets the eye

Besides being able to bundle your resources Optimus also features a provider model for dynamic stylesheet and script languages.

The providers available today are:

As a final step of the installation you’ll be able to choose the providers you want to include (thanks to Matt Brailsford for letting us lend some code from the Universal Media Picker project).

OptimusProviders

Depending on the ones you installed you’ll be able create files of that type

In the new dynamic scripts tree

OptimusDynamicScripts

And dynamic stylesheets tree

OptimusDynamicStylesheets

Once created you can start writing code in the editor, the editor will check for errors and highlight the linenumber in case of an error.

OptimusFileEditorpng

If the transformation is successful you’ll end up with a plain js/css file that you can then use (also in bundles)

Demo

For a quick demo check out this screencast


It’s a beta

So today the beta is available on http://our.umbraco.org/projects/developer-tools/optimus

In addition to installing the package you’ll need to do some manual web.config updates outlined here:
https://github.com/TimGeyssens/BundlingAndMinificationForTheMasses/blob/master/OptimusBetaInstallation.md(of course this will be done automatically by the final release)

It’s only been tested on Umbraco v6 but for the final release we’ll try to include the latest v4 (eta next friday).

Look who’s editing now 3

As a result of freedom fridays at the umbraco HQ I’ve made a new little umbraco package.

Make sure your content editors don’t end up editing the same document and overwriting each others changes with this addon for umbraco.

In environments with multiple editors the editors will see in the umbraco content tree which documents are currently being edited.

Tree

Also on the content page there will be a notification when another editors are viewing/editing the same document.

Page

For a quick demo check out this video

 

You can download the package on the project page at http://our.umbraco.org/projects/backoffice-extensions/look-who’s-editing-now

Umbraco Contour and Razor 7

Want to output Contour records with razor instead of xslt well I’ve created some dynamic objects you can use to do so (please note that this is just a primary version of the dynamic objects, this will be improved in a next Contour release)

Here is an example:

@using Contour.Addons.DynamicObjects
 
<ul id="comments">
 @foreach (dynamic record in Library
           .GetApprovedRecordsFromPage(@Model.Id).OrderBy("Created"))
 {
     <li>
          @record.Created.ToString("dd MMMM yyy")
          @if(string.IsNullOrEmpty(record.Website)){
             <strong>@record.Name</strong>
          }
          else{
             <strong>
               <a href="@record.Website" target="_blank">@record.Name</a>
             </strong>
          }
         <span>said</span>
        <p>@record.Comment</p>
     </li>
  }
</ul>

 

This example uses the comment form created from the comment form template and then simply outputs all comments submitted on the current page. To access the field values you can simply use the dot notation (.FieldCaption like @record.Comment)

Download the assembly here: (simply unzip and drop in your bin directory)

Contour.Addons.DynamicObjects.dll.zip

Make sure you are running at least version 4.7 of umbraco since it won’t work on older version and of course have Contour installed.

MASTER OF DATATYPES, the video 4

The video wasn’t available when I posted the slidedeck and sourcecode so now you can also watch the “Master of Datatypes” session. See how  easy it is to create your own custom umbraco datatypes (I’m creating 3 new datatypes in 30 minutes in the video).

Make sure to check out the buug.be site since you can watch all the other sessions from the Umbraco Be Festival to!

http://www.buug.be/en/events/umbraco-festival

Getting started with Umbraco is easy! 2

The getting started with umbraco post is the most visited one on this blog. I thought I would make an update since getting started with umbraco got a lot easier recently because there are 9 free videos on umbraco.tv outlining the basics for both site builders and developers. Learn about the basis building blocks like document types, templates and macros and also see how easy it is to use .net user controls.

You can find the free umbraco foundation videos on umbraco.tv

For site builders:

For developers

These should be your first stop when diving into Umbraco!

Richtext editor datatype and related stylesheets 1

You can relate stylesheets to the richttext editor datatype in umbraco, sometimes this will cause an unwanted effect. Like a background color that you don’t want, …

But this can easily be changed.

You can target the richttext editor with the class

.mceContentBody

So by appending this to the related stylesheet, you have more control over the styling in the richttext editor datatype.

(make sure to clear your browser cache, to view the result)

Next Page »