如何为Orchard Layout创建自定义容器元素?

时间:2016-04-07 12:24:18

标签: orchardcms orchardcms-1.9

我正在使用Orchard 1.9.3并遵循一些关于如何在Orchard中创建自定义普通元素的教程。我找不到任何关于创建容器元素的具体内容,所以我在源代码中挖了一下,这是我到目前为止所做的:

元素/ Procedure.cs

public class Procedure : Container
{
    public override string Category
    {
        get { return "Content"; }
    }

    public override string ToolboxIcon
    {
        get { return "\uf0cb"; }
    }

    public override LocalizedString Description
    {
        get { return T("A collection of steps."); }
    }

    public override bool HasEditor
    {
        get { return false; }
    }
}

驱动器/ ProcedureElementDriver.cs

public class ProcedureElementDriver : ElementDriver<Procedure> {}

服务/ ProcedureModelMap

public class ProcedureModelMap : LayoutModelMapBase<Procedure> {}

查看/ LayoutEditor.Template.Procedure

@using Orchard.Layouts.ViewModels;
<div class="layout-element-wrapper" ng-class="{'layout-container-empty': getShowChildrenPlaceholder()}">
<ul class="layout-panel layout-panel-main">
    <li class="layout-panel-item layout-panel-label">Procedure</li>
    @Display()
    @Display(New.LayoutEditor_Template_Properties(ElementTypeName: "procedure"))
    <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 class="layout-container-children-placeholder">
    @T("Drag a steps here.")
</div>
@Display(New.LayoutEditor_Template_Children())

所有这些都或多或少地从Row元素中复制。我现在有一个Procedure元素,我可以从工具箱拖到我的布局上,但它没有用我的模板渲染,即使我可以用这种方式覆盖其他布局元素的模板,我仍然可以'将任何孩子拖入其中。我曾希望只是继承Container就可以实现这一点。

我基本上只想制作一个限制性更强的行和列对,将一些自定义样式应用于任意内容列表。我怎样才能告诉Orchard一个过程只能包含在一个列中,并且它应该接受Steps(或其他一些元素)作为子项?

2 个答案:

答案 0 :(得分:3)

我想出了如何通过查看Mainbit's layout module来制作容器和可包含的元素。 容器元素需要一些额外的Angular代码才能使它们工作。 我仍然需要帮助确定如何限制哪些元素可以包含!

<强>脚本/ LayoutEditor.js

我必须使用指令扩展LayoutEditor模块,以保存与我的元素相关的所有Angular内容:

angular
.module("LayoutEditor")
.directive("orcLayoutProcedure", ["$compile", "scopeConfigurator", "environment",
    function ($compile, scopeConfigurator, environment) {
        return {
            restrict: "E",
            scope: { element: "=" },
            controller: ["$scope", "$element",
                function ($scope, $element) {
                    scopeConfigurator.configureForElement($scope, $element);
                    scopeConfigurator.configureForContainer($scope, $element);
                    $scope.sortableOptions["axis"] = "y";
                }
            ],
            templateUrl: environment.templateUrl("Procedure"),
            replace: true
        };
    }
]);

<强>脚本/ Models.js

Orchard的LayoutEditor供应商使用:

var LayoutEditor;
(function (LayoutEditor) {

LayoutEditor.Procedure = function (data, htmlId, htmlClass, htmlStyle, isTemplated, children) {
    LayoutEditor.Element.call(this, "Procedure", data, htmlId, htmlClass, htmlStyle, isTemplated);
    LayoutEditor.Container.call(this, ["Grid", "Content"], children);

    //this.isContainable = true;
    this.dropTargetClass = "layout-common-holder";

    this.toObject = function () {
        var result = this.elementToObject();
        result.children = this.childrenToObject();
        return result;
    };
};

LayoutEditor.Procedure.from = function (value) {
    var result = new LayoutEditor.Procedure(
        value.data,
        value.htmlId,
        value.htmlClass,
        value.htmlStyle,
        value.isTemplated,
        LayoutEditor.childrenFrom(value.children));
    result.toolboxIcon = value.toolboxIcon;
    result.toolboxLabel = value.toolboxLabel;
    result.toolboxDescription = value.toolboxDescription;
    return result;
};

LayoutEditor.registerFactory("Procedure", function (value) {
    return LayoutEditor.Procedure.from(value);
});

})(LayoutEditor || (LayoutEditor = {}));

这是一条告诉元素可以包含的内容的行:

LayoutEditor.Container.call(this, ["Grid", "Content"], children);

<强> ResourceManifest.cs

然后我制作了一个资源清单,以便在Orchard的模块中轻松提供这些资源。

public class ResourceManifest : IResourceManifestProvider
{
    public void BuildManifests(ResourceManifestBuilder builder)
    {
        var manifest = builder.Add();
        manifest.DefineScript("MyModule.Models").SetUrl("Models.js").SetDependencies("Layouts.LayoutEditor");
        manifest.DefineScript("MyModule.LayoutEditors").SetUrl("LayoutEditor.js").SetDependencies("Layouts.LayoutEditor", "MyModule.Models");
    }
}

默认情况下,.SetUrl()指向模块/主题中的/ Scripts文件夹。

<强>处理程序/ LayoutEditorShapeEventHandler.cs

最后,我添加了此处理程序以在使用布局编辑器的管理页面上加载我的脚本。

public class LayoutEditorShapeEventHandler : IShapeTableProvider
{
    private readonly Work<IResourceManager> _resourceManager;
    public LayoutEditorShapeEventHandler(Work<IResourceManager> resourceManager)
    {
        _resourceManager = resourceManager;
    }

    public void Discover(ShapeTableBuilder builder)
    {
        builder.Describe("EditorTemplate").OnDisplaying(context =>
        {
            if (context.Shape.TemplateName != "Parts.Layout")
                return;

            _resourceManager.Value.Require("script", "MyModule.LayoutEditors");
        });
    }
}

希望这将有助于将来的某些人。但是,我仍然不知道如何制作它,以便我的容器只 包含我的Containable,或者我的Containable只 允许我的容器包含它自己。似乎调整LayoutEditor.Container.call(this, ["Grid", "Content"], children);已足以实现这一目标,但事实并非如此。仍然欢迎更多的帮助。

答案 1 :(得分:1)

首先,谢谢你的回答。我觉得它真有帮助。尽管如此,我最终还是遇到了限制我的容器元素放置位置以及放置在其中的内容的问题。

我注意到这些限制是基于元素的类别。画布,网格,行,列或内容。 Orchard遍历所有类别并运行一些代码以了解该类别中的项目可以放置在何处。 Orchard的布局类别之外的任何内容都是内容。如果你有很多不同的自定义类别用于各种自定义元素,它们仍然是Orchard眼中的内容。所以......对于你拥有的每一个类别,Orchard都会运行一些代码并说该类别中的每个项目实际上都是一个内容,并且它们最终都有相同的放置规则。

我不希望任何自定义容器可以放在另一个自定义容器中,我不想要任何其他内容放在我的自定义容器中,所以我最终执行了以下步骤:

  1. 转到您的Procedure.cs文件并更改您的课程&#39;类别。

    公开覆盖字符串Category =&gt; &#34;集装箱&#34 ;;

  2. 转到Models.js文件并更改&#34; dropTargetClass&#34;中的值属性。

    this.dropTargetClass =&#39; layout-common-holder layout-customcontainer&#39;;

  3. 转到LayoutEditor.Template.ToolboxGroup.cshtml文件(您可以在主题中创建自己的文件)并更改&#34; ui-sortable&#34;中的值。 ul元素中的属性。

    ui-sortable =&#34; category.name ==&#39; Container&#39; ? $ parent.getSortableOptions(category.name):$ parent.getSortableOptions(&#39; Content&#39;)&#34;

  4. 转到Toolbox.js文件并编辑&#34; getSortableOptions&#34;功能,所以它包含你新创建的&#34;容器&#34;类别。注意&#34; layout-customcontainer&#34;上课出现了吼叫。我想删除在我的容器中放置网格和其他布局元素的功能,所以我也不得不改变它们的情况。

    switch (type) {
        case "Container":
            parentClasses = [".layout-column", ".layout-common-holder:not(.layout-customcontainer)"];
            placeholderClasses = "layout-element layout-container ui-sortable-placeholder";
            break;
        case "Grid":
            parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder:not(.layout-customcontainer)"];
            placeholderClasses = "layout-element layout-container layout-grid ui-sortable-placeholder";
            break;
        case "Row":
            parentClasses = [".layout-grid"];
            placeholderClasses = "layout-element layout-container layout-row row ui-sortable-placeholder";
            break;
        case "Column":
            parentClasses = [".layout-row:not(.layout-row-full)"];
            placeholderClasses = "layout-element layout-container layout-column ui-sortable-placeholder";
            floating = true; // To ensure a smooth horizontal-list reordering. https://github.com/angular-ui/ui-sortable#floating
            break;
        case "Content":
            parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder"];
            placeholderClasses = "layout-element layout-content ui-sortable-placeholder";
            break;
        case "Canvas":
            parentClasses = [".layout-canvas", ".layout-column", ".layout-common-holder:not(.layout-container)"];
            placeholderClasses = "layout-element layout-container layout-grid ui-sortable-placeholder";
            break;}
    
  5. 运行Gulpfile.js任务,因此您的更改将放在Orchard的LayoutEditor.js文件中。

  6. 现在,您有一个带有一些自定义限制的容器元素。

    我希望不要迟到对你有用。