Skip to content

Interactive Resource Editing

Rick Strahl edited this page Apr 12, 2015 · 23 revisions

Westwind.Globalization supports resource editing on source HTML pages by providing optional links in these pages to link directly to the referenced resources in the Web based resource editor. Essentially resource icons are added to all HTML elements that include a data-resource-id element, which in turn highlights the specified element with a clickable icon, that when clicked opens the localization admin form with the specified resource highlighted:

Resource Edit View adds clickable icons

When you click any of the red flags, a new window opens with the resource editor pre-set on the selected resource if one is matched.

Usage

To mark elements in your Web Page for editing you need to mark them up with two supported elements:

  • data-resource-id The specific resource id of the element to link to. This attribute needs to be attached to any element that is associated with the resource.

  • data-resource-set The resource set that that resource belongs to. This can be declared on the same element as the Id or anywhere in the parent element hierarchy. The library searches up the tree to the nearest resource-set reference found.

In practice you typically declare the resource set at the <body> or some view level top level element and resource ids for each element to display. Here's what this might look like:

<body data-resource-set="LocalizationForm">
   <div class="page-title" 
        data-resource-id="PageTitle">
     @DbRes.T("PageTitle")
   </div>

   <-- if you have non-wrapped text you can add a <span> tag -->
   <span data-resource-id="HelloWorld">@Resources.HelloWorld</span>
</body> 
Enabling Resource Links

In order to get the resource icons to load you need to load the following JavaScript library:

<script src="localizationAdmin/scripts/ww.resourceEditor.js"></script>

When you're ready to load the editing icons:

ww.resourceEditor.showResourceIcons({ adminUrl: "./" });

You have to provide an adminUrl which points at the resource editor and defaults to ./localizationAdmin/. This assumes the root of the project with the localization admin form in its default folder. Once you run the above commands the resource editing icons start showing up.

When you want to hide the icons you can use:

ww.resourceEditor.removeResourceIcons();
CSS and FontAwesome

You'll also need some CSS that determines how any editable icons display. FontAwesome is used for the flag icon, but you can change that if you're not using FontAwesome already.

<link href="./LocalizationAdmin/bower_components/fontawesome/css/font-awesome.min.css"
      rel="stylesheet"/>

<style>
.resource-editor-icon, .resource-editor-icon:hover,  .resource-editor-icon:visited {
    position: absolute;
    display: inline;
    height: 13px;
    width: 13px;     
    text-decoration: none;
    zIndex: 999999;
    opacity: 0.65;
    margin: -14px 0 0 -2px;
    cursor: pointer;
}
.resource-editor-icon:hover {
    opacity: 1;         
}
.resource-editor-icon:before {
    font-family: fontawesome;
        content: "\f024"; /* flag */
        font-size: 9pt;
        color: red;
}
</style>

How it works

This resource editing mechanism is based on a client side JavaScript implementation that checks for specific attributes on DOM elements and then injects icons into the HTML document to provide clickable links that open the Resource Editor with the selected resources active.

Attribute based Resource Identification

The icons are attached to HTML elements that have a specific data-resource-id attribute. In addition a data-resource-set attribute has to exist to identify the resource set, either on the same HTML element or at an element along the parent DOM tree.

On typical pages you'll have a set up like this:

<body data-resource-set="LocalizationForm">
   <div class="page-title" 
        data-resource-id="PageTitle">
     @DbRes.T("PageTitle")
   </div>

   <-- if you have non-wrapped text you can add a <span> tag -->
   <span data-resource-id="HelloWorld">@Resources.HelloWorld</span>
</body> 

The data-resource-id attribute can be attached to any element. In the example above the first element is already wrapped into a <div> tag and so I can simply attach the attribute to the parent. In the second example the text originally was just plain free standing text without any wrapping element - I added a <span> tag around the element to allow attaching of the data-resource-id attribute.

Since the logic is based on pure HTML and JavaScript, this mechanism works with any server side as well as any client side technology. Above I'm using DbRes.T() and strongly typed resources. You could also use this approach in WebForms pages (although in WebForms you can arguably use controls and meta-resource tags more easily).

For client side code the usage is still the same. For example the following uses AngularJs binding expressions and the usage of the attributes is identical:

<li>
    <a ng-show="view.resourceSets && view.resourceSets.length > 0"
        data-toggle="modal" data-target="#CreateClassDialog"
        title="{{view.resources.CreateClass_Title}}"
        data-resource-id="CreateClass">
        <i class="fa fa-code" style="font-weight: bold;"></i> {{::view.dbRes('CreateClass')}}
    </a>
</li>
<li>
    <a ng-show="view.resourceSets && view.resourceSets.length > 0"
        ng-click="view.onReloadResourcesClick()"
        title="{{view.dbRes('ReloadResources_Title')}}"
        data-resource-id="ReloadResources">
        <i class="fa fa-refresh"></i> {{::view.dbRes('ReloadResources')}}
    </a>
</li>

Again notice the data-resource-id attributes in both of the elements.

As you can see this approach requires an extra attribute to be added to map the resource id to a clickable icon.

What gets generated

Behind the scenes this library runs through the document and essentially injects DOM elements into the page that represent the icons. The icons are overlaid ontop of the existing DOM element as a small semi-transparent icon that is clickable.

The actual rendered runtime HTML for one of the icons and it's host element looks like this:

<!-- injected element -->
<res-edit class="resource-editor-icon" 
          target="resourceEditor" 
          title="Edit resource" 
          onclick="window.open('./?ResourceSet=LocalizationForm&amp;ResourceId=Add','resourceEdit')" 
          style="top: 0px; left: 0px;"></res-edit>

 <!-- original element -->
 <button class="btn btn-sm btn-default ng-binding" 
         title="Add new ResourceSet" 
         ng-click="view.onAddResourceClick()" 
         data-resource-id="Add">
    <i class="fa fa-plus"></i> Add
</button>

Why a <res-edit> tag? I used a custom tag name to avoid any CSS bleed issues with links or div tags. I had originally used an anchor tag, but I ran into formatting problems as CSS formatting for links would affect the rendering. Using a custom tag minimizes - but doesn't entirely remove - these problems.

Enabling/Disabling Edit Mode

In typical applications you'll want to provide resource edit links only in special admin modes and even then only when you explicitly decide to edit resources. Otherwise the icons just get in the way.

For this reason the icons are not visible by default and you have to explicitly call the ShowResourceIcons function.

Inside of the LocalizationAdmin form I enable and disable resource editing with two menu options which are alternately displayed or hidden depending on the state of a view variable in the AngularJs model.

Here's what the click code that is called from either of those buttons looks like to enable and disabling resource editing:

vm.showResourceIcons = function () {
    vm.resourceEditMode = !vm.resourceEditMode;
    if (vm.resourceEditMode)
        ww.resourceEditor.showResourceIcons({ adminUrl: "./" });
    else
        ww.resourceEditor.removeResourceIcons();
};

You can check out this behavior in the actual Localization Admin form which is localizable and then links to itself in edit mode.

Clone this wiki locally