Quantcast
Channel: Perficient Blogs
Viewing all 149 articles
Browse latest View live

8.1 Experience Editor JavaScript APIs

$
0
0
There are parts of Sitecore APIs that are well understood, widely used, and probably won’t change without a really good reason. And then there are relatively new APIs – some introduced along with new product features (e.g. xDB in 7.5, Content Testing in 8.0) and others added to support the shift in the underlying technologies (e.g. SPEAK-ification of the Experience Editor ribbon) . These APIs are young and as they grow and mature they also tend to change their shape and form. This is good news for the APIs – they are getting better indeed – but may surprise a developer maintaining a module for various Sitecore versions.

Sitecore.ExperienceEditor.js

Sitecore 8.0 introduced SPEAK-ified version of the Experience Editor ribbon. If you built or ported your own Page Editor extensions you have probably followed in Sitecore footsteps and used SPEAK pipelines along with Sitecore.ExperienceEditor.js APIs (I know I did). Your code might look like this:

define(["sitecore"], function (Sitecore) {
    Sitecore.Commands.MyNewCommand = {
        canExecute: function (context) {
            return Sitecore.ExperienceEditor.isInMode("edit");
        },

        execute: function (context) {
            context.app.disableButtonClickEvents();

            Sitecore.ExperienceEditor.PipelinesUtil.executePipeline(context.app.MyNewPipeline, function () {
                Sitecore.ExperienceEditor.PipelinesUtil.executeProcessors(Sitecore.Pipelines.MyNewPipeline, context);
            });

            context.app.enableButtonClickEvents();
        }
    };
});

you might also be leaning on a few other helpers:

Sitecore.ExperienceEditor.Dialogs.showModalDialog(...);
...
Sitecore.ExperienceEditor.TranslationsUtils.translateText(...);

These have moved in 8.1. Partly because it had to change (the original Sitecore.ExperienceEditor.js looked as if it was very quickly put together), and partly – I believe – because it’s easier to change a JavaScript API than it is a C# API. Plus, if you don’t document your APIs or otherwise expose implementation teams to its existence you may not feel that you are breaking anything when you’re changing it.

You will see that refactored commands in 8.1 all look similar to this:

define(
  [
    "sitecore",
    "/-/speak/v1/ExperienceEditor/ExperienceEditor.js",
    "/-/speak/v1/ExperienceEditor/TranslationUtil.js"
  ],
function (Sitecore, ExperienceEditor, TranslationUtil) {
  Sitecore.Commands.Lock =
  {
     ...
     ExperienceEditor.PipelinesUtil.executePipeline(...);
     ...
     TranslationUtil.translateText(...);
     ...
  }
});

Sitecore API Wrapper

The refactoring in 8.1 didn’t change the signatures of the methods that I have used – only changed where I would find them. Still, it is a breaking change – my code stopped working. Now I need to fix it and ideally do it and maintain backwards compatibility with 8.0. Here’s what I have quickly come up with. In SitecoreApiWrapper.js:

define(["sitecore"], function (Sitecore) {
    var resolve = function (attr) {
        // ***** Sitecore 8.0 *****
        var result = Sitecore.ExperienceEditor[attr];

        // ***** Sitecore 8.1 *****
        if (!result) {
            result = require("/-/speak/v1/ExperienceEditor/ExperienceEditor.js")[attr];
        }

        return result;
    };

    return {
        PipelinesUtil: function () {
            return resolve("PipelinesUtil");
        },

        Web: function () {
            return resolve("Web");
        },

        Dialogs: function() {
            return resolve("Dialogs");
        },

        TranslationsUtils: function () {
            return Sitecore.ExperienceEditor.TranslationsUtils ||
                   require("/-/speak/v1/ExperienceEditor/TranslationUtil.js");
        }
    };
});

It will basically first try the original namespace and then fall back to requiring a 8.1 module where the things live now. Reflection is very natural with JavaScript where object.property is equivalent to object["property"] and it saved me quite a few keystrokes. I still wish JavaScript had method_missing though.

Here’s how my code looks now:

require.config({
    paths: {
        sitecoreApiWrapper: "/-/speak/v1/mymodule/SitecoreApiWrapper"
    }
});

define(["sitecore", "sitecoreApiWrapper"], function (Sitecore, SitecoreApiWrapper) {
    Sitecore.Commands.MyNewCommand = {
        canExecute: function (context) {
            return context.currentContext.webEditMode === "edit";
        },

        execute: function (context) {
            context.app.disableButtonClickEvents();

            SitecoreApiWrapper.PipelinesUtil().executePipeline(context.app.MyNewPipeline, function () {
                SitecoreApiWrapper.PipelinesUtil().executeProcessors(Sitecore.Pipelines.MyNewPipeline, context);
            });

            context.app.enableButtonClickEvents();
        }
    };
});

The Sitecore.ExperienceEditor.isInMode() was replaced with going after the raw value on the context – this is what both 8.0 and 8.1 do anyway.

I did smile at one change though. TranslationsUtils became TranslationUtil – both words lost the plural vs. singular battle. PipelinesUtil stood its ground.


To branch or not to branch? Part II

$
0
0

In my previous post we talked about the major purpose for which the branch templates were originally invented: create different kinds of hierarchies in one click.

We covered one of the cases: page hierarchy. Now let’s have a look at another case.

Renderings Hierarchy (Case II)

Another type of the hierarchy that is often created in Sitecore is a hierarchy of renderings. When you are creating multiple identical pages for your products, articles, etc., what you are actually doing is reproducing the same hierarchy multiple times.

Let’s have a look at the example. The pages below display typical product/articles pages where every page has the same structure, layout and list of renderings.

City 1

  • Lead
  • Carousel
  • Button
  • Highlight 1
  • Highlight 2

City 2

  • Lead
  • Carousel
  • Button
  • Highlight 1
  • Highlight 2

City 3

  • Lead
  • Carousel
  • Button
  • Highlight 1
  • Highlight 2

As you can see, the renderings above create a hierarchy under the page, making the case ideal for the branch.

So, when you create a new page using the branch template, the system will create a new item by copying the structure created under the branch. In this particular case it will be copying the page, all page fields including the layout, and all the rendering data sources stored as that page’s children. The full rendering data sources hierarchy will be recreated under the newly created page item. But…of course there is a “but” :)

The page renderings that are used on the page will still refer to the branch datasource. What does that mean? It means that although Sitecore automatically creates new data sources for every rendering in the new hierarchy, it does not automatically replace the the links to data sources for the newly created page.

Screen Shot 2015-11-16 at 4.18.23 PM

So, your newly created page still references the data sources that are located under the branch. Unfortunately, when that happens, Content Administrators are not notified about it in any way and might get confused when they see no changes on their pages after updating data directly in data sources. This means that Content Administrators have to remember to update data source links after creating a page from the branch template.

Sometimes developers knowing about that issue might make a change and reassign data sources automatically by creating a custom solution. This option is also available in BrainJocks SCORE by default.

But if the system does not do it for you, you can reassign the data sources:

  • Navigate to the Presentation tab->Details in the Content Editor
  • Select the Edit option for the Default layout
  • Navigate to the Controls tab
  • Select the component and click the Edit button
  • Select the new data source in the related field

As soon as this operation is finished for every component, the magic will happen: the components on the new page will not refer the original data sources and can be modified on their own. The changes will not affect the source branch item, so you can go wild.

Thus, when you need to decide when to create a branch template for pages that are similar in layout, you need to ask yourself two questions:

  • How often might the template change?
  • Should pages created out of it show changes?

When you have answers to these two questions, it all becomes easy:

  • If the page does not need to show any updates performed to the template, the branch template will be the solution. Any page created once and rarely updated is a perfect candidate for the branch: e.g. news articles
  • In case there is no expectation to update the template any time soon but pages need to have similar structure and unique datasources on each page, the branch will also fit.
  • If there is a page where the change to the template should propagate to all the pages, the data template is the answer.
  • If pages are updated on a regular basis and require unique data sources, use a data template but have in mind that you will have to:

* Create unique items as fields in standard values. In this case, the template will be rigid and will not allow much control for Content Admins

* OR restrain from adding renderings requiring unique data sources in the data template, and allow Content Admin add them on page level

* OR insert the default renderings into the data template. The default renderings might contain instructions on how to create a unique data source for every item.

Screen Shot 2015-10-21 at 2.58.53 PM

Now you know everything you need to know about branch templates to be able to make a decision and even bring it up for discussion with your development team. Send me a note if it was helpful or if there is anything you would like to add on branch templates.

The post To branch or not to branch? Part II appeared first on JocksToTheCore.

Sass Maps and Iterators

$
0
0

One of the top rules for programmers is to stay DRY – don’t repeat yourself. CSS preprocessors are great for helping UI developers accomplish this goal. However, there are still some instances where it seems as if you can’t help but repeat yourself. Here’s a common example of background positions using a sprite:

a {
    background: url(../img/social-media-large.png) no-repeat;
    &.pinterest {
      background-position: -11px -50px;
    }
    &.facebook {
      background-position: -93px -50px;
    }
    &.twitter {
      background-position: -51px -50px;
    }
    &.flickr {
      background-position: -178px -51px;
    }
    &.vimeo {
      background-position: -133px -50px;
    }
    &.youtube {
      background-position: -232px -51px;
    }
  }

Typing “background-position” 6 times is extremely repetitive. However, each icon needs its own background position, so how can we avoid repetition in this situation? Using a Sass map and iterator will keep this code DRY and compact, while creating an easily maintainable chunk of code.

Let’s start by creating the Sass map. Sass maps store key/value pairs that we will use to pair the icon’s class name with its background-position values. Sass maps should be stored in your variables file, since they are like an extended variable.

$social-icons: (
    pinterest: -11px -50px,
    facebook: -93px -50px,
    twitter: -51px -50px,
    flickr: -178px -51px,
    vimeo: -133px -50px,
    youtube: -232px -51px
);

The Sass map is declared with the dollar sign and given a name, just like other Sass variables, and it stores the meat in key/value pairs inside of parentheses and separated by commas. If you compare the two code samples, you will see that the keys in the Sass map match the class names on the icons exactly.

Now that we have defined our Sass map, we have to use it. We will use an iterator to loop through the Sass map and fill in our CSS. This is a very simple example, but we will examine it line-by-line starting from the outside.

@each $icon, $background-position in $social-icons {
   
}

@each is the Sass keyword that sets up our iterator. Following the @each declaration, we have three variables signified by ‘$’. The only familiar variable at this point is the very last one, $social-icons. This is the name of our Sass map that we set up earlier. The other two variables, $icon and $background-position, are new. These are variables that I set up just now in this line of code. Neither of these variables are declared or defined anywhere else. These variables are for use inside of the iterator and can be named however you please. Obviously, the iterator’s syntax will be easier to understand if you pick good, semantic names. The first variable I picked is $icon, signifying each icon’s HTML with a class that I will be targeting. The second variable is $background-position, which signifies the CSS values for background-position that I defined in the map. Each iteration of $icon will be a key in our Sass map, and $background-position will be a value. So we will be iterating through each $icon, $background-position (or key, value) in $social icons, our Sass map.

Let’s add the next line:

@each $icon, $background-position in $social-icons {
   .#{$icon} {
        
   }
}

This syntax will be familiar to Sass users. The first character is a dot, which signifies a class selector in CSS. The rest of the selector represents interpolation syntax in Sass, which is necessary for appending variables to selectors like this. This entire line means that we will be targeting class names that are stored in $icon. So far, our loop will generate the following CSS:

.pinterest {
        
}
.facebook {
        
}
.twitter {
        
}
.flickr {
        
}
.vimeo {
        
}
.youtube {

}

We’re ready to add the final line of our iterator!

@each $icon, $background-position in $social-icons {
   .#{$icon} {
        background-position: $background-position;
   }
}

This line is probably the most familiar of all. This line fills in our selectors with the CSS that we want, which is the values for background-position that match up with the values for $icon. This will take EXACTLY what I’ve put in for the values in my Sass map and fill them in for background-position.

So here is our final product! Exactly what was written at the beginning of the article, but a lot more DRY and maintainable (and not to mention COOL!).

.pinterest {
    background-position: -11px -50px;
}
.facebook {
    background-position: -93px -50px;
}
.twitter {
    background-position: -51px -50px;
}
.flickr {
    background-position: -178px -51px;
}
.vimeo {
    background-position: -133px -50px;
}
.youtube {
    background-position: -232px -51px;
}

The last tie-in I will mention is nesting the iterator. You probably noticed the nesting and use of the ampersand in the first code snippet. These iterators can be nested and combined with the ampersand to achieve the same effect. This decision is completely personal and depends on your views on nesting, since both will output the exact same CSS.

a {
    background: url(../img/social-media-large.png) no-repeat;
    @each $icon, $background-position in $footer-social {
      &.#{$icon} {
        background-position: $background-position;
      }
    }
  }

We just traded 21 lines of code for 8 lines of code. We cut our total lines by more than half! Doesn’t that feel great? Sass maps are extremely powerful. Look for potential usages in your projects!

The post Sass Maps and Iterators appeared first on JocksToTheCore.

Content-First Strategy using BrainJocks SCORE

$
0
0

Being a creative while working at a highly skilled dev firm has provided me a lot of insight on how workflows are changing for the better. The days of building sites from high fidelity compositions are fading fast. Development teams no longer have to wait for “signed off” wireframes and designs before getting started. Content, after all, is the UX. And the sooner it begins to populate the site build, the better the experience for all.

Lorem Ipsum Must Die

We’ve all seen it. I’ve relied on it many times when designing sites in the past: Beautiful, pixel-perfect comps with Greek text filling the gaps. Everything lines up nicely and the client can’t wait to use their powerful CMS to build pages to look just like it did in Photoshop or Sketch.

The reality, of course, is this rarely happens. What does happen?

1. The customer never gets around to writing the content for all these wonderful comps and the end result is a site that looks half-baked. Or…

2. Content Admins get frustrated that the page templates provided can not accommodate the copy/imagery they wish to insert.

Often times, the agency engagement is over, and the customer must rely on their own IT resources to adjust the template.

Original Creative
lorem-concept

Actual Rendering with Content (Now imagine what happens when it gets translated to German.)

lorem-actual

So how can this be avoided? After all, the content strategy for the new site may still be getting fleshed out.

Many times, simply using the site’s existing content will provide enough fidelity. (I’ve even seen use of competitors’ site content used as a placeholder.) It provides a more accurate representation of the live site and also help expose gaps early so that they can be iterated on.

Iterations Are The New Workflow

In the past, developers and project managers hated to see modifications made during a website’s build. These changes were often time consuming, expensive and delayed the launch of the site. Often, UX and creative teams were disengaged by that point. It was up to dev teams to patch things up. Ever ask developers, who are pressed to launch, to go backwards? It’s not pleasant.

But what if iterations happened earlier? Much earlier.

By utilizing a Content-First Strategy from the very first sprint, components and pages begin to take shape. Starting with global elements (like header/footer), then moving to pages that represent the most valuable content (like product/article detail pages), the benefit of working with live content is felt immediately.

This “raw” state where CSS styling has yet to be applied – resembles more of a glorified wireframe than a completed web page. Each page is composed of a variety of structural and content components rendered in a default Bootstrap format. It might not be pretty to look at, but it’s there. Actual content is living in the environment for which it is made for – and it’s responsive. Changing the structure of a page or a components rendering to improve the UX can be done on the fly. Nothing is set in stone. And best of all, none of the content will be lost when making these transformations.

Below are examples of three highlight components and how they render in raw and final formats.

Highlights shown in raw (default) styling

highlights-raw

Highlights shown with CSS applied

highlights-styled

As wireframes and style tiles (see: http://styletil.es/) mature, CSS and interactions are added intermittently to the branch template, and the brand begins to take shape. In the beginning, it might just be fonts, navigation, buttons and a color palette.

I have to admit I was somewhat skeptical about how clients would react to this process. But, as it turns out, they loved it. Not only are they getting a chance to see their site come alive, but they can also see how pages are built within the Sitecore Experience Editor using SCORE. As iterations continue, content components (like carousels, filters, highlights…) begin to take shape. Before you know it, you’ve just built over half of the website, and have an arsenal of re-usable components to use in fleshing out the rest.

This Old Dog Learned A New Trick

I understand this approach is different. Sites have been built for years using a similar formula that goes something like: 1. Research; 2. Content Strategy; 3. Information Architecture; 4. User Experience; 5. Design; 6. Development; 7. Content Entry; and 8. QA (with and a lot more numbers in-between).

I’ve used slight variants of this approach in working on countless desktop, tablet and mobile comps through the years. The one constant, then and now? The client will change their mind.

There has to be a better way, and a Content-First Strategy is a big step in the right direction. Is it perfect? No, not yet. But, as this new workflow is refined, I have no doubt that the old formula will begin to resemble art boards and Rubylith.

The post Content-First Strategy using BrainJocks SCORE appeared first on JocksToTheCore.

Improve Sitecore Content Editor Performance

$
0
0

While Sitecore continues to extend Content Editor functionality to the Experience Editor, Content Editor remains the interface of choice for developers and power users. Its performance can significantly impact the productivity of any development team. With the fairly simple adjustments I outline here, you can optimize Sitecore Content Editor performance and usability.

Tweaking the Tree Structure

A common culprit when performance degradation occurs is the Content Editor tree structure. The number of items under a parent item impacts how quickly that parent unfolds. Sitecore recommends that the children or items under any parent item should ideally be limited to 60 or fewer, and should not exceed 100. Having more than 100 items per folder will eventually result in slow response and increased loading time when a user starts to expand items. If a single folder item contains more than 100 items, it’s the right time to re-organize content.

This guidance sounds simple enough to implement, until you encounter a project where business constraints prevent making changes to the tree structure. For example, product information may need to be imported from an external service (PIM). In such situations, adding these three settings will improve navigation and the overall Content Editor experience:

<setting name="ContentEditor.CheckHasChildrenOnTreeNodes" set:value="false"/>
<setting name="ContentEditor.RenderCollapsedSections" value="false" />
<setting name="ContentEditor.CheckSecurityOnTreeNodes" value="false" />

Usually, it is good to consider applying these through the Sitecore patching mechanism per targeted environment. Keep in mind that:

  • RenderCollapsedSections is a hidden setting and it can help a lot.
  • CheckHasChildrenOnTreeNodes and the ContentEditor.CheckSecurityOnTreeNodes typically only enhance speed in cases where the folder has more than 500+ items.

It’s also important to note one downside to disabling CheckHasChildrenOnTreeNodes: Sitecore doesn’t know if there are child items under a single folder. When set to “false,” the user will see a black arrow pointing next to the item, suggesting that there are child items. The user can’t tell there are no additional items until he clicks on the folder, at which point the arrow indicator will disappear. When set to ‘true’, Sitecore checks if there are additional items stored and, if not, hides the arrow automatically.

Removing Item Versions

If items have more than 5 versions and performance issues are still noticeable, you should consider removing item versions. This code snippet (credit: Maryna Veller) is from a Powershell script that does just that:

$folder = "/sitecore/content/products/data"
$items = Get-ChildItem -Path $folder -recurse
foreach($item in $items){
  $versions = Get-Item -Path $item.FullPath -Version *|foreach-object{
    if($_.Version -ne $item.Version){
       $_.Versions.RemoveVersion()
    }
  }
}

By using Sitecore Powershell Extension plugin and defining the root item folder ($folder variable), this script will remove all previous item versions.

One final thing to check is how items and templates are actually defined. ‘Rich Text Fields’ and the amount of data stored in them can affect performance. In rare cases where there are more than 1000 items under a single folder item, storing a lot of content in Rich Text Fields (>500kb) can significantly decrease performance and increase memory consumption. Also, based on the value size of individual items, the action of expanding tree nodes places these objects in LOH (Large Object Heap) and GC doesn’t clear them until full garbage collection.

The post Improve Sitecore Content Editor Performance appeared first on JocksToTheCore.

Using Gulp and Unicorn within a SCORE scaffolded project

$
0
0

I would like to share some findings from my investigation into the replacement of TDS with alternative open source tools such as Gulp and Unicorn.

Gulp is a toolkit that will help you automate painful or time-consuming tasks in your development workflow, including build operations. Gulp is a pure JavaScript module for NodeJS. JavaScript is well known for Web Developers. It can speed up the process of making changes to existing code and writing new Gulp tasks. Gulp has plenty of plugins as well that can help meet a variety of needs.

Unicorn is a utility for Sitecore that solves the issue of moving templates, renderings and other database items between Sitecore instances. It simplifies the process of serializing and sharing items. Unicorn 3 uses YAML spec for serialization of items. YAML is a language that is designed to store object graphs in a human-readable fashion. This post goes into more detail about the ‘hows’ and ‘whys’ of the YAML serializer.

Prerequisites

So, here’s what we need before we begin:

Steps

Let’s do several steps to replace TDS in the currently scaffolded project.

  1. Install Sitecore 8.0 Update-4 rev. 150621 instance to path [your_project_name]\sandbox. For example, in my case it was “D:\Projects\uctest\sandbox” (see screen below):

1

Also, in this step we must install the “Sitecore PowerShell Extensions-3.3 for Sitecore 8” module.

2

As you can see from the screens above, I prefer doing that using SIM. The SIM (Sitecore Instance Manager) is a key tool for managing the park of Sitecore instances. You can install, locate, maintain, reinstall or delete Sitecore products.

  1. Unzip the SCORE+Visual+Studio+Solution+Scaffold+v2.0.14.zip into the root folder of your project. For example, in my case it was “D:\Projects\uctest”.
  1. Remove the TDS project folders from the solutions root directory. To be more exact, the folders to remove are:
  • Rename.Me.TDS.Master
  • Rename.Me.TDS.Master.Content
  • Rename.Me.TDS.Core
  1. Unzip the package (GulpUnicoreTDSReplacement.zip) and copy with replacing into the solutions root folder.
  1. Run PowerShell script “scaffold.ps1” using any preferred command console. I prefer ConEmu. ConEmu-Maximus5 is a Windows console window enhancement which presents multiple consoles and simple GUI applications as one customizable tabbed GUI window with various features. For example, to overcome the issue with execution policy, I ran following:
 
PowerShell.exe -ExecutionPolicy Bypass -File scaffold.ps1

parameters: solution: uctest, tenant: uctest, company: Test company, site: uctest. We can see it in the screen below:

3

  1. Open Visual Studio (in my case, VS2013) and install the following NuGet packages for the solution:
  • Score.8.0.150621.2.0.14.0 – except for Environment project
  • Score.BootstrapUI.8.0.150621.2.0.6.0 – only for Web project
  • Unicorn 3.1.0 – only for Web project

Please see the screens below:

456

  1. Build the solution.
  1. Install Gulp packages which are needed for our tasks, set up initial Unicorn configuration and copy everything into the sandbox. To do that, go to the solutions root folder using command console and run the following:
 
npm install

7

 
gulp Install-Unicorn

8

  1. Log in to the Sitecore instance as administrator and install update packages in the sequence below:
  • Score.TDS.Core
  • Score.TDS.Master
  • ScoreUI.TDS.Master
  • Score.BootstrapUI.TDS.Core
  • Score.BootstrapUI.TDS.Master

via url http://[your_instance]/sitecore/admin/UpdateInstallationWizard.aspx from:

  • “[solution_root]\packages\Score.8.0.150621.2.0.14.0\tools\packages\”
  • “[solution_root]\packages\Score.UI.8.0.150621.2.0.9.0\tools\packages\”
  • “[solution_root]\packages\Score.BootstrapUI.8.0.150621.2.0.6.0\tools\packages\” folders.

Currently, I don’t have a solution for automating the process that is described in this step. I hope it will be solved in the near future.

  1. Install the SCORE+Bootstrap+3+Tenant+Scaffolding+Automation-2.0.1.zip package using the Sitecore control panel.
  1. Open the Unicorn Control Panel to revert item serialization with YAML format from my package that was prepared earlier.

In order to do that we must open the link http://[your_instance]/unicorn.aspx and do the following:

  • Synchronize the Uctest.Core.Items configuration.
  • Synchronize the Uctest.Master.Items configuration.
  • Synchronize the Uctest.Master.Content.Items configuration.

9

I’m aware of the warning shown in the screen below, but it doesn’t matter given the scope of this particular demonstration. So, disregard it please. :)

10

 

  1. Let’s create some code :). Create a new class with the name HomeController.cs in Web project/Areas/your_tenant_name/Controllers. The code must contain something like what is shown below:
 
using System.Web.Mvc;

namespace uctest.Web.Areas.uctest.Controllers
{
	public class HomeController : Controller
	{
		[HttpGet]
		public ActionResult Index()
		{
			ViewBag.Message = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy " +
							  "text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has " +
							  "survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised " +
							  "in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software " +
							  "like Aldus PageMaker including versions of Lorem Ipsum.";

			return View();
		}
	}
}

Create a new Razor view with the name Index.cshtml in Web project/Areas/your_tenant_name/Views/Home. The code must contain something like what is shown here:

 
@model dynamic

@{
	ViewBag.Title = "Something from controller:";
}

@ViewBag.Message

Save All in Visual Studio. Our view and controller must be situated like in the screen below:

11

  1. Open your Web project file (your_project_name.Web.scproj) with your preferred text editor. In my case it’s Notepad++. Uncomment AfterBuild target and insert the following commands:
 
<Exec Command="cd $(SolutionDir)" ContinueOnError="false" />
<Exec Command="gulp" ContinueOnError="false" />

It’s a very important step that binds the Visual Studio build process with Gulp’s default task running.

12

  1. Build the solution.
  1. Log in to Sitecore as an administrator and execute the “Publish Site” command.
  1. Open link http://[your_instance]/[your_tenant_name]/home and…voilà, it works!!!

13

What was done

To ensure proper operation of Unicorn, I prepared in advance an item serialization for controller rendering (controller: Home, action: Index) and showed it on the home page for our tested tenant. We can make changes in the controller or razor view and, after building the solution, we can see those changes in the browser.

I’ve created the *.Core.Items serialization for checking Unicorn functionality regarding Core database without any reason except testing. Those items can be found by following the paths:

  • /sitecore/templates/uctest/extended user
  • /sitecore/system/Settings/Security/Profiles/extended user

They must not be included in the scaffolding package.

That “extended user” is for example only and must be removed from scaffolding in the future if these item serializations are to be approved for inclusion in the scaffolded project.

The package we copied into the SCORE scaffolded project folder in step 4 contains the following:

14

Where:

File name Description
Serializations Folder with prepared serialization and subdirectory with *.nuspec files named “specs” which are needed for creation of Nuget packages from serialized items for each Unicorn configuration part. Serialized items have “Rename.Me” placeholders which will be replaced during running of “scaffold.ps1”. The replacement of “Rename.Me” placeholder old and good functionality of “scaffold.ps1” so I didn’t change any line of code. Also there is a subdirectory named “packed” that is for holding Nuget packages from serialized items for each Unicorn configuration part. The packages were created after each “build solution” command in Visual Studio, of course, if we did step 13.
gulpfile.js This is a file that will act as a manifest to define our Gulp tasks. Tasks that we want to execute will be found within this file.
package.json This file is used to give information to Node (npm) that allows it to identify the project as well as handle the project’s dependencies.
Rename.Me.sln The current scaffolded project consists of this VS solution file. But links to *.TDS* projects in my version have been removed. That’s why we did copy with replacing in step 4.

15

The most interesting of them all is gulpfile.js which consists the Gulp tasks. The main tasks from this one are:

Task name Description
“Pack-serializations This task creates Nuget packages from Unicorn item serialization folders. It will be needed in the future for continuous integration tasks.
“Copy-To-Sandbox” Copies everything necessary from our project files except serialization into the “sandbox” folder.
“Install-Unicorn” Because Unicorn was installed into the project as a Nuget package, we need to configure and install it into “sandbox” with our preferences.

The “Pack-serializations” and “Copy-To-Sandbox” Gulp tasks run after every VS build as part of the scope of the default Gulp task.

 gulp.task("default", ["Pack-serializations", "Copy-To-Sandbox"], function () { }); 

The “Install-Unicorn” task was run in step 8. But if we need reconfigure Unicorn it will be better to make changes in this task and run it again.

Unicorn provides an include/exclude predicate system for configuring serialization. It’s explained very well in Kam Figy’s post on Unicorn 3.1. I want to show the configuration of this project below. Here is part of the configuration from the Unicorn.config file that describes what item paths we include and/or exclude (configuration names, descriptions, etc.). We can compare that with the Unicorn Control Panel shown in step 11:

<sitecore>
	<unicorn>
...
		<configurations>
			<configuration name="Uctest.Core.Items" description="Testing of Unicorn multiple configuration. Items serialization of our project from Core DB.">
					<predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true">
						<include name="CoreTemplates" database="core" path="/sitecore/templates/uctest" />
						<include name="CoreExtendedUser" database="core" path="/sitecore/system/Settings/Security/Profiles/extended user" />
					</predicate>
				</configuration>
				<configuration name="Uctest.Master.Items" description="Testing of Unicorn multiple configuration. Items serialization of our project from Master DB.">
					<predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true">
						<include name="Layouts" database="master" path="/sitecore/layout/Layouts/uctest" />
						<include name="Renderings" database="master" path="/sitecore/layout/Renderings/uctest" />
						<include name="Models" database="master" path="/sitecore/layout/Models/uctest" />
						<include name="Placeholder Settings" database="master" path="/sitecore/layout/Placeholder Settings/uctest" />
						<include name="Templates" database="master" path="/sitecore/templates/uctest" />
						<include name="Branches" database="master" path="/sitecore/templates/Branches/uctest" />
					</predicate>
				</configuration>
				<configuration name="Uctest.Master.Content.Items" description="Testing of Unicorn multiple configuration. Items serialization of our project from Master DB and related to content only.">
					<predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true">
						<include database="master" path="/sitecore/content/uctest" name="Content" >
							<exclude path="/sitecore/content/uctest/Selections" />
						</include>
					</predicate>
				</configuration>
		</configurations>
...

That is another important setting from the Unicorn.config file. The target data store is where we write serialized items to.

<sitecore>
	<unicorn>
...
		<defaults>
...
			<targetDataStore type="Rainbow.Storage.SerializationFileSystemDataStore, Rainbow" physicalRootPath="~/../../Serializations/$(configurationName)" useDataCache="false" singleInstance="true"/>
...

Conclusion

Of course, this isn’t a complete solution. Many steps are unpolished. Many things must be added and many givens must be reviewed. For example, we need a Gulp watch task to observe and record deleted files from Web project and have relevant file data in “sandbox.” Also, we need to automate the process described in step 9. I have provided only a basic direction that is just my personal opinion on the issue of TDS replacement. Due to my own delusions, I used to have some doubts regarding the debug process into “sandbox.” But, as it turns out, the debugging process isn’t impacted negatively. We can attach the w3wp.exe process as before and all works well. So I think that we are on the right path.

The post Using Gulp and Unicorn within a SCORE scaffolded project appeared first on JocksToTheCore.

Why BrainJocks Switched to Sass

$
0
0

BrainJocks has released SCORE v2.0, and our development team is loving it! This release brought many changes, but one of the biggest was to the front-end code. We have switched our CSS preprocessor from LESS to Sass, as many other developers have chosen to do. Even Bootstrap, which had been one of LESS’s biggest supporters, has switched their source code over to Sass. You may think: these preprocessor languages are so similar, so why switch? I’m going to break down some benefits of using Sass over LESS, and why our lives as front-end developers will be much easier with SCORE v2.0 and beyond.

 

Using @extend

Another change to SCORE with v2.0 was stripping out almost all component class names and putting the task of Bootstrap style inheritance into the CSS. The syntax for accomplishing inheritance is much simpler in Sass.

LESS:

.score-button-toolbar {
    &:extend(.btn-toolbar all); //inherit bootstrap
    a {
        &:extend(.btn-toolbar .btn all);
    }
    & > a {
        &:extend(.btn-toolbar > .btn all);
    }
}

SCSS:

.score-button-toolbar {
    @extend .btn-toolbar; //inherit bootstrap
}

The LESS version isn’t terrible, but it’s not good either. I don’t feel comfortable writing LESS extend statements from memory, and I had to do a lot of hunting through Bootstrap’s code to get the necessary selectors to target under the button toolbar. Sass’s version is simply @extend ______. That’s it!

 

Sass Maps

I wrote a blog article recently about Sass maps and iterators and how powerful they are. You can check it out here. LESS also has the ability to loop, but they are recursive and only iterate through numbers. Here is an example from the LESS documentation:

.loop(@counter) when (@counter > 0) {
  .loop((@counter - 1));    // next iteration
  width: (10px * @counter); // code for each iteration
}

div {
  .loop(5); // launch the loop
}

Sass iterators, on the other hand, can iterate through almost anything. Here is my example from my Sass maps article, which iterates through class names and fills an entire value for its background position (two numbers separated by a space). The class names and associated background position values can be conveniently stored in a Sass map with your variables.

@each $icon, $background-position in $social-icons {
   .#{$icon} {
        background-position: $background-position;
   }
}

Sass also supports logic statements in a much larger capacity than LESS does, and they support for and while loops. MUCH more powerful programming!

 

Better Documentation

LESS had the upper hand with documentation for a while, but I think Sass has now surpassed them in this category. I have spent plenty of time scouring LESS’s site trying to find something specific. Sass’s site has very clear CTAs:

sass_site

While LESS, on the other hand:

less_site

Huh??? I would have no idea which option to click on if I was searching (again) for the &:extend syntax because I couldn’t remember it. Their actual documentation is adequate, but finding anything is really difficult.

 

Syntax

Syntax complaints could be considered minor, but syntax is a big part of what makes a programming language great. CSS uses ‘@’ to signify directives, such as @keyframes and @media, and Sass does the same. Sass uses it to define and include mixins, import files, and signify loops. LESS uses the ‘@’ symbol to signify a variable, which is a little weird when used alongside directives like @media. Variables should be separate from directives, and Sass accomplishes that by using ‘$’ for variables. Additionally, mixins are clearly defined and included using directives in Sass, while all classes are potential mixins in LESS. Sass’s syntax provides clear separation between concepts, which makes it feel a lot cleaner and more organized.

 

I will end by saying that even using LESS is infinitely better than writing plain CSS. CSS preprocessors are amazing tools and we strongly encourage all SCORE customers to use them. However, if you’ve been writing LESS for a while, it may be time to switch to Sass. LESS is great for beginners to the preprocessor world, but Sass is a lot more powerful. Hopefully the reasons in this article have convinced you: this is the time for Sass! Happy coding! :)

The post Why BrainJocks Switched to Sass appeared first on JocksToTheCore.

An unhandled Microsoft .Net Framework exception occurred in w3wp.exe

$
0
0

“Unhandled exception” is not something that makes people happy. If this exception suddenly appears and crashes your beautiful Sitecore site, first you probably feel surprise, then fear and finally panic. If you are reading this article, I assume you are done with the first part and now want to know how to fix it.

Let’s have a closer look at the issue. This is how the error looks:

image2015-11-2 12-9-59

There are multiple reasons why this error can happen but the most probable for Sitecore projects is StackOverflowException.

StackOverflowException is different from all other exception types. MSDN states that:

Starting with the .NET Framework 2.0, you can’t catch a StackOverflowException object with a try/catch block, and the corresponding process is terminated by default.

This the reason why that exception crashes the IIS w3wp.exe process and the whole site (and other sites if they share the same App Pool) goes down. Of course, if you are lucky, you will find the cause of the issue by just checking logs as I did. Unfortunately, luck is something that rarely happens and only with the best:). It is more likely to see very little or no information about this error in log files.

This happens because the code that writes exception details into the log is stored in try/catch block. That code is not executed for StackOverflowException which means that the error will be logged only if it is detected before the exception is thrown.

So, if there is nothing in the logs, what can you do? There is a solution. It is called a Memory Dump.

Collecting the Memory Dump

It is all about timing. A memory dump should be collected at the moment when StackOverflowException is thrown but the application is not released yet (i.e., the moment you see the error dialog on your screen). You can collect it by using Windows Task Manager. Open it, go to the Details tab, find the w3wp.exe process by process ID and run the “Create dump file” command with a right mouse click. The file you will get as a result of these steps is a full memory dump for the process.

If you do not see the dialog and cannot easily reproduce the error, there is still a way to collect the memory dump. You will need to set up a tool that will listen to the process and automatically collect it as soon as an exception thrown again. There are number of tools that can do that. I personally like Microsoft Debug Diagnostic Tool. It is easy to install and configure. Check this article for details how to capture StackOverflowException.

By the way, if you are collecting the dump file in a remote environment, do not forget to compress it before downloading. The zipped archive will be ~90% smaller.

Analyzing the Memory Dump

Now, when you have your file, you need to analyze it. I prefer Microsoft Debug Diagnostic Tool for doing that. That is one of hidden gem every .NET developer should know about. It may be not as powerful as WinDbg but it is much easier to use.

To analyze your data dump, run the DebugDiag 2 Analysis app, pick the CrachHangAnalysis Rule, add your dump file as shown below and start the analysis.

image2016-2-16 23-2-28

In a few seconds you will get your report. There are a lot of interesting things you can find in it and you can explore them later.

What you need to do now is scroll down until you see “Previous .NET Exceptions Report”:

image2016-2-16 23-6-6

Click on the Thread ID and voilà… This is the information you have been looking for.
For example, this is what I found in my stack:

...
Sitecore.Data.Managers.ItemManager.GetItem(Sitecore.Data.ID, Sitecore.Globalization.Language, Sitecore.Data.Version, Sitecore.Data.Database)+d9
Sitecore.Data.TemplateRecords.GetTemplate(Sitecore.Data.ID, Sitecore.Globalization.Language)+c8
Sitecore.Data.Items.TemplateItem.get_BaseTemplates()+a7
Sitecore.PathAnalyzer.Extensions.ItemExtensions.GetAllBaseTemplates(System.Collections.Generic.List`1, Sitecore.Data.Items.TemplateItem, Boolean)+2b
Sitecore.PathAnalyzer.Extensions.ItemExtensions.GetAllBaseTemplates(System.Collections.Generic.List`1, Sitecore.Data.Items.TemplateItem, Boolean)+51
and many more repetitions of last line

And this is the line of code that opened my eyes and gave me a clue as to what actually happened.

Sitecore.Data.Items.TemplateItem.get_BaseTemplates()+a7

As you can see, in my case the issue was related to template inheritance. Template parents can be edited by anybody who has access and it happened that some content editor created circular references.

And for comparison, this is what I found in my logs:

4220 15:32:10 ERROR Circular template inheritance detected in 'Advanced'
4220 15:32:10 ERROR This may be caused by explicitly assigned base id's or by the setting 'DefaultBaseTemplate' in web.config.
4220 15:32:10 ERROR Template trail: System/Templates/Sections/Advanced : System/Templates/Standard template : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories : Products/Secondary Categories

You can see the template name here which gives you enough information to open Content Editor and fix the issue.

Great job, Sitecore!

The post An unhandled Microsoft .Net Framework exception occurred in w3wp.exe appeared first on JocksToTheCore.


SCORE 2.0 Component Assembly 101, Part 1: The Basic Component

$
0
0

If you’re a seasoned Sitecore developer, feel free to skip this post. If your company just bought SCORE and you’re looking for information on how to build things “the SCORE way,” you found it. I want to get into some theory, some nomenclature and the mindset of a SCORE developer.

 

What it means to Componentize

So let’s talk about components. When you look at a modern website, you can typically break it down into conceptual chunks of functionality. These chunks are so prevalent throughout the web that entire frameworks are built around them. Just take a look at ZurbBootstrapMDL or any others. See anything familiar? See anything that’s really the same thing across those frameworks?

Those chunks are referred to as Components. A component could be as simple as a button that links to another page, or as complex as a form that executes custom logic. It’s up to you as the Sitecore developer to define the granularity of your application’s components, and to embrace the SCORE way of delivering them. Really, when you’re building applications in Sitecore, there are two rules you should live by. First: if it gives you flexibility, then you should componentize (but remember to NOT overdo it!). Second: don’t fight the framework.

componentize
verb
(transitive) To split into separate components, especially interchangeable pieces.

At BrainJocks, when we talk about components, we throw around two terms: Atomic and Molecular. An Atomic component is a single rendering, which may or may not have rendering parameters or a data source. It can work on its own, and doesn’t depend on any other components on the page (although two atomic components could interact with each other through events). An example may be a Two Column component, a Hero component, a Button component that raises an event when clicked, another component that executes an action when an event is raised, etc.

On the other hand, a Molecular component is composed of multiple renderings and datasources. Molecular components empower your content authors to build things such as Carousels. Really, when you think about a carousel, it would be created as an outer “Carousel Wrapper” component, which exposes a placeholder. Within that placeholder, you should be able to place any number of “Carousel Panel” components, and each panel should let you place an image and some text within it (or whatever component you want to support). To the end user, this is a single component, but really it’s composed of multiple mini-components that work together.

In Sitecore, when we build components, there are a few major pieces: Templates, Renderings, Placeholders and Models.

 

Where SCORE fits in

So where does SCORE fit into all of this? With SCORE, you gain the power of Dynamic Placeholders; Area support (although Sitecore 8.1 finally added this, yay!); an extended rules engine for things like placeholders, datasources and queries; validation annotations tied back to datasource fields; some automatic SEO help; a set of extremely useful base templates; a (very extensive) library of general use components; rendering transformations; a scoping, eventing and communication framework for JavaScript; and more.

At the end of the day, the end goal is to enable developers to create a very rich “component assembling” experience for your content authors. If you have ever had the pleasure of building a large-scale Sitecore application without a framework like SCORE, then it’s very easy to see the power it brings to the table.

 

But why should I care?

Now, I have something to admit. The first Sitecore build I worked on was done by a team of 4 developers. My first Sitecore implementation didn’t use datasources. My first Sitecore implementation had around 100 page types. Each page type consisted of a Layout and single Sublayout (Web Forms version of a Rendering) that represented the page contents between the header and footer. The only content was shared across the entire instance, but none of it was used as a data source. Instead, we stored everything in an “extras” folder that every multi-list and drop-link in the system pointed to.

At best, a single broken link would cause a giant blank space between the header and footer. At worst, a single broken link would trigger yellow screens in the craziest places. We didn’t know what rendering parameters were (and didn’t care, who needs those anyways?). We didn’t support page editor (pff, looks cool but don’t care! I have tickets that NEED to get done!) and the site had around 2000 pages.

It wasn’t that I was stupid, or my team was stupid, because we were far from it. In fact, that team was one of the best I’ve ever worked on. The problem was that we just didn’t know. No one had seen the light, no one had made mistakes with Sitecore before and we fought the framework at every corner. I was ready to throw Sitecore away. I went to Sitecore North America 2014 in Las Vegas (really, I just wanted an excuse to go to Vegas), and there I saw SCORE for the first time. SCORE blew my mind.

If you want to make the same mistakes I did, feel free to stop reading this series now. In fact, it’s a good learning experience. Remember when you used to tie the same model to your repository and views? If not, go ahead and scaffold up a new site using SCORE 2.0, and let’s build some components.

 

So let’s start by creating a basic component

Here’s our user story:

Story:

As a content author, I would like the ability to insert a biography component onto a content page.

Acceptance Criteria:

  • A biography component can be placed into any nested content area.
  • When creating a biography, the content author should be able to specify:
    • Portrait – Image
    • Name – Single Line Text
    • Description – Rich Text

Also, our designer is ahead of the game and already has given us a component thumbnail. Sweet! Let’s upload this to /sitecore/media library/system/playground/thumbnails.

silhoutte

 

The Datasource Template

This should be easy enough to create. Start with a template in Sitecore, and add your fields. Don’t forget your standard values! I like to follow the convention of a Root folder for your tenant application. My tenant is named “playground,” so I will stick all of my templates under /sitecore/templates/playground.

Mine looks like this:

datasource-template

 

The Datasource Model

This part is not as immediately apparent. After all, you can build an entire Sitecore application without creating a single C# model. Here’s what your model would look like:

public class BiographyDatasource : ScoreUIItem
{
    public static class Fields
    {
        public const string Portrait = "Portrait";
        public const string Name = "Person Name";
        public const string Description = "Description";
    }
    
    // replace with your template's ID
    public static readonly ID TemplateId = ID.Parse("{A3AA61C2-B969-408B-9428-F000DBF89427}");
 
    public BiographyDatasource(Item item) : base(item) { }
 
    public ImageField Portrait
    {
        get { return this.InnerItem.Fields[Fields.Portrait]; }
    }
 
    public string PersonName
    {
        get { return this.InnerItem.Fields[Fields.Name].Value; }
    }
 
    public string Description
    {
        get { return this.InnerItem.Fields[Fields.Description].Value; }
    }
 
    public static bool TryParse(Item item, out BiographyDatasource parsedItem)
    {
        parsedItem = item == null || item.IsDerived(TemplateId) == false ? null : new BiographyDatasource(item);
        return parsedItem != null;
    }
 
    public static implicit operator BiographyDatasource(Item innerItem)
    {
        return innerItem != null  innerItem.IsDerived(TemplateId) ? new BiographyDatasource(innerItem) : null;
    }
 
    public static implicit operator Item(BiographyDatasource customItem)
    {
        return customItem != null ? customItem.InnerItem : null;
    }
}

Things to note:

  1. Yes, we inherit from ScoreUIItem. It wraps Sitecore’s CustomItem, and exposes a nifty utility method for determining if this item is a local, site shared or multi site shared content item.
  2. Our constructor needs to accept a Sitecore item, and needs to call our base class’ constructor with that item.
  3. Exposing our template ID and field names as constants grants us the power of strong typing, and magic strings are hidden. I prefer to create a static sub-class called Fields. This allows me to write things like Biography.Fields.Description throughout my application.
  4. Exposing a TryParse and implicit casting operators allow us to cast to and from Sitecore.Data.Items.Item. This bit of code is some unfortunate boilerplate that all of your Datasource models will have, but in the end it’s worth it.
  5. I like to stick these models in a Base or Core project. SCORE scaffolds a Data project, which is also a good place.

 

The Rendering Model

For all of you MVC folks, you can think of Rendering Models as your View Models. When working with SCORE, your rendering Model will inherit one of three things:

public class YourRenderingModel : Score.UI.Web.Areas.ScoreUI.Models.RenderingModelBase
public class YourRenderingModel : Score.UI.Web.Areas.ScoreUI.Models.RenderingModelBase<YourRenderingParameters>
public class YourRenderingModel : Score.UI.Web.Areas.ScoreUI.Models.RenderingModelBase<YourRenderingParameters, YourDatasourceModel>

There’s no real rules on which one you should and shouldn’t use. Each has a purpose, and I’ll try to elaborate:

  1. Use the RenderingModelBase signature if you’re building something like a basic structural component (no datasource, no rendering parameters).
  2. Use RenderingModelBase<YourRenderingParameters> if you’re building a basic presentation component (such as a wrapper… think SCORE’s ‘style box’).  Rendering Parameters are really helpful for things like injecting custom CSS into presentation components. Even if you don’t need your own rendering parameters, you should probably use SCORE UI’s Score.UI.Data.RenderingParameters.BaseComponentParameters (corresponding Sitecore template located at /sitecore/templates/ScoreUI/Base/Rendering Parameters/Base Component).
  3. Use RenderingModelBase<YourRenderingParameters, YourDatasourceModel> when you need to allow content authors to enter actual content for your components. Again, if you don’t have a use case for custom rendering parameters, use SCORE UI’s BaseComponentParameters.

SCORE UI’s BaseComponentParameters enables the ability for your component to use SCORE’s Show/Hide mechanism. If you didn’t know, Show/Hide allows you inject CSS classes which media queries target to show and hide things on different viewports. This means that if you have something like a massive hero image that should be hidden on phones, you can allow content authors to configure that capability.

For our Biography rendering, let’s re-use SCORE UI’s Score.UI.Data.RenderingParameters.HighlightParameters (corresponding Sitecore template located at /sitecore/templates/ScoreUI/Base/Rendering Parameters/Highlight). This will allow us to define custom Biography variations under /sitecore/content/Playground/Selections/Highlight Styles.

Here is my rendering model:

public class BiographyRenderingModel : RenderingModelBase<HighlightParameters, BiographyDatasource>
{
    public BiographyRenderingModel() : base("biography-wrapper") { }
 
    protected override BiographyDatasource InitializeDatasource(Item item)
    {
        BiographyDatasource ds;
        return BiographyDatasource.TryParse(item, out ds) ? ds : null;
    }
}

The important pieces here are that:

  1. Whenever you inherit from RenderingModelBase, you should call the base constructor and pass in a unique class name for your component. This class name will surface in @Model.Classes along with other classes added by various rendering parameters.
  2. Your class isn’t fully initialized by just calling the constructor. Sitecore will additionally call InitializeDatasource and pass in the Datasource item defined by your rendering. If you ever need to construct one of your rendering models, you should handle calling InitializeDatasource as well.

To go along with this rendering model, we need to create a Model definition item in Sitecore (/sitecore/layout/models/your-site). Mine looks like this:

 

model item

 

The View

Let’s start by creating a View Rendering under /sitecore/layouts/renderings. I am going to create mine at /sitecore/layouts/renderings/playground/features, which looks like this (note: I’ve edited the image to conserve space, and you can get to the thumbnail field if you enable standard fields at View > Standard Fields):

rendering condensed

Things to note:

  1. I created a folder called Features underneath my tenant’s renderings folder to store this rendering. SCORE will pick up on the Feature’s folder and add that as a tab to the “Select a Rendering” dialog. I chose the word Features because SCORE Bootstrap UI stores Highlight under a tab called Features, and I want to add Biography as a selectable component within the same tab.
  2. This is a View Rendering, which means that we do not need a corresponding controller. We will use a Controller Rendering in a future post.
  3. We are using SCORE’s “content-all” token to automatically select our tenant datasource locations. If you’re not using SCORE, you can define a path or query at this point.

Here’s our view:

view

@using Playground.Data
@model Playground.Web.Areas.Playground.Models.BiographyRenderingModel

<div class="@Model.Classes">
    @if (Model.HasDatasource)
    {
        <div class="portrait @Model.RenderingParameters.ImageClass">
            @Html.Sitecore().Field(BiographyDatasource.Fields.Portrait)
        </div>
        <div class="name">
            @Html.Sitecore().Field(BiographyDatasource.Fields.Name)
        </div>
        <div class="description">
            @Html.Sitecore().Field(BiographyDatasource.Fields.Description)
        </div>

    }
    else if (Sitecore.Context.PageMode.IsExperienceEditor)
    {
        <div class="error">
            WARNING: Biography component has no datasource!
        </div>

    }
</div>

Things to Note:

  1. Using @Html.Sitecore().Field(“field name”) allows Page Editor to work correctly with MVC.
  2. Wrapping your component in a DIV with a custom class is always a best practice. This provides your designers with a high level of flexibility.
  3. We check if the component has a datasource. If the datasource happens to be null (e.g., a content author deletes it and chooses to remove links), then the component will hide (aside from the outer wrapping div). When in page editor without a datasource, our content author will get a useful error message.

We’re almost done!

 

Placeholder Settings

Now this is where I’ve cheated. To figure out which placeholders this rendering should work in, I’ve gone to Bootstrap UI’s Highlight rendering (/sitecore/layout/Renderings/BootstrapUI/Content/Features/HighLight), and checked its links (Navigate > Links > Items that refer to the selected item). I found these:

  1. Snippet – [/sitecore/layout/Placeholder Settings/Playground/Snippet]
  2. Nested Content Area – [/sitecore/layout/Placeholder Settings/Playground/Playground Containers/Nested Content Area]

So this means that we should edit these placeholders (only the ones for our site!) and add our Biography rendering to the “Allowed Controls.” It’s that simple!

 

Testing it out

Now, when we open a page up in Page Editor, we should see our rendering available in Nested Content Areas under the Features tab:

Select a Rendering

If you add this to a page and check out its rendering parameters, you’ll notice that you have a few options:

  1. Highlight Style comes from /sitecore/content/Playground/Selections/Highlight Styles, and this uses SCORE’s standard CSS injection features. Whatever gets placed here will get translated into Model.Classes.
  2. Image Style comes from /sitecore/content/Playground/Selections/Image Styles, and this also uses SCORE’s standard CSS injection features. Whatever you put in here will appear at Model.RenderingParameters.ImageClass.
  3. The Show/Hide functionality is present. These also drive CSS classes and they will appear at Model.Classes.

You can confirm by inspecting the resulting HTML.

 

So what did we learn?

Building components in Sitecore can be a daunting task, especially if you’re new to the platform. While SCORE will help accelerate you in the right direction, there are still fundamental building blocks that you need to wrap your head around in order to be an effective developer. Some portions are similar to ASP.NET MVC, while others require a new mindset.

We just walked through building a very basic component, and I hope that this helps in some way. In the next post, I want to walk through modifying this component to pull additional profile data from an external system. To do that, we’ll use a Controller Rendering and some domain objects.

Until next time!

P.S. If you want to check out the source, you can find it here: https://github.com/jdylanmc/score-2.x-playground

The post SCORE 2.0 Component Assembly 101, Part 1: The Basic Component appeared first on JocksToTheCore.

Media Indexing Approaches

$
0
0

Sitecore has powerful search capabilities for those who are interested in runtime performance. Lucene is embedded by default with a standard set of indexes for all databases that is automatically refreshed upon change of content. LINQ-based queries allow you to easily retrieve documents and filter them. So, to make a website faster, it’s wise not to query the Sitecore database and instead get data from the Lucene index.

Typical search functionality includes displaying some text and image data on a search results page with filtering and pagination. Media is an important part of the visualization of any data and this article will show how to store media in Lucene.

Standard image field type indexing

Let’s say we have custom index configuration and a template which is included in the crawling process. We have an Image field in the template and the easiest way to include it in indexing is to add such field by field name*:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <indexConfigurations>
        <configuration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">
          …
          <fieldMap type="Sitecore.ContentSearch.FieldMap, Sitecore.ContentSearch">
            <fieldNames hint="raw:AddFieldByFieldName">
              <field fieldName="Image" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.GUID" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider"/>
            …
            </fieldNames>
          </fieldMap>
          …
        </configuration>
      </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>

*The code and configuration are tested using Sitecore 8.1 Update-1.

After content is published and the index is updated, you can see the actual value in the index. If there is no such field in the records, try to change Alt field for the media item. You may be surprised but the ImageFieldReader class, which is responsible for the crawling of media items, will put the Alt field value into the index:

namespace Sitecore.ContentSearch.FieldReaders
{
    public class ImageFieldReader : FieldReader
    {
        public override object GetFieldValue(IIndexableDataField indexableField)
        {
            ImageField imageField = FieldTypeManager.GetField((Field) (indexableField as SitecoreItemDataField)) 
                as ImageField;
            if (imageField == null)
                return (object) null;
            if (string.IsNullOrEmpty(imageField.Alt))
                return (object) null;
            else
                return (object) imageField.Alt;
        }
    }
}

 

Give me the URL!

When there is a need to have more control over what to put into the index, computed fields can serve the purpose. They can also be helpful if we want to reference fields from different entities under the same name, “Image.” For example, for a Product entity the field name could be Product Image and for a Category entity the field could be called Category Image. Only the image URL matters, ultimately, so logic tells us that we should store URLs in a computed field. It’s also important to ensure the same code:

  • works across all environments
  • is independent of host name and protocol
  • returns null if image field is not assigned in order to avoid creating an empty record in index document
public class Image: BaseComputedField
{
    public override object ComputeFieldValue(IIndexable indexable)
    {
        var indexableItem = (SitecoreIndexableItem)indexable;

        if (indexableItem == null || indexableItem.Item == null)
        {
            return null;
        }

        Item item = indexableItem.Item;

        if (item.IsDerived(TemplateIds.Product))   
        {
            return GetMediaItemUrl(indexableItem.Item, "Product Image");
        }

        if (item.TemplateID.Equals(TemplateIds.Category))
        {
            return GetMediaItemUrl(item, "Category Image");
        }

        return null;
    }
}

where BaseComputedField class is:

public class BaseComputedField : IComputedIndexField
{
    // implement interface here

    protected string GetMediaItemUrl(Item item, string fieldName)
    {
        if (item != null)
        {
            var imageField = (ImageField)item.Fields[fieldName];

            if (imageField != null && imageField.MediaItem != null)
            {
                return GetMediaUrl(imageField.MediaItem);
            }
        }

        return null;
    }

    protected string GetMediaUrl(MediaItem mediaItem)
    {
        var mediaUrlOptions = new MediaUrlOptions {AbsolutePath = false, AlwaysIncludeServerUrl = false};

        return Sitecore.StringUtil.EnsurePrefix('/', MediaManager.GetMediaUrl(mediaItem, mediaUrlOptions));
    }
}

 

Non-trivial usages of media (removal case)

Now, when such code escapes into the wild, you cannot control and predict how content editors will work with media items. Some content editors can remove media items with the Leave links option. This is not a big issue as we already handled this case and it will not create a field in the index.

But what if a content editor uses the option Link to another item? What if the link is changed to some non-media item, like a media library root item? The code will still work and generates the link /-/media/3D6658D8A0BF4E75B3E2D050FABCF4E1.ashx but it’s not pointing to the media resource.

To figure out if it’s a media item, we can use:
1. item.Paths.IsMediaItem, which will check that the item’s path starts with /sitecore/media library/. Forget about this solution. It’s not applicable for anything unrelated to media items such as folders under media library.
2. MediaItem properties such as extension or size. This is more reliable and, to apply it, let’s adjust the logic above:

if (imageField != null && imageField.MediaItem != null && ((MediaItem)imageField.MediaItem).Size > 0)

 

Non-trivial usages of media (attach/detach)

It’s always a good practice to invest time in training a customer on content editing and cover all possible methods of Sitecore backend usage. But a client’s behavior can still bring lots of surprises. One such example is editing the media items themselves by attaching/detaching of media.

What happens in such case? The value of the media URL remains the same; and, there is no change on UI, either. This is due to media response caching. The default Sitecore setting which regulates it is

<setting name="MediaResponse.MaxAge" value="7.00:00:00"/> // adds max-age = 7 days to media response headers

Caching brings us many benefits, like making interaction with the user faster and saving bandwidth. That’s why it’s not a good practice to turn it off. It’s time for our code to evolve then.

Storing media item ID

To eliminate any issue with media response caching, we will generate an image link during every rendering execution. MediaUrlOptions class has useful property called DisableBrowserCache which adds ts query parameter to image url with revision/datetime. That’s why there is no need to store and calculate image URL in the index; it’s enough to store just the media item ID:

protected ID GetMediaItemId(Item item, string fieldName)
{
    if (item != null)
    {
        var imageField = (ImageField)item.Fields[fieldName];

        if (imageField != null && imageField.MediaItem != null && ((MediaItem)imageField.MediaItem).Size > 0)
        {
            return imageField.MediaID;
        }
    }

    return null;
}

 

Conclusion

It looks like we have a universal solution now which works perfectly for all known cases.

di kaprio

The post Media Indexing Approaches appeared first on JocksToTheCore.

Adventures in Dependency Injection with Sitecore 8.1

$
0
0

Dependency Injection, specifically MVC controller injection, is stupid simple to set up in a vanilla ASP.NET MVC site. For you guys out there that are only working in Sitecore part of the time (or for the first time), however, it may seem like an impossible feature to set up. I mean, you don’t even have access to the Global.asax.cs in Sitecore (at least you shouldn’t), so how do you go about registering your dependencies? I’ll give you a hint: pipelines!

Lots of other guys have blogged about doing this, around doing it the right way, being multi-tenant friendly and have offered plenty of examples. The two I found extremely helpful are:

  1. Sean Holmesby: http://www.seanholmesby.com/safe-dependency-injection-for-mvc-and-webapi-within-sitecore/
  2. Pavel Veller: http://jockstothecore.com/to-the-controller-and-back-part-3-di-and-multitenancy/

So I wanted to talk through how this works, some of the nuances with the latest version of Sitecore and how you, too, can have controller injection in your Sitecore application.

The Pipeline

Sitecore has a ton of pipelines. Some of them fire when a page is requested, some fire when media is uploaded, some fire when publishing occurs. The one we want is called initialize, and (I believe) it fires during the Application_Start event. The initialize pipeline has a processor called InitializeControllerFactory. This processor uses the SitecoreControllerFactory class to instantiate controllers. Unfortunately, this class had a subtle change from Sitecore 8.0 to 8.1, which changes how we patch around this particular processor. If you check out SitecoreControllerFactory in Sitecore 8.0, it has code similar to this:

protected virtual IController CreateControllerInstance(RequestContext requestContext, string controllerName)
{
    if (Sitecore.Mvc.Extensions.StringExtensions.EqualsText(controllerName, this.SitecoreControllerName))
        return this.CreateSitecoreController(requestContext, controllerName);
    if (TypeHelper.LooksLikeTypeName(controllerName))
    {
        Type type = TypeHelper.GetType(controllerName);
        if (type != (Type) null)
            return TypeHelper.CreateObject<IController>(type);
    }
    return this.InnerFactory.CreateController(requestContext, controllerName);
}

However, in 8.1 this class has changed to run this code instead:

protected virtual IController CreateControllerInstance(RequestContext requestContext, string controllerName)
{
    if (Sitecore.Mvc.Extensions.StringExtensions.EqualsText(controllerName, this.SitecoreControllerName))
        return this.CreateSitecoreController(requestContext, controllerName);
    if (TypeHelper.LooksLikeTypeName(controllerName))
    {
        Type type = TypeHelper.GetType(controllerName);
        if (type != (Type) null)
        {
            IController controller = DependencyResolver.Current.GetService(type) as IController ?? TypeHelper.CreateObject<IController>(type);
            if (controller != null)
                return controller;
        }
    }
return this.InnerFactory.CreateController(requestContext, controllerName);
}

The important thing to note here is that in 8.0, MVC’s dependency resolver is not respected, but in 8.1 it is. This means that if you’re working in Sitecore 8.0, you’ll want to patch out the InitializeControllerFactory, but in 8.1 you’ll watch to patch after it.

Our Processor

Here’s the processor we’re going to add to our 8.1 instance. Of course, you should throw this into a patch file and place it somewhere in App_Config/Include. Lately I’ve been rolling with App_Config/Include/Tenant/MyPatch.config, but you should use what makes sense for you:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="Playground.Base.Pipelines.RegisterIoC, Playground.Base" patch:after="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']"/>
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

We’ll follow Sean and Pavel’s lead as far as code goes. These guys got it right, and their implementation works. As far as IoC containers, I prefer both Unity and SimpleInjector. For our purposes, let’s go with SimpleInjector:

public class RegisterIoC
{
    public void Process(PipelineArgs args)
    {
        var container = GetDependencyContainer();

        System.Web.Mvc.IDependencyResolver chainedMvcResolver =
            new ChainedMvcResolver(new SimpleInjectorDependencyResolver(container),
                System.Web.Mvc.DependencyResolver.Current);
        System.Web.Mvc.DependencyResolver.SetResolver(chainedMvcResolver);

        System.Web.Http.Dependencies.IDependencyResolver chainedWebApiResolver =
            new ChainedWebApiResolver(new SimpleInjectorWebApiDependencyResolver(container),
                GlobalConfiguration.Configuration.DependencyResolver);
        System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = chainedWebApiResolver;
    }

    private SimpleInjector.Container GetDependencyContainer()
    {
        var container = new SimpleInjector.Container();

        // register dependencies as needed

        return container;
    }
}

// Adapted from: 
//  http://jockstothecore.com/to-the-controller-and-back-part-3-di-and-multitenancy/
//  http://www.seanholmesby.com/safe-dependency-injection-for-mvc-and-webapi-within-sitecore/
public class ChainedMvcResolver : System.Web.Mvc.IDependencyResolver
{
    IDependencyResolver _fallbackResolver;
    IDependencyResolver _newResolver;

    public ChainedMvcResolver(IDependencyResolver newResolver, IDependencyResolver fallbackResolver)
    {
        _newResolver = newResolver;
        _fallbackResolver = fallbackResolver;
    }

    public object GetService(Type serviceType)
    {
        object result = null;

        result = _newResolver.GetService(serviceType);
        if (result != null)
        {
            return result;
        }

        return _fallbackResolver.GetService(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        IEnumerable<object> result = Enumerable.Empty<object>();

        result = _newResolver.GetServices(serviceType);
        if (result.Any())
        {
            return result;
        }

        return _fallbackResolver.GetServices(serviceType);
    }
}

// the ChainedWebApiResolver.cs is also adapted from http://www.seanholmesby.com/safe-dependency-injection-for-mvc-and-webapi-within-sitecore/

As far as packages go for simple injector, you’ll want the following for Nuget:

  <package id="SimpleInjector" version="3.1.1" targetFramework="net45" />
  <package id="SimpleInjector.Extensions.ExecutionContextScoping" version="3.1.1" targetFramework="net45" />
  <package id="SimpleInjector.Integration.Web" version="3.1.1" targetFramework="net45" />
  <package id="SimpleInjector.Integration.Web.Mvc" version="3.1.1" targetFramework="net45" />
  <package id="SimpleInjector.Integration.WebApi" version="3.1.1" targetFramework="net45" />

 

Now here’s where the story gets interesting…

After I set this up locally and started playing around, everything seemed fine. I was able to create a dummy controller rendering which expected an interface, and I had my interface registered with SimpleInjector. Whenever I would use that controller rendering, my implementation would get injected in. “Great!” I thought, until I started poking deeper into Sitecore. Turns out other people faced the same issue I was facing: The silly AnalyticsDataController from Sitecore has more than one constructor!

Here’s my exact error from the Sitecore Launchpad:

Screen Shot 2016-03-16 at 8.57.20 PM

I dug around on the internet for a solution, but the best I could find was to register that controller with SimpleInjector directly, effectively tying your application to Sitecore 8. That was no good, because I was working on an enterprise layer to support multiple sites across multiple Sitecore versions. I kept referring back to Sean Holmesby’s post about how to set up IoC, and noticed he was using Castle Windsor to do the heavy lifting. When I compared it to my approach using SimpleInjector, I found the solution.

As it turns out, Castle Windsor uses a controller instantiation strategy to always construct objects using the greediest constructor it can fulfill. This is why Sean’s approach and demo doesn’t suffer from the dreaded AnalyticsDataController problem. To solve this, I ended up adding my own constructor resolution strategy to SimpleInjector, where if a controller has multiple constructors, I take the cheapest one.

public class SimplestConstructorBehavior : SimpleInjector.Advanced.IConstructorResolutionBehavior
{
    public ConstructorInfo GetConstructor(Type serviceType, Type implementationType)
    {
        return (from ctor in implementationType.GetConstructors()
                orderby ctor.GetParameters().Length ascending
                select ctor).FirstOrDefault();
    }
}

// and back in my container registration...
public class RegisterIoC
{
    // do stuff...

    private SimpleInjector.Container GetDependencyContainer()
    {
        var container = new SimpleInjector.Container();
        container.Options.ConstructorResolutionBehavior = new SimplestConstructorBehavior();

        // register dependencies as needed

        return container;
    }
}

And viola, Analytics is back online! And the best part? I don’t have to hardcode any silly dependencies!

Now for the ‘Gotcha’

Let’s assume we have a setup similar to this:

namespace Playground.Web.Areas.Playground.Controllers
{
    public class SanityCheckController : System.Web.Mvc.Controller
    {
        private IExampleService exampleService;

        public SanityCheckController(IExampleService exampleService)
        {
            this.exampleService = exampleService;
        }

        [HttpGet]
        public ActionResult DependencyResolution()
        {
            var model = new ExampleModel();

            if (exampleService == null)
            {
                model.Message = "Service was null";
            }
            else
            {
                model.Message = exampleService.GetMessage();
            }

            return PartialView(model);
        }
    }
}

With a Controller Rendering that looks like so:

ioc controller

With our example service looking something like:

public interface IExampleService
{
    string GetMessage();
}

public class ExampleService : IExampleService
{
    public string GetMessage()
    {
        return string.Format("Hello. The time is currently {0}", DateTime.Now.TimeOfDay);
    }
}

And within our pipeline we register dependencies like so:

private SimpleInjector.Container GetDependencyContainer()
{
    var container = new SimpleInjector.Container();
    container.Options.ConstructorResolutionBehavior = new SimplestConstructorBehavior();
    container.Register(typeof(IExampleService), typeof(ExampleService), new WebRequestLifestyle());
    return container;
}

This all looks good right?

Except when you add your new component to the screen, you get this error:

The controller for path '/' was not found or does not implement IController.

The solution? Well…it’s simple but the explanation is a little tricky. When Sitecore tries to resolve controllers, it will detect fully qualified controller names and try to resolve them using reflection. If the controller name is not fully qualified, it will defer to the MVC runtime. That, of course, will cause failures because Sitecore will try to construct controllers manually and our injected controllers do not have default constructors. The solution, if you happen to encounter this problem, is to create your controller renderings via convention (and NOT fully qualify them). In this case, ours would look like this:

ioc controller 2

This does break a few of our core principles around multi-tenancy, but it will circumvent the problem if you encounter it.

I hope this post helps in your Sitecore journey :)

The post Adventures in Dependency Injection with Sitecore 8.1 appeared first on JocksToTheCore.

Unsuspected Error Handling: Solving Sitecore Puzzles

$
0
0

Being a Sitecore developer sometimes means that you are faced with errors that at first glance are both vague and puzzling. Most of the errors can be solved by using previous experience, common sense, a simple Google search for an article or quick chat with a colleague. But other times, there are errors that require deep investigation and nontraditional ways of troubleshooting. I came across two errors that occurred within the last month that, though unrelated, are both puzzling and required more investigation. I put together this blog post in order to reduce your need for deep investigation and just make the solution a simple Google search away.

 

Error: Placeholder ID

So let’s begin with the first puzzling error that I encountered. I was working in my local environment trying to access a Sitecore content page item in Content Editor when I was faced with a vague error message. As you can see in the image below, the message doesn’t offer a lot to go on.

 

ivan image 1 placeholder id

 

 

 

 

 

 

 

 

Not all items with the same template were affected. By clicking on the Details, I could see that the first line said the Building Placeholder method had failed.

 

Ivan image 2 YS ph id

 

I checked the deployment server and found no issues with problematic items that existed in my local environment. Two different environments had the same code base but were acting differently.

Content changes and erasing the entire structure in my local environment didn’t help. Further analysis took me to the point where I was looking at config changes in both environments. One of my colleagues (Yury Fedarovich) suggested that I should check the renderings field in the layout section of an item. Items which were showing up without errors on remote server looked unsuspicious. So how could I have this issue in my local environment?

 

Ivan image 3 item buckets 2016-04-02_1507

 

In order to look at the item and renderings layout field in my local environment that had the placeholder ID error, I used the Sitecore admin tool called ‘DB browser.’ Sitecore installation comes with DB browser (url: YOUR_SC_INSTANCE/sitecore/admin/dbbrowser.aspx), which helps with accessing items in a much quicker way than the Sitecore GUI does. It gives you the raw view of all the fields within an item that are stored in the SQL database.

Ivan image 4 layout renderings

 

I copied the renderings field with the error and formatted it in Visual Studio. This is where I noticed that the rendering and its placeholder was missing a datasource ID and no placeholder path was defined. Sitecore was not able to resolve the ID highlighted in the red rectangle below.

 

 

Short description of Renderings namespaces:

r – rendering field definition
d – device (default)
r uid – auto-generated rendering ID
p – pointer to the auto-generated rendering ID
s:ds – datasource ID
s:id – source rendering ID
s:ph – placeholder path (dynamic or regular)

 

The Cause

So what caused this error to occur?

After examining all the IDs in the renderings layout field, I noticed that one of the placeholder definitions was missing appropriate syntax (see highlighted red rectangle, shown above). The next obvious step was to look at standard values of the page template items. The difference between my local and items deployed on the server was hidden in ‘Final renderings.’ Since BrainJocks’ practice is to do all our development work in the ‘Shared’ renderings domain, someone must have accidentally changed it and added additional renderings directly on the server in ‘Final’ rendering mode.

Final renderings layout combines shared and versioned presentation details; therefore, even if we had correct and synced Shared details among all environments, ‘Final’ contained the definition for the missing rendering placeholder (ID). That was the reason why page items didn’t throw the unpleasant ‘placeholder ID’ error in Content Editor.

 

Ivan 6 Content Editor Std Values

 

One important thing to mention here is that the deployment process didn’t update the ‘_Standard Values’ rendering field correctly. Having templates’ ‘Standard Values’ items out-of-sync created a side effect and masked the problem that would surely show up in new environment.

 

Solution

Using DB Browser and navigating to affected items, I was able to remove parts of the Renderings field that contained rendering placeholders without a source.

 

Also, syncing and removing the ‘Final’ Renderings definition on the server matched Page Templates ‘_Standard Values’ with our source control.

 

Error: Missing Images on Content Delivery Server

The second error occurred when the client noticed on their LIVE server that some images were not rendering correctly. Though they appeared fine when they were first uploaded, after a certain amount of time the images stopped showing up. I went to examine the path and HTML source for one of the images, but both looked fine. When trying to access the image, I got the error shown below.

 

 

IIS was trying to load images as ASP.NET MVC View (???). The actual resolved path of those image source URLs created a path that looked strange and not even close to the source from HTML or the browser URL request. It is important here to add this: Even the images with the exact same names, sizes and extensions as the ones that were already in Sitecore, which we tried to upload and put on the page, were failing.

 

Short-term Solution

If your issue is urgent, such as images appearing broken on the live site, you can use this short-term solution to mask the problem and use Item IDs for resolving media items:

<setting name="Media.UseItemPaths" value="false"/>

Although the short-term solution is a quick fix, it is not the final solution. Using IDs instead of Sitecore item names as a part of image path will look like this:

HOSTNAME-/media/655A40220AF44871AE6CF642158069DE.jpg?h=637&la=en&w=956&hash=FE23BAA7FC0C12FF961AE4B3E84AAE2ED495D19B

 

Possible Cause and Solution

The possible cause of the problem might be the “NOT_A_VALID_FILESYSTEM_PATH” file in the website root folder. It is created by IIS web server when the media extension is incorrect and both of the following conditions are true:

  1. The argument provided to the “Server.MapPath” method includes a character that can’t appear in a valid filename, such as colon (“:”) or question mark (“?”).
  2. The <httpRuntime> section of the web.config file includes the following attribute: relaxedUrlToFileSystemMapping=”true”
If you have this file in the website root folder, please perform the following:
  1. Change the “relaxedUrlToFileSystemMapping” attribute value to “false”.
  2. Remove or rename the “NOT_A_VALID_FILESYSTEM_PATH” file.
  3. Make sure that all your recently uploaded media items have the correct value in the “Extension” field without special characters like “:”, “?”, “^”, etc.

 

Conclusion

Working with Sitecore is fun, interesting and we all can learn something new every day. If you ever come across the problems I’ve had in the past few weeks, I hope this post will guide you in the right direction. Happy Sitecoreing!

The post Unsuspected Error Handling: Solving Sitecore Puzzles appeared first on JocksToTheCore.

A Recipe for Solid SSL in Sitecore

$
0
0

When building a modern website, a developer needs to pay attention to many things. One of those is security; it always should be placed at the top of the priority list. And the best way to protect site bytes and user input while they’re traveling between a browser and web servers is Transport Layer Security (TLS a.k.a. SSL). If you want to learn how TLS can be implemented in Sitecore, you don’t need to search further. Let’s start…

 

Building blocks

There are two important rules that need to be followed for every SSL implementation in Sitecore:

  1. Links to site resources must use the right schema. That means whenever a link to the page, image or any other resource is generated, that link automatically comes with the correct schema (HTTP or HTTPS).
  2. Resource access protection is key. Only one schema is allowed for every resource, which means all requests with different schema should be rejected or redirected using the correct schema.

Following these two rules will give you the functionality you want without bringing that concern into the business logic code.

 

What Sitecore gives us out of the box

Out of the box, Sitecore supports two modes: “HTTP for the whole site” and “HTTPS for the whole site.”

Schema selection is controlled by the “scheme” site attribute in the config file. The Sitecore link provider internally respects that attribute and renders the correct URL. That configuration covers the first part of the required implementation we just discussed.

Resource access protection should be offloaded to IIS or Load Balancer or any other Sservice outside of Sitecore. Rules for that protection are defined per site/domain and there is no need to manage them in Sitecore.

These two modes should be enough for the typical site unless the complications described in next section are critical for your implementation. Moreover, “all under HTTPS” will become the preferable option very soon when HTTP/2 finally becomes a reality. Unfortunately, that happy time has not yet arrived as of Spring of 2016, but use HTTP/2 with HTTPS if that’s a viable option for you.

 

What are the downsides of a “whole site under HTTPS” strategy

Transport Layer Security is great and it brings lots of benefits. It protects your site by ensuring no one can read something that they shouldn’t be able to see. And once your bytes are protected from unauthorized eyes, they’re also protected from being changed by unauthorized entities. That is a second significant benefit. The Internet is full of “smart” devices which may reject traffic they don’t understand, cache something that shouldn’t be cached or even alter your content. Transport Level Security is the best protection from all these “XXX in-the-middle” inconveniences.

So, if SSL is so good, why not use it for every page? A few thoughts:

  1. Transport Level Encryption delays the first page load. Without it, a page can be delivered with one round trip of latency. A 3-way SSL handshake significantly increases that time. In the worse case scenario, it adds hundreds of milliseconds or even seconds.
  2. If SSL is used for a page, every resource on that page should be protected as well. Otherwise, it will not be loaded. Unfortunately, it’s still possible to find resources that do not support HTTPS; if you have to use them, it can be an issue. I have seen big sites that were switched from HTTPS to HTTP because of a single IFrame that wasn’t available over HTTPS.

To solve these issues, many sites want to encrypt only pages that contain sensitive data, like forms, and keep HTTP for the rest of the site. How we can achieve that in Sitecore?

 

Page-level SSL

Let’s talk about how we can enable SSL only for the specific pages we choose.

First we need to add a flag to every page to show if it should be protected. So, we’ll add the “Require SSL” field to the page template and make that field versioned for multi-lingual differences – if necessary.

The next step is to implement a custom link provider that renders HTTPS links when necessary:

  • The provider should respect the “scheme” site attribute.
  • It should also use the “Require SSL” page field to figure out what schema should be used for a given page.

Be careful with the alwaysIncludeServerUrl link manager attribute. Your code should always render a full URL if the target link schema is different from the one used for the current page.

The next step is access protection – i.e., protecting a page from being rendered with the wrong schema if requested by a user. Intercept the request in the <httpRequestBegin> pipeline after the ItemResolver processor has been executed. Here you can detect the site, get the page item from the context and check the “Require SSL” field value. You also need to detect the protocol used in the current request. Once you compare the protocol used in the request with the protocol allowed by page, you can return a redirect message if they don’t match.

Now let’s talk about how we can detect the protocol used when the page is requested. Your first approach might be based on the Request.IsSecureConnection property. If you’re sure you will never implement SSL offloading, that’s good enough. Continue reading if you’re not sure about that.

SSL offload does exactly what it is meant to do. Certain devices (like a load balancer) will handle SSL encryption in front of the site so the web server should not care about certificates and traffic encryption/decryption. As a result of that offloading, the site will always get an HTTP request instead of HTTPS. If we don’t cover that in our code, the page will go into an infinite page redirect loop:

  1. Load Balancer gets HTTPS request for page.
  2. Load Balancer decrypts it and forwards to the site as HTTP request.
  3. Site checks required schema for page, sees a mismatch (Request.IsSecureConnection returns false here) and returns redirect to HTTPS response message.
  4. Browser performs redirect and asks for HTTPS version of the page.
  5. Now we are back to Step 1…

This is solvable, but it is not as easy as you might think. Unfortunately, there is no single flag that tells the web server that this request originally came as HTTPS and the schema was changed as part of SSL offloading. Every vendor has its own rules; please see this StackOverflow topic for more details. Common practices now for notifying a site include using different ports or adding a custom HTTP header. Feel free to hard code detection logic in your code if you control the offloading process and know how that is configured in your case. Otherwise, you can implement the custom pipeline that will be called for SSL detection. Processors in that pipeline can vary to address different environments:

<configuration xmlns:patch="<a class="external-link" href="http://www.sitecore.net/xmlconfig/" rel="nofollow">http://www.sitecore.net/xmlconfig/"</a>>
  <sitecore>
    <pipelines>
      <score.sslDetection>
        <processor type="Score.Custom.Pipelines.SslDetection.Detectors.SslDetectionByHeader, Score.Custom">
          <HeaderName>Forwarded</HeaderName>
          <HeaderValue>proto=https</HeaderValue>
        </processor>
      </score.sslDetection>
    </pipelines>
  </sitecore>
</configuration>

Now you know enough to implement robust SSL for your site. Go coding or just use SCORE, which already includes that feature :)

The post A Recipe for Solid SSL in Sitecore appeared first on JocksToTheCore.

How to Test PageMode.IsExperienceEditorEditing in Sitecore

$
0
0

If you are passionate about testing automation in Sitecore, sooner or later you will want to mock Context.PageMode.IsExperienceEditorEditing (or Context.PageMode.IsPageEditorEditing in pre-Sitecore 8) properties. This post will give you step-by-step instructions on how to do that using Sitecore.FakeDb.

First of all, you need to define a “shell” site in the app.config file.

<sites>
    <site name="shell" domain="sitecore"></site>
</sites>

SiteContextFactory.Sites.Add() method has no use here. Sitecore uses the lower level API SiteManager.GetSite(“shell”), so the “shell” site has to be set up in app.config or you need to use a custom provider in SiteManager.

After finishing with the “shell” site, you need to take care of the current context site. It can be set up using standard Sitecore.FakeDb SiteContextSwitcher helper. There are only two essential attributes to set up – enableWebEdit and masterDatabase.

var fakeSiteContext = new FakeSiteContext(
new StringDictionary
{
    {"enableWebEdit", "true"},
    {"masterDatabase", "master"}
});
var siteContextSwitcher = new SiteContextSwitcher(fakeSiteContext);

Now you are ready for the last step – switch site mode. You need to call Context.Site.SetDisplayMode method for that:

Context.Site.SetDisplayMode(DisplayMode.Edit, DisplayModeDuration.Remember);

Now you have everything you need and can assert that. Below is a full test listing using NUnit and FluentAssertions:

[Test]
public void TestIsPageEditorEditing()
{
    //arrange
    var fakeSiteContext = new Sitecore.FakeDb.Sites.FakeSiteContext(
        new Sitecore.Collections.StringDictionary
        {
            {"enableWebEdit", "true"},
            {"masterDatabase", "master"},
        });

    using (new Sitecore.Sites.SiteContextSwitcher(fakeSiteContext))
    {
        //act
        Sitecore.Context.Site.SetDisplayMode(DisplayMode.Edit, DisplayModeDuration.Remember);

        //assert
        Assert.IsTrue(Sitecore.Context.PageMode.IsPageEditorEditing);

        //Available only in Sitecore 8+
        Assert.IsTrue(Sitecore.Context.PageMode.IsExperienceEditorEditing);
    }
}

You also can find full code for the solution in GitHub. Happy testing!

The post How to Test PageMode.IsExperienceEditorEditing in Sitecore appeared first on JocksToTheCore.

How to Get Sitecore Dictionary in JavaScript

$
0
0

It’s very easy to get translations in back-end code — either Razor views or .cs files — by simply calling to Sitecore.Globalization.Translate.Text(). But what about JavaScript widgets? There we have several options:

  • Item Web API results in overhead and is hard to use without additional implementation.
  • StringDictionary embeds values right in HTML and needs to be configured accordingly.
  • Injecting translated text into .js components via HTML tags has the same drawbacks as StringDictionary.

All these options are cumbersome and inconvenient.

I will show you a convenient way to have Translate.Text() right in JavaScript! The idea is to use a JavaScript dictionary object in our .js widgets/components. To achieve the goal we need the following:

  • Serialize dictionary values into .json files
  • Implement Dictionary.js

Let’s start coding!

Serializing the dictionary into .json files

Serializing the whole dictionary creates one .json file per language in a temp folder. The file’s name looks like “dictionary.{language}.json”, e.g. “dictionary.fr-CA.json”. The dictionary is serialized each time we perform a site publish or when we publish a Dictionary root item or its descendants.

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Managers;
using Sitecore.Diagnostics;
using Sitecore.Events;
using Sitecore.Globalization;
using Sitecore.IO;
using Sitecore.Pipelines;
using Sitecore.Publishing;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;

namespace Company.Project.EventHandlers
{
    public class SerializeDictionaryToJson
    {
        private static ID DictionaryFolderTemplateID = new ID("{267D9AC7-5D85-4E9D-AF89-99AB296CC218}");
       
        public void OnPublishEnd(object sender, EventArgs args)
        {
            var sitecoreArgs = args as SitecoreEventArgs;
            
            if (sitecoreArgs == null) return;

            var publisher = sitecoreArgs.Parameters[0] as Publisher;

            if (publisher == null) return;

            var rootItem = publisher.Options.RootItem;
            
            if (rootItem == null || 
				rootItem.TemplateID == DictionaryFolderTemplateID || 
				rootItem.TemplateID == TemplateIDs.DictionaryEntry || 
				rootItem.ID == ItemIDs.Dictionary)
            {
                SerializeDictionaryToJsonFiles();
            }
        }

        public void SerializeDictionaryToJsonFiles()
        {
            var db = Database.GetDatabase("web");
            var languages = LanguageManager.GetLanguages(db);

            foreach (var language in languages)
            {
                var values = GetDictionaryValues(db, language);
                CreateDictionaryJsonFile(values, language);
            }

            Log.Info("Dictionary has been serialized to json files successfully.", this);
        }

        public void CreateDictionaryJsonFile(IDictionary<string, object> values, Language language)
        {
            var json = JsonConvert.SerializeObject(values, new KeyValuePairConverter());
            var filePath = $"{TempFolder.Folder}/dictionary.{language.Name}.json";
            FileUtil.WriteToFile(filePath, json);
        }

        public IDictionary<string, object> GetDictionaryValues(Database db, Language language)
        {
            IDictionary<string, object> dictionary = new ExpandoObject();
            
            using (new LanguageSwitcher(language))
            {
                var root = db.GetItem("/sitecore/system/Dictionary");

                var items = root.Axes.GetDescendants()
                   .Where(i => i.TemplateID == TemplateIDs.DictionaryEntry);

                foreach (var item in items)
                {
                    var key = item[FieldIDs.DictionaryKey];
                    dictionary[key] = item[FieldIDs.DictionaryPhrase];
                }
            }

            return dictionary;
        }
    }
}

The last thing is to plug SerializeDictionaryToJson.cs to publish:end event by using patch config.

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <events>
      <event name="publish:end">
        <handler type="Company.Project.EventHandlers.SerializeDictionaryToJson, Company.Project" method="OnPublishEnd"/>
      </event>
    </events>
  </sitecore>
</configuration>

 

Implement Dictionary.js

I assume you are using a module loader; in my example it’s require.js. Dictionary.js loads the proper .json file only once per page based on the current context language and provides translation.

define(["jquery"], function ($) {
 
    Dictionary._instance = null;

    function Dictionary() {
        this.values = {};
    }

    Dictionary.prototype.translate = function (key) {
        return this.values[key] || key;
    }
    
    Dictionary.prototype.getContextLanguage = function () {
        return $('meta[http-equiv="content-language"]').attr("content");
    }

    Dictionary.prototype.loadValues = function () {
        var language = this.getContextLanguage();
        var valuesUrl = "/temp/dictionary." + language + ".json";

        // We disable browser's cache to ensure translations are up to date
        $.ajax({ cache: false, async: false, url: valuesUrl })
            .done(function (data) {
                this.values = Object.freeze(data);
            }.bind(this))
            .fail(function () {
                console.error("Couldn't load dictionary values");
            });
    }

    Dictionary.getInstance = function () {
        if (Dictionary._instance == null) {
            var dictionary = new Dictionary();
            dictionary.loadValues();
            Dictionary._instance = dictionary;
        }
        return Dictionary._instance;
    }

    return Dictionary.getInstance();
});

 

How to use Dictionary.js

In this sample, our SearchBox widget utilizes translations based on the current page language.

define(["Dictionary"], function (dictionary) {
    
	function SearchBox(options) {
		this.noResultsFoundText = dictionary.translate("NoResultsFound");
		
		//...
	}

	//...
		
	return SearchBox;
});

dictionary.en.json snippet

{ ... "NoResultsFound": "Sorry, we have no content matching your criteria." ... }

dictionary.fr-CA.json snippet

{ ... "NoResultsFound": "Désolé, nous avons aucun contenu ne correspond à vos critères." ... }

 

Dictionary.js features

  • Doesn’t inject values into HTML.
  • Doesn’t impact SEO.
  • Lazy loading.
  • No need to configure.
  • Small overhead: serialized .json file is 13kB for 300 items in real-world application.
  • Can be loaded from browser’s cache.

The post How to Get Sitecore Dictionary in JavaScript appeared first on JocksToTheCore.


Indexing Patterns in Sitecore

$
0
0

Proper Search Index implementation is an essential part of development for the Sitecore platform. When you begin to work with indexes, you have to decide what index to use in your project and how store data in it. This article intends to show you possible options and give you tools to make educated decisions.

 

The Basics: Sitecore Indexes

Let’s start from the basics. Sitecore provides three predefined indexes that most developers know about (and, eleven more indexes were added in Sitecore 8+ but at this point that’s not important!):

  • sitecore_core_index
  • sitecore_master_index
  • sitecore_web_index

These three indexes contain all the versions for all the items from the corresponding Sitecore database. Sitecore uses these indexes for Item Buckets, Search based Fields like “Multilist with Search”, media items search, etc.

Now, after we consider how Sitecore uses its indexes, it’s time to decide how to store the custom data that we need. Let’s talk about typical scenarios, which could include site content search, Product Catalog, Blog, Locations, Employee Directory, etc. All of these scenarios have commonalities: They all use some subset of Sitecore items, those items share the same Template (sometimes a few templates) and they represent one business area of the site. In software engineering we call that the “Business Domain.”

So, what are our options (patterns) to store the data?

 

God Index

A God Index is an approach where all the data is stored in existing sitecore_DbName_index index. That index is available out of the box and seems to be a good candidate for storing our data. Typically, a developer only needs to add computed fields for custom data to make the index work.

Despite its simplicity, the approach I’ve described has several disadvantages. If you are familiar with the “God Object” pattern you can probably guess what one of those could be: The index has too many responsibilities.

Below are issues we have seen in sites implementing that pattern:

  1. The index keeps too much data. Data for every version, in every language, for every Sitecore item is stored in that index. Moreover, every document includes all possible fields. As a result, index update/rebuild is slow and rebuild causes significant downtime because of the index’s size.
  2. Data for multiple tenants is stored in one index. You cannot maintain your sites independently because of shared storage. A configuration or data model update that you make for one site can break other tenants.
  3. Queries are overcomplicated. We need to add extra filters to exclude data that isn’t relevant for our business logic.
  4. Every document contains lots of extra fields. That affects performance and reduces data readability and the ability to debug.
  5. All the data shares the same update strategy. You cannot update specific entities like products, blogs, pages and articles on individual schedules.
  6. Multi-region implementations use the index from different time zones. This limits the time when index maintenance can be performed.
  7. Maintenance collapse. Very soon you can arrive at a state where nobody knows how exactly the index is used. In such situations, you can’t refactor the index. Instead, you have to freeze the existing data model and flow.

All of these issues significantly complicate index maintenance. That’s the price we have to pay for simplified configuration. But, there is an alternative approach–which we’ll call “Domain Index”–that addresses the issues above.

 

Domain Index

With a Domain Index we are not trying to put all our business data into the existing Sitecore_DbName_index. Instead, we identify our business domains and configure a new index for every domain. That includes building individual indexes per tenant for multi-tenant implementations, and creating separate indexes for master and web databases.

The Upside

A Domain Index needs to include only the data (documents and fields) that is relevant for our current business area. Data should be stored in the format that works best for us. This is how index names can look in a product catalog:

  • myTenant_products_master_index
  • myTenant_products_web_index

If you want to learn the advantages of Domain Index, please scroll back up to the section outlining the issues presented by the God Index. The Domain Index addresses all of them!

The Downside

The one negative to a Domain Index is more complicated setup. It’s key to configure the indexes to exclude data “noise.” The configuration below is applicable for Sitecore 8.1. The same result can be achieved in previous Sitecore versions, but the paths may be different.

  • Filter Items by Root Item – sitecore/contentSearch/configuration/indexes/index/locations/crawler/Root
  • Filter items by Template Type – sitecore/contentSearch/indexConfigurations/yourIndexConfiguration/documentOptions/include
  • Remove standard fields by turning off indexAllFields in sitecore/contentSearch/indexConfigurations/yourIndexConfiguration or exclude fields one by one using sitecore/contentSearch/indexConfigurations/yourIndexConfiguration/DocumentOptions/exclude hint=”list:AddExcludedField” section
  • Add computed fields into sitecore/contentSearch/indexConfigurations/yourIndexConfiguration/documentOptions/include section
  • Configure update strategy (you can read more about that in this John West post)

 

The Sitecore Perspective

Some of may be asking yourselves: That’s all great, but doesn’t using a Domain Index conflict with Sitecore’s strategy? Does Sitecore want us to use that pattern?

The answer is – Yes! Sitecore is actually using that pattern by itself.

Now it is time to look at these new 11 Indexes assigned to Sitecore 8. There are some names:

  • sitecore_marketing_asset_index_master
  • sitecore_marketing_asset_index_web
  • sitecore_fxm_master_index
  • sitecore_fxm_web_index

That index name schema should look familiar.

And now, if you take a look at three default Sitecore_DbName_index indexes from a domains perspective, you will immediately realize that they have also implemented a Domain Index pattern. Their domain is “Content Authoring” and these indexes are well designed for that domain. So how can a Domain Index become a God Index? It is because of you and me–developers–who start using indexes for the wrong purpose.

That reminds me of Schrödinger’s cat. Sitecore indexes implement a Content Authoring Domain search out of the box. But the moment developers query them for the purposes of another business area, something strange happens. The indexes cease to be pure Domain Indexes. They take on something from dark side of the God Index anti-pattern.

Happy Searching. May the Force be with you.

The post Indexing Patterns in Sitecore appeared first on JocksToTheCore.

Defaulting to Shared Layout Editing in Sitecore 8.1

$
0
0

At BrainJocks, we’ve been using both shared and final rendering fields from the page editor (sorry – visual experience editor) since Sitecore 8.0.  BrainJocks SCORE™ includes a toggle in the ribbon when run in Sitecore 8.0 that allows page designers to select between shared and final rendering fields when editing pages and standard values.  At first, this created quite a stir for our content assembly teams, but we adopted some best practices and a plan for when to use each.

We learned through experience that teams should start off a project by using the shared rendering field.  Most projects don’t have a clear path to localization at conception, so it makes sense to go ahead and make the initial site delivery by using the shared field, which can be the basis for the first language specific localization when / if that occurs.

When Sitecore 8.1 arrived, we disabled our own shared / final toggle in favor of the Sitecore feature that performs the same function.  Problem was, the Sitecore editor in 8.1 defaults to final, and there wasn’t a way to change the editor default to shared.  Teams who forgot to toggle the field spent time adding components into the final rendering field only to have to rebuild the page later to move the items into the shared field.

To help our teams, we built this simple processor for the loggedin pipeline to allow us to change the default from final to shared in Sitecore 8.1:

using Sitecore.ExperienceEditor;
using Sitecore.Pipelines.LoggedIn;
using Sitecore.Security.Accounts;
using Sitecore.Web.UI.HtmlControls;

namespace Score.Custom.Pipelines.Editor.ExperienceEditor
{
    public class DefaultToAllVersions : LoggedInProcessor
    {
        public override void Process(LoggedInArgs args)
        {
            if (SkipProcessor(args)) return;

            Registry.SetString(Constants.RegistryKeys.EditAllVersions,
                Constants.Registry.CheckboxTickedRegistryValue);
        }

        public virtual bool SkipProcessor(LoggedInArgs args)
        {
            var user = User.FromName(args.Username, true);
            var existing = Registry.GetString(Constants.RegistryKeys.EditAllVersions);
            return user == null && string.IsNullOrEmpty(existing);
        }
    }
}

And to patch this into the proper place, here’s the configuration patch:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <processors>
      <loggedin>
        <processor mode="on"
          patch:after="*[last()]" 
          type="Score.Custom.Pipelines.Editor.ExperienceEditor.DefaultToAllVersions, Score.Custom" />
      </loggedin>
    </processors>
  </sitecore>
</configuration>

The post Defaulting to Shared Layout Editing in Sitecore 8.1 appeared first on JocksToTheCore.

Styling Experience Editor for a Better Content Admin Experience

$
0
0

When building a new site using BrainJocks SCORE, are you paying attention to the styling of the Experience Editor view?

Some project team members may consider this a waste of time, especially for projects that are low on budget and/or need to be finished very quickly. But neglecting Experience Editor has meaningful consequences – and your Content Administrators will be the ones who suffer. A frustrating authoring and editing experience can make it impossible to leverage the full power of even the best website.

Our ultimate goal with BrainJocks’ projects is to style Experience Editor to look as close to the front end of the site as possible, optimizing the admin experience. I’ll explain two types of Experience Editor styling that we address when we build websites.

 

A Fast Path to Functional

The first is a component that is unusable in Experience Editor without some additional CSS. A common scenario is when some components are utilizing absolute positioning or floats that break the component (or part of it) outside of its placeholder. Here is an example from our BrainJuice demo site:

bj_regions

 

These components are SCORE Highlights that were manipulated with CSS. The image (wine mark) is a foreground image, so it had to be absolutely positioned to appear behind the value for temperature or rain. This achieves the following look in Experience Editor:

bj_regions_ee

 

Not horrible, right? It looks pretty close to the front end. At first glance, you might think all you need to do is fix the cut-off image. However, if you try to edit the information in the component, you will see that the value for temperature is not editable because the image is in the way. You can see in the image below that hovering over the Highlight body field only gives you an editing box for the image.

bj_region_ee2

 

The solution in this scenario is very simple: it’s actually only one line of code. All you have to do is just “reset” the position of the image. In this case, I used “position: initial,” but there are several values that will achieve the desired result.

bj_regions_ee_fixed

 

You’re probably already addressing these issues in your current projects because they’re blockers that your administrators will definitely bring up.

 

Setting Up for User Efficiency

So let’s talk about the next scenario, which is a component that would be easier to use with the help of additional Experience Editor styling. For this scenario I will use our SCORE Slider component on BrainJuice:

bj_slider

 

This Slider has 10 panes in it. As you probably know, JavaScript components need to be “flattened out” in Experience Editor, so every pane needs to be shown at the same time. This results in the following look:

bj_slider_ee

 

I could only fit one entire pane and part of the next in the above screenshot. Could you imagine what 10 of these looks like? The Content Administrator will have to scroll for ages to get to the content below this Slider. Since Sitecore throws you back up to the top of your page every time you click “Save,” this is going to make your admins feel very frustrated, very quickly!

It’s also quite obvious that each pane does not need to stretch to 100% of the page width. We can improve this experience by simply floating each item and giving them a set width for Experience Editor, as follows:

bj_slider_ee_fixed

 

I don’t know of anyone who would prefer to work with the first option. It may look fine and every field can be edited, but it makes for a poor admin experience. Floating the Slider panes and giving them a set width makes the Experience Editor view look a lot closer to the front end view — and that makes the page much easier to work with.

 

I have seen many sites that have not gotten any special Experience Editor attention. The result is not pretty. Spending some extra time styling your components in Experience Editor will be well worth it at the end of your project. You may be surprised at how little time it actually takes to make the administrator side of your site look great.

The post Styling Experience Editor for a Better Content Admin Experience appeared first on JocksToTheCore.

SCORE 2.0 Component Assembly 101, Part 2: Form Components

$
0
0

In my first post in this series, we walked through the process of building a simple component. Let’s go a bit further now and build something very useful in Sitecore: a custom form. While a module like Web Forms for Marketers can definitely help you build forms, it can be heavy handed and sometimes doesn’t quite fit the bill. That’s where form components come in.

Luckily, BrainJocks SCORE has a few features and patterns that can help you out, and keep your content authors happy at the same time.

 

Form Component Requirements

Here’s our user story for this form:

As a Content Assembler, I would like the ability to supply a ‘Contact Us’ form on any page within our site.

This form should have:

  1. Name, Required, Must be Alpha.
  2. Email, Required, Must be valid format.
  3. Comments, Required, Must be under 500 characters.

I also want the ability to specify the error messages that are displayed to the user whenever validation fails on a form field and to select a custom style for the form.

 

Getting Started

Let’s start with our datasource template. First, I’ll create a template at /sitecore/templates/My Site/Forms/Contact Us Form. This template has no special inheritance; it’s just a template! My fields look something like this:

 

Datasource Template

 

Next I’ll add some custom rendering parameters so that I can give my content authors the ability to select a custom style for this form. This part may or may not be necessary depending on your requirements, but if you are working on an enterprise framework that will support multiple sites and multiple languages, you definitely want to complete this step.

I’ll start by creating a template which acts as a folder to hold form styles, and I’ll call this “Form Styles”. This template has no fields, and allows SCORE’s List Item (/sitecore/templates/Score/Base/List Item) to be inserted. I will add an instance of this template to my tenant’s selections, with a few default styles. Mine looks like this:

Form Styles Template

After this is created, I can add a custom set of rendering parameters that allow my content team to select any styles they need. I’ve created a template for my rendering parameters at /sitecore/templates/My Site/Forms/Contact Us Form Rendering Parameters. You should always inherit custom rendering parameters from /sitecore/templates/ScoreUI/Base/Rendering Parameters/Base Component. This allows for our form to use SCORE’s Show/Hide feature out of the box.

I’ve added one additional field to my Contact Us Form rendering parameters:

 

Rendering Parameters

 

Now, the query here is important. This query allows us to select out our styles from our tenant’s selections folder. My query looks like this:

query:#selections#*[@@templateid='{FB02DA7F-D050-4452-B008-AE2C46FB1319}']/*

What’s critical to note here is that my Contact Us Form Styles template has an ID of {FB02DA7F-D050-4452-B008-AE2C46FB1319}. The #selections# token in the query gets replaced dynamically by SCORE’s pre-scaffolded Mappable Queries rule (under Component Datasource Locations).

 

Some Code

Now that we have two templates, let’s add some code so that we can use the power of strong typing.

public class ContactDatasource : ScoreUIItem
{
    // be sure this matches your template's ID
    public static readonly ID Template = new ID("{5E1AFEBC-CB85-4A47-AB20-B53E47626D7A}");
 
    public static class Fields
    {
        public const string NameRequiredError = "Name Required Error";
        public const string NameFormatError = "Name Format Error";
        public const string NameLabel = "Name Label";
 
        public const string EmailRequiredError = "Email Required Error";
        public const string EmailFormatError = "Email Format Error";
        public const string EmailLabel = "Email Label";
 
        public const string CommentsLengthError = "Comments Length Error";
        public const string CommentsRequiredError = "Comments Required Error";
        public const string CommentsLabel = "Comments Label";
    }
 
    public ContactDatasource(Item item) : base(item)
    {
    }
 
    public static bool TryParse(Item item, out ContactDatasource datasource)
    {
        datasource = item == null || item.IsDerived(Template) == false ? null : new ContactDatasource(item);
        return datasource != null;
    }
 
    #region implicit casting
    public static implicit operator ContactDatasource(Item innerItem)
    {
        return innerItem != null && innerItem.IsDerived(Template) ? new ContactDatasource(innerItem) : null;
    }
 
    public static implicit operator Item(ContactDatasource customItem)
    {
        return customItem != null ? customItem.InnerItem : null;
    }
    #endregion
}

 

So, a few things to note…

  1. We inherit from ScoreUIItem. This class inherits from CustomItem and exposes a few helpers.
  2. We expose our fields as constants to avoid magic strings elsewhere.
  3. We expose our template’s ID.
  4. We allow casting to and from this item from a generic Sitecore Item.

At a minimum, you should always wrap your custom datasources in classes and provide functionality similar to what you see here.

Now, for some rendering parameters:

public class ContactRenderingParameters : BaseComponentParameters
{
    public static class Fields
    {
        public static string ContactFormStyle = "Contact Form Style";
    }
 
    public override void LoadRenderingParameters(Rendering rendering)
    {
        base.LoadRenderingParameters(rendering);
        this.ClassSelection = rendering.Parameters.GetUserFriendlyValue(Fields.ContactFormStyle);
    }
}

 

Remember when we made our rendering parameter’s template inherit from SCORE’s Base Component Parameters? We do the same here for our custom class. This will enable show/hide on our component. To pull out our Content Assembler’s custom Form Style selection, we utilize SCORE’s “GetUserFriendlyValue” extension when overriding the LoadRenderingParameters function. Class selection, Show/Hide selections and the rendering model’s default class will all get aggregated into @Model.Classes for usage in our HTML.

I stick both of these classes in the Data project of my default SCORE solution. You can stick them wherever it makes sense for you!

 

The Web Layer

Now, in our web layer we need a few things.

First off, we’re creating a Form, so we’ll need a controller to submit to. Mine looks like this:

 

public class ContactController : SitecoreController
{
    private IContactService contactService;
 
    public ContactController(IContactService contactService)
    {
        this.contactService = contactService;
    }
 
    [HttpPost]
    public ActionResult ContactFormSubmit(ContactRenderingModel model)
    {
        if (!ModelState.IsValid)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            Response.TrySkipIisCustomErrors = true;
 
            var errors =
                ModelState.Where(v => v.Value.Errors.Count > 0)
                    .Select(x => new {Name = x.Key, Message = x.Value.Errors[0].ErrorMessage});
 
            // grab your form errors and send them to JS here
            return new JsonResult() { Data = errors };
        }
        else
        {
            Response.StatusCode = (int)HttpStatusCode.OK;
            contactService.ProcessSubmission(model.Email, model.Name, model.Comments);
 
            // return anything you need to your JS here.
            return new JsonResult() {};
        }
    }
}

 

Notice that I’m using Dependency Injection to inject an instance of IContactService into my controller. This is not required, but it’s something I always set up and use. You can follow along with how to do that yourself at http://jockstothecore.com/adventures-in-dependency-injection/.

It’s also worth noting that we have a POST method. If you want a corresponding GET, you can set up your component as a Sitecore Controller Rendering, but I’ll probably just use a View Rendering.

My service is simple; at this point it’s just C#:

 

public interface IContactService
{
    void ProcessSubmission(string email, string name, string comment);
}
 
public class ContactService : IContactService
{
    public void ProcessSubmission(string email, string name, string comment)
    {
        // process the form submission here. from here on out it's just C#.NET, right? 🙂
 
        return;
    }
}

 

Now this is where it gets a little bit interesting. We need to use a View Model to hold our Form inputs for posting to the server, and this View Model needs to be able to validate itself and expose error messages according to what our content authors provide. In Sitecore, we like to call these “Rendering Models.” Mine looks like this:

 

public class ContactRenderingModel : RenderingModelBase<ContactRenderingParameters, ContactDatasource>
{
    public ContactRenderingModel() : base("contact-form") { }
 
    [SitecoreRequired(ContactDatasource.Fields.NameRequiredError)]
    [SitecoreRegularExpression("[a-zA-Z ,.'-]*", ContactDatasource.Fields.NameFormatError)]
    [SitecoreDisplayName(Key = ContactDatasource.Fields.NameLabel)]
    public string Name { get; set; }
 
    [SitecoreRequired(ContactDatasource.Fields.EmailRequiredError)]
    [SitecoreRegularExpression(@".+\@.+\..+", ContactDatasource.Fields.EmailFormatError)]
    [SitecoreDisplayName(Key = ContactDatasource.Fields.EmailLabel)]
    public string Email { get; set; }
 
    [SitecoreRequired(ContactDatasource.Fields.CommentsRequiredError)]
    [SitecoreStringLength(500, ContactDatasource.Fields.CommentsLengthError)]
    [SitecoreDisplayName(Key = ContactDatasource.Fields.CommentsLabel)]
    public string Comments { get; set; }
 
    protected override ContactDatasource InitializeDatasource(Item item)
    {
        ContactDatasource datasource;
        if (ContactDatasource.TryParse(item, out datasource))
        {
            return datasource;
        }
        return null;
    }
}

 

There’s a few things going on here that you should pay attention to:

  1. We’re inheriting from RenderingModelBase. This is the mechanism we use to tie our custom Rendering Parameters and Datasource to our Rendering Model.
  2. We call our Base Constructor and pass in a string. This string will expose itself in @Model.Classes in our view.
  3. We use SitecoreRequired, SitecoreStringLength, SitecoreDisplayName, etc. All of these wrap up normal ASP.NET MVC annotations that you would use in a vanilla MVC site. If you dig around in the SCORE documentation you will find a whole slew of available options.
  4. During initialization of the Datasource, we ensure that it’s a Contact item. If it’s not, bad things may happen (like unhandled exceptions). You should handle these scenarios appropriately.

Next, we need a View. I’ve set mine up like this:

 

@model Namespace.To.Your.Tenants.ContactRenderingModel
 
@{
    var formId = Guid.NewGuid().ToString("N");
}
 
@using (Html.BeginUXModule("mysite/Components/ContactForm",
    new
    {
        IsEditing = Sitecore.Context.PageMode.IsExperienceEditorEditing,
        FormId = formId
    },
    new {@class = Model.Classes}))
{
    Html.EnableClientValidation();
    Html.EnableUnobtrusiveJavaScript();
 
    using (Ajax.BeginRouteForm("ContactFormSubmit",
        new
        {
            scItemPath = Model.Datasource.ID
        },
        new AjaxOptions()
        {
            HttpMethod = "POST"
        },
        new {id = formId}))
        {
            <div class="custom-form-control-group custom-form-nickname">
                <div class="custom-form-label">
                    @Html.EditableLabelFor(m => m.Name)
                </div>
                <div class="custom-form-control">
                    @Html.TextBoxFor(m => m.Name)
                </div>
                @Html.EditableValidationMessageFor(m => m.Name)
            </div>
            <div class="custom-form-control-group custom-form-email">
                <div class="custom-form-label">
                    @Html.EditableLabelFor(m => m.Email)
                </div>
                <div class="custom-form-control">
                    @Html.TextBoxFor(m => m.Email)
                </div>
                @Html.EditableValidationMessageFor(m => m.Email)
            </div>
            <div class="custom-form-control-group custom-form-comments">
                <div class="custom-form-label">
                    @Html.EditableLabelFor(m => m.Comments)
                </div>
                <div class="custom-form-control">
                    @Html.TextAreaFor(m => m.Comments)
                </div>
                @Html.EditableValidationMessageFor(m => m.Comments)
            </div>
            <button type="button" class="contact-form-button">Go!</button>
        }
    }

 

So, there’s a lot going on here, some of which may be new to you. First off, Html.BeginUXModule is a SCORE helper that ties your component to a JavaScript module. In SCORE, JavaScript modules are organized via Require.JS. This method supports three very important arguments:

  1. The Require.JS path of the JavaScript module to load into the DOM.
  2. Any arguments you want to path to that Module. Here I am passing two: IsExperienceEditorEditing, and the ID that I’ll use for my form. You should probably always pass IsExperienceEditorEditing because you often times don’t want rogue JavaScript executing from Experience Editor.
  3. Any attributes you want to pass to your wrapping DIV. BeginUXModule creates a DIV in the DOM, and anything specified in the third argument will be an attribute there.

Now, within my UXModule I have some divs that wrap up my fields. Notice how I stick unique CSS classes on almost everything? It’s because I love my UI developers. If you don’t do this, they’ll have a hard time styling your components, and will generally loathe you. Did I overkill it here? Probably, but burnt chicken is better than raw chicken.

For my Form, I’m using an Ajax Form. To know where to submit to, it’s going to look in my route table for a route named “ContactFormSubmit” and it’s going to be passing something called scItemPath. We’ll set this up in a second, as these are two very crucial pieces that make any form work.

The only other magic in here are the custom HTML extensions provided by SCORE: @Html.EditableValidationMessageFor(m => m.Name), and @Html.EditableLabelFor(m => m.Name). These behave JUST like the native MVC methods, except they work with the attributes from our Rendering Model to allow the content author to edit the text in experience editor. Nifty, right?

In order to resolve that Require.JS JavaScript path in the @Html.BeginUXModule, we need to navigate to our tenant’s require.config.js and add in this setting:


window.require.paths.mysite = "/Areas/MySite/js";

 

Speaking of JavaScript and Require.JS, here’s what I’ve got:

 

define([
    "jquery",
    "underscore",
    "jqueryvalidate",
    "unobtrusiveajax"
],
function ($, _) {
    function ContactForm(scope, formId) {
        var $form = $("#" + formId, scope);
        var validator = $form.validate();
 
        function submitForm() {
            var action = $form.attr("action");
            var type = $form.data("ajax-method");
            var formData = $form.serialize();
 
            $.ajax({
                url: action,
                type: type,
                data: formData
            }).fail(function(response) {
                if (response.status === 400) {
                    var data = response.responseJSON;
                    var errors = {};
                    for (var i = 0; i < data.length; i++) {
                        errors[data[i].Name] = data[i].Message;
                    }
 
                    $form.data('validator').showErrors(errors);
                }
            });
        }
 
        $(".contact-form-button").on('click', function (event) {
            event.preventDefault();
            submitForm();
        });
    }
 
    return function init(args) { 
        return args.IsEditing === true ? null : new ContactForm(args.scope, args.FormId);
    }
})

 

This should be pretty straightforward if you’re familiar with JavaScript and Require.JS. If not, I highly recommend taking a crash course in Require.JS, as it’s used pretty heavily in SCORE UI. What’s happening here is that the SCORE Module Loader is responsible for initializing any component that uses @HTML.BeginUXModule. The Module Loader will then find the required JavaScript module, call the function returned from the module and pass in an argument object. This argument object will have any custom arguments that you passed to your module (in our case, IsEditing and FormId) as well as a custom “scope” item. This scope item can be used in jQuery selections so that your jQuery DOM selections are scoped to your component. Notice how I initialize the module if the page is in normal mode, but I do not if it’s in editing mode.

Also, in order to be able to submit to “ContactFormSubmit”, we need to go into our Area configuration and set it up as a route:

 

public class MySiteAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get
        {
            return "MySite";
        }
    }
 
    public override void RegisterArea(AreaRegistrationContext context)
    {
        // Register your MVC routes in here
 
        context.MapRoute("ContactFormSubmit", "contactformsubmit/{*scItemPath}", new
        {
            controller = "Contact",
            action = "ContactFormSubmit",
            scItemPath = "{*scItemPath}"
        });
    }
}

 

So what’s this scItemPath thing? You shouldn’t have to worry about it too much, but I like to think of it as how Sitecore knows what the context is during a Post. You can read more about it here: http://jockstothecore.com/to-the-controller-and-back-part-1-routing/

The last piece we need to make this form component work is a Rendering. Keep in mind that I set up Dependency Injection in my solutions (you probably should, too!), so if you use a controller rendering + dependency injection, you would call out your controllers in a slightly different way (via Convention rather than fully qualified). For this post, however, I’m just going to use a View Rendering. It’s the same method as in our last post, except I’m calling out our custom rendering parameters and custom datasource in the appropriate fields. View Renderings also require a custom Sitecore Model to go with them. This Sitecore model should point back to your ContactRenderingModel.

Of course, we will allow this Rendering to be placed in any Nested Content Area for our tenant. You remember how to do that from the previous post, right? 😉

So now, when we insert this form into the page, it should look like this:

 

View Rendering for Form Component

Notice how our labels and error messages are editable by the content author?! Normally, I would make the button editable, too, but I didn’t bother because we’re going to remove the button in the next post. 🙂

 

Ta-da: Our Form Component!

 

Here’s the final product in action!
Form Component

 

Ready to try your hand at building form components? Let me know how it goes!

The post SCORE 2.0 Component Assembly 101, Part 2: Form Components appeared first on JocksToTheCore.

Background to Foreground Image Solution for Responsive Web Development

$
0
0

Proper design plays a key role when it comes to the topic of responsive web design (RWD). But sometimes we don’t have the luxury of a flushed out design to begin with. We often have to manage and make practical use of the assets in hand, and in some cases, background images can become a problem for smaller screens.

I’m typically tasked with turning a fixed-pixel site into a fully responsive site, which often involves lots of thought and understanding of what should/can be accomplished. Add a CMS with big muscles to the equation and it gets complicated very quickly.

 

Problem with text over background images

There is a problem we face with background images that have text layered on top of them. They typically work fine for desktop/laptop screens, but can often become illegible on smaller mobile screens. Here’s an example on a desktop screen:

screenshot-desktop

It looks good…but then there’s the mobile screen:

screenshot-mobile

Ain’t nobody got time for that!

 

The overlay effect

So, what if we were to create some kind of overlay effect over the entire image which would make the text legible? Something like this (mobile screen):
screenshot-mobile-overlay

It’s looking much better. But…what if the brand you’re working on has bright, vivid imagery that is compromised with dark overlays in order to contrast the text?

 

Practical solution

I’ve recently found a decent solution for this issue. Using media queries, let’s just switch out the background image with a foreground image. Here’s the desktop screen with background image:

 

screenshot-desktop

 

And, voilà! Here’s a mobile screen with foreground image implemented — 100% responsive — and both text and the image now have great visual clarity:

 

screenshot-final

 

Nothing ground breaking here, but it serves its purpose well. Let me explain first, and then I will demonstrate.

You may know that BrainJocks is a team of Sitecore specialists. You also may be familiar with or even be using BrainJocks SCORE, our modular development framework. SCORE includes a library comprised of reusable components, most of which are based on Twitter Bootstrap’s framework (as a default starting point). I’ve used one of our content components here, called a SCORE Hero, but this implementation isn’t tied to any one component (in this case).

Whether you’re combining SCORE components to form the necessary markup for this procedure or simply writing plain HTML outside of our realm, this little technique may benefit your cause.

 

How to do it

Step 1: You need a wrapper with a background image (desktop-version.jpg) in place. In this example I am using a “score-hero” component with a class of “cover” that positions the background image size to cover in CSS. This will serve as our desktop implementation. (Note: we place background images in an inline style so that content administrators have the ability to switch out images within the DOM.)

Step 2: You need an img tag in the foreground (mobile-version.jpg). This will serve as our mobile version.

Step 3: Your text and link, of course…

Given the content component we’ve decided to use for this example, our admin selects a Hero component in the Experience Editor and populates the content with both background image (on the wrapper) and foreground image, as well as text and link.

So, what we need here are two images and one component. This is the HTML that is generated from SCORE:



<div class="score-hero cover" style="background-image: url('../img/desktop-version.jpg');">
  <div class="score-hero-image">
    <img src="../img/mobile-version.jpg" alt="#">
  </div>
  <h1>Hero Header</h1>
  <div class="score-hero-body">
    Hero body text. Lorem ipsum dolor sit amet. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </div>
  <div class="score-call-to-action">
    <a href="/" class="score-button">Button</a>
  </div>
</div>


 

So, visually, we now have something that looks like this for mobile:

 

screenshot-mobile-incomplete

 

And it looks this for desktop:

 

screenshot-desktop-incomplete

Time to style it.

Step 4: You need to replace the background image with a background color for mobile screens only. Now, remember, we’re using an inline style for the background image, which means we need to use the ugly “!important” for the proper override in this case. If you’re not concerned with the need for an inline style here, then you can simply cascade your overriding media query style for the image to color replacement. (Note: we are using Bootstrap’s default variable “$screen-xs-max” for the pixel size since our platform is based on Bootstrap.)

SCSS:

 

.score-hero {
    @media only screen and (max-width: $screen-xs-max) {
        background: rgba(0, 0, 0, 0.8) !important;
    }
}

 

Compile…and now mobile screens up to 767px wide now look like this:

 

screenshot-final

 

Step 5: Next, you need to set the foreground image to “display: none;” to hide it on desktop. In this case, I’m setting it to “display: block;” only for extra small screens. So easy!

SCSS:

 

.score-hero {
    @media only screen and (max-width: $screen-xs-max) {
        background: rgba(0, 0, 0, 0.8) !important;
    }
    .score-hero-image {
        display: none;
        img {
            width: 100%;
        }
        @media only screen and (max-width: $screen-xs-max) {
            display: block;
        }
    }
}

 

Compile…and now screens above 768px wide look like this:

(768px – Bootstrap default for $screen-sm)

 

screenshot-768

 

(992px – Bootstrap default for $screen-md)

 

screenshot-992

(1200px – Bootstrap default for $screen-lg)

screenshot-desktop

Final code used in styling this demo

SCSS (for score-hero):
_site-heroes.scss (SCORE users)

.score-hero {
    @extend .jumbotron; //inherit bootstrap
    @include vertical-space($vertical-spacing);
    overflow: hidden; //to crop foreground image for border-radius
    @media only screen and (max-width: $screen-xs-max) {
        background: rgba(0, 0, 0, 0.8) !important;
        padding-top: 0;
    }
    @media only screen and (min-width: $screen-sm-min) {
        text-align: right;
    }
    .score-hero-image {
        display: none;
        img {
            width: 100%;
        }
        @media only screen and (max-width: $screen-xs-max) {
            display: block;
            margin-left: -15px;
            margin-right: -15px;
        }
    }
    h1 {
        color: #fff;
    }
    .score-hero-body {
        color: #aaa;
        margin-bottom: 30px;
        p {
            @media only screen and (min-width: $screen-sm-min) {
                width: 50%;
                float: right;
            }
        }
    }
    .score-call-to-action {
        clear: both;
        a {
            font-size: 10px;
            font-weight: bold;
            text-transform: uppercase;
        }
    }
}

 

SCSS (for “.cover” class with all components that accept background images):
_site-background.scss (SCORE users)

 

.score-stripe, .score-style-box, .score-carousel-pane, .score-full-width-hero, .score-hero, .score-section-header, .score-well {
    &.cover {
        background-position:center center;
        background-repeat:no-repeat;
        background-size:cover;
    }
    &.contain {
        background-repeat:no-repeat;
        background-size:contain;
    }
    &.repeat {
        background-repeat:repeat;
    }
    &.repeat-x {
        background-repeat:repeat-x;
    }
    &.repeat-y {
        background-repeat:repeat-y;
    }
}

 

There’s one more step when we’re using SCORE. In “experience editor” mode we’ll need to override our “display: none;” for the “.score-hero-image” to “display: block;” at all times in page_editor.scss. Why? Your content admins need to be able to see the foreground image that will be used in Experience Editor. Without this overriding page editor style, they will lack the capability to insert or even switch out the image.

SCSS (for experience editor/page editor override):
page_editor.scss (SCORE users)

 

.score-hero {
    .score-hero-image {
        display: block;
    }
}

 

Compile, and now page-editor.css cascades after main.css to override the “display: none;” on the hero image. Here’s a demo.

Super easy, right?

 

The post Background to Foreground Image Solution for Responsive Web Development appeared first on JocksToTheCore.

Viewing all 149 articles
Browse latest View live