hide/show toggle works (but only when element is not expanded)

This commit is contained in:
2019-08-30 21:10:15 +02:00
parent 8805f6b4f1
commit 565d75a2c2
11 changed files with 1243 additions and 595 deletions
@@ -1,6 +1,7 @@
{
"javascript": [
"~/App_Plugins/brothers.uNesting/uNesting.js"
"~/App_Plugins/brothers.uNesting/uNesting.js",
"~/App_Plugins/brothers.uNesting/uNesting.directives.js"
],
"css": [
"~/App_Plugins/brothers.uNesting/uNesting.css"
@@ -90,7 +90,7 @@
position: relative;
margin-top: 1px;
padding: 20px 0;
color: #1b264f;
color: #000;
border-radius: 3px 3px 0 0;
border-bottom: none;
background: none;
@@ -107,8 +107,7 @@
top: 50%;
margin-top: -12px;
left: 3px;
font-size: 1.4rem;
z-index: 1;
font-size: 20px;
}
.unesting-item-header-content.--has-icon
@@ -130,15 +129,15 @@
bottom: -15px;
}
.unesting-item-header:hover .unesting-item-header-inner .unesting-item-header-content
/*.unesting-item-header:hover .unesting-item-header-inner .unesting-item-header-content
{
padding-right: 130px;
}
}*/
.unesting-item-header-content
{
line-height: 20px;
color: #1b264f;
color: #000;
white-space: nowrap;
position: relative;
}
@@ -189,9 +188,10 @@ un-config
{
position: absolute;
right: 0;
top: 50%;
top: 0;
bottom: 0;
align-items: center;
padding: 5px;
margin-top: -22px;
display: flex;
grid-gap: 8px;
}
@@ -200,6 +200,7 @@ un-config
{
transition: opacity .12s ease-in-out;
opacity: 0;
background: white;
}
.unesting-item-header:hover .unesting-icons > *
@@ -215,11 +216,11 @@ un-config
height: 32px;
justify-content: center;
align-items: center;
border-radius: 20px;
border: 1px solid #e9e9eb;
border-radius: 16px;
cursor: pointer;
color: #1b264f;
color: #000;
transition: background 0.12s ease;
border: 1px solid #f6f6f7;
}
.unesting-icon.is-negative:hover
@@ -241,7 +242,7 @@ un-config
height: 3px;
width: 3px;
border-radius: 50%;
background: #1b264f;
background: #000;
display: inline-block;
margin: 0 1px;
opacity: .6;
@@ -280,7 +281,7 @@ un-config
.unesting-content > .umb-pane
{
margin: 30px 20px;
margin: 30px 20px 30px 20px;
}
.unesting-item.is-active > .unesting-content
@@ -324,9 +325,14 @@ un-config
border-bottom-color: #e9e9eb;
}
.unesting-item .unesting-item .unesting-icons > *
{
background: #faf8f8;
border-color: #e9e9eb;
}
/* media */
.unesting-media
{
display: flex;
@@ -431,7 +437,7 @@ un-config
background: #f6f4f4;
border-radius: 4px;
width: 180px;
min-height: 60px;
/*min-height: 60px;*/
max-height: 65px;
padding: 10px 15px;
display: block;
@@ -444,7 +450,7 @@ un-config
font-size: 14px;
white-space: nowrap;
text-overflow: ellipsis;
color: #1b264f;
color: #333;
height: 20px;
overflow: hidden;
margin-bottom: 5px;
@@ -514,7 +520,7 @@ un-config
{
display: block;
font-size: 14px;
color: #1b264f;
color: #000;
font-weight: 600;
margin-bottom: 4px;
}
@@ -531,9 +537,9 @@ un-config
/* doctypepicker */
.unesting-doctype-textarea
.unesting-doctype-template
{
width: 100%;
width: 400px;
height: 64px;
max-height: 200px;
min-height: 32px;
@@ -572,7 +578,7 @@ un-config
.unesting-item[unesting-alias="newsletterHeadline"] .unesting-text-partial[unesting-index="0"]
{
font-size: 16px;
color: #1b264f;
color: #000;
font-weight: 600;
}
@@ -594,9 +600,12 @@ un-config
content: '“';
}
.umb-nested-content-property-container
{
margin-bottom: 12px;
}
/* generic overrides */
.btn-info
{
color: #454957;
@@ -0,0 +1,457 @@
angular.module('umbraco.directives').directive('unContent', function ($compile)
{
return {
restrict: 'E',
scope: {
item: '=',
node: '=',
config: '='
},
link: function (scope, element)
{
// get template
var template = scope.config && scope.config.nameTemplate ? scope.config.nameTemplate : null;
// compile & render template
function render()
{
// merge element values into local scope
angular.merge(scope, scope.item);
// nothing when no template is specified
if (!template)
{
element.html('');
//element.html(scope.node.documentType.description);
return;
}
// create html and compile
element.html(template);
$compile(element.contents())(scope);
}
//scope.$watch('item', function (value)
//{
// render();
//});
// first-time rendering
render();
}
};
});
angular.module('umbraco.directives').directive('unMedia', function ($http, $compile, umbRequestHelper)
{
var sizes = {
small: 'width=30&height=30&mode=crop&quality=60',
medium: 'width=60&height=60&mode=crop&quality=60',
large: 'width=100&height=100&mode=crop&quality=60',
wide: 'width=100&height=60&mode=crop&quality=60',
high: 'width=60&height=100&mode=crop&quality=60'
};
return {
restrict: 'E',
scope: {
model: '=',
key: '@',
titleKey: '@',
limit: '@',
size: '@',
hideLabel: '@'
},
template: '<div class="unesting-media" unesting-size="{{_size}}">' +
'<div class="unesting-media-item" ng-repeat="item in media" ng-class="{\'has-title\': !!item.title}">' +
'<img src="{{item.src}}" title="{{item.title}}" class="unesting-media-item-image" />' +
'<span class="unesting-media-item-text" ng-if="item.title">{{item.title | unHtml }}</span>' +
'</div>' +
'<span class="unesting-media-more" ng-if="count > media.length">+{{count - media.length}}</span>' +
'</div>',
link: function (scope, element)
{
scope._size = sizes[scope.size] ? scope.size : 'medium';
var resize = sizes[scope._size];
var limit = scope.limit || 5;
scope.media = [];
var titleCache = {};
// compile & render template
function render()
{
var ids = scope.model;
if (!scope.model)
{
return;
}
if (_.isArray(scope.model))
{
if (typeof scope.model[0] !== 'string' && !scope.key)
{
console.error("You need the <un-media key='my_key' /> property for nested media");
return;
}
ids = _.map(scope.model, function (item)
{
if (typeof item === 'string')
{
return item;
}
var value = item[scope.key];
if (scope.titleKey)
{
titleCache[value] = item[scope.titleKey];
}
return value;
}).join(',');
}
ids = _.filter(ids.split(','), function (id) { return !!id; });
scope.count = ids.length;
var query = "ids=" + ids.slice(0, limit).join('&ids=');
var url = $http.get(Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + "/backoffice/UmbracoApi/Unesting/GetMediaByUdis?" + query);
umbRequestHelper.resourcePromise(url, 'Failed to retrieve data for media ids').then(function (result)
{
_.each(result, function (src, id)
{
scope.media.push({
id: id,
src: src + "?" + resize,
title: titleCache[id]
});
});
// hide label if requested
if (scope.media.length > 0 && (scope.hideLabel === true || scope.hideLabel === 'true' || scope.hideLabel === '1'))
{
element.closest('.unesting-item-header').addClass('no-label');
}
});
}
render();
}
};
});
angular.module('umbraco.directives').directive('unText', function ($filter)
{
return {
restrict: 'E',
scope: {
model: '=',
maxLines: '@',
hideLabel: '@'
},
template: '<div class="unesting-text" ng-if="items.length" ng-style="{ \'-webkit-line-clamp\': {{maxLines}}, \'max-height\': \'{{maxLines * 20}}px\' }">' +
'<span class="unesting-text-partial" unesting-index="{{$index}}" ng-repeat="text in items" ng-bind-html="text"></span>' +
'</div>',
link: function (scope, element)
{
scope.maxLines = +scope.maxLines || 2;
scope.items = [];
if (!scope.model)
{
return;
}
// hide label if requested
if (scope.hideLabel === true || scope.hideLabel === 'true' || scope.hideLabel === '1')
{
element.closest('.unesting-item-header').addClass('no-label');
}
var partials = _.filter(!_.isArray(scope.model) ? [scope.model] : scope.model, function (text) { return !!text; });
scope.items = _.map(partials, function (text)
{
return $filter('unHtml')(text, 1000);
});
}
};
});
angular.module('umbraco.directives').directive('unBoxes', function ($compile)
{
return {
restrict: 'E',
scope: {
model: '=',
key: '@',
titleKey: '@',
limit: '@',
size: '@',
hideLabel: '@'
},
template: '<div class="unesting-boxes" unesting-size="{{size}}">' +
'<div class="unesting-boxes-item" ng-repeat="item in items" ng-class="{\'has-title\': !!item.title}">' +
'<span class="unesting-boxes-item-headline" ng-if="item.headline">{{item.headline | unHtml }}</span>' +
'<span class="unesting-boxes-item-text" ng-if="item.text" ng-style="{ \'max-height\': \'{{item.maxLines * 20}}px\', \'-webkit-line-clamp\': {{item.maxLines}} }">{{item.text | unHtml:200 }}</span>' +
'</div>' +
'<span class="unesting-boxes-more" ng-if="count > items.length">+{{count - items.length}}</span>' +
'</div>',
link: function (scope, element)
{
var maxLines = {
medium: 3,
large: 6
};
scope.size = maxLines[scope.size] ? scope.size : 'medium';
var limit = +scope.limit || 3;
scope.items = [];
if (!scope.model)
{
return;
}
// hide label if requested
if (scope.hideLabel === true || scope.hideLabel === 'true' || scope.hideLabel === '1')
{
element.closest('.unesting-item-header').addClass('no-label');
}
if (!_.isArray(scope.model))
{
console.error("The <un-boxes model='my_array' /> model has to be an array");
return;
}
if (_.isObject(scope.model[0]) && !scope.key)
{
console.error("You need the <un-boxes key='my_key' /> property for nested elements");
return;
}
var items = [];
_.each(scope.model, function (item)
{
var max = maxLines[scope.size];
if (item)
{
if (typeof item === 'string')
{
items.push({
maxLines: max,
text: item
});
}
var headline = item[scope.titleKey];
items.push({
maxLines: headline ? max - 1 : max,
headline: headline,
text: item[scope.key]
});
}
});
scope.items = items.slice(0, limit);
scope.count = items.length;
}
};
});
angular.module('umbraco.directives').directive('unFigure', function ($filter)
{
return {
restrict: 'E',
scope: {
image: '=',
text: '=',
headline: '=',
size: '@',
maxLines: '@',
hideLabel: '@'
},
template: '<div class="unesting-figure" ng-if="hasContent">' +
'<un-media ng-if="image" model="image" size="{{size}}" />' +
'<div class="unesting-figure-content">' +
'<span class="unesting-figure-headline" ng-if="headline">{{headline | unHtml }}</span>' +
'<span class="unesting-figure-text" ng-if="text" ng-style="{ \'max-height\': \'{{maxLines * 20}}px\', \'-webkit-line-clamp\': {{maxLines}} }">{{text | unHtml:800 }}</span>' +
'</div>' +
'</div>',
link: function (scope, element)
{
scope.hasContent = !!(scope.text || scope.headline || scope.image);
// hide label if requested
if (scope.hideLabel === true || scope.hideLabel === 'true' || scope.hideLabel === '1')
{
element.closest('.unesting-item-header').toggleClass('no-label', scope.hasContent);
}
// calculate max lines
scope.maxLines = +scope.maxLines || 3;
if (scope.headline)
{
scope.maxLines -= 1;
}
}
};
});
angular.module('umbraco.directives').directive('unConfig', function ($filter)
{
return {
restrict: 'E',
scope: {
hideLabel: '@',
asColumns: '@'
},
template: '',
link: function (scope, element)
{
if (scope.hideLabel === true || scope.hideLabel === 'true' || scope.hideLabel === '1')
{
element.closest('.unesting-item-header').addClass('no-label');
}
if (scope.asColumns === true || scope.asColumns === 'true' || scope.asColumns === '1')
{
element.closest('.unesting-item-header').addClass('as-columns');
}
}
};
});
angular.module("umbraco.directives").directive('uNestingContentEditor', [
function ()
{
var link = function ($scope)
{
// Clone the model because some property editors
// do weird things like updating and config values
// so we want to ensure we start from a fresh every
// time, we'll just sync the value back when we need to
$scope.model = angular.copy($scope.ngModel);
$scope.nodeContext = $scope.model;
// Find the selected tab
var selectedTab = $scope.model.variants[0].tabs[0];
if ($scope.tabAlias)
{
angular.forEach($scope.model.variants[0].tabs, function (tab)
{
if (tab.alias.toLowerCase() === $scope.tabAlias.toLowerCase())
{
selectedTab = tab;
return;
}
});
}
$scope.tabs = $scope.model.variants[0].tabs;
var contentTab = _.find($scope.tabs, function (tab)
{
var alias = tab.alias.toLowerCase();
return tab.id !== 0 && alias !== 'unestingsettings' && (!$scope.tabAlias || alias === $scope.tabAlias.toLowerCase());
});
$scope.contentProperties = _.filter(contentTab.properties, function (prop)
{
return prop.propertyAlias.toLowerCase() !== 'unestinghide';
});
//var settingsTab = _.find($scope.tabs, function (tab)
//{
// var alias = tab.alias.toLowerCase();
// return tab.id !== 0 && alias === 'unestingsettings';
//});
//$scope.settingsProperties = settingsTab ? settingsTab.properties : [];
$scope.settingsProperties = [];
// Listen for sync request
var unsubscribe = $scope.$on("ncSyncVal", function (ev, args)
{
if (args.key === $scope.model.key)
{
// Tell inner controls we are submitting
$scope.$broadcast("formSubmitting", { scope: $scope });
// Sync the values back
angular.forEach($scope.ngModel.variants[0].tabs, function (tab)
{
if (tab.alias.toLowerCase() === selectedTab.alias.toLowerCase())
{
var localPropsMap = selectedTab.properties.reduce(function (map, obj)
{
map[obj.alias] = obj;
return map;
}, {});
angular.forEach(tab.properties, function (prop)
{
if (localPropsMap.hasOwnProperty(prop.alias))
{
prop.value = localPropsMap[prop.alias].value;
}
});
}
});
}
});
$scope.$on('$destroy', function ()
{
unsubscribe();
});
};
return {
restrict: "E",
replace: true,
templateUrl: Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + "/views/propertyeditors/nestedcontent/nestedcontent.editor.html",
scope: {
ngModel: '=',
tabAlias: '='
},
link: link
};
}
]);
@@ -32,7 +32,8 @@
ng-model="config.ncTabAlias" required></select>
</td>
<td>
<textarea class="unesting-doctype-textarea" ng-model="config.nameTemplate" rows="1" cols="40"></textarea>
<div class="unesting-doctype-template" model="config.nameTemplate" umb-ace-editor="aceOptions"></div>
<!--<textarea class="unesting-doctype-textarea" ng-model="config.nameTemplate" rows="1" cols="40"></textarea>-->
</td>
<td>
<button type="button" class="btn btn-danger" ng-click="remove($index)">
@@ -43,7 +44,7 @@
</tbody>
</table>
<div>
<button type="button" class="btn" ng-click="add()" ng-disabled="!canAdd()">
<button type="button" class="btn" ng-click="add()">
<localize key="general_add">Add</localize>
</button>
<i class="icon icon-help-alt medium umb-nested-content__help-icon" ng-click="showHelpText = !showHelpText"></i>
@@ -1,4 +1,4 @@
<div class="umb-pane unesting-editor-pane" ng-class="{ 'has-settings': hasSettings }">
<div class="umb-pane unesting-editor-pane" ng-class="{ 'has-settings': settingsProperties.length > 0 }">
<div class="unesting-editor-pane-content">
<div ng-repeat="property in contentProperties" class="umb-nested-content-property-container">
@@ -11,7 +11,8 @@
</div>
</div>
<div class="unesting-editor-pane-settings" ng-if="hasSettings">
<div class="unesting-editor-pane-settings" ng-if="settingsProperties.length > 0">
<div ng-repeat="property in settingsProperties" class="umb-nested-content-property-container">
<umb-property property="property" unesting-property="{{property.propertyAlias}}" ng-class="{'umb-nested-content--not-supported': property.notSupported}">
@@ -16,7 +16,7 @@
<div class="unesting-item" ng-repeat="node in nodes"
unesting-alias="{{node.documentType.alias}}"
ng-class="{ 'is-active' : $parent.realCurrentNode.key === node.key, 'umb-nested-content__item--single' : $parent.singleMode, 'is-hidden': !!model.value[$index]['uNestingHide'] === '1' }">
ng-class="{ 'is-active' : $parent.realCurrentNode.key === node.key, 'umb-nested-content__item--single' : $parent.singleMode, 'is-hidden': isHidden(model.value[$index]) }">
<div class="unesting-item-header" ng-click="$parent.editNode($index)" ng-hide="$parent.singleMode">
@@ -67,7 +67,7 @@
<i class="icon icon-trash-alt"></i>
</a>
<a class="unesting-icon is-negative hidden-toggle" localize="title" title="general_visibility" ng-if="canHide(model.value[$index])" ng-click="clickHide($event, node, $index);" prevent-default>
<a class="unesting-icon is-negative hidden-toggle" localize="title" title="general_visibility" ng-if="canHide(model.value[$index])" ng-click="clickHide($event, node, ncTabAlias);" prevent-default>
<i class="icon icon-lock"></i>
</a>
</div>
File diff suppressed because it is too large Load Diff
@@ -1,52 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Editors;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
namespace UmbracoPackages
{
/// <remarks>
/// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
/// access to ALL of the methods on this controller will need access to the media application.
/// </remarks>
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
public class MediaExtendedController : ContentControllerBase
{
public MediaExtendedController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { }
/// <summary>
/// Return media for the specified UDIs
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public Dictionary<Udi, string> GetByUdis([FromUri]Udi[] ids)
{
var foundMedia = Services.MediaService.GetByIds(ids.Select(x => (x as GuidUdi).Guid));
return foundMedia.ToDictionary(media => (Udi)media.GetUdi(), media =>
{
string json = media.GetValue<string>("umbracoFile");
return JsonConvert.DeserializeObject<SrcData>(json).Src;
});
}
class SrcData
{
public string Src { get; set; }
}
}
}
+2 -1
View File
@@ -395,6 +395,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="App_Plugins\brothers.uNesting\uNesting.directives.js" />
<Content Include="App_Plugins\brothers.uNesting\uNesting.editor.html" />
<Content Include="App_Plugins\brothers.uNesting\uNesting.css" />
<Content Include="App_Plugins\brothers.uNesting\uNesting.docTypePicker.html" />
@@ -471,7 +472,7 @@
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="MediaExtendedController.cs" />
<Compile Include="UnestingController.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
+111
View File
@@ -0,0 +1,111 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Editors;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
namespace UmbracoPackages
{
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorize(Constants.Applications.Content)]
public class UnestingController : ContentControllerBase
{
private IContentTypeCommonRepository ContentTypeRepository { get; set; }
public UnestingController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper, IContentTypeCommonRepository contentTypeRepository)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
ContentTypeRepository = contentTypeRepository;
}
/// <summary>
/// Return media for the specified UDIs
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public Dictionary<Udi, string> GetMediaByUdis([FromUri]Udi[] ids)
{
var foundMedia = Services.MediaService.GetByIds(ids.Select(x => (x as GuidUdi).Guid));
return foundMedia.ToDictionary(media => (Udi)media.GetUdi(), media =>
{
string json = media.GetValue<string>("umbracoFile");
return JsonConvert.DeserializeObject<SrcData>(json).Src;
});
}
/// <summary>
/// Gets an empty content item for the
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <param name="parentId"></param>
public Dictionary<string, ContentItemDisplay> GetScaffolds([FromUri]string[] a)
{
int parentId = -20;
// string contentTypeAlias, int parentId
var contentTypes = ContentTypeRepository.GetAllTypes().Where(x => a.Contains(x.Alias, StringComparer.InvariantCultureIgnoreCase));
if (!contentTypes.Any())
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return contentTypes.Select(contentType =>
{
var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0));
var mapped = MapToDisplay(emptyContent);
// TODO we need access to the translation service
// translate the content type name if applicable
//mapped.ContentTypeName = Services.TextService.UmbracoDictionaryTranslate(mapped.ContentTypeName);
// if your user type doesn't have access to the Settings section it would not get this property mapped
if (mapped.DocumentType != null)
{
//mapped.DocumentType.Name = Services.TextService.UmbracoDictionaryTranslate(mapped.DocumentType.Name);
}
//remove the listview app if it exists
mapped.ContentApps = mapped.ContentApps.Where(x => x.Alias != "umbListView").ToList();
return mapped;
}).ToDictionary(x => x.ContentTypeAlias, x => x);
}
/// <summary>
/// Used to map an <see cref="IContent"/> instance to a <see cref="ContentItemDisplay"/> and ensuring a language is present if required
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
private ContentItemDisplay MapToDisplay(IContent content)
{
var display = Mapper.Map<ContentItemDisplay>(content);
display.AllowPreview = display.AllowPreview && content.Trashed == false && content.ContentType.IsElement == false;
return display;
}
class SrcData
{
public string Src { get; set; }
}
}
}
@@ -1,6 +1,6 @@
@inherits Umbraco.Web.Mvc.UmbracoViewPage
<section class="section section--themed section--header section--content-center-bottom">
<div class="section__hero-content">
<h1 class="no-air">@Model.GetProperty("PageTitle").GetValue()</h1>
@*<h1 class="no-air">@Model.GetProperty("PageTitle").GetValue()</h1>*@
</div>
</section>