mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 11:44:58 +08:00
Including Orchard.ContentPicker
--HG-- branch : 1.x
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.MetaData;
|
||||||
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
using Orchard.Core.Common.Models;
|
||||||
|
using Orchard.Core.Contents.Settings;
|
||||||
|
using Orchard.Core.Contents.ViewModels;
|
||||||
|
using Orchard.DisplayManagement;
|
||||||
|
using Orchard.Mvc;
|
||||||
|
using Orchard.Settings;
|
||||||
|
using Orchard.Themes;
|
||||||
|
using Orchard.UI.Navigation;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Controllers {
|
||||||
|
public class AdminController : Controller {
|
||||||
|
private readonly ISiteService _siteService;
|
||||||
|
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||||
|
|
||||||
|
public AdminController(
|
||||||
|
IOrchardServices orchardServices,
|
||||||
|
ISiteService siteService,
|
||||||
|
IContentDefinitionManager contentDefinitionManager) {
|
||||||
|
_siteService = siteService;
|
||||||
|
_contentDefinitionManager = contentDefinitionManager;
|
||||||
|
Services = orchardServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOrchardServices Services { get; set; }
|
||||||
|
|
||||||
|
[Themed(false)]
|
||||||
|
public ActionResult Index(ListContentsViewModel model, PagerParameters pagerParameters) {
|
||||||
|
var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
|
||||||
|
|
||||||
|
var query = Services.ContentManager.Query(VersionOptions.Latest, GetCreatableTypes(false).Select(ctd => ctd.Name).ToArray());
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(model.Options.SelectedFilter)) {
|
||||||
|
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.Options.SelectedFilter);
|
||||||
|
if (contentTypeDefinition == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
model.TypeDisplayName = !string.IsNullOrWhiteSpace(contentTypeDefinition.DisplayName)
|
||||||
|
? contentTypeDefinition.DisplayName
|
||||||
|
: contentTypeDefinition.Name;
|
||||||
|
query = query.ForType(model.Options.SelectedFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (model.Options.OrderBy) {
|
||||||
|
case ContentsOrder.Modified:
|
||||||
|
query = query.OrderByDescending<CommonPartRecord>(cr => cr.ModifiedUtc);
|
||||||
|
break;
|
||||||
|
case ContentsOrder.Published:
|
||||||
|
query = query.OrderByDescending<CommonPartRecord>(cr => cr.PublishedUtc);
|
||||||
|
break;
|
||||||
|
case ContentsOrder.Created:
|
||||||
|
query = query.OrderByDescending<CommonPartRecord>(cr => cr.CreatedUtc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.Options.FilterOptions = GetCreatableTypes(false)
|
||||||
|
.Select(ctd => new KeyValuePair<string, string>(ctd.Name, ctd.DisplayName))
|
||||||
|
.ToList().OrderBy(kvp => kvp.Value);
|
||||||
|
|
||||||
|
var pagerShape = Services.New.Pager(pager).TotalItemCount(query.Count());
|
||||||
|
var pageOfContentItems = query.Slice(pager.GetStartIndex(), pager.PageSize).ToList();
|
||||||
|
|
||||||
|
var list = Services.New.List();
|
||||||
|
list.AddRange(pageOfContentItems.Select(ci => Services.ContentManager.BuildDisplay(ci, "SummaryAdmin")));
|
||||||
|
|
||||||
|
foreach(IShape item in list.Items) {
|
||||||
|
item.Metadata.Type = "ContentPicker";
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic tab = Services.New.RecentContentTab()
|
||||||
|
.ContentItems(list)
|
||||||
|
.Pager(pagerShape)
|
||||||
|
.Options(model.Options)
|
||||||
|
.TypeDisplayName(model.TypeDisplayName ?? "");
|
||||||
|
|
||||||
|
return new ShapeResult(this, Services.New.ContentPicker().Tab(tab));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<ContentTypeDefinition> GetCreatableTypes(bool andContainable) {
|
||||||
|
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable && (!andContainable || ctd.Parts.Any(p => p.PartDefinition.Name == "ContainablePart")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Orchard.ContentPicker.Settings;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Drivers;
|
||||||
|
using Orchard.ContentManagement.Handlers;
|
||||||
|
using Orchard.ContentPicker.ViewModels;
|
||||||
|
using Orchard.Localization;
|
||||||
|
using Orchard.Utility.Extensions;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Drivers {
|
||||||
|
public class ContentPickerFieldDriver : ContentFieldDriver<Fields.ContentPickerField> {
|
||||||
|
private readonly IContentManager _contentManager;
|
||||||
|
|
||||||
|
public ContentPickerFieldDriver(IContentManager contentManager) {
|
||||||
|
_contentManager = contentManager;
|
||||||
|
T = NullLocalizer.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
|
private static string GetPrefix(Fields.ContentPickerField field, ContentPart part) {
|
||||||
|
return part.PartDefinition.Name + "." + field.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDifferentiator(Fields.ContentPickerField field, ContentPart part) {
|
||||||
|
return field.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DriverResult Display(ContentPart part, Fields.ContentPickerField field, string displayType, dynamic shapeHelper) {
|
||||||
|
return Combined(
|
||||||
|
ContentShape("Fields_ContentPicker", GetDifferentiator(field, part), () => shapeHelper.Fields_ContentPicker()),
|
||||||
|
ContentShape("Fields_ContentPicker_SummaryAdmin", GetDifferentiator(field, part), () => shapeHelper.Fields_ContentPicker_SummaryAdmin())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DriverResult Editor(ContentPart part, Fields.ContentPickerField field, dynamic shapeHelper) {
|
||||||
|
return ContentShape("Fields_ContentPicker_Edit", GetDifferentiator(field, part),
|
||||||
|
() => {
|
||||||
|
var model = new ContentPickerFieldViewModel {
|
||||||
|
Field = field,
|
||||||
|
ContentItems = _contentManager.GetMany<ContentItem>(field.Ids, VersionOptions.Published, QueryHints.Empty).ToList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
model.SelectedIds = string.Concat(",", field.Ids);
|
||||||
|
|
||||||
|
return shapeHelper.EditorTemplate(TemplateName: "Fields/ContentPicker.Edit", Model: model, Prefix: GetPrefix(field, part));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DriverResult Editor(ContentPart part, Fields.ContentPickerField field, IUpdateModel updater, dynamic shapeHelper) {
|
||||||
|
var model = new ContentPickerFieldViewModel();
|
||||||
|
|
||||||
|
updater.TryUpdateModel(model, GetPrefix(field, part), null, null);
|
||||||
|
|
||||||
|
var settings = field.PartFieldDefinition.Settings.GetModel<ContentPickerFieldSettings>();
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(model.SelectedIds)) {
|
||||||
|
field.Ids = new int[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
field.Ids = model.SelectedIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.Required && field.Ids.Length == 0) {
|
||||||
|
updater.AddModelError("Id", T("The field {0} is mandatory", field.Name.CamelFriendly()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Editor(part, field, shapeHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Importing(ContentPart part, Fields.ContentPickerField field, ImportContentContext context) {
|
||||||
|
var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems");
|
||||||
|
if (contentItemIds != null) {
|
||||||
|
field.Ids = contentItemIds.Split(',')
|
||||||
|
.Select(context.GetItemFromSession)
|
||||||
|
.Select(contentItem => contentItem.Id).ToArray();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
field.Ids = new int[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Exporting(ContentPart part, Fields.ContentPickerField field, ExportContentContext context) {
|
||||||
|
if (field.Ids.Any()) {
|
||||||
|
var contentItemIds = field.Ids
|
||||||
|
.Select(x => _contentManager.Get(x))
|
||||||
|
.Select(x => _contentManager.GetItemMetadata(x).Identity.ToString())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("ContentItems", string.Join(",", contentItemIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Describe(DescribeMembersContext context) {
|
||||||
|
context
|
||||||
|
.Member(null, typeof(string), T("Ids"), T("A formatted list of the ids, e.g., {1},{42}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.FieldStorage;
|
||||||
|
using Orchard.ContentManagement.Utilities;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Fields {
|
||||||
|
public class ContentPickerField : ContentField {
|
||||||
|
private static readonly char[] separator = new [] {'{', '}', ','};
|
||||||
|
internal LazyField<IEnumerable<ContentItem>> _contentItems = new LazyField<IEnumerable<ContentItem>>();
|
||||||
|
|
||||||
|
public int[] Ids {
|
||||||
|
get { return DecodeIds(Storage.Get<string>()); }
|
||||||
|
set { Storage.Set(EncodeIds(value)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ContentItem> ContentItems {
|
||||||
|
get {
|
||||||
|
return _contentItems.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EncodeIds(ICollection<int> ids) {
|
||||||
|
if (ids == null || !ids.Any()) {
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use {1},{2} format so it can be filtered with delimiters
|
||||||
|
return "{" + string.Join("},{", ids.ToArray()) + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] DecodeIds(string ids) {
|
||||||
|
if(String.IsNullOrWhiteSpace(ids)) {
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids.Split(separator, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Handlers;
|
||||||
|
using Orchard.ContentManagement.MetaData;
|
||||||
|
using Orchard.ContentPicker.Fields;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Handlers {
|
||||||
|
public class ContentPickerFieldHandler : ContentHandler {
|
||||||
|
private readonly IContentManager _contentManager;
|
||||||
|
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||||
|
|
||||||
|
public ContentPickerFieldHandler(
|
||||||
|
IContentManager contentManager,
|
||||||
|
IContentDefinitionManager contentDefinitionManager) {
|
||||||
|
|
||||||
|
_contentManager = contentManager;
|
||||||
|
_contentDefinitionManager = contentDefinitionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Loading(LoadContentContext context) {
|
||||||
|
base.Loading(context);
|
||||||
|
|
||||||
|
var fields = context.ContentItem.Parts.SelectMany(x => x.Fields.Where(f => f.FieldDefinition.Name == typeof (ContentPickerField).Name)).Cast<ContentPickerField>();
|
||||||
|
|
||||||
|
// define lazy initializer for ContentPickerField.ContentItems
|
||||||
|
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(context.ContentType);
|
||||||
|
if (contentTypeDefinition == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in fields) {
|
||||||
|
var localField = field;
|
||||||
|
field._contentItems.Loader(x => _contentManager.GetMany<ContentItem>(localField.Ids, VersionOptions.Published, QueryHints.Empty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/Orchard.Web/Modules/Orchard.ContentPicker/Module.txt
Normal file
12
src/Orchard.Web/Modules/Orchard.ContentPicker/Module.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Name: Orchard.ContentPicker
|
||||||
|
AntiForgery: enabled
|
||||||
|
Author: The Orchard Team
|
||||||
|
Website: http://orchardcontentpicker.codeplex.com
|
||||||
|
Version: 1.5.1
|
||||||
|
OrchardVersion: 1.4
|
||||||
|
Description: UI for selecting Content Items.
|
||||||
|
Features:
|
||||||
|
Orchard.ContentPicker:
|
||||||
|
Description: UI for selecting Content Items.
|
||||||
|
Dependencies: Contents
|
||||||
|
Category: Input Editor
|
@@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>9.0.30729</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{F301EF7D-F19C-4D83-AA94-CB64F29C037D}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Orchard.ContentPicker</RootNamespace>
|
||||||
|
<AssemblyName>Orchard.ContentPicker</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<MvcBuildViews>false</MvcBuildViews>
|
||||||
|
<FileUpgradeFlags>
|
||||||
|
</FileUpgradeFlags>
|
||||||
|
<OldToolsVersion>4.0</OldToolsVersion>
|
||||||
|
<UpgradeBackupLocation>
|
||||||
|
</UpgradeBackupLocation>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
<UseIISExpress>false</UseIISExpress>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations">
|
||||||
|
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web.DynamicData" />
|
||||||
|
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="System.Web.Abstractions" />
|
||||||
|
<Reference Include="System.Web.Routing" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Scripts\ContentPicker.js" />
|
||||||
|
<Content Include="Styles\ContentPicker.css" />
|
||||||
|
<Content Include="Web.config" />
|
||||||
|
<Content Include="Views\Web.config" />
|
||||||
|
<Content Include="Scripts\Web.config" />
|
||||||
|
<Content Include="Styles\Web.config" />
|
||||||
|
<Content Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Content Include="Module.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||||
|
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||||
|
<Name>Orchard.Framework</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\Core\Orchard.Core.csproj">
|
||||||
|
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||||
|
<Name>Orchard.Core</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Models\" />
|
||||||
|
<Folder Include="Views\Admin\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Controllers\AdminController.cs" />
|
||||||
|
<Compile Include="Drivers\ContentPickerFieldDriver.cs" />
|
||||||
|
<Compile Include="Fields\ContentPickerField.cs" />
|
||||||
|
<Compile Include="Handlers\ContentPickerFieldHandler.cs" />
|
||||||
|
<Compile Include="ResourceManifest.cs" />
|
||||||
|
<Compile Include="Services\ContentPickerNavigationProvider.cs" />
|
||||||
|
<Compile Include="Services\ContentPickerShapes.cs" />
|
||||||
|
<Compile Include="Settings\ContentPickerFieldEditorEvents.cs" />
|
||||||
|
<Compile Include="Settings\ContentPickerFieldSettings.cs" />
|
||||||
|
<Compile Include="Tokens\FieldTokens.cs" />
|
||||||
|
<Compile Include="ViewModels\ContentPickerFieldViewModel.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\ContentPicker.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\RecentContentTab.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\ContentPicker.SummaryAdmin.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\DefinitionTemplates\ContentPickerFieldSettings.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\EditorTemplates\Fields\ContentPicker.Edit.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\Fields\ContentPicker.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\Fields\ContentPicker.SummaryAdmin.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Placement.info">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target> -->
|
||||||
|
<Target Name="AfterBuild" DependsOnTargets="AfterBuildCompiler">
|
||||||
|
<PropertyGroup>
|
||||||
|
<AreasManifestDir>$(ProjectDir)\..\Manifests</AreasManifestDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<!-- If this is an area child project, uncomment the following line:
|
||||||
|
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||||
|
-->
|
||||||
|
<!-- If this is an area parent project, uncomment the following lines:
|
||||||
|
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Parent" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||||
|
<CopyAreaManifests ManifestPath="$(AreasManifestDir)" CrossCopy="false" RenameViews="true" />
|
||||||
|
-->
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuildCompiler" Condition="'$(MvcBuildViews)'=='true'">
|
||||||
|
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
|
||||||
|
</Target>
|
||||||
|
<ProjectExtensions>
|
||||||
|
<VisualStudio>
|
||||||
|
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||||
|
<WebProjectProperties>
|
||||||
|
<UseIIS>False</UseIIS>
|
||||||
|
<AutoAssignPort>True</AutoAssignPort>
|
||||||
|
<DevelopmentServerPort>45979</DevelopmentServerPort>
|
||||||
|
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||||
|
<IISUrl>
|
||||||
|
</IISUrl>
|
||||||
|
<NTLMAuthentication>False</NTLMAuthentication>
|
||||||
|
<UseCustomServer>True</UseCustomServer>
|
||||||
|
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
|
||||||
|
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||||
|
</WebProjectProperties>
|
||||||
|
</FlavorProperties>
|
||||||
|
</VisualStudio>
|
||||||
|
</ProjectExtensions>
|
||||||
|
</Project>
|
12
src/Orchard.Web/Modules/Orchard.ContentPicker/Placement.info
Normal file
12
src/Orchard.Web/Modules/Orchard.ContentPicker/Placement.info
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<Placement>
|
||||||
|
<Place Fields_ContentPicker_Edit="Content:2.3"/>
|
||||||
|
|
||||||
|
<Match DisplayType="Detail">
|
||||||
|
<Place Fields_ContentPicker="Content:after"/>
|
||||||
|
</Match>
|
||||||
|
|
||||||
|
<Match DisplayType="SummaryAdmin">
|
||||||
|
<Place Fields_ContentPicker_SummaryAdmin="Content:after"/>
|
||||||
|
</Match>
|
||||||
|
|
||||||
|
</Placement>
|
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Orchard.ContentPicker")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyProduct("Orchard")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("a5bcfb31-0501-4f12-865d-b04acdc46d7d")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Revision and Build Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
[assembly: AssemblyVersion("1.5")]
|
||||||
|
[assembly: AssemblyFileVersion("1.5")]
|
||||||
|
|
@@ -0,0 +1,10 @@
|
|||||||
|
using Orchard.UI.Resources;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker {
|
||||||
|
public class ResourceManifest : IResourceManifestProvider {
|
||||||
|
public void BuildManifests(ResourceManifestBuilder builder) {
|
||||||
|
var manifest = builder.Add();
|
||||||
|
manifest.DefineScript("ContentPicker").SetUrl("ContentPicker.js", "ContentPicker.js").SetDependencies("jQuery");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,26 @@
|
|||||||
|
jQuery(function ($) {
|
||||||
|
|
||||||
|
$("form").bind("orchard-admin-contentpicker-open", function (ev, data) {
|
||||||
|
data = data || {};
|
||||||
|
// the popup will be doing full page reloads, so will not be able to retain
|
||||||
|
// a pointer to the callback. We will generate a temporary callback
|
||||||
|
// with a known/unique name and pass that in on the querystring so it
|
||||||
|
// is remembers across reloads. Once executed, it calls the real callback
|
||||||
|
// and removes itself.
|
||||||
|
var callbackName = "_contentpicker_" + new Date().getTime();
|
||||||
|
data.callbackName = callbackName;
|
||||||
|
$[callbackName] = function (returnData) {
|
||||||
|
delete $[callbackName];
|
||||||
|
data.callback(returnData);
|
||||||
|
};
|
||||||
|
$[callbackName].data = data;
|
||||||
|
|
||||||
|
var adminIndex = location.href.toLowerCase().indexOf("/admin/");
|
||||||
|
if (adminIndex === -1) return;
|
||||||
|
var url = location.href.substr(0, adminIndex)
|
||||||
|
+ "/Admin/Orchard.ContentPicker?"
|
||||||
|
+ "callback=" + callbackName
|
||||||
|
+ "&" + (new Date() - 0);
|
||||||
|
var w = window.open(url, "_blank", data.windowFeatures || "width=685,height=700,status=no,toolbar=no,location=no,menubar=no,resizable=no,scrollbars=yes");
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="webpages:Enabled" value="false" />
|
||||||
|
</appSettings>
|
||||||
|
<system.web>
|
||||||
|
<httpHandlers>
|
||||||
|
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||||
|
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||||
|
</httpHandlers>
|
||||||
|
</system.web>
|
||||||
|
<system.webServer>
|
||||||
|
<staticContent>
|
||||||
|
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
|
||||||
|
</staticContent>
|
||||||
|
|
||||||
|
<handlers accessPolicy="Script,Read">
|
||||||
|
<!--
|
||||||
|
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||||
|
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||||
|
-->
|
||||||
|
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
@@ -0,0 +1,22 @@
|
|||||||
|
using Orchard.Localization;
|
||||||
|
using Orchard.UI.Navigation;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Services {
|
||||||
|
public class ContentPickerNavigationProvider : INavigationProvider {
|
||||||
|
public ContentPickerNavigationProvider() {
|
||||||
|
T = NullLocalizer.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
|
public string MenuName {
|
||||||
|
get { return "content-picker"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetNavigation(NavigationBuilder builder) {
|
||||||
|
builder.Add(T("Content Picker"),
|
||||||
|
menu => menu
|
||||||
|
.Add(T("Recent Content"), "5", item => item.Action("Index", "Admin", new {area = "Orchard.ContentPicker"}).LocalNav()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Web;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.DisplayManagement;
|
||||||
|
using Orchard.DisplayManagement.Descriptors;
|
||||||
|
using Orchard.Environment;
|
||||||
|
using Orchard.UI.Navigation;
|
||||||
|
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Services {
|
||||||
|
public class ContentPickerShapes : IShapeTableProvider {
|
||||||
|
private readonly Work<INavigationManager> _navigationManager;
|
||||||
|
private readonly Work<WorkContext> _workContext;
|
||||||
|
private readonly Work<IShapeFactory> _shapeFactory;
|
||||||
|
|
||||||
|
public ContentPickerShapes(
|
||||||
|
Work<INavigationManager> navigationManager,
|
||||||
|
Work<WorkContext> workContext,
|
||||||
|
Work<IShapeFactory> shapeFactory) {
|
||||||
|
_navigationManager = navigationManager;
|
||||||
|
_workContext = workContext;
|
||||||
|
_shapeFactory = shapeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Discover(ShapeTableBuilder builder) {
|
||||||
|
builder.Describe("ContentPicker")
|
||||||
|
.OnDisplaying(displaying => {
|
||||||
|
ContentItem contentItem = displaying.Shape.ContentItem;
|
||||||
|
if (contentItem != null) {
|
||||||
|
displaying.ShapeMetadata.Alternates.Add("ContentPicker_" + displaying.ShapeMetadata.DisplayType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Shape]
|
||||||
|
public IHtmlString ContentPickerNavigation(dynamic Display) {
|
||||||
|
|
||||||
|
IEnumerable<MenuItem> menuItems = _navigationManager.Value.BuildMenu("content-picker");
|
||||||
|
|
||||||
|
// Set the currently selected path
|
||||||
|
Stack<MenuItem> selectedPath = NavigationHelper.SetSelectedPath(menuItems, _workContext.Value.HttpContext.Request.RequestContext.RouteData);
|
||||||
|
|
||||||
|
dynamic shapeFactory = _shapeFactory.Value;
|
||||||
|
|
||||||
|
// Populate local nav
|
||||||
|
dynamic localMenuShape = shapeFactory.LocalMenu().MenuName("content-picker");
|
||||||
|
NavigationHelper.PopulateLocalMenu(shapeFactory, localMenuShape, localMenuShape, selectedPath);
|
||||||
|
return Display(localMenuShape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.MetaData;
|
||||||
|
using Orchard.ContentManagement.MetaData.Builders;
|
||||||
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
using Orchard.ContentManagement.ViewModels;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Settings {
|
||||||
|
public class ContentPickerFieldEditorEvents : ContentDefinitionEditorEventsBase {
|
||||||
|
|
||||||
|
public override IEnumerable<TemplateViewModel> PartFieldEditor(ContentPartFieldDefinition definition) {
|
||||||
|
if (definition.FieldDefinition.Name == "ContentPickerField") {
|
||||||
|
var model = definition.Settings.GetModel<ContentPickerFieldSettings>();
|
||||||
|
yield return DefinitionTemplate(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<TemplateViewModel> PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) {
|
||||||
|
if (builder.FieldType != "ContentPickerField") {
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = new ContentPickerFieldSettings();
|
||||||
|
if (updateModel.TryUpdateModel(model, "ContentPickerFieldSettings", null, null)) {
|
||||||
|
builder.WithSetting("ContentPickerFieldSettings.Hint", model.Hint);
|
||||||
|
builder.WithSetting("ContentPickerFieldSettings.Required", model.Required.ToString(CultureInfo.InvariantCulture));
|
||||||
|
builder.WithSetting("ContentPickerFieldSettings.Multiple", model.Multiple.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return DefinitionTemplate(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Orchard.ContentPicker.Settings {
|
||||||
|
public class ContentPickerFieldSettings {
|
||||||
|
public string Hint { get; set; }
|
||||||
|
public bool Required { get; set; }
|
||||||
|
public bool Multiple { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
html { background:none !important }
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #333;
|
||||||
|
background:#f3f4f5;
|
||||||
|
font-family: Segoe UI,Trebuchet,Arial,Sans-Serif;
|
||||||
|
line-height:1.6em;
|
||||||
|
padding:12px;
|
||||||
|
width:640px;
|
||||||
|
min-width:640px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#orchard-content-picker * { font:100% normal Segoe UI,Trebuchet,Arial,Sans-Serif; }
|
||||||
|
|
||||||
|
.content-picker-tab
|
||||||
|
{
|
||||||
|
margin: 6px;
|
||||||
|
padding: 18px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #E4E5E6;
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="webpages:Enabled" value="false" />
|
||||||
|
</appSettings>
|
||||||
|
<system.web>
|
||||||
|
<httpHandlers>
|
||||||
|
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||||
|
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||||
|
</httpHandlers>
|
||||||
|
</system.web>
|
||||||
|
<system.webServer>
|
||||||
|
<staticContent>
|
||||||
|
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
|
||||||
|
</staticContent>
|
||||||
|
|
||||||
|
<handlers accessPolicy="Script,Read">
|
||||||
|
<!--
|
||||||
|
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||||
|
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||||
|
-->
|
||||||
|
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.Events;
|
||||||
|
using Orchard.ContentPicker.Fields;
|
||||||
|
using Orchard.Localization;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.Tokens {
|
||||||
|
public interface ITokenProvider : IEventHandler {
|
||||||
|
void Describe(dynamic context);
|
||||||
|
void Evaluate(dynamic context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContentPickerFieldTokens : ITokenProvider {
|
||||||
|
private readonly IContentManager _contentManager;
|
||||||
|
|
||||||
|
public ContentPickerFieldTokens(IContentManager contentManager) {
|
||||||
|
_contentManager = contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
|
public void Describe(dynamic context) {
|
||||||
|
context.For("ContentPickerField", T("Content Picker Field"), T("Tokens for Content Picker Fields"))
|
||||||
|
.Token("Content", T("Content Item"), T("The content item."))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Evaluate(dynamic context) {
|
||||||
|
context.For<ContentPickerField>("ContentPickerField")
|
||||||
|
.Token("Content", (Func<ContentPickerField, object>)(field => field.Ids[0]))
|
||||||
|
.Chain("Content", "Content", (Func<ContentPickerField, object>)(field => _contentManager.Get(field.Ids[0])))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentPicker.Fields;
|
||||||
|
|
||||||
|
namespace Orchard.ContentPicker.ViewModels {
|
||||||
|
|
||||||
|
public class ContentPickerFieldViewModel {
|
||||||
|
|
||||||
|
public ICollection<ContentItem> ContentItems { get; set; }
|
||||||
|
public string SelectedIds { get; set; }
|
||||||
|
public ContentPickerField Field { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
@using Orchard.ContentManagement;
|
||||||
|
@{
|
||||||
|
ContentItem contentItem = Model.ContentItem;
|
||||||
|
}
|
||||||
|
<div class="summary" itemscope="itemscope" itemid="@contentItem.Id" itemtype="http://orchardproject.net/data/ContentItem">
|
||||||
|
<div class="properties">
|
||||||
|
@*<input type="checkbox" value="@contentItem.Id" name="itemIds"/>*@
|
||||||
|
<h3>@Html.ItemDisplayText(contentItem)</h3> - <div class="contentType">@contentItem.TypeDefinition.DisplayName</div>
|
||||||
|
@if (Model.Header != null) {
|
||||||
|
<div class="header">@Display(Model.Header)</div>
|
||||||
|
}
|
||||||
|
@if (Model.Meta != null) {
|
||||||
|
<div class="metadata">@Display(Model.Meta)</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="related" data-display-text="@Html.ItemDisplayText(contentItem)" data-id="@contentItem.Id" data-edit-link="@Html.Encode(Html.ItemEditLink(contentItem))" data-display-link="@Html.Encode(Html.ItemDisplayLink(contentItem))" >
|
||||||
|
@Html.Link(T("Select").Text, "#", new { @class = "button select"})
|
||||||
|
</div>
|
||||||
|
@if (Model.Content != null) {
|
||||||
|
<div class="primary">@Display(Model.Content)</div>
|
||||||
|
}
|
||||||
|
</div>
|
@@ -0,0 +1,95 @@
|
|||||||
|
@{
|
||||||
|
// these need to be in the head because MediaBrowser.js defines a callback that the thumbnail images call when they load,
|
||||||
|
// which could happen as soon as they render.
|
||||||
|
Style.Require("jQueryUI_Orchard").AtHead();
|
||||||
|
Script.Require("jQueryUI_Tabs").AtHead();
|
||||||
|
|
||||||
|
SetMeta("X-UA-Compatible", "IE=edge,chrome=1");
|
||||||
|
Style.Include("~/themes/theadmin/styles/site.css");
|
||||||
|
Style.Include("~/themes/theadmin/styles/ie.css").UseCondition("lte IE 8").SetAttribute("media", "screen, projection");
|
||||||
|
Style.Include("~/themes/theadmin/styles/ie6.css").UseCondition("lte IE 6").SetAttribute("media", "screen, projection");
|
||||||
|
|
||||||
|
Script.Include("ContentPicker.js");
|
||||||
|
Style.Include("ContentPicker.css");
|
||||||
|
|
||||||
|
}
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>@T("Select Content Item")</title>
|
||||||
|
@Display.Metas()
|
||||||
|
@Display.HeadScripts()
|
||||||
|
@Display.HeadLinks()
|
||||||
|
@Display.StyleSheetLinks()
|
||||||
|
</head>
|
||||||
|
<body id="orchard-content-picker">
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$.extend({
|
||||||
|
contentPicker: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
$.contentPicker.cannotPerformMsg="@T("Cannot perform requested operation")";
|
||||||
|
$.contentPicker.accessDeniedMsg="@T("Authentication timed-out: please log-on again")";
|
||||||
|
$.contentPicker.logonUrl="@Url.Action("LogOn", new { Controller = "Account", Area = "Orchard.Users" })";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@Display.ContentPickerNavigation()
|
||||||
|
|
||||||
|
<div class="content-picker-tab">
|
||||||
|
@Display(Model.Tab)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@using(Script.Foot()) {
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
$(".select").on("click", function () {
|
||||||
|
try {
|
||||||
|
var container = $(this).closest("[data-id]");
|
||||||
|
var result = {
|
||||||
|
id: container.attr("data-id"),
|
||||||
|
displayText: container.attr("data-display-text"),
|
||||||
|
editLink: container.attr("data-edit-link"),
|
||||||
|
displayLink: container.attr("data-display-link")
|
||||||
|
};
|
||||||
|
|
||||||
|
window.opener.jQuery[query("callback")](result);
|
||||||
|
} catch (ex) {
|
||||||
|
alert($.contentPicker.cannotPerformMsg);
|
||||||
|
alert(ex);
|
||||||
|
}
|
||||||
|
window.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("ul a").each(function () {
|
||||||
|
var self = $(this);
|
||||||
|
var link = self.attr("href");
|
||||||
|
// if the link doesn't define the "callback" query string, then append it
|
||||||
|
// n.b., pagers already append it
|
||||||
|
if (query("callback", link).length == 0) {
|
||||||
|
link = link + "?callback=" + query("callback");
|
||||||
|
self.attr("href", link);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// get a querystring value
|
||||||
|
function query(name, querystring) {
|
||||||
|
name = name.toLowerCase();
|
||||||
|
var search = querystring || location.search;
|
||||||
|
var parts = search.replace("?", "").replace("#", "").split("&");
|
||||||
|
for (var i = 0, l = parts.length; i < l; i++) {
|
||||||
|
var part = parts[i];
|
||||||
|
var eqIndex = part.indexOf("=");
|
||||||
|
if (eqIndex !== -1 && part.substr(0, eqIndex).toLowerCase() === name) {
|
||||||
|
return part.substr(eqIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
|
@Display.FootScripts()
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -0,0 +1,20 @@
|
|||||||
|
@model Orchard.ContentPicker.Settings.ContentPickerFieldSettings
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<div>
|
||||||
|
@Html.CheckBoxFor(m => m.Required) <label for="@Html.FieldIdFor(m => m.Required)" class="forcheckbox">@T("A content item is required")</label>
|
||||||
|
<span class="hint">@T("Check to ensure the user is providing at least one content item.")</span>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<div>
|
||||||
|
@Html.CheckBoxFor(m => m.Multiple) <label for="@Html.FieldIdFor(m => m.Multiple)" class="forcheckbox">@T("Allow multiple content items")</label>
|
||||||
|
<span class="hint">@T("Check to allow user the to select multiple content items.")</span>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<label for="@Html.FieldIdFor(m => m.Hint)">@T("Help text")</label>
|
||||||
|
@Html.TextAreaFor(m => m.Hint, new { @class = "textMedium", rows = "5" } )
|
||||||
|
<span class="hint">@T("The help text is written under the field when authors are selecting content items.")</span>
|
||||||
|
@Html.ValidationMessageFor(m => m.Hint)
|
||||||
|
</fieldset>
|
@@ -0,0 +1,110 @@
|
|||||||
|
@model Orchard.ContentPicker.ViewModels.ContentPickerFieldViewModel
|
||||||
|
@using Orchard.Utility.Extensions;
|
||||||
|
@using Orchard.ContentPicker.Settings;
|
||||||
|
|
||||||
|
@{
|
||||||
|
Script.Require("ContentPicker").AtFoot();
|
||||||
|
Script.Require("jQueryUI_Sortable").AtFoot();
|
||||||
|
Style.Include("content-picker-admin.css");
|
||||||
|
|
||||||
|
var settings = Model.Field.PartFieldDefinition.Settings.GetModel<ContentPickerFieldSettings>();
|
||||||
|
}
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<label @if(settings.Required) { <text>class="required"</text> }>@Model.Field.DisplayName</label>
|
||||||
|
<div id="save-message-@Html.FieldIdFor(m => m.Field.Ids)" class="message message-Warning content-picker-message">@T("You need to save your changes.")</div>
|
||||||
|
<table id="content-picker-@Html.FieldIdFor(m => m.Field.Ids)" class="items content-picker" summary="@Model.Field.DisplayName">
|
||||||
|
<colgroup>
|
||||||
|
<col id="Col1" style="width:20px" />
|
||||||
|
<col id="Col2" />
|
||||||
|
<col id="Col3" />
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" > ↓</th>
|
||||||
|
<th scope="col">@T("Content Item")</th>
|
||||||
|
<th scope="col"> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var contentItem in Model.ContentItems) {
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td>
|
||||||
|
<span data-id="@contentItem.Id" data-fieldid="@Html.FieldIdFor(m => m.Field.Ids)" class="content-picker-item">@Html.ItemEditLink(contentItem)</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span data-id="@contentItem.Id" class="content-picker-remove button grey">@T("Remove")</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<span id="btn-@Html.FieldIdFor(m => m.Field.Ids)" class="button">@T("Add")</span>
|
||||||
|
|
||||||
|
@Html.HiddenFor(m => m.SelectedIds)
|
||||||
|
<span class="hint">@settings.Hint</span>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
@using (Script.Foot()) {
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
var required = @(settings.Required ? "true" : "false");
|
||||||
|
var multiple = @(settings.Multiple ? "true" : "false");
|
||||||
|
var addButton = $('#btn-@Html.FieldIdFor(m => m.Field.Ids)');
|
||||||
|
var @Html.FieldIdFor(m => m.Field.Ids)_Template = '<tr><td> </td><td><span data-id="{contentItemId}" data-fieldid="@Html.FieldIdFor(m => m.Field.Ids)" class="content-picker-item">{edit-link}</span></td><td><span data-id="{contentItemId}" class="content-picker-remove button grey">@T("Remove")</span></td></tr>';
|
||||||
|
|
||||||
|
var refreshIds = function() {
|
||||||
|
var id = $('#@Html.FieldIdFor(m => m.SelectedIds)');
|
||||||
|
id.val('');
|
||||||
|
$("span[data-fieldid = @Html.FieldIdFor(m => m.Field.Ids)]").each(function() {
|
||||||
|
id.val(id.val() + "," + $(this).attr("data-id"));
|
||||||
|
});
|
||||||
|
|
||||||
|
var itemsCount = $("span[data-fieldid = @Html.FieldIdFor(m => m.Field.Ids)]").length;
|
||||||
|
|
||||||
|
if(!multiple && itemsCount > 0) {
|
||||||
|
addButton.hide();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addButton.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
refreshIds();
|
||||||
|
|
||||||
|
addButton.click(function() {
|
||||||
|
addButton.trigger("orchard-admin-contentpicker-open", {
|
||||||
|
callback: function(data) {
|
||||||
|
var template = @Html.FieldIdFor(m => m.Field.Ids)_Template.replace( /\{contentItemId\}/g , data.id).replace( /\{edit-link\}/g , data.editLink);
|
||||||
|
var content = $(template);
|
||||||
|
$('#content-picker-@Html.FieldIdFor(m => m.Field.Ids) tbody').append(content);
|
||||||
|
|
||||||
|
refreshIds();
|
||||||
|
$('#save-message-@Html.FieldIdFor(m => m.Field.Ids)').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#content-picker-@Html.FieldIdFor(m => m.Field.Ids) .content-picker-remove').live("click", function() {
|
||||||
|
$(this).closest('tr').remove();
|
||||||
|
refreshIds();
|
||||||
|
$('#save-message-@Html.FieldIdFor(m => m.Field.Ids)').show();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#content-picker-@Html.FieldIdFor(m => m.Field.Ids) tbody").sortable({
|
||||||
|
handle: 'td:first',
|
||||||
|
stop: function(event, ui) {
|
||||||
|
refreshIds();
|
||||||
|
$('#save-message-@Html.FieldIdFor(m => m.Field.Ids)').show();
|
||||||
|
}
|
||||||
|
}).disableSelection();
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
@using Orchard.ContentPicker.Fields
|
||||||
|
@using Orchard.Utility.Extensions;
|
||||||
|
|
||||||
|
@{
|
||||||
|
var field = (ContentPickerField) Model.ContentField;
|
||||||
|
string name = field.DisplayName;
|
||||||
|
var contentItems = field.ContentItems;
|
||||||
|
}
|
||||||
|
<p class="content-picker-field content-picker-field-@name.HtmlClassify()">
|
||||||
|
<span class="name">@name:</span>
|
||||||
|
@if(contentItems.Any()) {
|
||||||
|
foreach(var contentItem in contentItems) {
|
||||||
|
<span class="value">@Html.ItemEditLink(contentItem)</span>
|
||||||
|
if(contentItem != contentItems.Last()) {
|
||||||
|
<span>,</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
<span class="value">@T("No content items.")</span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
|
@@ -0,0 +1,23 @@
|
|||||||
|
@using Orchard.ContentPicker.Fields
|
||||||
|
@using Orchard.Utility.Extensions;
|
||||||
|
|
||||||
|
@{
|
||||||
|
var field = (ContentPickerField) Model.ContentField;
|
||||||
|
string name = field.DisplayName;
|
||||||
|
var contentItems = field.ContentItems;
|
||||||
|
}
|
||||||
|
<p class="content-picker-field content-picker-field-@name.HtmlClassify()">
|
||||||
|
<span class="name">@name:</span>
|
||||||
|
@if(contentItems.Any()) {
|
||||||
|
foreach(var contentItem in contentItems) {
|
||||||
|
<span class="value">@Html.ItemDisplayLink(contentItem)</span>
|
||||||
|
if(contentItem != contentItems.Last()) {
|
||||||
|
<span>,</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
<span class="value">@T("No content items.")</span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
|
@@ -0,0 +1,38 @@
|
|||||||
|
@using Orchard.Core.Contents.ViewModels;
|
||||||
|
@{
|
||||||
|
var typeDisplayName = Model.TypeDisplayName;
|
||||||
|
var pageTitle = T("Recent Content");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(typeDisplayName)) {
|
||||||
|
pageTitle = T("Manage {0} Content", typeDisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.Title = pageTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="manage">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@using (Html.BeginFormAntiForgeryPost()) {
|
||||||
|
<fieldset class="bulk-actions">
|
||||||
|
<label for="filterResults" class="bulk-filter">@T("Show")</label>
|
||||||
|
<select id="filterResults" name="Options.SelectedFilter">
|
||||||
|
@Html.SelectOption((string)Model.Options.SelectedFilter, "", T("any (show all)").ToString())
|
||||||
|
@foreach(var filterOption in Model.Options.FilterOptions) {
|
||||||
|
@Html.SelectOption((string)Model.Options.SelectedFilter, (string)filterOption.Key, (string)filterOption.Value)
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<label for="orderResults" class="bulk-order">@T("Ordered by")</label>
|
||||||
|
<select id="orderResults" name="Options.OrderBy">
|
||||||
|
@Html.SelectOption((ContentsOrder)Model.Options.OrderBy, ContentsOrder.Created, T("recently created").ToString())
|
||||||
|
@Html.SelectOption((ContentsOrder)Model.Options.OrderBy, ContentsOrder.Modified, T("recently modified").ToString())
|
||||||
|
@Html.SelectOption((ContentsOrder)Model.Options.OrderBy, ContentsOrder.Published, T("recently published").ToString())
|
||||||
|
</select>
|
||||||
|
<button type="submit" name="submit.Filter" value="yes please">@T("Apply")</button>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="contentItems bulk-items">
|
||||||
|
@Display(Model.ContentItems)
|
||||||
|
</fieldset>
|
||||||
|
@Display(Model.Pager)
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="webpages:Enabled" value="false" />
|
||||||
|
</appSettings>
|
||||||
|
<system.web>
|
||||||
|
<httpHandlers>
|
||||||
|
</httpHandlers>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Enabling request validation in view pages would cause validation to occur
|
||||||
|
after the input has already been processed by the controller. By default
|
||||||
|
MVC performs request validation before a controller processes the input.
|
||||||
|
To change this behavior apply the ValidateInputAttribute to a
|
||||||
|
controller or action.
|
||||||
|
-->
|
||||||
|
<pages
|
||||||
|
validateRequest="false"
|
||||||
|
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||||
|
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||||
|
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<controls>
|
||||||
|
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" namespace="System.Web.Mvc" tagPrefix="mvc" />
|
||||||
|
</controls>
|
||||||
|
</pages>
|
||||||
|
</system.web>
|
||||||
|
|
||||||
|
<system.webServer>
|
||||||
|
<validation validateIntegratedModeConfiguration="false"/>
|
||||||
|
<handlers>
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
|
||||||
|
<bindingRedirect oldVersion="2.0.0.0" newVersion="3.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
41
src/Orchard.Web/Modules/Orchard.ContentPicker/Web.config
Normal file
41
src/Orchard.Web/Modules/Orchard.ContentPicker/Web.config
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
|
||||||
|
<remove name="host" />
|
||||||
|
<remove name="pages" />
|
||||||
|
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||||
|
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
|
|
||||||
|
<system.web.webPages.razor>
|
||||||
|
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||||
|
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
|
||||||
|
<namespaces>
|
||||||
|
<add namespace="System.Web.Mvc" />
|
||||||
|
<add namespace="System.Web.Mvc.Ajax" />
|
||||||
|
<add namespace="System.Web.Mvc.Html" />
|
||||||
|
<add namespace="System.Web.Routing" />
|
||||||
|
<add namespace="System.Web.WebPages" />
|
||||||
|
<add namespace="System.Linq"/>
|
||||||
|
<add namespace="System.Collections.Generic"/>
|
||||||
|
<add namespace="Orchard.Mvc.Html"/>
|
||||||
|
</namespaces>
|
||||||
|
</pages>
|
||||||
|
</system.web.webPages.razor>
|
||||||
|
|
||||||
|
<system.web>
|
||||||
|
<compilation targetFramework="4.0">
|
||||||
|
<assemblies>
|
||||||
|
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||||
|
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||||
|
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
|
||||||
|
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||||
|
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||||
|
</assemblies>
|
||||||
|
</compilation>
|
||||||
|
</system.web>
|
||||||
|
|
||||||
|
</configuration>
|
Reference in New Issue
Block a user