mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
#21304: Fixed Text Element HTML filter issues.
- Implemented HTML filters for Html, Text and Paragraph elements - Tokens are only processed on the front-end, not in the editor page itself. This also prevents an exception when the {Shape.Execute} token is used with a theme specific shape. Work Item: 21304
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
using Orchard.Layouts.Elements;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Layouts.Elements;
|
||||
using Orchard.Layouts.Framework.Display;
|
||||
using Orchard.Layouts.Framework.Drivers;
|
||||
using Orchard.Layouts.ViewModels;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Layouts.Drivers {
|
||||
public class HtmlElementDriver : ElementDriver<Html> {
|
||||
private readonly IEnumerable<IHtmlFilter> _htmlFilters;
|
||||
public HtmlElementDriver(IEnumerable<IHtmlFilter> htmlFilters) {
|
||||
_htmlFilters = htmlFilters;
|
||||
}
|
||||
|
||||
protected override EditorResult OnBuildEditor(Html element, ElementEditorContext context) {
|
||||
var viewModel = new HtmlEditorViewModel {
|
||||
@@ -18,5 +26,17 @@ namespace Orchard.Layouts.Drivers {
|
||||
|
||||
return Editor(context, editor);
|
||||
}
|
||||
|
||||
protected override void OnDisplaying(Html element, ElementDisplayContext context) {
|
||||
var text = element.Content;
|
||||
var flavor = "html";
|
||||
var processedText = ApplyHtmlFilters(text, flavor);
|
||||
|
||||
context.ElementShape.ProcessedText = processedText;
|
||||
}
|
||||
|
||||
private string ApplyHtmlFilters(string content, string flavor) {
|
||||
return _htmlFilters.Aggregate(content, (t, filter) => filter.ProcessContent(t, flavor));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,17 @@
|
||||
using Orchard.Layouts.Elements;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Layouts.Elements;
|
||||
using Orchard.Layouts.Framework.Display;
|
||||
using Orchard.Layouts.Framework.Drivers;
|
||||
using Orchard.Layouts.ViewModels;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Layouts.Drivers {
|
||||
public class ParagraphElementDriver : ElementDriver<Paragraph> {
|
||||
private readonly IEnumerable<IHtmlFilter> _htmlFilters;
|
||||
public ParagraphElementDriver(IEnumerable<IHtmlFilter> htmlFilters) {
|
||||
_htmlFilters = htmlFilters;
|
||||
}
|
||||
|
||||
protected override EditorResult OnBuildEditor(Paragraph element, ElementEditorContext context) {
|
||||
var viewModel = new ParagraphEditorViewModel {
|
||||
@@ -18,5 +26,17 @@ namespace Orchard.Layouts.Drivers {
|
||||
|
||||
return Editor(context, editor);
|
||||
}
|
||||
|
||||
protected override void OnDisplaying(Paragraph element, ElementDisplayContext context) {
|
||||
var text = element.Content;
|
||||
var flavor = "html";
|
||||
var processedText = ApplyHtmlFilters(text, flavor);
|
||||
|
||||
context.ElementShape.ProcessedText = processedText;
|
||||
}
|
||||
|
||||
private string ApplyHtmlFilters(string content, string flavor) {
|
||||
return _htmlFilters.Aggregate(content, (t, filter) => filter.ProcessContent(t, flavor));
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,17 +14,14 @@ namespace Orchard.Layouts.Drivers {
|
||||
}
|
||||
|
||||
protected override EditorResult OnBuildEditor(Text element, ElementEditorContext context) {
|
||||
var flavor = GetFlavor();
|
||||
|
||||
var viewModel = new TextEditorViewModel {
|
||||
Flavor = flavor,
|
||||
Text = element.Content
|
||||
Content = element.Content
|
||||
};
|
||||
var editor = context.ShapeFactory.EditorTemplate(TemplateName: "Elements.Text", Model: viewModel);
|
||||
|
||||
if (context.Updater != null) {
|
||||
context.Updater.TryUpdateModel(viewModel, context.Prefix, null, null);
|
||||
element.Content = viewModel.Text;
|
||||
element.Content = viewModel.Content;
|
||||
}
|
||||
|
||||
return Editor(context, editor);
|
||||
@@ -32,18 +29,14 @@ namespace Orchard.Layouts.Drivers {
|
||||
|
||||
protected override void OnDisplaying(Text element, ElementDisplayContext context) {
|
||||
var text = element.Content;
|
||||
var flavor = GetFlavor();
|
||||
var processedText = ToHtml(text, flavor);
|
||||
var flavor = "textarea";
|
||||
var processedText = ApplyHtmlFilters(text, flavor);
|
||||
|
||||
context.ElementShape.ProcessedText = processedText;
|
||||
}
|
||||
|
||||
private string ToHtml(string content, string flavor) {
|
||||
private string ApplyHtmlFilters(string content, string flavor) {
|
||||
return _htmlFilters.Aggregate(content, (t, filter) => filter.ProcessContent(t, flavor));
|
||||
}
|
||||
|
||||
private static string GetFlavor() {
|
||||
return "textarea";
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,8 @@
|
||||
using Orchard.Layouts.Helpers;
|
||||
using Orchard.Layouts.Framework.Elements;
|
||||
using Orchard.Layouts.Helpers;
|
||||
|
||||
namespace Orchard.Layouts.Framework.Elements {
|
||||
public abstract class ContentElement : Element, IContentElement {
|
||||
namespace Orchard.Layouts.Elements {
|
||||
public abstract class ContentElement : Element {
|
||||
public override string Category {
|
||||
get { return "Content"; }
|
||||
}
|
@@ -1,4 +1,3 @@
|
||||
using Orchard.Layouts.Framework.Elements;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Layouts.Elements {
|
||||
|
@@ -1,5 +1,3 @@
|
||||
using Orchard.Layouts.Framework.Elements;
|
||||
|
||||
namespace Orchard.Layouts.Elements {
|
||||
public class Paragraph : ContentElement {
|
||||
public override string ToolboxIcon {
|
||||
|
@@ -1,5 +1,3 @@
|
||||
using Orchard.Layouts.Framework.Elements;
|
||||
|
||||
namespace Orchard.Layouts.Elements {
|
||||
public class Text : ContentElement {
|
||||
public override string ToolboxIcon {
|
||||
|
@@ -1,5 +0,0 @@
|
||||
namespace Orchard.Layouts.Framework.Elements {
|
||||
public interface IContentElement {
|
||||
string Content { get; set; }
|
||||
}
|
||||
}
|
@@ -29,6 +29,6 @@ Features:
|
||||
Dependencies: Orchard.Layouts, Orchard.Projections
|
||||
Orchard.Layouts.Tokens:
|
||||
Name: Element Tokens
|
||||
Description: Provides an element token provider, enabling elements to be rendered using a token.
|
||||
Description: Provides an element token provider that enables elements to be rendered using a token and enables tokens to be used inside of various elements such as Html, Text and Paragraph.
|
||||
Category: Layout
|
||||
Dependencies: Orchard.Layouts, Orchard.Tokens
|
||||
|
@@ -99,6 +99,7 @@
|
||||
<Content Include="Scripts\LayoutEditor.min.js">
|
||||
<DependentUpon>LayoutEditor.js</DependentUpon>
|
||||
</Content>
|
||||
<Content Include="Scripts\LayoutEditor\Directives\Html.js" />
|
||||
<Content Include="Scripts\LayoutEditor\Directives\Editor.js" />
|
||||
<Content Include="Scripts\LayoutEditor\Directives\Canvas.js" />
|
||||
<Content Include="Scripts\LayoutEditor\Directives\Child.js" />
|
||||
@@ -130,6 +131,7 @@
|
||||
<Content Include="Scripts\Models\Container.js" />
|
||||
<Content Include="Scripts\Models\Content.js" />
|
||||
<Content Include="Scripts\Models\Element.js" />
|
||||
<Content Include="Scripts\Models\Html.js" />
|
||||
<Content Include="Scripts\Models\Grid.js" />
|
||||
<Content Include="Scripts\Models\Helpers.js" />
|
||||
<Content Include="Scripts\Models\Row.js" />
|
||||
@@ -419,6 +421,7 @@
|
||||
<Compile Include="Drivers\CanvasElementDriver.cs" />
|
||||
<Compile Include="Drivers\ShapeElementDriver.cs" />
|
||||
<Compile Include="Elements\Canvas.cs" />
|
||||
<Compile Include="Elements\ContentElement.cs" />
|
||||
<Compile Include="Elements\Shape.cs" />
|
||||
<Compile Include="Filters\TokensFilter.cs" />
|
||||
<Compile Include="Framework\Drivers\ImportContentContextWrapper.cs" />
|
||||
@@ -437,8 +440,6 @@
|
||||
<Compile Include="Framework\Display\ElementCreatingDisplayShapeContext.cs" />
|
||||
<Compile Include="Framework\Drivers\ImportElementContext.cs" />
|
||||
<Compile Include="Framework\Drivers\ImportLayoutContext.cs" />
|
||||
<Compile Include="Framework\Elements\ContentElement.cs" />
|
||||
<Compile Include="Framework\Elements\IContentElement.cs" />
|
||||
<Compile Include="Handlers\ElementDriversCoordinator.cs" />
|
||||
<Compile Include="Helpers\DictionaryExtensions.cs" />
|
||||
<Compile Include="Helpers\EditorResultExtensions.cs" />
|
||||
@@ -612,6 +613,9 @@
|
||||
<Content Include="Scripts\LayoutEditor.js.bundle" />
|
||||
<Content Include="Scripts\Models.js.bundle" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\LayoutEditor.Template.Html.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
@@ -63,42 +63,6 @@
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
//this.addElement = function (contentType) {
|
||||
// var elementType = contentType.id;
|
||||
// var deferred = new $.Deferred();
|
||||
// var dialog = new window.Orchard.Layouts.Dialog(".dialog-template." + self.settings.editorDialogName);
|
||||
|
||||
// if (contentType.hasEditor) {
|
||||
// var url = self.settings.endpoints.add + "&typeName=" + elementType;
|
||||
|
||||
// dialog.show();
|
||||
// dialog.load(url);
|
||||
|
||||
// dialog.element.on("command", function(e, args) {
|
||||
// if (args.command == "add" || args.command == "save") {
|
||||
// deferred.resolve(args);
|
||||
// dialog.close();
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// var url = self.settings.endpoints.addDirect;
|
||||
|
||||
// $.ajax(url, {
|
||||
// data: {
|
||||
// typeName: elementType,
|
||||
// __RequestVerificationToken: self.settings.antiForgeryToken
|
||||
// },
|
||||
// type: "POST"
|
||||
// }).then(function(response) {
|
||||
// deferred.resolve({
|
||||
// element: response
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// return deferred.promise();
|
||||
//};
|
||||
|
||||
var serializeCanvas = function () {
|
||||
var layoutData = self.editor.canvas.toObject();
|
||||
return JSON.stringify(layoutData, null, "\t");
|
||||
|
@@ -430,7 +430,7 @@ angular
|
||||
if (!$scope.element.inlineEditingIsActive) {
|
||||
$scope.element.inlineEditingIsActive = true;
|
||||
$element.find(".layout-toolbar-container").show();
|
||||
var selector = "#layout-editor-" + $scope.$id + " .layout-content-h-t-m-l .layout-content-markup[data-templated=false]";
|
||||
var selector = "#layout-editor-" + $scope.$id + " .layout-html .layout-content-markup[data-templated=false]";
|
||||
var firstContentEditorId = $(selector).first().attr("id");
|
||||
tinymce.init({
|
||||
selector: selector,
|
||||
@@ -631,6 +631,42 @@ angular
|
||||
angular
|
||||
.module("LayoutEditor")
|
||||
.directive("orcLayoutContent", ["$sce", "scopeConfigurator", "environment",
|
||||
function ($sce, scopeConfigurator, environment) {
|
||||
return {
|
||||
restrict: "E",
|
||||
scope: { element: "=" },
|
||||
controller: ["$scope", "$element",
|
||||
function ($scope, $element) {
|
||||
scopeConfigurator.configureForElement($scope, $element);
|
||||
$scope.edit = function () {
|
||||
$scope.$root.editElement($scope.element).then(function (args) {
|
||||
$scope.$apply(function () {
|
||||
if (args.cancel)
|
||||
return;
|
||||
|
||||
$scope.element.data = args.element.data;
|
||||
$scope.element.setHtml(args.element.html);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
|
||||
$scope.element.setHtml = function (html) {
|
||||
$scope.element.html = html;
|
||||
$scope.element.htmlUnsafe = $sce.trustAsHtml(html);
|
||||
};
|
||||
|
||||
$scope.element.setHtml($scope.element.html);
|
||||
}
|
||||
],
|
||||
templateUrl: environment.templateUrl("Content"),
|
||||
replace: true
|
||||
};
|
||||
}
|
||||
]);
|
||||
angular
|
||||
.module("LayoutEditor")
|
||||
.directive("orcLayoutHtml", ["$sce", "scopeConfigurator", "environment",
|
||||
function ($sce, scopeConfigurator, environment) {
|
||||
return {
|
||||
restrict: "E",
|
||||
@@ -662,7 +698,7 @@ angular
|
||||
$scope.element.setHtml($scope.element.html);
|
||||
}
|
||||
],
|
||||
templateUrl: environment.templateUrl("Content"),
|
||||
templateUrl: environment.templateUrl("Html"),
|
||||
replace: true,
|
||||
link: function (scope, element) {
|
||||
// Mouse down events must not be intercepted by drag and drop while inline editing is active,
|
||||
|
@@ -18,6 +18,7 @@
|
||||
<file>LayoutEditor/Directives/Child.js</file>
|
||||
<file>LayoutEditor/Directives/Column.js</file>
|
||||
<file>LayoutEditor/Directives/Content.js</file>
|
||||
<file>LayoutEditor/Directives/Html.js</file>
|
||||
<file>LayoutEditor/Directives/Grid.js</file>
|
||||
<file>LayoutEditor/Directives/Row.js</file>
|
||||
<file>LayoutEditor/Directives/Popup.js</file>
|
||||
|
File diff suppressed because one or more lines are too long
@@ -19,9 +19,6 @@
|
||||
});
|
||||
});
|
||||
};
|
||||
$scope.updateContent = function (e) {
|
||||
$scope.element.setHtml(e.target.innerHTML);
|
||||
};
|
||||
|
||||
// Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
|
||||
$scope.element.setHtml = function (html) {
|
||||
@@ -33,16 +30,7 @@
|
||||
}
|
||||
],
|
||||
templateUrl: environment.templateUrl("Content"),
|
||||
replace: true,
|
||||
link: function (scope, element) {
|
||||
// Mouse down events must not be intercepted by drag and drop while inline editing is active,
|
||||
// otherwise clicks in inline editors will have no effect.
|
||||
element.find(".layout-content-markup").mousedown(function (e) {
|
||||
if (scope.element.editor.inlineEditingIsActive) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
replace: true
|
||||
};
|
||||
}
|
||||
]);
|
@@ -78,7 +78,7 @@
|
||||
if (!$scope.element.inlineEditingIsActive) {
|
||||
$scope.element.inlineEditingIsActive = true;
|
||||
$element.find(".layout-toolbar-container").show();
|
||||
var selector = "#layout-editor-" + $scope.$id + " .layout-content-h-t-m-l .layout-content-markup[data-templated=false]";
|
||||
var selector = "#layout-editor-" + $scope.$id + " .layout-html .layout-content-markup[data-templated=false]";
|
||||
var firstContentEditorId = $(selector).first().attr("id");
|
||||
tinymce.init({
|
||||
selector: selector,
|
||||
|
@@ -0,0 +1,48 @@
|
||||
angular
|
||||
.module("LayoutEditor")
|
||||
.directive("orcLayoutHtml", ["$sce", "scopeConfigurator", "environment",
|
||||
function ($sce, scopeConfigurator, environment) {
|
||||
return {
|
||||
restrict: "E",
|
||||
scope: { element: "=" },
|
||||
controller: ["$scope", "$element",
|
||||
function ($scope, $element) {
|
||||
scopeConfigurator.configureForElement($scope, $element);
|
||||
$scope.edit = function () {
|
||||
$scope.$root.editElement($scope.element).then(function (args) {
|
||||
$scope.$apply(function () {
|
||||
if (args.cancel)
|
||||
return;
|
||||
|
||||
$scope.element.data = args.element.data;
|
||||
$scope.element.setHtml(args.element.html);
|
||||
});
|
||||
});
|
||||
};
|
||||
$scope.updateContent = function (e) {
|
||||
$scope.element.setHtml(e.target.innerHTML);
|
||||
};
|
||||
|
||||
// Overwrite the setHtml function so that we can use the $sce service to trust the html (and not have the html binding strip certain tags).
|
||||
$scope.element.setHtml = function (html) {
|
||||
$scope.element.html = html;
|
||||
$scope.element.htmlUnsafe = $sce.trustAsHtml(html);
|
||||
};
|
||||
|
||||
$scope.element.setHtml($scope.element.html);
|
||||
}
|
||||
],
|
||||
templateUrl: environment.templateUrl("Html"),
|
||||
replace: true,
|
||||
link: function (scope, element) {
|
||||
// Mouse down events must not be intercepted by drag and drop while inline editing is active,
|
||||
// otherwise clicks in inline editors will have no effect.
|
||||
element.find(".layout-content-markup").mousedown(function (e) {
|
||||
if (scope.element.editor.inlineEditingIsActive) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
@@ -898,14 +898,6 @@ var LayoutEditor;
|
||||
return result;
|
||||
};
|
||||
|
||||
var getEditorObject = this.getEditorObject;
|
||||
this.getEditorObject = function () {
|
||||
var dto = getEditorObject();
|
||||
return $.extend(dto, {
|
||||
Content: this.html
|
||||
});
|
||||
}
|
||||
|
||||
this.setHtml(html);
|
||||
};
|
||||
|
||||
@@ -926,3 +918,71 @@ var LayoutEditor;
|
||||
};
|
||||
|
||||
})(LayoutEditor || (LayoutEditor = {}));
|
||||
var LayoutEditor;
|
||||
(function ($, LayoutEditor) {
|
||||
|
||||
LayoutEditor.Html = function (data, htmlId, htmlClass, htmlStyle, isTemplated, contentType, contentTypeLabel, contentTypeClass, html, hasEditor) {
|
||||
LayoutEditor.Element.call(this, "Html", data, htmlId, htmlClass, htmlStyle, isTemplated);
|
||||
|
||||
this.contentType = contentType;
|
||||
this.contentTypeLabel = contentTypeLabel;
|
||||
this.contentTypeClass = contentTypeClass;
|
||||
this.html = html;
|
||||
this.hasEditor = hasEditor;
|
||||
|
||||
this.getInnerText = function () {
|
||||
return $($.parseHTML("<div>" + this.html + "</div>")).text();
|
||||
};
|
||||
|
||||
// This function will be overwritten by the Content directive.
|
||||
this.setHtml = function (html) {
|
||||
this.html = html;
|
||||
this.htmlUnsafe = html;
|
||||
}
|
||||
|
||||
this.toObject = function () {
|
||||
return {
|
||||
"type": "Html"
|
||||
};
|
||||
};
|
||||
|
||||
this.toObject = function () {
|
||||
var result = this.elementToObject();
|
||||
result.contentType = this.contentType;
|
||||
result.contentTypeLabel = this.contentTypeLabel;
|
||||
result.contentTypeClass = this.contentTypeClass;
|
||||
result.html = this.html;
|
||||
result.hasEditor = hasEditor;
|
||||
return result;
|
||||
};
|
||||
|
||||
var getEditorObject = this.getEditorObject;
|
||||
this.getEditorObject = function () {
|
||||
var dto = getEditorObject();
|
||||
return $.extend(dto, {
|
||||
Content: this.html
|
||||
});
|
||||
}
|
||||
|
||||
this.setHtml(html);
|
||||
};
|
||||
|
||||
LayoutEditor.Html.from = function (value) {
|
||||
var result = new LayoutEditor.Html(
|
||||
value.data,
|
||||
value.htmlId,
|
||||
value.htmlClass,
|
||||
value.htmlStyle,
|
||||
value.isTemplated,
|
||||
value.contentType,
|
||||
value.contentTypeLabel,
|
||||
value.contentTypeClass,
|
||||
value.html,
|
||||
value.hasEditor);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
LayoutEditor.registerFactory("Html", function(value) { return LayoutEditor.Html.from(value); });
|
||||
|
||||
})(jQuery, LayoutEditor || (LayoutEditor = {}));
|
||||
|
@@ -19,5 +19,6 @@
|
||||
<file>Models/Row.js</file>
|
||||
<file>Models/Column.js</file>
|
||||
<file>Models/Content.js</file>
|
||||
<file>Models/Html.js</file>
|
||||
</files>
|
||||
</bundle>
|
File diff suppressed because one or more lines are too long
@@ -36,14 +36,6 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
var getEditorObject = this.getEditorObject;
|
||||
this.getEditorObject = function () {
|
||||
var dto = getEditorObject();
|
||||
return $.extend(dto, {
|
||||
Content: this.html
|
||||
});
|
||||
}
|
||||
|
||||
this.setHtml(html);
|
||||
};
|
||||
|
||||
|
@@ -0,0 +1,68 @@
|
||||
var LayoutEditor;
|
||||
(function ($, LayoutEditor) {
|
||||
|
||||
LayoutEditor.Html = function (data, htmlId, htmlClass, htmlStyle, isTemplated, contentType, contentTypeLabel, contentTypeClass, html, hasEditor) {
|
||||
LayoutEditor.Element.call(this, "Html", data, htmlId, htmlClass, htmlStyle, isTemplated);
|
||||
|
||||
this.contentType = contentType;
|
||||
this.contentTypeLabel = contentTypeLabel;
|
||||
this.contentTypeClass = contentTypeClass;
|
||||
this.html = html;
|
||||
this.hasEditor = hasEditor;
|
||||
|
||||
this.getInnerText = function () {
|
||||
return $($.parseHTML("<div>" + this.html + "</div>")).text();
|
||||
};
|
||||
|
||||
// This function will be overwritten by the Content directive.
|
||||
this.setHtml = function (html) {
|
||||
this.html = html;
|
||||
this.htmlUnsafe = html;
|
||||
}
|
||||
|
||||
this.toObject = function () {
|
||||
return {
|
||||
"type": "Html"
|
||||
};
|
||||
};
|
||||
|
||||
this.toObject = function () {
|
||||
var result = this.elementToObject();
|
||||
result.contentType = this.contentType;
|
||||
result.contentTypeLabel = this.contentTypeLabel;
|
||||
result.contentTypeClass = this.contentTypeClass;
|
||||
result.html = this.html;
|
||||
result.hasEditor = hasEditor;
|
||||
return result;
|
||||
};
|
||||
|
||||
var getEditorObject = this.getEditorObject;
|
||||
this.getEditorObject = function () {
|
||||
var dto = getEditorObject();
|
||||
return $.extend(dto, {
|
||||
Content: this.html
|
||||
});
|
||||
}
|
||||
|
||||
this.setHtml(html);
|
||||
};
|
||||
|
||||
LayoutEditor.Html.from = function (value) {
|
||||
var result = new LayoutEditor.Html(
|
||||
value.data,
|
||||
value.htmlId,
|
||||
value.htmlClass,
|
||||
value.htmlStyle,
|
||||
value.isTemplated,
|
||||
value.contentType,
|
||||
value.contentTypeLabel,
|
||||
value.contentTypeClass,
|
||||
value.html,
|
||||
value.hasEditor);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
LayoutEditor.registerFactory("Html", function(value) { return LayoutEditor.Html.from(value); });
|
||||
|
||||
})(jQuery, LayoutEditor || (LayoutEditor = {}));
|
@@ -1,5 +1,4 @@
|
||||
using System.Web.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.Layouts.Elements;
|
||||
using Orchard.Layouts.Framework.Display;
|
||||
@@ -9,6 +8,10 @@ using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Layouts.Services {
|
||||
public abstract class LayoutModelMapBase<T> : ILayoutModelMap where T : Element {
|
||||
public int Priority {
|
||||
get { return 10; }
|
||||
}
|
||||
|
||||
public virtual string LayoutElementType { get { return typeof(T).Name; } }
|
||||
|
||||
public virtual bool CanMap(Element element) {
|
||||
@@ -64,20 +67,22 @@ namespace Orchard.Layouts.Services {
|
||||
public class ContentModelMap : ILayoutModelMap {
|
||||
private readonly IShapeDisplay _shapeDisplay;
|
||||
private readonly IElementDisplay _elementDisplay;
|
||||
private readonly UrlHelper _urlHelper;
|
||||
|
||||
public ContentModelMap(IShapeDisplay shapeDisplay, IElementDisplay elementDisplay, UrlHelper urlHelper) {
|
||||
public ContentModelMap(IShapeDisplay shapeDisplay, IElementDisplay elementDisplay) {
|
||||
_shapeDisplay = shapeDisplay;
|
||||
_elementDisplay = elementDisplay;
|
||||
_urlHelper = urlHelper;
|
||||
}
|
||||
|
||||
public string LayoutElementType { get { return "Content"; } }
|
||||
public bool CanMap(Element element) {
|
||||
public virtual int Priority {
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public virtual string LayoutElementType { get { return "Content"; } }
|
||||
public virtual bool CanMap(Element element) {
|
||||
return !(element is Container);
|
||||
}
|
||||
|
||||
public Element ToElement(IElementManager elementManager, DescribeElementsContext describeContext, JToken node) {
|
||||
public virtual Element ToElement(IElementManager elementManager, DescribeElementsContext describeContext, JToken node) {
|
||||
var elementTypeName = (string)node["contentType"];
|
||||
var descriptor = elementManager.GetElementDescriptorByTypeName(describeContext, elementTypeName);
|
||||
var element = elementManager.ActivateElement(descriptor);
|
||||
@@ -88,13 +93,6 @@ namespace Orchard.Layouts.Services {
|
||||
element.HtmlStyle = (string)node["htmlStyle"];
|
||||
element.IsTemplated = (bool)(node["isTemplated"] ?? false);
|
||||
|
||||
// To support inline editing, we need to tell the element to update its content.
|
||||
var contentElement = element as IContentElement;
|
||||
if (contentElement != null) {
|
||||
var html = (string)node["html"];
|
||||
contentElement.Content = html;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -112,4 +110,32 @@ namespace Orchard.Layouts.Services {
|
||||
node["html"] = _shapeDisplay.Display(_elementDisplay.DisplayElement(element, content: describeContext.Content, displayType: "Design"));
|
||||
}
|
||||
}
|
||||
|
||||
public class HtmlModelMap : ContentModelMap {
|
||||
public HtmlModelMap(IShapeDisplay shapeDisplay, IElementDisplay elementDisplay)
|
||||
: base(shapeDisplay, elementDisplay) {
|
||||
}
|
||||
|
||||
public override int Priority {
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override string LayoutElementType {
|
||||
get { return "Html"; }
|
||||
}
|
||||
|
||||
public override bool CanMap(Element element) {
|
||||
return element is Html;
|
||||
}
|
||||
|
||||
public override Element ToElement(IElementManager elementManager, DescribeElementsContext describeContext, JToken node) {
|
||||
var html = (string)node["html"];
|
||||
var element = (Html)base.ToElement(elementManager, describeContext, node);
|
||||
|
||||
// To support inline editing, we need to update the element's content.
|
||||
element.Content = html;
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,6 +3,7 @@ using Orchard.Layouts.Framework.Elements;
|
||||
|
||||
namespace Orchard.Layouts.Services {
|
||||
public interface ILayoutModelMap : IDependency {
|
||||
int Priority { get; }
|
||||
string LayoutElementType { get; }
|
||||
bool CanMap(Element element);
|
||||
Element ToElement(IElementManager elementManager, DescribeElementsContext describeContext, JToken node);
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.UI.WebControls.WebParts;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
|
@@ -59,7 +59,7 @@ namespace Orchard.Layouts.Services {
|
||||
}
|
||||
|
||||
public ILayoutModelMap GetMapFor(Element element) {
|
||||
return _maps.Value.Single(x => x.CanMap(element));
|
||||
return SelectMap(x => x.CanMap(element));
|
||||
}
|
||||
|
||||
private Element ParseEditorNode(JToken node, Container parent, int index, DescribeElementsContext describeContext) {
|
||||
@@ -77,7 +77,7 @@ namespace Orchard.Layouts.Services {
|
||||
|
||||
private Element LoadElement(JToken node, Container parent, int index, DescribeElementsContext describeContext) {
|
||||
var type = (string)node["type"];
|
||||
var map = _maps.Value.Single(x => x.LayoutElementType == type);
|
||||
var map = SelectMap(x => x.LayoutElementType == type);
|
||||
var element = map.ToElement(_elementManager, describeContext, node);
|
||||
|
||||
element.Container = parent;
|
||||
@@ -85,5 +85,9 @@ namespace Orchard.Layouts.Services {
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private ILayoutModelMap SelectMap(Func<ILayoutModelMap, bool> predicate) {
|
||||
return _maps.Value.OrderByDescending(x => x.Priority).FirstOrDefault(predicate);
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,11 +8,11 @@ using Orchard.Tokens;
|
||||
namespace Orchard.Layouts.Tokens {
|
||||
[OrchardFeature("Orchard.Layouts.Tokens")]
|
||||
public class ElementTokens : Component, ITokenProvider {
|
||||
private readonly ElementManager _elementManager;
|
||||
private readonly ElementDisplay _elementDisplay;
|
||||
private readonly IElementManager _elementManager;
|
||||
private readonly IElementDisplay _elementDisplay;
|
||||
private readonly IShapeDisplay _shapeDisplay;
|
||||
|
||||
public ElementTokens(ElementManager elementManager, ElementDisplay elementDisplay, IShapeDisplay shapeDisplay) {
|
||||
public ElementTokens(IElementManager elementManager, IElementDisplay elementDisplay, IShapeDisplay shapeDisplay) {
|
||||
_elementManager = elementManager;
|
||||
_elementDisplay = elementDisplay;
|
||||
_shapeDisplay = shapeDisplay;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
namespace Orchard.Layouts.ViewModels {
|
||||
public class TextEditorViewModel {
|
||||
public string Text { get; set; }
|
||||
public string Flavor { get; set; }
|
||||
public string Content { get; set; }
|
||||
}
|
||||
}
|
@@ -4,5 +4,6 @@
|
||||
}
|
||||
<fieldset class="autofocus">
|
||||
@Html.LabelFor(m => m.Text, T("Body"))
|
||||
@Html.TextAreaFor(m => m.Text, new { @class = "text large", rows = 10, autofocus = "autofocus" })
|
||||
@Html.TextAreaFor(m => m.Text, 25, 80, new { @class = "text large tokenized", autofocus = "autofocus" })
|
||||
@Html.Hint(T("Note: HTML markup will be rendered unencoded."))
|
||||
</fieldset>
|
@@ -3,6 +3,7 @@
|
||||
Script.Include("AutoFocus.js");
|
||||
}
|
||||
<fieldset class="autofocus">
|
||||
@Html.LabelFor(m => m.Text, T("Body"))
|
||||
@Display.Body_Editor(EditorFlavor: Model.Flavor, Text: Model.Text, AutoFocus: true)
|
||||
@Html.LabelFor(m => m.Content, T("Body"))
|
||||
@Html.TextAreaFor(m => m.Content, 25, 80, new { @class = "text large tokenized", autofocus = "autofocus" })
|
||||
@Html.Hint(T("Note: HTML markup will be rendered encoded."))
|
||||
</fieldset>
|
@@ -40,7 +40,7 @@
|
||||
typeLabel: "@Model.DisplayText.Text",
|
||||
typeClass: "@Model.DisplayText.Text.HtmlClassify()",
|
||||
data: LayoutEditor.decode("@Url.Encode(Model.ElementData)"),
|
||||
html: "@Url.Encode(Model.ElementHtml)",
|
||||
html: LayoutEditor.decode("@Url.Encode(Model.ElementHtml)"),
|
||||
isTemplated: false
|
||||
},
|
||||
elementEditorModel: @Html.Raw(Model.ElementEditorModel.ToJson())
|
||||
|
@@ -1,11 +1,8 @@
|
||||
@using Orchard.DisplayManagement.Shapes
|
||||
@using Orchard.Layouts.Elements
|
||||
@using Orchard.Layouts.Helpers
|
||||
@{
|
||||
var element = (Html)Model.Element;
|
||||
var tagBuilder = TagBuilderExtensions.AddCommonElementAttributes(new OrchardTagBuilder("div"), Model);
|
||||
var text = element.Content;
|
||||
}
|
||||
@tagBuilder.StartElement
|
||||
@Html.Raw(text)
|
||||
@Html.Raw(Model.ProcessedText)
|
||||
@tagBuilder.EndElement
|
@@ -1,10 +1,8 @@
|
||||
@using Orchard.DisplayManagement.Shapes
|
||||
@using Orchard.Layouts.Elements
|
||||
@using Orchard.Layouts.Helpers
|
||||
@{
|
||||
var tagBuilder = TagBuilderExtensions.AddCommonElementAttributes(new OrchardTagBuilder("p"), Model);
|
||||
var element = (Paragraph) Model.Element;
|
||||
}
|
||||
@tagBuilder.StartElement
|
||||
@Html.Raw(element.Content)
|
||||
@Html.Raw(Model.ProcessedText)
|
||||
@tagBuilder.EndElement
|
||||
|
@@ -1 +1 @@
|
||||
@Html.Raw((string)Model.ProcessedText)
|
||||
@Model.Element.Content
|
@@ -1,5 +1,4 @@
|
||||
@using Orchard.Layouts.ViewModels;
|
||||
<div class="layout-element-wrapper">
|
||||
<div class="layout-element-wrapper">
|
||||
<ul class="layout-panel layout-panel-main">
|
||||
<li class="layout-panel-item layout-panel-label">{{::element.contentTypeLabel}}</li>
|
||||
<li class="layout-panel-item layout-panel-action layout-panel-action-edit" ng-show="{{element.hasEditor}}" title="Edit {{element.contentTypeLabel.toLowerCase()}} content (Enter)" ng-click="edit()"><i class="fa fa-code"></i></li>
|
||||
@@ -8,5 +7,5 @@
|
||||
<li class="layout-panel-item layout-panel-action" title="@T("Move {{element.contentTypeLabel.toLowerCase()}} up (Ctrl+Up)")" ng-click="element.moveUp()" ng-class="{disabled: !element.canMoveUp()}"><i class="fa fa-chevron-up"></i></li>
|
||||
<li class="layout-panel-item layout-panel-action" title="@T("Move {{element.contentTypeLabel.toLowerCase()}} down (Ctrl+Down)")" ng-click="element.moveDown()" ng-class="{disabled: !element.canMoveDown()}"><i class="fa fa-chevron-down"></i></li>
|
||||
</ul>
|
||||
<div id="layout-content-markup-{{::$id}}" class="layout-content-markup" ng-bind-html="element.htmlUnsafe" ng-blur="updateContent($event)" data-templated="{{element.isTemplated}}"></div>
|
||||
<div id="layout-content-markup-{{::$id}}" class="layout-content-markup" ng-bind-html="element.htmlUnsafe" data-templated="{{element.isTemplated}}"></div>
|
||||
</div>
|
@@ -0,0 +1,11 @@
|
||||
<div class="layout-element-wrapper">
|
||||
<ul class="layout-panel layout-panel-main">
|
||||
<li class="layout-panel-item layout-panel-label">{{::element.contentTypeLabel}}</li>
|
||||
<li class="layout-panel-item layout-panel-action layout-panel-action-edit" ng-show="{{element.hasEditor}}" title="Edit {{element.contentTypeLabel.toLowerCase()}} content (Enter)" ng-click="edit()"><i class="fa fa-code"></i></li>
|
||||
@Display(New.LayoutEditor_Template_Properties(ElementTypeName: "{{element.contentTypeLabel.toLowerCase()}}"))
|
||||
<li class="layout-panel-item layout-panel-action" title="@T("Delete {{element.contentTypeLabel.toLowerCase()}} (Del)")" ng-click="delete(element)"><i class="fa fa-remove"></i></li>
|
||||
<li class="layout-panel-item layout-panel-action" title="@T("Move {{element.contentTypeLabel.toLowerCase()}} up (Ctrl+Up)")" ng-click="element.moveUp()" ng-class="{disabled: !element.canMoveUp()}"><i class="fa fa-chevron-up"></i></li>
|
||||
<li class="layout-panel-item layout-panel-action" title="@T("Move {{element.contentTypeLabel.toLowerCase()}} down (Ctrl+Down)")" ng-click="element.moveDown()" ng-class="{disabled: !element.canMoveDown()}"><i class="fa fa-chevron-down"></i></li>
|
||||
</ul>
|
||||
<div id="layout-content-markup-{{::$id}}" class="layout-content-markup" ng-bind-html="element.htmlUnsafe" ng-blur="updateContent($event)" data-templated="{{element.isTemplated}}"></div>
|
||||
</div>
|
Reference in New Issue
Block a user