Skip to content

Commit

Permalink
Just push the changes of our-self-host and revert the out of sync cha…
Browse files Browse the repository at this point in the history
…nges
Warren Buckley committed May 12, 2023
1 parent adc7980 commit c99c6a1
Showing 1 changed file with 134 additions and 59 deletions.
193 changes: 134 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Our Umbraco TagHelpers
A community project of C# ASP.NET TagHelpers for the Open Source CMS Umbraco

A community project of C# ASP.NET TagHelpers for the Open Source CMS Umbraco

## Installing

Add the following Nuget Package to your Umbraco website project `Our.Umbraco.TagHelpers` with Visual Studio, Rider or with the dotnet CLI tool as follows when inside the directory with the .CSProj file for the Umbraco website project.

```
@@ -14,34 +15,39 @@ dotnet add package Our.Umbraco.TagHelpers

With the Nuget package added you need to register the collection of TagHelpers for Razor views and partials to use them.
Browse to `/Views/_ViewImports.cshtml` in your Umbraco project and add the following line at the bottom

```cshtml
@addTagHelper *, Our.Umbraco.TagHelpers
```

## `<our-dictionary>`

This is a tag helper element `<our-dictionary>` that will use the current page's request Language/Culture to use a dictionary translation from the Umbraco translation section.

* Find dictionary key
* Find translation for Current Culture/Language of the page
* If no translation found see if we have fallback attribute set fallback-lang or umb-dictionary-fallback-lang
* Attempt to find dictionary item for that ISO language fallback
* No translation found - leave default/value inside tag untouched for final fallback
- Find dictionary key
- Find translation for Current Culture/Language of the page
- If no translation found see if we have fallback attribute set fallback-lang or umb-dictionary-fallback-lang
- Attempt to find dictionary item for that ISO language fallback
- No translation found - leave default/value inside tag untouched for final fallback

```cshtml
<h3><our-dictionary key="home">My Header</our-dictionary></h3>
<h3><our-dictionary key="home" fallback-lang="da-DK">My Header</our-dictionary></h3>
```

## `our-if`

This is a tag helper attribute that can be applied to any DOM element in the razor template or partial. It will include its element and children on the page if the expression inside the `our-if` attribute evaluates to true.

### Simple Example

```cshtml
<div our-if="(DateTime.UtcNow.Minute % 2) == 0">This will only render during <strong>even</strong> minutes.</div>
<div our-if="(DateTime.UtcNow.Minute % 2) == 1">This will only render during <strong>odd</strong> minutes.</div>
```

### Example Before

```cshtml
@if (Model.ContentPickerThing != null)
{
@@ -57,6 +63,7 @@ This is a tag helper attribute that can be applied to any DOM element in the raz
```

### Example After

```cshtml
<a our-if="Model.ContentPickerThing != null" href="@Model.ContentPickerThing?.Url()" class="btn btn-action">
<span>@Model.ContentPickerThing.Name</span>
@@ -65,6 +72,7 @@ This is a tag helper attribute that can be applied to any DOM element in the raz
```

## `<our-macro>`

This tag helper element `<our-macro>` will render an Umbraco Macro Partial View and will use the current page/request for the Macro rendering & context.

If you wish, you can modify this behaviour and pass the context/content node that the Macro will render with using an optional attribute `content` on the `<our-macro>` tag and passing an `IPublishedContent` into the attribute. This allows the same Macro Partial View Macro code/snippet to work in various scenarios when the content node/context is changed.
@@ -81,11 +89,13 @@ So to pass/set a value for the macro parameter `startNodeId` then I will need to
```

## BeginUmbracoForm Replacement

This is to make it easier to create a HTML `<form>` that uses an Umbraco SurfaceController and would be an alternative of using the `@Html.BeginUmbracoForm` approach. This taghelper runs against the `<form>` element along with these attributes `our-controller`and `our-action` to help generate a hidden input field of `ufprt` containing the encoded path that this form needs to route to.

https://our.umbraco.com/Documentation/Fundamentals/Code/Creating-Forms/

### Before

```cshtml
@using (Html.BeginUmbracoForm("ContactForm", "Submit", FormMethod.Post, new { @id ="customerForm", @class = "needs-validation", @novalidate = "novalidate" }))
{
@@ -112,6 +122,7 @@ https://our.umbraco.com/Documentation/Fundamentals/Code/Creating-Forms/
```

### After

```cshtml
<form our-controller="ContactForm" our-action="Submit" method="post" id="customerForm" class="fneeds-validation" novalidate>
<div asp-validation-summary="All"></div>
@@ -137,12 +148,14 @@ https://our.umbraco.com/Documentation/Fundamentals/Code/Creating-Forms/
```

## `<our-lang-switcher>`

This tag helper element `<our-lang-switcher>` will create a simple unordered list of all languages and domains, in order to create a simple language switcher.
As this produces alot of HTML markup that is opionated with certain class names and elements, you may wish to change and control the markup it produces.
As this produces alot of HTML markup that is opionated with certain class names and elements, you may wish to change and control the markup it produces.

With this tag helper the child DOM elements inside the `<our-lang-switcher>` element is used as a Mustache templating language to control the markup.

### Example

```cshtml
<our-lang-switcher>
<div class="lang-switcher">
@@ -165,6 +178,7 @@ With this tag helper the child DOM elements inside the `<our-lang-switcher>` ele
```

If you do not specify a template and use `<our-lang-switcher />` it will use the following Mustache template

```mustache
<ul class='lang-switcher'>
{{#Languages}}
@@ -177,20 +191,22 @@ If you do not specify a template and use `<our-lang-switcher />` it will use the
</ul>
```


## `<our-svg>`

This tag helper element `<our-svg>` will read the file contents of an SVG file and output it as an inline SVG in the DOM.
It can be used in one of two ways, either by specifying the `src` attribute to a physcial static file served from wwwRoot or by specifying the `media-item` attribute to use a picked IPublishedContent Media Item.

### Basic usage:

```cshtml
<our-svg src="/assets/icon.svg" />
<our-svg media-item="@Model.Logo" />
```

### Advanced usage: *(as of version 1.x.x)
### Advanced usage: \*(as of version 1.x.x)

Additional properties have been added to cache the output and also to ensure the SVG contains a viewbox property instead of the width & height properties to aid in making the vector image responsive within a parent HTML element.

Additional properties have been added to cache the output and also to ensure the SVG contains a viewbox property instead of the width & height properties to aid in making the vector image responsive within a parent HTML element.
```cshtml
<our-svg src="/assets/icon.svg" class="my-css-class" ensure-viewbox="true" cache="true" cache-minutes="180" ignore-appsettings="true" />
<our-svg media-item="@Model.Logo" class="my-css-class" ensure-viewbox="true" cache="true" cache-minutes="180" ignore-appsettings="true" />
@@ -218,20 +234,20 @@ Applying any of the below configurations within your `appsettings.json` file wil

> **Note:** SVG caches are cleared on application restart, or by resaving the media in the media library.


## `<our-fallback>`

This tag helper element `<our-fallback>` uses the same fallback mode logic that is only available on the `Value()` method of the `IPublishedContent` interface that uses a string for the property name to lookup. In addition if the fallback value from a language or ancestors is not available we are still able to fallback to the content inside the tag.

```cshtml
@* Current way *@
@Model.Value("Header", fallback:Fallback.ToLanguage)
<h3><our-fallback property="Header" mode="Fallback.ToLanguage" culture="da-DK">I do NOT have a DK culture variant of this property</our-fallback></h3>
<h3><our-fallback property="Header" mode="Fallback.ToAncestors">I do NOT have a Header property set on ANY parent and ancestors</our-fallback></h3>
<h3><our-fallback property="Header" mode="Fallback.ToAncestors">I do NOT have a Header property set on ANY parent and ancestors</our-fallback></h3>
```

## `<our-version>`

This tag helper element `<our-version>` prints out version number for a given Assembly name loaded into the current AppDomain or if none is given then the EntryAssembly version is displayed, which would be the Umbraco website project you are building.

```cshtml
@@ -243,11 +259,13 @@ This tag helper element `<our-version>` prints out version number for a given As
```

## `our-member-include` and `our-member-exclude`

This is a tag helper attribute that can be applied to any DOM element in the razor template or partial. It will show or hide its element and children on the page when passing a comma seperated string of member groups that the current logged in member for the exclude or include variants.

There are two special Member Groups you can use:
* `*` - All anonymous users
* `?` - All authenticated users

- `*` - All anonymous users
- `?` - All authenticated users

```cshtml
<div our-member-include="Staff">Only members of Staff Member Group will see this.</div>
@@ -283,11 +301,13 @@ Use the alias of the User Group
```

## `<our-edit-link>`
This is a tag helper element which renders an edit link on the front end only if the current user is logged into umbraco and has access to the content section.

This is a tag helper element which renders an edit link on the front end only if the current user is logged into umbraco and has access to the content section.

The link will open the current page in the umbraco backoffice. You can override the umbraco url if you are using a different url for the backoffice.

### Simple example

This is the most basic example. The link will render wherever you put it in the HTML.

```html
@@ -326,12 +346,14 @@ If you want the edit link to open in a new tab, just add the `target="_blank"` a
```

## `our-active-class`

This is a tag helper attribute that can be applied to `<a>` element in the razor template or partial. It will use the value inside the attribute and append it to the class attribute of the `<a>`.
If the link inside the href attribute can be found by its route as a content node, if so then it will check with the current page being rendered if its the same node or an ancestor.

This allows for the navigation item to still have the class added to it when a child or grandchildren page is the currently page being rendered.

### Simple Example

```cshtml
@foreach (var item in Model.Root().Children)
{
@@ -347,17 +369,19 @@ Alternatively you can use the `our-active-class` attribute in conjuction with `o
{
<li our-active-href="@item.Url()" our-active-class="selected">
<a href="@item.Url()" class="nav-link">@item.Name</a>
</li>
</li>
}
</ul>
```

## `<our-link>`

This tag helper element `<our-link>` will create a simple anchor tag using the Umbraco Multi Url Picker property editor that uses the C# Model `Umbraco.Cms.Core.Models.Link`

Note if the link set is an external link and you set the target of the link to be `_blank`, then the link will have the noopener attribute added to the link.

### Simple Example

```cshtml
<our-link link="@Model.ctaLink">
<h2>Hi There</h2>
@@ -372,12 +396,35 @@ Alternatively if you use the `<our-link>` without child DOM elements then it wil

With this tag helper the child DOM elements inside the `<our-link>` is wrapped with the `<a>` tag

### Making the link optional

You can also add `Fallback` for the link to become optional, if there is no link and there is child content, this content is still rendered, you can also replace the wrapping element by using `FallbackElement`.

```cshtml
<our-link link="@Model.ctaLink" Fallback="true" FallbackElement="div">
<span>some text</span>
</our-link>
@*No link will result in*@
<div>
<span>some text</span>
</div>
<our-link link="@Model.ctaLink" Fallback="true">
<span>some text</span>
</our-link>
@*No link and no fallback HTML tag name specified will result in*@
<span>some text</span>
```

## `<our-cache>`

This tag helper element `<our-cache>` is a wrapper around the [DotNet CacheTagHelper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/cache-tag-helper?view=aspnetcore-6.0) - it operates in exactly the same way, with the same options as the DotNet CacheTagHelper, except, it is automatically 'not enabled', when you are in Umbraco Preview or Umbraco Debug mode.

### Without this tag helper

Essentially this is a convenience for setting
Essentially this is a convenience for setting

```cshtml
<cache enabled="!UmbracoContext.IsDebug && !UmbracoContext.InPreviewMode">[Your Long Running Expensive Code Here]</cache>
@@ -390,23 +437,29 @@ Essentially this is a convenience for setting
```

### Clearing the Cache 'on publish'

The Umbraco convention with other Cache Helpers, eg Html.CachedPartial is to clear all memory caches whenever any item is published in the Umbraco Backoffice. By default the our-cache tag helper will do the same, however you can turn this part off on an individual TagHelper basis by setting update-cache-key-on-publish="false".

```cshtml
<our-cache>[Your Long Running Expensive Code Here]</our-cache>
```

is the same as:

```cshtml
<our-cache update-cache-on-publish="true">[Your Long Running Expensive Code Here]</our-cache>
```

But to turn it off:

```cshtml
<our-cache update-cache-on-publish="false">[Your Long Running Expensive Code Here]</our-cache>
```

(NB if you had a thousand tag helpers on your site, all caching large amounts of content, and new publishes to the site occurring every second - this might be detrimental to performance, so do think of the context of your site before allowing the cache to be cleared on each publish)
(NB if you had a thousand tag helpers on your site, all caching large amounts of content, and new publishes to the site occurring every second - this might be detrimental to performance, so do think of the context of your site before allowing the cache to be cleared on each publish)

### Examples

All examples will skip the cache for Umbraco preview mode and debug mode, and evict cache items anytime Umbraco publishes content, media or dictionary items.

```cshtml
@@ -424,55 +477,31 @@ All examples will skip the cache for Umbraco preview mode and debug mode, and ev
</our-cache>
```

This example will turn off the automatic clearing of the tag helper cache if 'any page' is published, but still clear the cache if the individual page is published:

```cshtml
<our-cache update-cache-on-publish="false" vary-by="@Model.UpdateDate.ToString()">
<p>@DateTime.Now - A set Date in time</p>
</our-cache>
```

## `our-self-host`
This is a tag helper attribute that can be applied to any element using a `src` or `href` attribute in the razor template or partial. It will automatically download and self hosting of third party assets, like javascript, css or images.

### Simple Example
```cshtml
<script src="https://unpkg.com/alpinejs@3.10.5/dist/cdn.min.js" our-self-host>
```

This will download the linked file to your local filesystem, and swap out the src attribute with a reference to the now locally hosted file.

### Folder location for downloaded files
By default the files will be saved in `~/assets/`, and keep the folder path of the url. The root folder can be configured in appsettings.json, by adding a value at `Our.Umbraco.TagHelpers:OurSelfHost:RootFolder` specifying the desired rootfolder. The default value is `~/assets/`.

You can further divide the files into folders, by adding a `folder` attribute to the script tag, eg:
```cshtml
<script src="https://unpkg.com/alpinejs@3.10.5/dist/cdn.min.js" our-self-host folder="libraries">
```
This will save the file in `~/assets/libraries/alpinejs@3.10.5/dist/cdn.min.js`.

### Handling extensionless urls to files
In case the url is extensionless, like `https://unpkg.com/alpinejs`, you can add an `ext` attribute, for specifying the extension of the file, eg:
```cshtml
<script src="https://unpkg.com/alpinejs" our-self-host ext="js">
```
This will save the file as `~/assets/alpinejs.js`, enabling eg. MIME types for .js files.

### Caching
The file is saved once, and never updated unless you manually remove the file. The lookup for the local file is cached in the Runtime Cache.

## `<our-img>`

Introduced in version 1.x.x. This tag helper element `<our-img>` will produce performance orientated `<img>` or `<picture>`.

It can be used in one of two ways, either by specifying the `src` attribute to a physical static file served from wwwRoot or by specifying the `media-item` attribute to use a picked IPublishedContent Media Item.

### Properties

Properties appended with s, m, l, xl & xxl translate to screen widths defined by the default configuration or via the relevant properties in the `appsettings.json` (see the next section for more details).

- `src` - `string` based absolute or relative file URL. e.g. `/assets/image.jpg`.
- `media-item` - `MediaWithCrops` based class property from the view model. e.g. `Model.Image`.
- `alt` - Native alternative text property.
- `style` - Native style property.
- `class` - Native CSS class property.
- `abovethefold` - Set to `true` if the image typically appears on screen during inital page load to raise its page load lifecycle priority level.
- `abovethefold` - Set to `true` if the image typically appears on screen during inital page load to raise its page load lifecycle priority level.
- `width` - Native width property. Use in conjunction with the `height` property.
- `width--s` - Image width for small screens. Use in conjunction with the `height--s` property.
- `width--m` - Image width for medium screens. Use in conjunction with the `height--m` property.
@@ -485,7 +514,7 @@ Properties appended with s, m, l, xl & xxl translate to screen widths defined by
- `height--l` - Image height for large screens. Use in conjunction with the `width--l` property.
- `height--xl` - Image height for extra large screens. Use in conjunction with the `width--xl` property.
- `height--xxl` - Image height for extra extra large screens. Use in conjunction with the `width--xxl` property.
- `cropalias` - Crop alias to be used by default.
- `cropalias` - Crop alias to be used by default.
- `cropalias--s` - Crop alias to be used on small screens.
- `cropalias--m` - Crop alias to be used on medium screens.
- `cropalias--l` - Crop alias to be used on large screens.
@@ -510,47 +539,62 @@ Applying any of the below configurations within your `appsettings.json` file wil
"UseNativeLazyLoading": true, // If enabled, loading="true" is used. If disabled, the 'src' property is replaced with 'data-src' which most lazy loading JavaScript libraries will interpret and lazy load the image.
"LazyLoadCssClass": "lazyload", // If 'UseNativeLazyLoading' is disabled, the class property is given an additional class for JavaScript libraries to target. Note: 'lazyload' is used by the lazysizes library.
"LazyLoadPlaceholder": "SVG", // If 'UseNativeLazyLoading' is disabled, the 'src' property is given either an empty SVG (if value is "SVG") or a lower quality version of the original image is used (if value is "LowQualityImage")
"LazyLoadPlaceholderLowQualityImageQuality": 5, // If 'UseNativeLazyLoading' is disabled and 'LazyLoadPlaceholder' is "LowQualityImage", what image quality should be rendered. Numeric values 1-100 accepted.
"LazyLoadPlaceholderLowQualityImageQuality": 5, // If 'UseNativeLazyLoading' is disabled and 'LazyLoadPlaceholder' is "LowQualityImage", what image quality should be rendered. Numeric values 1-100 accepted.
"ApplyAspectRatio": false, // If enabled, the aspect-ratio CSS style is applied to the style property, and the width & height properties are removed.
"AlternativeTextMediaTypePropertyAlias": "alternativeText" // The media property alias to pull through the alt text value. If not found, the media title or filename will be used instead.
}
}
}

### Examples

#### Example 1

This will produce a simple `<img>` tag with an alt tag either defined within the media properties in Umbraco, or auto generated based on the file name.

```cshtml
<our-img media-item="Model.Image" />
```

**Output:**

```cshtml
<img alt="Some alt text" width="1920" height="1280" src="/media/path/image.jpg?width=1920&amp;rnd=133087885756657361" loading="lazy" decoding="async" fetchpriority="low">
```

#### Example 2
This will produce an `<img>` tag with:
- an alt tag as defined within the tag,
- the width,
- the height (calculated by the aspect ratio of the orginal dimensions),

This will produce an `<img>` tag with:

- an alt tag as defined within the tag,
- the width,
- the height (calculated by the aspect ratio of the orginal dimensions),
- no lazy loading with a higher fetch priority in the page load lifecycle.

```cshtml
<our-img media-item="Model.Image" width="200" alt="My custom alt text" abovethefold="true" />
```

**Output:**

```cshtml
<img alt="My custom alt text" width="200" height="133.33333333333331" src="/media/path/image.jpg?width=200&amp;rnd=133087885756657361" loading="eager" fetchpriority="high">
```

#### Example 3
This will produce an `<img>` tag with:

This will produce an `<img>` tag with:

- JavaScript based lazy loading as instructed by the "UseNativeLazyLoading" appsetting set to `false`. This sets the image URL as `data-src` property instead of `src`. Additionally, the `src` property is instead given an empty SVG with the same aspect ratio. Finally, the CSS class `lazyload` has been added.
- the width,
- the width,
- the height (calculated by the aspect ratio of the orginal dimensions).

```cshtml
<our-img media-item="article.ListingImage" width="200" />
```

**Output:**

```cshtml
<img alt="Some alt text" width="200" height="133.33333333333331" data-src="/media/uv2bljv1/meetup-organizers-at-codegarden.jpg?width=200&amp;rnd=133087885756657361" src="data:image/svg&#x2B;xml,%3Csvg xmlns=&#x27;http://www.w3.org/2000/svg&#x27; viewBox=&#x27;0 0 200 133.33333333333331&#x27;%3E%3C/svg%3E" class="lazyload" />
```
@@ -560,7 +604,9 @@ This will produce an `<img>` tag with:
```cshtml
<our-img media-item="Model.Image" width="200" width--s="400" width--m="600" cropalias="mobile" cropalias--m="desktop" />
```

**Output:**

```cshtml
<picture>
<source srcset="/media/path/image.jpg?width=600&amp;height=300&amp;rnd=133087885756657361" media="(min-width: 768px)" width="600" height="300">
@@ -569,10 +615,39 @@ This will produce an `<img>` tag with:
</picture>
```

## `our-self-host`
This is a tag helper attribute that can be applied to any element using a `src` or `href` attribute in the razor template or partial. It will automatically download and self hosting of third party assets, like javascript, css or images. This was written by Soren Kottal for 24Days.in Umbraco Advent calendar 2022 article - https://24days.in/umbraco-cms/2022/static-assets-taghelper/

### Simple Example
```cshtml
<script src="https://unpkg.com/alpinejs@3.10.5/dist/cdn.min.js" our-self-host>
```

This will download the linked file to your local filesystem, and swap out the src attribute with a reference to the now locally hosted file.

### Folder location for downloaded files
By default the files will be saved in `~/assets/`, and keep the folder path of the url. The root folder can be configured in appsettings.json, by adding a value at `Our.Umbraco.TagHelpers:OurSelfHost:RootFolder` specifying the desired rootfolder. The default value is `~/assets/`.

You can further divide the files into folders, by adding a `folder` attribute to the script tag, eg:
```cshtml
<script src="https://unpkg.com/alpinejs@3.10.5/dist/cdn.min.js" our-self-host folder="libraries">
```
This will save the file in `~/assets/libraries/alpinejs@3.10.5/dist/cdn.min.js`.

### Handling extensionless urls to files
In case the url is extensionless, like `https://unpkg.com/alpinejs`, you can add an `ext` attribute, for specifying the extension of the file, eg:
```cshtml
<script src="https://unpkg.com/alpinejs" our-self-host ext="js">
```
This will save the file as `~/assets/alpinejs.js`, enabling eg. MIME types for .js files.

### Caching
The file is saved once, and never updated unless you manually remove the file. The lookup for the local file is cached in the Runtime Cache.

## Video 📺
[![How to create ASP.NET TagHelpers for Umbraco](https://user-images.githubusercontent.com/1389894/138666925-15475216-239f-439d-b989-c67995e5df71.png)](https://www.youtube.com/watch?v=3fkDs0NwIE8)

[![How to create ASP.NET TagHelpers for Umbraco](https://user-images.githubusercontent.com/1389894/138666925-15475216-239f-439d-b989-c67995e5df71.png)](https://www.youtube.com/watch?v=3fkDs0NwIE8)

## Attribution
The logo for Our.Umbraco.TagHelpers is made by [Freepik](https://www.freepik.com) from [flaticon.com](https://www.flaticon.com)

The logo for Our.Umbraco.TagHelpers is made by [Freepik](https://www.freepik.com) from [flaticon.com](https://www.flaticon.com)

0 comments on commit c99c6a1

Please sign in to comment.