-
-
Notifications
You must be signed in to change notification settings - Fork 134
Interactive Resource Editing
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 and a data-resource-set
attribute on any parent 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:
This is the Web Resource Editor with Resource Editing Links enabled (how very meta of me, huh?). When you click any of the red flags, a new window opens with another copy of the Resource Editor (without edit flags) pre-set on the selected resource set and resource id if one is matched. If no match is found the Add Resource window is opened instead. In effect if you have the right markup in the page any HTML page can be made to link to the resource editor.
In order for elements in your Web Page to be linked for resource editing you need to mark them up with two supported attributes:
-
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 the resource belongs to. This can be declared on the actual element or anywhere in the parent element hierarchy. The library searches up the tree to find the nearest data-resource-set attribute and uses its value.
In practice you typically declare data-resource-set
at the <body>
or some wrapper 'view-level' element and data-resource-id
on each element to display the icon on. Here's what this might look like in an ASP.NET MVC based view:
<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>
Clicking on any of these resource links causes a lookup for the LocalizationForm resource set and the PageTitle and HelloWorld resource ids respectively.
For WebForms there's a special DbResourceControl that automatically generates the resource link for most Web Controls so you don't have to explicitly set the attributes.
Note, that the resource editing tags are not directly tied to ASP.NET resources. They are processed on the client side and generate links to the resource editor form, so they can be dropped onto any HTML elements.
For example the Resource Editor Form doesn't use server side HTML at all but rather uses AngularJs for all of its UI generation. You can still use the data-resource-id
and data-resource-set
tags on the client side content:
<div>
<p data-resource-id="CreateClassInfo">
{{::view.resources.CreateClassInfo}}
</p>
<p data-resource-id="CreateClassInfo2">
{{::view.resources.CreateClassInfo2}}
</p>
</div>
In this example, the database resources are fed to JavaScript using strongly typed resources from the JavaScriptResourceHandler and it works just as well for these resources as long as the id's correlate to the database resource ids.
In order to get the resource icons to load you need to load ww.resourceEditor.js library. The library has a dependency on jQuery so you first need to load jQuery if your application doesn't already load it. You can use a CDN link or your local copy, or use the copy provided by the LocalizationAdmin application:
<script src="LocalizationAdmin/bower_components/jquery/dist/jquery.min.js"></script>
Next add the actual ww.resourceEditor.js script:
<script src="localizationAdmin/scripts/ww.resourceEditor.js"></script>
When you're ready to actually display the editing icons make a call to showResourceIcons()
:
ww.resourceEditor.showResourceIcons({ adminUrl: "./LocalizationAdmin/" });
You have to provide an adminUrl which points at the resource editor and defaults to ./LocalizationAdmin/
. This URL is used to generate the target links when you click on the resource links. The URL is appended with query string values for ResourceSet
,ResourceId
and Content
which are used to look up or add new resources to the Web Resource Editor. Content is used if a resource cannot be found and is passed using the inner text of the control that data-resource-id
is bound to as long as it doesn't exceed 500 characters (due to URL length limitations).
When you want to hide the icons to turn off editing, you can use:
ww.resourceEditor.removeResourceIcons();
Typically you use these two methods from buttons somewhere in your UI, that enable or disable resource editing, so this code is fired typically from a button click or other user action of some sort.
You'll also need some CSS that determines editable icons display. By default FontAwesome is used for the flag icon, but you can change that by modifying the .resource-editor-icon:before
style and removing the FontAwesome font reference and changing the character displayed to a standard character (like a # for example):
<!-- optional - if you don't use change the CSS to display plain character -->
<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;
margin: -14px 0 0 -2px;
cursor: pointer;
opacity: 0.45;
}
.resource-editor-icon:hover {
opacity: 1;
}
.resource-editor-icon:before {
font-family: fontawesome;
content: "\f024"; /*flag*/
/*font-family: Arial;
content: "#";*/
font-size: 9pt;
color: red;
}
</style>
You can add the style to individual pages or to a global style sheet.
This resource editing mechanism is based on a client side JavaScript implementation that checks for specific attributes on DOM elements and then injects icon overlays into the HTML document to provide clickable links that open the Resource Editor with the selected resources active.
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 on an HTML page. 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 as an example here to embed the actual values.
In ASP.NET WebForms pages that use meta:resourcekey
tags you can use a DbResourceControl that can automatically generate the data-resource-id
and data-resource-set
attributes for any WebControls on the page so you don't have to manually create the attributes.
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.
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&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. The CSS uses absolute positioning with a high zIndex value and opacity to overlay existing content so the impact of the icons should be minimal.
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, as well as causing overhead in their generation into the page.
For this reason the icons are not visible by default and you have to explicitly call the ShowResourceIcons() function.
For example, in the LocalizationAdmin edit 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:
// initial state
vm.showResourceIcons = false;
// toggle handler from menu option or button typically
vm.showResourceIcons = function () {
vm.resourceEditMode = !vm.resourceEditMode; // toggle mode
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.
Resource editing with linkable resources is very useful in dynamic applications that allow editing of content for localization (as well as basic content editing). Although it requires a little bit of setup, plus adding extra attributes onto content, this feature provides an easy way to make applications dynamically editable for localization. The DbResourceControl for WebForms provides an even easier approach as most WebControls can automatically be linked for resource editing.
-
Interactive Resource Editing with WebForms
for more information on how you can automate generation of the data-resource-id tags without explicitly having to enter the attributes. -
Server Side Resources for JavaScript with JavaScriptResourceHandler
lets you use ASP.NET Resources in client side only JavaScript application by serving Server side resources as JavaScript resource objects to the client.