Joseph Michael Pesch
VP Programming

Piranha CMS Uses TinyMCE and Removes Certain Tags Like FontAwesome <i> Tags

by 9. May 2015 10:27

I was using Piranha CMS with the out-of-the-box implementation in conjunction with an MVC Bootstrap HTML/CSS template.  This was working great with the exception of certain tags (specifically in my case the <i> tag used in conjunction with FontAwesome) would get removed.  This is because by default the TinyMCE html editor that Piranha CMS uses will only retain the configured allowable tags.  I fixed this issue by adding my <i> tag to the configuration of allowable tags using the "extended_valid_elements" configuration setting of TinyMCE.  This setting adds additional allowed tags/attributes in the TinyMCE editor in addition to the default allowed tags/attributes. 

In my case the specific setting looked like this: extended_valid_elements : 'i[*]'

In order to implement this with Piranha CMS I needed to add a new file "TinyMCE.cshtml" to the folder "Areas\Manager\Views\Shared\Partial" in my MVC project (side note, that full folder path did not already exist so I added the necessary sub-folders).  Here is the full content of the TinyMCE.cshtml file:

<script type="text/javascript" src="~/res.ashx/areas/manager/content/js/ext/tiny_mce/tinymce.min.js"></script>
<script type="text/javascript">
  tinymce.init({
    extended_valid_elements : 'i[*]',
    mode: 'specific_textareas',
    editor_selector: "editor",
    convert_urls: false,
    plugins: [
        "autoresize autolink code hr paste piranhaimage link"
    ],
    width: "100%",
    height: "340",
    autoresize_min_height: 340,
    @if (File.Exists(Server.MapPath("~/areas/manager/content/css/editor.css"))) {
        <text>content_css: "@Url.Content("~/areas/manager/content/css/editor.css")",</text>
        }
    toolbar: "bold italic underline | bullist numlist hr | formatselect removeformat | cut copy paste | link piranhaimage | code",
  });
</script>

Tags:

ASP.Net | MVC

Piranha CMS for MVC Installation

by 22. February 2015 05:44

When I first installed Prianha CMS for MVC I was having issues running it.  I started over and installed via NuGet package manager console in the following order:

PM > Install-Package PiranhaCMS.Core

PM > Install-Package PiranhaCMS.WebPages

PM > Install-Package PiranhaCMS.MVC

PM > Install-Package PiranhaCMSMVC

 

Tags:

C# | MVC

Convert Standard MVC Website to SPA (Single Page Application) Using Sammy.js

by 19. February 2015 07:17

Step One: The Layout Page

For MVC the layout page is a template that ASP.NET uses to render a single HTML document by merging it with the markup in a view page.  In a SPA, the Layout becomes a shell page into which the view's markup is loaded via AJAX calls. The Layout page's lifespan is now the user's session, rather than just the lifespan of the page, so be careful what you scope at this level; the safety net of a page refresh that cleans up after us is gone, and browser memory leaks are distinctly counter-excellent in nature.

To convert a standard MVC website to SPA we'll use NuGet to add Sammy.js to our project. Sammy (among other things) is a jQuery-dependent JavaScript framework which lets us add URL routing to the client side of our app.

Once we've brought in Sammy, we'll add it to a bundle (along with jQuery) in BundleConfig.RegisterBundles:

bundles.Add(new ScriptBundle("~/js/mvc-spa").Include(
    "~/Scripts/jquery-{version}.js",
    "~/Scripts/sammy-{version}.js"));

Then we'll render the bundle at the bottom of our Layout page:

            @Scripts.Render("~/js/mvc-spa")
    </body>
</html>

We'll also need to designate the area of the Layout where the view content will be loaded by finding the element we are currently calling RenderBody and giving it a unique id. For this example, let's go with "page".

<!-- ... -->
</header>
<section id="page">
	@RenderBody()
</section>
<footer>
<!-- ... -->    

Step Two: Go Partial

Next, we need to go through our views, and, with the exception of the Home/Index view, convert each to a Partial View.

Unlike vanilla MVC Views, Partial Views are not merged with the Layout page to render as complete HTML documents. When you make a controller request that returns a Partial View, the response is merely an HTML fragment–precisely what we're looking for in a SPA page.

To convert a View to a Partial, simply change the View call to a call to PartialView in its corresponding Controller Action:

public class SpaFtwController : Controller {
    public ActionResult Index() {
        return PartialView();
    }
}

As I may have mentioned above, do not convert your default view to a partial. This view is the "single page" in "single-page application", and it still needs to render as a complete HTML document, just the once. However, we should move this Index view's content into a separate Partial View, and replace it with some sort of splash content that will only display while our app is still loading. More on that in the next step.

Step Three: One Route to rule them all

The typical usage of Sammy is to describe multiple hash-based routes, along with the js to be executed when the user navigates to them. What we're going to do in this case, though, is create a solitary Sammy route that acts as a pass-through to the existing MVC routing already in place on the server-side.

For example, a request to /#/spaftw would load the content from /SpaFTW into our app. Using fragment identifiers for routing is a classic SPA technique; it changes the browser's URL without causing a whole page request, while also allowing the back button to still work as expected, and enables deep-linking into the app.

Here is a module that contains the code to do just this. We'll add it to our project in a file named Routing.js.

var Routing = function (appRoot, contentSelector, defaultRoute) {
function getUrlFromHash(hash) { var url = hash.replace('#/', ''); if (url === appRoot) url = defaultRoute; return url; }
return { init: function () { Sammy(contentSelector, function () { this.get(/\#\/(.*)/, function (context) { var url = getUrlFromHash(context.path); context.load(url).swap(); }); }).run('#/'); } }; }

Let's unpack that. See the this.get call about two-thirds of the way down? That's Sammy's bread and butter. We're using a regular expression to describe a route URL that captures any href beginning with '/#'. When a request is made for a URL matching this expression, Sammy intercepts it and runs the function that we've passed as get's second parameter. This function grabs this path, strips out the hash, makes an AJAX request for the Partial View for that URL, and swaps it into the element designated by contentSelector. Which, of course, will be our content area in the Layout page.

Finally, we need to wire this into our Layout page. Add Routing.js to our bundle, after Sammy.js:

bundles.Add(new ScriptBundle("~/js/mvc-spa").Include(
        "~/Scripts/jquery-{version}.js",
        "~/Scripts/sammy-{version}.js",
        "~/Scripts/Routing.js"));

Then, add the following script block to the Layout page, after rendering the bundle:

@Scripts.Render("~/js/mvc-spa")
<script>
$(function () {
    var routing = new Routing('@Url.Content("~/")', '#page', 'welcome');
    routing.init();
});
</script>

This instantiates a Routing instance with the root URL for the application (this becomes important if our app is deployed anywhere other than '/'), the selector of our content area ('#page'), and the route to default to when the user navigates to the root of the app. This should be the Partial View that inherited the original content from our Home/Index view, in step two.

Original version of this modified post published here:

http://blog.apterainc.com/bid/313071/Turn-your-ASP-NET-MVC-app-into-a-Single-Page-Application-with-one-classy-Sammy-js-route

 

Tags:

C# | MVC

ASP.Net MVC Bind Boolean to DropDownList Using @Html.DropDownListFor

by 25. June 2014 07:41

I was having difficulty binding a bool property to a DropDownList using the @Html.DropDownListFor() method.  What ended up working well was to do the following:

 

Add this to the View Controller class:

private void Select_YN_Rebind()
{
  List<SelectListItem> Select_YN = new List<SelectListItem>();
  Select_YN.Add(new SelectListItem
  {
    Text = "No",
    Value = bool.FalseString
  });
  Select_YN.Add(new SelectListItem
  {
    Text = "Yes",
    Value = bool.TrueString
  });
  ViewData["Select_YN"] = Select_YN;
}


Add call to the new method in the View Controller Create method (or whatever other method is appropriate) before returning the view:

public ActionResult Create()
{
  Select_YN_Rebind();
  return View();
}

Call the @Html.DropDownListFor() as shown below:

 @Html.DropDownListFor(model => model.YourBoolPropertyHere
, (IEnumerable<SelectListItem>)ViewData["Select_YN"])

 

Tags:

ASP.Net | MVC

ASP.Net MVC 5 Issue Validating Numbers (Decimal) when Number Contains Commas

by 20. June 2014 11:37

ASP.Net MVC 5 number (decimal) validation failing when user entered data contains commas.  To get around this issue I created a custom

Create the following object and bind it in the Global.asax as shown below.  NOTE: For javascript client side validations create a new *.js file and make sure to include it AFTER the jquery.validate* in the BundleConfig.cs.

JAVASCRIPT OVERRIDE

$.validator.methods.range = function (value, element, param) {
  var globalizedValue = value.replace(",", ".");
  return this.optional(element) || (globalizedValue >= param[0] && globalizedValue <= param[1]);
}
$.validator.methods.number = function (value, element) {
  return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value);
};

GLOBAL.ASAX ADDITION

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());

NEW .CS FILE

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MyApp.Models.Binders
{
  public class DecimalModelBinder : IModelBinder
  {
    public object BindModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
      ValueProviderResult valueResult = bindingContext.ValueProvider
          .GetValue(bindingContext.ModelName);
      ModelState modelState = new ModelState { Value = valueResult };
      object actualValue = null;
      try
      {
        //Check if this is a nullable decimal and a null or empty string has been passed
        var isNullableAndNull = (bindingContext.ModelMetadata.IsNullableValueType &&
                                 string.IsNullOrEmpty(valueResult.AttemptedValue));

        //If not nullable and null then we should try and parse the decimal
        if (!isNullableAndNull)
        {
          actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
        }
      }
      catch (FormatException e)
      {
        modelState.Errors.Add(e);
      }

      bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
      return actualValue;
    }
  }
}

Tags:

ASP.Net | MVC