Compare commits

...

62 Commits

Author SHA1 Message Date
Sebastien Ros
63be17f440 Upgrading Lucene dll 2015-11-10 10:50:38 -08:00
Sipke Schoorstra
06ee7849c1 Removed tokenization from dynamic form error messages. 2015-11-03 22:34:11 +01:00
Sipke Schoorstra
61c91ff858 Merge pull request #5884 from phillipsj/1.9.x
Resolves #5878 : URL Field for Dynamic Forms
2015-11-03 22:08:22 +01:00
Lombiq
92cbf8925b Merge branch 'master' into 1.9.x 2015-11-03 21:38:19 +01:00
Lombiq
c8b7c64d93 Changing DotNest casing to the official one in the Readme 2015-11-03 21:37:13 +01:00
Lombiq
9572ef9ad3 Removing unnecessary Web.config file from the unused "Orchard.Dashboards" module folder, #6010
Fixes #6010
2015-11-03 21:25:51 +01:00
Sipke Schoorstra
388932b41f Merge pull request #5992 from harmony7/LayoutEditorSaveJquery
With the Element editor dialog, use dialog iframe's jQuery for form submission
2015-10-29 14:27:57 +01:00
Katsuyuki Ohmuro
829f69198c With the Element editor dialog, use dialog frame's jQuery for form submission. 2015-10-29 21:40:47 +09:00
Jamie Phillips
4648a252b9 Correcting formatting and handling of error message.
Corrected the formatting and correct the handling of the error message.
2015-10-23 17:12:24 -04:00
Sébastien Ros
219f29cd20 Merge pull request #5972 from rtpHarry/patch-4
Revamp readme.md and update version to 1.9.2
2015-10-22 12:20:48 -07:00
Sébastien Ros
51003bf582 Merge pull request #5967 from carlwoodhouse/redis-patch
[Fixes #5958] Improving Redis extensions use of keys
2015-10-22 12:19:26 -07:00
Sebastien Ros
0d5cff66a9 Fixing Azure Portal integration 2015-10-21 14:41:41 -07:00
Lombiq
7e66c98dd5 Adding the ability to add a menu item under another item directly, #4009 2015-10-21 19:52:03 +02:00
Jamie Phillips
14c2ee7944 Updating Validation Message for URL Field
This change is made to now be in sync with the recent changes to how validation messages are being handled.
2015-10-20 20:34:23 -04:00
Matthew Harris
9ae372a920 revamp and update version to 1.9.2
It was still talking about the project in the context of v1 and had a duplicate section about getting involved
2015-10-21 00:11:42 +01:00
Carl Woodhouse
eecb61a132 Redis extensions use of keys #5958 2015-10-20 12:35:34 +01:00
Sébastien Ros
4574a9fb0b Merge pull request #5915 from rtpHarry/patch-1
[Fixes #5912] Improve warning css in multi-tenant edit
2015-10-19 16:35:44 -07:00
Matthew Harris
bec9a6d792 Merge branch '1.9.x' into patch-1
Conflicts:
	src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Edit.cshtml
2015-10-20 00:09:16 +01:00
Kegan Maher
dbe89d0a82 avoid null exception in AzureBlobStorageProvider.GetStoragePath, fixes #4402 2015-10-16 14:19:39 -07:00
Sipke Schoorstra
255547288b Fixed T usage in ValidationRules, round 2. 2015-10-16 10:45:08 +02:00
Lombiq
a9abc294e3 Fixing that module tests codegen created projects with the old .NET framework version 2015-10-15 15:51:44 -07:00
Sebastien Ros
101d61b808 Merge branch 'master' into 1.9.x 2015-10-15 15:00:14 -07:00
Sipke Schoorstra
054925c297 Fixed T usage in ValidationRules. 2015-10-15 21:47:01 +02:00
Sébastien Ros
ff97d1e975 Merge pull request #5918 from rtpHarry/patch-3
[Fixes #5908] Triple columns don't fit on small screens
2015-10-15 12:22:16 -07:00
Sébastien Ros
e26fee3d6c Merge pull request #5844 from escofieldnaxos/feature/Content-Picker-MultiSelect
Enhancement to allow multi-select for the content picker
2015-10-15 12:09:10 -07:00
Sebastien Ros
ec0ea5e321 Updating ManageOwnMedia defaults
Fixes #5894
2015-10-15 11:41:07 -07:00
Sébastien Ros
dd9d67fe48 Merge pull request #5952 from dcinzona/patch-2
Fixes #5896 - AzureFileStorageProvider
2015-10-15 11:36:49 -07:00
Sébastien Ros
9105187f78 Merge pull request #5950 from mattcowen/1.9.2
Fix for orchard issue #5869
2015-10-15 11:19:12 -07:00
Nicholas Mayne
1da6066e83 Merge pull request #5921 from rtpHarry/fix-m-ui-glitch
fix multitenancy ui glitch - fixes #5913
2015-10-15 08:41:56 +01:00
Sébastien Ros
52c6debc97 Merge pull request #5937 from dcinzona/patch-1
Fixes for #5936 #5938 #5941 and #5891
2015-10-14 09:11:08 -07:00
Sébastien Ros
f3be4fa2c7 Merge pull request #5946 from dcinzona/azure.storage-5.0.2.0
[Fixes #5935] Updates Azure.Storage to 5.0.2.0
2015-10-14 09:08:56 -07:00
Gustavo Tandeciarz
d64541d47a Fixes #5896 - AzureFileStorageProvider
Needs verification that this will not break anything else - don't think it will.
2015-10-14 10:15:06 -04:00
mattcowen
9714c2c5f0 Fix for orchard issue 5869 2015-10-14 11:47:56 +01:00
dcinzona
855d183be3 Fixes #5935 Updates Azure.Storage to 5.0.2.0 2015-10-13 15:38:57 -04:00
Gustavo Tandeciarz
a37e548b25 Update media-library.js
Fixed typo
2015-10-13 07:26:52 -04:00
Gustavo Tandeciarz
99695f07cc Update media-library.js
Adjusted for default dimention based on window width (css media query)
fixed class lookup as .thumbnail has 0 height on load.
2015-10-13 07:26:13 -04:00
Gustavo Tandeciarz
63ca6ee2d8 Media Library Recents - Fixes issue #5938
The Recents link doesn't work when rootMediaFolder is null.
2015-10-12 15:07:57 -04:00
Gustavo Tandeciarz
042c47cc3f Media Library - Fixes issue #5941
Sets the opacity of the list items in the media library to .3 when new items are loading.
2015-10-12 15:05:39 -04:00
Gustavo Tandeciarz
49ab41d4dc Fixes issue #5936 - page count = infinity
Sets defaults to 200 if any dimension = 0
2015-10-12 14:15:50 -04:00
Erik Scofield
7fb63fd9eb Fix incorrect project reference probably from a merge from the Naxos branch to this feature. 2015-10-09 11:08:15 -05:00
Matthew Harris
e853550bda fix multitenancy ui glitch 2015-10-09 10:45:17 +01:00
Matthew Harris
24c68bebe4 fix triple columns not fitting on small screens 2015-10-08 21:33:18 +01:00
Matthew Harris
0a82363187 fix css issue 2015-10-08 21:26:37 +01:00
Sébastien Ros
1e87eee2e4 Merge pull request #5852 from Codinlab/issue/5737
[Fixes #5737] ChangeListView throws NRE on unpublished Lists
2015-10-08 12:27:02 -07:00
Sébastien Ros
53244d702c Merge pull request #5851 from mjy78/issue/5125
[Fixes #5125] Ensure the modified taxonomy items are not lost if a model validation…
2015-10-08 12:26:25 -07:00
Sébastien Ros
07cc3a6bad Merge pull request #5804 from mvarblow/patch-2
Prevent no-op tasks for taxonomy field updates.
2015-10-08 12:19:11 -07:00
Sébastien Ros
6f4762a30c Merge pull request #5785 from mjy78/issue/21244
[Fixes #5073] Display warning when insecure custom forms are created
2015-10-08 12:12:53 -07:00
Sébastien Ros
ce3179307d Merge pull request #5784 from mjy78/issue/20514
[Fixes #4343] Remove id from custom form returnUrl hidden field
2015-10-08 12:11:06 -07:00
Erik Scofield
2620dc820d ~Fix resource include
~Rename javascript resource from RecentContentTab to SelectableContentTab for use in Search content picker as well.
+Add Selectable to Search Content Picker
+Add Select All to Search Content Picker
2015-10-06 23:27:30 -05:00
Sebastien Ros
9c88c7fcd1 Fixing draft indexation 2015-10-02 15:44:35 +02:00
Jamie Phillips
a01b7dde23 URL Field for Dynamic Forms
Created this because I was binding to a content type that had a
URL
field.  Need to do this validation when submitting the dynamic form.
2015-09-30 21:35:44 -04:00
myates
65ae99abd4 Ensure the modified taxonomy items are not lost if a model validation error occurs. 2015-09-25 15:43:44 +10:00
Erik Scofield
59d95f11ee Enhancement to allow multi-select for the content picker 2015-09-23 00:11:43 -05:00
mvarblow
c7fde5bc72 Update TermCountProcessor.cs
Don't process the same term multiple times if it happens to be the parent of multiple terms on the list.
2015-09-18 10:59:32 -04:00
mvarblow
d080037af9 Update TaxonomyService.cs 2015-09-18 10:45:16 -04:00
mvarblow
5a6ba5ddd6 Update ITermCountProcessor.cs 2015-09-18 10:43:53 -04:00
mvarblow
658a5601a5 Update TermsPartHandler.cs
Queue a single task to process all terms updated within this work context.
2015-09-18 10:42:54 -04:00
mvarblow
d958df3041 Update TermsPartHandler.cs 2015-09-14 17:03:30 -04:00
mvarblow
8690278bed Update TaxonomyService.cs
Improves, but does not fully resolve, the performance problems described in issue #5663.
2015-09-14 17:01:08 -04:00
myates
a28b966685 Issue 21244 - Display warning when insecure custom forms are created 2015-09-11 17:52:19 +10:00
myates
3656e5e466 Issue 20514 - Remove id from custom form returnUrl hidden field 2015-09-11 17:31:45 +10:00
Thierry Fleury
2b61e3368d Fixes #5737 : ChangeListView throws NRE on unpublished Lists 2015-09-03 11:01:18 +02:00
71 changed files with 780 additions and 27877 deletions

View File

@@ -1,6 +1,13 @@
# Orchard
Orchard is a free, open source, community-focused Content Management System built on the ASP.NET MVC platform.
[![Join the chat at https://gitter.im/OrchardCMS/Orchard](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/OrchardCMS/Orchard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
You can try it for free on [DotNest.com](https://dotnest.com) or on Microsoft Azure by clicking on this button
[![Deploy to Azure](https://azuredeploy.net/deploybutton.png)](https://ms.portal.azure.com/#create/OutercurveFoundation.OrchardCMS.0.5.9)
## About The Orchard Project
#### Please visit our website at http://orchardproject.net for the most current information about this project.
@@ -13,26 +20,29 @@ Orchard is delivered under the [.NET Foundation](http://www.dotnetfoundation.org
Our mission is to empower our users and foster a dedicated and diverse community that builds the CMS that we all want to use.
There are many ways you can [contribute to Orchard](http://orchardproject.net/contribution): you can [fix bugs](https://github.com/OrchardCMS/Orchard/issues), contribute modules and themes to [our gallery](http://gallery.orchardproject.net/), [write documentation](https://github.com/OrchardCMS/OrchardDoc), [translate Orchard](http://orchardproject.net/localize), or answer questions [on our forums](http://orchard.codeplex.com/discussions) and [on Stack Overflow](http://stackoverflow.com/questions/tagged/orchardcms).
## Project Status
Orchard is currently in version 1.9.1. We invite participation by the developer community in shaping the projects direction, so that we can publicly validate our designs and development approach.
Our 1.9.1 release is available from our Downloads page, and is easy to [Install Orchard using the Web Platform Installer](http://www.orchardproject.net/docs/Installing-Orchard.ashx). We encourage interested developers to check out the source code on the Orchard Github site and get involved with the project.
Orchard is currently in version 1.9.2. We invite participation by the developer community in shaping the projects direction, so that we can publicly validate our designs and development approach.
Our 1.9.2 release is available from our Downloads page, and is easy to [Install Orchard using the Web Platform Installer](http://docs.orchardproject.net/Documentation/Installing-Orchard). We encourage interested developers to check out the source code on the Orchard Github site and get involved with the project.
* [Download the latest release](https://github.com/OrchardCMS/Orchard/releases)
* [Feature roadmap](http://www.orchardproject.net/docs/feature-roadmap.ashx)
* [Feature roadmap](http://docs.orchardproject.net/Documentation/feature-roadmap)
* [Docs and designs/specs](http://www.orchardproject.net/docs)
* [About us](http://www.orchardproject.net/about)
* [Contact us](mailto:ofeedbk@microsoft.com)
## How To Get Involved
We hope that by engaging with the community in the very early stages of the project that we will be able to shape Orchard into a valuable set of tools and applications for the community. The Orchard team is committed to open community participation and accepts code contributions today. We encourage community participation at all levels from general project feedback to bug fixes and patches.
We hope that by engaging with the community we will continue to shape Orchard into a valuable set of tools and applications. The Orchard team is committed to open community participation and accepts code contributions. We encourage community participation at all levels from general project feedback to bug fixes and patches.
There are many ways you can [contribute to Orchard](http://orchardproject.net/contribution):
* [Check out the code](https://github.com/OrchardCMS/Orchard)
* [Check out the docs](http://orchardproject.net/docs)
* [Write documentation](https://github.com/OrchardCMS/OrchardDoc)
* [Find and file a bug](https://github.com/OrchardCMS/Orchard/issues)
* [Propose a feature idea](http://orchard.uservoice.com)
* [Ask and answer questions](http://www.orchardproject.net/discussions)
* [Ask and answer questions in our forums](http://www.orchardproject.net/discussions) and [on Stack Overflow](http://stackoverflow.com/questions/tagged/orchardcms)
* [Participate in our gitter.im chatroom](https://gitter.im/OrchardCMS/Orchard)
* [Participate in forum discussions](http://orchard.codeplex.com/discussions)
* [Submit a patch](http://www.orchardproject.net/docs/Contributing-patches.ashx)
* [Submit a pull request](http://docs.orchardproject.net/Documentation/Contributing-patches)
* [Translate Orchard](http://orchardproject.net/localize)
* [Contribute modules and themes to our gallery](http://gallery.orchardproject.net/)
* [Send us feedback](mailto:ofeedbk@microsoft.com)

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
This is a modified version including a [assembly: SecutiryTransparent] attribute in AssemblyInfo.cs

View File

@@ -23,19 +23,20 @@
<!-- Prompts for the database name and fills it into the database scripts -->
<parameter name="Database Name" description="Name of the database for Orchard." defaultValue="orchard" tags="SQL, dbName">
<parameterEntry type="TextFile" scope="install.sql" match="PlaceHolderForDb" />
</parameter>
<!-- Prompts for the database username and fills it into the database scripts.
The SQL tag indicates it is a parameter required for SQL, the DbUsername tag indicates this is a Db username -->
<parameter name="Database Username" description="User name to access you application database." defaultValue="orcharduser" tags="SQL, DbUsername">
<parameterEntry type="TextFile" scope="install.sql" match="PlaceHolderForUser" />
<parameterEntry type="TextFile" scope="createuser.sql" match="PlaceHolderForUser" />
<parameterEntry type="TextFile" scope="createlogin.sql" match="PlaceHolderForUser" />
</parameter>
<!-- Prompts for the database password and fills it into the database scripts.
The SQL tag indicates it is a parameter required for SQL, the DbUserPassword tag indicates this is a Db password -->
<parameter name="Database Password" description="Password for the Database Username." tags="New, Password, SQL, DbUserPassword">
<parameterEntry type="TextFile" scope="install.sql" match="PlaceHolderForPassword" />
<parameterEntry type="TextFile" scope="createlogin.sql" match="PlaceHolderForPassword" />
</parameter>
<!-- Prompts for the admin creds and uses it for the administrator connection string. This is used to create a login and assign permissions.

View File

@@ -561,6 +561,23 @@
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
<Target Name="DeleteDebugFiles" AfterTargets="AfterBuild">
<RemoveDir Directories="Themes;Core;Modules" />
</Target>
<Target Name="CopyDebugFiles" AfterTargets="DeleteDebugFiles" Condition="'$(Configuration)' == 'Debug'">
<PropertyGroup>
<SrcFolder>..\..</SrcFolder>
</PropertyGroup>
<ItemGroup>
<Excluded Include="$(SrcFolder)\**\bin\**\*;$(SrcFolder)\**\obj\**\*;$(SrcFolder)\**\*.user;$(SrcFolder)\**\*.cs;$(SrcFolder)\**\*.csproj;$(SrcFolder)\**\.hg\**\*" />
<Src-Themes Include="$(SrcFolder)\Orchard.Web\Themes\**\*" Exclude="@(Excluded)" />
<Src-Core Include="$(SrcFolder)\Orchard.Web\Core\**\*" Exclude="@(Excluded)" />
<Src-Modules Include="$(SrcFolder)\Orchard.Web\Modules\**\*" Exclude="@(Excluded)" />
</ItemGroup>
<Copy SourceFiles="@(Src-Themes)" DestinationFolder="Themes\%(RecursiveDir)" />
<Copy SourceFiles="@(Src-Core)" DestinationFolder="Core\%(RecursiveDir)" />
<Copy SourceFiles="@(Src-Modules)" DestinationFolder="Modules\%(RecursiveDir)" />
</Target>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
@@ -580,6 +597,11 @@
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PreBuildEvent>del "$(TargetDir)\Modules"
del "$(TargetDir)\Themes"
del "$(TargetDir)\Media"</PreBuildEvent>
</PropertyGroup>
<!-- 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">

View File

@@ -192,7 +192,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-5.0.2.0" newVersion="5.0.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31BF3856AD364E35" culture="neutral"/>

View File

@@ -203,7 +203,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-5.0.2.0" newVersion="5.0.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31BF3856AD364E35" culture="neutral"/>

View File

@@ -199,7 +199,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-5.0.2.0" newVersion="5.0.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31BF3856AD364E35" culture="neutral"/>

View File

@@ -34,7 +34,6 @@ namespace Orchard.Core.Navigation.Controllers {
_menuService = menuService;
_menuManager = menuManager;
_navigationManager = navigationManager;
Services = orchardServices;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
@@ -155,7 +154,7 @@ namespace Orchard.Core.Navigation.Controllers {
ModelState.AddModelError(key, errorMessage.ToString());
}
public ActionResult CreateMenuItem(string id, int menuId, string returnUrl) {
public ActionResult CreateMenuItem(string id, int menuId, string returnUrl, string parentMenuItemPosition = null) {
if (!Services.Authorizer.Authorize(Permissions.ManageMenus, _menuService.GetMenu(menuId), T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
@@ -164,25 +163,31 @@ namespace Orchard.Core.Navigation.Controllers {
if (menuPart == null)
return HttpNotFound();
// load the menu
var menu = Services.ContentManager.Get(menuId);
if (menu == null)
return HttpNotFound();
try {
// filter the content items for this specific menu
menuPart.MenuPosition = Position.GetNext(_navigationManager.BuildMenu(menu));
try {
if (!String.IsNullOrEmpty(parentMenuItemPosition)) {
var menuEntries = _menuService.GetMenuParts(menuId).Select(CreateMenuItemEntries);
menuPart.MenuPosition = GetNextChildPosition(menuEntries, parentMenuItemPosition);
}
else {
// filter the content items for this specific menu
menuPart.MenuPosition = Position.GetNext(_navigationManager.BuildMenu(menu));
}
var model = Services.ContentManager.BuildEditor(menuPart);
return View(model);
}
catch (Exception exception) {
if (exception.IsFatal()) {
throw;
}
}
Logger.Error(T("Creating menu item failed: {0}", exception.Message).Text);
Services.Notifier.Error(T("Creating menu item failed: {0}", exception.Message));
@@ -191,7 +196,7 @@ namespace Orchard.Core.Navigation.Controllers {
}
[HttpPost, ActionName("CreateMenuItem")]
public ActionResult CreateMenuItemPost(string id, int menuId, string returnUrl) {
public ActionResult CreateMenuItemPost(string id, int menuId, string returnUrl, string parentMenuItemPosition = null) {
if (!Services.Authorizer.Authorize(Permissions.ManageMenus, _menuService.GetMenu(menuId), T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
@@ -205,12 +210,18 @@ namespace Orchard.Core.Navigation.Controllers {
if (menu == null)
return HttpNotFound();
var model = Services.ContentManager.UpdateEditor(menuPart, this);
menuPart.MenuPosition = Position.GetNext(_navigationManager.BuildMenu(menu));
if (!String.IsNullOrEmpty(parentMenuItemPosition)) {
var menuEntries = _menuService.GetMenuParts(menuId).Select(CreateMenuItemEntries);
menuPart.MenuPosition = GetNextChildPosition(menuEntries, parentMenuItemPosition);
}
else {
menuPart.MenuPosition = Position.GetNext( _navigationManager.BuildMenu(menu));
}
menuPart.Menu = menu;
Services.ContentManager.Create(menuPart);
if (!ModelState.IsValid) {
@@ -222,5 +233,23 @@ namespace Orchard.Core.Navigation.Controllers {
return this.RedirectLocal(returnUrl, () => RedirectToAction("Index"));
}
private static string GetNextChildPosition(IEnumerable<MenuItemEntry> menuItems, string parentMenuItemPosition) {
var parentMenuItemPositionPlusDot = parentMenuItemPosition + ".";
var childElements = menuItems.Where(childElement => childElement.Position.StartsWith(parentMenuItemPositionPlusDot));
if (childElements.Any()) {
var result = childElements
.Select(childElement => {
var positionParts = childElement.Position.Substring(parentMenuItemPositionPlusDot.Length).Split(new[] { '.' }, 2, StringSplitOptions.RemoveEmptyEntries);
return positionParts.Any() ? int.Parse(positionParts[0]) : 0;
})
.Max();
return parentMenuItemPositionPlusDot + (result + 1);
}
return parentMenuItemPositionPlusDot + "1";
}
}
}

View File

@@ -52,6 +52,27 @@
}
});
$(function () {
$(".navigation-menu-item > div").on("click", function () {
if ($(".navigation-menu-item > div.menu-item-selected").length) {
if ($(this).hasClass("menu-item-selected")) {
$(this).removeClass("menu-item-selected");
}
else {
$(".navigation-menu-item > div").removeClass("menu-item-selected");
$(this).addClass("menu-item-selected")
}
}
else {
$(this).addClass("menu-item-selected");
}
});
$(".menu-item-actions > .button").on("click", function (e) {
if ($(".navigation-menu-item > div.menu-item-selected").length) {
e.originalEvent.currentTarget.href = $(this).attr("href") + "&parentMenuItemPosition=" + $(".navigation-menu-item > div.menu-item-selected > .navigation-position > input").val();
}
});
});
})(jQuery);

View File

@@ -172,4 +172,13 @@
.dir-rtl div.menu-item-actions {
left:10px;
right: inherit;
}
}
.navigation-menu li div.menu-item-selected {
background-color: #6a7b42;
color: #fff;
}
.navigation-menu li div.menu-item-selected a {
color: #edf9f5;
}

View File

@@ -46,6 +46,8 @@
<div class="container">
<div class="navigation-menu">
@if (Model.MenuItemEntries.Any()) {
@Html.Hint(T("If you'd like to add a new menu item under another one directly then select the parent by clicking on it."))
@RenderMenuItems(Model.MenuItemEntries, 0)
}
else {
@@ -77,8 +79,8 @@
}
@helper RenderMenuItems(IList<MenuItemEntry> menuItems, int index) {
@helper RenderMenuItems(IList<MenuItemEntry> menuItems, int index) {
@:<ol>
// store current level to detect lowerb or upper level

View File

@@ -10,7 +10,7 @@ namespace Lucene.Models {
public class LuceneDocumentIndex : IDocumentIndex {
public List<AbstractField> Fields { get; private set; }
public List<Field> Fields { get; private set; }
private string _name;
private string _stringValue;
@@ -24,7 +24,7 @@ namespace Lucene.Models {
public int ContentItemId { get; private set; }
public LuceneDocumentIndex(int documentId, Localizer t) {
Fields = new List<AbstractField>();
Fields = new List<Field>();
SetContentItemId(documentId);
IsDirty = false;
@@ -92,7 +92,7 @@ namespace Lucene.Models {
public IDocumentIndex SetContentItemId(int contentItemId) {
ContentItemId = contentItemId;
Fields.Add(new Field("id", contentItemId.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
Fields.Add(new StringField("id", contentItemId.ToString(), Field.Store.YES));
return this;
}
@@ -102,19 +102,26 @@ namespace Lucene.Models {
if(_removeTags) {
_stringValue = _stringValue.RemoveTags(true);
}
Fields.Add(new Field(_name, _stringValue ?? String.Empty,
_store ? Field.Store.YES : Field.Store.NO,
_analyze ? Field.Index.ANALYZED : Field.Index.NOT_ANALYZED));
Fields.Add(new TextField(
_name,
_stringValue ?? String.Empty,
_store ? Field.Store.YES : Field.Store.NO
//,_analyze ? Field.Index.ANALYZED : Field.Index.NOT_ANALYZED
));
break;
case TypeCode.Int32:
Fields.Add(new NumericField(_name,
_store ? Field.Store.YES : Field.Store.NO,
true).SetIntValue(_intValue));
Fields.Add(new DoubleField(
_name,
_intValue,
_store ? Field.Store.YES : Field.Store.NO
));
break;
case TypeCode.Single:
Fields.Add(new NumericField(_name,
_store ? Field.Store.YES : Field.Store.NO,
true).SetDoubleValue(_doubleValue));
Fields.Add(new DoubleField(
_name,
_doubleValue,
_store ? Field.Store.YES : Field.Store.NO
));
break;
case TypeCode.Empty:
break;

View File

@@ -11,7 +11,7 @@ using Lucene.Net.Util;
using Orchard.Indexing;
using Orchard.Logging;
using Lucene.Net.Documents;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search.QueryParsers;
using Lucene.Net.Analysis.Tokenattributes;
namespace Lucene.Services {
@@ -33,7 +33,7 @@ namespace Lucene.Services {
private bool _asFilter;
// pending clause attributes
private Occur _occur;
private BooleanClause.Occur _occur;
private bool _exactMatch;
private bool _notAnalyzed;
private float _boost;

View File

@@ -73,7 +73,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-5.0.2.0" newVersion="5.0.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -63,7 +63,7 @@ namespace Orchard.Azure.Services.FileSystems {
_publicHostName = publicHostName;
}
private void EnsureInitialized() {
protected void EnsureInitialized() {
if (_storageAccount != null) {
return;
}
@@ -355,7 +355,7 @@ namespace Orchard.Azure.Services.FileSystems {
// as opposed to the File System implementation, if nothing is done on the stream
// the file will be emptied, because Azure doesn't implement FileMode.Truncate
_blob.DeleteIfExists();
_blob = _blob.Container.GetBlockBlobReference(_blob.Uri.ToString());
_blob = _blob.Container.GetBlockBlobReference(_blob.Name);
_blob.UploadFromStream(new MemoryStream(new byte[0]));
return OpenWrite();
}

View File

@@ -60,6 +60,7 @@ namespace Orchard.Azure.Services.FileSystems.Media {
/// <param name="url">The public URL of the media.</param>
/// <returns>The corresponding local path.</returns>
public string GetStoragePath(string url) {
EnsureInitialized();
if (url.StartsWith(_absoluteRoot)) {
return HttpUtility.UrlDecode(url.Substring(Combine(_absoluteRoot, "/").Length));
}

View File

@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>$$ProjectName$$</RootNamespace>
<AssemblyName>$$ProjectName$$</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<OldToolsVersion>4.0</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

View File

@@ -72,6 +72,7 @@
<ItemGroup>
<Compile Include="ViewModels\NavigationPartViewModel.cs" />
<Content Include="Scripts\ContentPicker.js" />
<Content Include="Scripts\SelectableContentTab.js" />
<Content Include="Styles\content-picker-admin.css" />
<Content Include="Styles\ContentPicker.css" />
<Content Include="Styles\Images\move.gif" />

View File

@@ -5,6 +5,7 @@ namespace Orchard.ContentPicker {
public void BuildManifests(ResourceManifestBuilder builder) {
var manifest = builder.Add();
manifest.DefineScript("ContentPicker").SetUrl("ContentPicker.js", "ContentPicker.js").SetDependencies("jQuery");
manifest.DefineScript("SelectableContentTab").SetUrl("SelectableContentTab.js", "SelectableContentTab.js").SetDependencies("jQuery");
}
}
}

View File

@@ -80,14 +80,26 @@
addButton.click(function() {
addButton.trigger("orchard-admin-contentpicker-open", {
callback: function(data) {
var tmpl = template.replace( /\{contentItemId\}/g , data.id)
.replace( /\{edit-link\}/g , data.editLink)
.replace( /\{status-text}/g , data.published? "" : " - " + notPublishedText);
var content = $(tmpl);
$(self).find('table.content-picker tbody').append(content);
if (Array.isArray && Array.isArray(data)) {
data.forEach(function (d) {
var tmpl = template.replace(/\{contentItemId\}/g, d.id)
.replace(/\{edit-link\}/g, d.editLink)
.replace(/\{status-text}/g, d.published ? "" : " - " + notPublishedText);
var content = $(tmpl);
$(self).find('table.content-picker tbody').append(content);
});
refreshIds();
$(self).find('.content-picker-message').show();
} else {
var tmpl = template.replace(/\{contentItemId\}/g, data.id)
.replace(/\{edit-link\}/g, data.editLink)
.replace(/\{status-text}/g, data.published ? "" : " - " + notPublishedText);
var content = $(tmpl);
$(self).find('table.content-picker tbody').append(content);
refreshIds();
$(self).find('.content-picker-message').show();
refreshIds();
$(self).find('.content-picker-message').show();
}
},
baseUrl: baseUrl,
part: partName,

View File

@@ -0,0 +1,32 @@
jQuery(function ($) {
Initialize = function () {
$('.button.addSelected').on('click', function () {
var selectedItems = $('.content-picker-itemCheck:checked');
var itemsToAdd = new Array();
$.each(selectedItems, function (index, item) {
var related = $(item).siblings('.content-picker-item').children('.related');
var data = {
id: related.data("id"),
displayText: related.data("display-text"),
editLink: related.data("edit-link"),
editUrl: related.data("edit-url"),
adminUrl: related.data("admin-url"),
displayLink: related.data("display-link"),
published: related.data("published")
};
return itemsToAdd.push(data);
});
window.opener.jQuery[query("callback")](itemsToAdd);
window.close();
});
$('.content-picker-SelectAll').on('click', function () {
$('.content-picker-itemCheck').prop('checked', $(this).prop("checked"));
});
};
$(document).ready(function () {
return Initialize();
});
});

View File

@@ -19,4 +19,37 @@ body {
padding: 18px;
background: white;
border: 1px solid #E4E5E6;
}
.content-picker-item
{
margin-left: 20px;
}
.content-picker-itemCheck
{
position:absolute;
}
label[for="selectAll"]:before
{
content:'';
display:block;
margin-top:20px;
}
label[for="selectAll"]
{
display:inline;
}
.addSelected
{
margin-bottom: 10px;
}
.page-size-options > div:first-child
{
display:inline-block;
}

View File

@@ -3,27 +3,30 @@
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>
<input type="checkbox" class="content-picker-itemCheck" />
<div class="content-picker-item">
<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-edit-url="@Html.Encode(Url.ItemEditUrl(contentItem))"
data-admin-url="@Html.Encode(Url.ItemAdminUrl(contentItem))"
data-display-link="@Html.Encode(Html.ItemDisplayLink(contentItem))"
data-published="@contentItem.VersionRecord.Published.ToString().ToLower()" >
@Html.Link(T("Select").Text, "#", new { @class = "button select"})
</div>
@if (Model.Content != null) {
<div class="primary">@Display(Model.Content)</div>
}
</div>
<div class="related"
data-display-text="@Html.ItemDisplayText(contentItem)"
data-id="@contentItem.Id"
data-edit-link="@Html.Encode(Html.ItemEditLink(contentItem))"
data-edit-url="@Html.Encode(Url.ItemEditUrl(contentItem))"
data-admin-url="@Html.Encode(Url.ItemAdminUrl(contentItem))"
data-display-link="@Html.Encode(Html.ItemDisplayLink(contentItem))"
data-published="@contentItem.VersionRecord.Published.ToString().ToLower()" >
@Html.Link(T("Select").Text, "#", new { @class = "button select"})
</div>
@if (Model.Content != null) {
<div class="primary">@Display(Model.Content)</div>
}
</div>

View File

@@ -1,5 +1,7 @@
@using Orchard.Core.Contents.ViewModels;
@{
Script.Require("SelectableContentTab");
var typeDisplayName = Model.TypeDisplayName;
var pageTitle = T("Recent Content");
@@ -8,6 +10,7 @@
}
Layout.Title = pageTitle;
}
<div class="manage">
@@ -33,6 +36,7 @@
<fieldset class="contentItems bulk-items">
@Display(Model.ContentItems)
</fieldset>
@Html.Link(T("Add Selected").Text, "#", new { @class = "button addSelected"})
@Display(Model.Pager)
}

View File

@@ -8,19 +8,28 @@ using Orchard.CustomForms.Models;
using Orchard.CustomForms.ViewModels;
using Orchard.ContentManagement.Handlers;
using System;
using Orchard.Core.Contents.Settings;
using Orchard.Security;
using Orchard.Localization;
namespace Orchard.CustomForms.Drivers {
public class CustomFormPartDriver : ContentPartDriver<CustomFormPart> {
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IOrchardServices _orchardServices;
private readonly IAuthorizationService _authService;
public CustomFormPartDriver(
IContentDefinitionManager contentDefinitionManager,
IOrchardServices orchardServices) {
IOrchardServices orchardServices,
IAuthorizationService authService) {
_contentDefinitionManager = contentDefinitionManager;
_orchardServices = orchardServices;
_authService = authService;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
protected override DriverResult Display(CustomFormPart part, string displayType, dynamic shapeHelper) {
// this method is used by the widget to render the form when it is displayed
@@ -55,6 +64,19 @@ namespace Orchard.CustomForms.Drivers {
};
updater.TryUpdateModel(viewModel, Prefix, null, null);
// Warn if the custom form is set to save a content item that is viewable by anonymous users (publicly accessible)
if (viewModel.CustomFormPart.SaveContentItem) {
// If it's draftable then don't display the warning because the generated content items won't be publicly accessible
var typeDefinition = _contentDefinitionManager.ListTypeDefinitions().Where(x => String.Equals(x.Name, viewModel.CustomFormPart.ContentType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (typeDefinition != null && !typeDefinition.Settings.GetModel<ContentTypeSettings>().Draftable) {
// Create a dummy content item of the specified type to check permissions against
if (_authService.TryCheckAccess(Orchard.Core.Contents.Permissions.ViewContent, null, _orchardServices.ContentManager.New(viewModel.CustomFormPart.ContentType))) {
_orchardServices.Notifier.Add(UI.Notify.NotifyType.Warning, T("Your custom form will save data to content items that are publicly accessible."));
}
}
}
return Editor(part, shapeHelper);
}

View File

@@ -14,7 +14,7 @@
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
@Display(editor)
@Html.Hidden("returnUrl", Request.RawUrl);
@Html.Hidden("returnUrl", Request.RawUrl, new { id = string.Empty });
<fieldset class="submit-button">
<button type="submit" name="submit.Save" value="submit.Save">@Model.ContentPart.SubmitButtonText</button>

View File

@@ -1,60 +0,0 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.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=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false"/>
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.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=5.2.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.5.1">
<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=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="Orchard.Framework"/>
<add assembly="Orchard.Core"/>
<add assembly="Orchard.Layouts"/>
</assemblies>
</compilation>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NHibernate" publicKeyToken="AA95F207798DFDB4" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.0.4000" newVersion="4.0.0.4000"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Iesi.Collections" publicKeyToken="AA95F207798DFDB4" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Autofac" publicKeyToken="17863AF14B0044DA" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.5.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -0,0 +1,79 @@
using Orchard.DynamicForms.Elements;
using Orchard.Forms.Services;
using Orchard.Layouts.Framework.Drivers;
using Orchard.Layouts.Framework.Display;
using Orchard.Layouts.Helpers;
using Orchard.Tokens;
using DescribeContext = Orchard.Forms.Services.DescribeContext;
namespace Orchard.DynamicForms.Drivers {
public class UrlFieldElementDriver : FormsElementDriver<UrlField> {
private readonly ITokenizer _tokenizer;
public UrlFieldElementDriver(IFormManager formManager, ITokenizer tokenizer) : base(formManager) {
_tokenizer = tokenizer;
}
protected override EditorResult OnBuildEditor(UrlField element, ElementEditorContext context) {
var autoLabelEditor = BuildForm(context, "AutoLabel");
var webAddressFieldEditor = BuildForm(context, "UrlField");
var webAddressFieldValidation = BuildForm(context, "UrlFieldValidation", "Validation:10");
return Editor(context, autoLabelEditor, webAddressFieldEditor, webAddressFieldValidation);
}
protected override void DescribeForm(DescribeContext context) {
context.Form("UrlField", factory => {
var shape = (dynamic) factory;
var form = shape.Fieldset(
Id: "UrlField",
_Value: shape.Textbox(
Id: "Value",
Name: "Value",
Title: "Value",
Classes: new[] {"text", "medium", "tokenized"},
Description: T("The value of this URL field.")));
return form;
});
context.Form("UrlFieldValidation", factory => {
var shape = (dynamic) factory;
var form = shape.Fieldset(
Id: "UrlFieldValidation",
_IsRequired: shape.Checkbox(
Id: "IsRequired",
Name: "IsRequired",
Title: "Required",
Value: "true",
Description: T("Tick this checkbox to make this email field a required field.")),
_MaximumLength: shape.Textbox(
Id: "MaximumLength",
Name: "MaximumLength",
Title: "Maximum Length",
Classes: new[] {"text", "medium", "tokenized"},
Description: T("The maximum length allowed.")),
_CustomValidationMessage: shape.Textbox(
Id: "CustomValidationMessage",
Name: "CustomValidationMessage",
Title: "Custom Validation Message",
Classes: new[] {"text", "large", "tokenized"},
Description: T("Optionally provide a custom validation message.")),
_ShowValidationMessage: shape.Checkbox(
Id: "ShowValidationMessage",
Name: "ShowValidationMessage",
Title: "Show Validation Message",
Value: "true",
Description: T("Autogenerate a validation message when a validation error occurs for the current field. Alternatively, to control the placement of the validation message you can use the ValidationMessage element instead.")));
return form;
});
}
protected override void OnDisplaying(UrlField element, ElementDisplayContext context) {
context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, context.GetTokenData());
context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, context.GetTokenData());
context.ElementShape.ProcessedValue = _tokenizer.Replace(element.RuntimeValue, context.GetTokenData());
}
}
}

View File

@@ -0,0 +1,9 @@
using Orchard.DynamicForms.Validators.Settings;
namespace Orchard.DynamicForms.Elements {
public class UrlField : LabeledFormElement {
public UrlFieldValidationSettings ValidationSettings {
get { return Data.GetModel<UrlFieldValidationSettings>(""); }
}
}
}

View File

@@ -167,7 +167,9 @@
<Compile Include="Bindings\InputFieldBindings.cs" />
<Compile Include="Bindings\TaxonomyFieldBindings.cs" />
<Compile Include="Drivers\FieldsetElementDriver.cs" />
<Compile Include="Drivers\UrlFieldElementDriver.cs" />
<Compile Include="Elements\Fieldset.cs" />
<Compile Include="Elements\UrlField.cs" />
<Compile Include="Forms\AddModelErrorForm.cs" />
<Compile Include="Forms\SelectDynamicForms.cs" />
<Compile Include="Bindings\TextFieldBindings.cs" />
@@ -217,7 +219,9 @@
<Compile Include="ValidationRules\EmailAddress.cs" />
<Compile Include="ValidationRules\RegularExpression.cs" />
<Compile Include="ValidationRules\StringLength.cs" />
<Compile Include="ValidationRules\UrlAddress.cs" />
<Compile Include="Validators\QueryValidator.cs" />
<Compile Include="Validators\Settings\UrlFieldValidationSettings.cs" />
<Compile Include="Validators\TaxonomyValidator.cs" />
<Compile Include="Validators\EnumerationValidator.cs" />
<Compile Include="Validators\CheckBoxValidator.cs" />
@@ -271,6 +275,7 @@
<Compile Include="Validators\ReCaptchaValidator.cs" />
<Compile Include="Validators\TextAreaValidator.cs" />
<Compile Include="Validators\TextFieldValidator.cs" />
<Compile Include="Validators\UrlFieldValidator.cs" />
<Compile Include="ViewModels\FieldValidationSettings.cs" />
<Compile Include="ViewModels\FormBindingSettings.cs" />
<Compile Include="Helpers\ContentTypeDefinitionExtensions.cs" />
@@ -506,6 +511,12 @@
<ItemGroup>
<Content Include="Assets.json" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Elements\UrlField.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Elements\UrlField.Design.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

View File

@@ -1,5 +1,4 @@
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
using Orchard.Tokens;
namespace Orchard.DynamicForms.Services {

View File

@@ -1,5 +1,4 @@
using System;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
@@ -22,7 +21,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return T(Tokenize(ErrorMessage.WithDefault(String.Format("{0} must match the value of {1}.", context.FieldName, TargetName)), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} must match the value of {1}.", context.FieldName, TargetName)
: T(ErrorMessage, context);
}
}
}

View File

@@ -28,7 +28,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return T(Tokenize(ErrorMessage.WithDefault(String.Format("{0} is not a valid email address.", context.FieldName)), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is not a valid email address.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
@@ -18,7 +17,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return T(Tokenize(ErrorMessage.WithDefault(String.Format("{0} is a mandatory field.", context.FieldName)), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is a mandatory field.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
@@ -18,7 +17,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return T(Tokenize(ErrorMessage.WithDefault(String.Format("An option is required for {0}.", context.FieldName)), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("An option is required for {0}.", context.FieldName)
: T(ErrorMessage, context);
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Text.RegularExpressions;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
@@ -27,7 +26,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return T(Tokenize(ErrorMessage.WithDefault(String.Format("{0} must match the following pattern: {1}.", context.FieldName, Pattern)), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} must match the following pattern: {1}.", context.FieldName, Pattern)
: T(ErrorMessage);
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
@@ -18,7 +17,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return T(Tokenize(ErrorMessage.WithDefault(String.Format("{0} is a required field.", context.FieldName)), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is a required field.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -40,12 +40,13 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
if (!String.IsNullOrWhiteSpace(ErrorMessage))
return T(Tokenize(String.Format(ErrorMessage, context.FieldName, Minimum, Maximum), context));
if(!String.IsNullOrWhiteSpace(ErrorMessage))
return T(ErrorMessage, context.FieldName, Minimum, Maximum);
if(Minimum != null && Maximum != null)
if (Minimum != null && Maximum != null)
return T("{0} must be between {1} and {2} characters long.", context.FieldName, Minimum, Maximum);
else if (Minimum != null)
if (Minimum != null)
return T("{0} must be at least {1} characters long.", context.FieldName, Minimum);
return T("{0} must be at most {1} characters long.", context.FieldName, Maximum);

View File

@@ -0,0 +1,36 @@
using System;
using System.Text.RegularExpressions;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
namespace Orchard.DynamicForms.ValidationRules {
public class UrlAddress : ValidationRule {
public UrlAddress() {
RegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase;
Pattern = @"^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$";
}
public string Pattern { get; set; }
public RegexOptions RegexOptions { get; set; }
public override void Validate(ValidateInputContext context) {
if (!Regex.IsMatch(context.AttemptedValue, Pattern, RegexOptions)) {
var message = GetValidationMessage(context);
context.ModelState.AddModelError(context.FieldName, message.Text);
}
}
public override void RegisterClientAttributes(RegisterClientValidationAttributesContext context) {
context.ClientAttributes["data-val-regex"] = GetValidationMessage(context).Text;
context.ClientAttributes["data-val-regex-pattern"] = Pattern;
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is not a valid URL.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.DynamicForms.Services.Models;
namespace Orchard.DynamicForms.Validators.Settings {
public class UrlFieldValidationSettings : ValidationSettingsBase {
public bool? IsRequired { get; set; }
public int? MaximumLength { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using Orchard.DynamicForms.Elements;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.ValidationRules;
namespace Orchard.DynamicForms.Validators {
public class UrlFieldValidator : ElementValidator<UrlField> {
private readonly IValidationRuleFactory _validationRuleFactory;
public UrlFieldValidator(IValidationRuleFactory validationRuleFactory) {
_validationRuleFactory = validationRuleFactory;
}
protected override IEnumerable<IValidationRule> GetValidationRules(UrlField element) {
var settings = element.ValidationSettings;
if (settings.IsRequired == true)
yield return _validationRuleFactory.Create<Required>(settings.CustomValidationMessage);
if (settings.MaximumLength != null) {
yield return _validationRuleFactory.Create<StringLength>(r => {
r.Maximum = settings.MaximumLength;
r.ErrorMessage = settings.CustomValidationMessage;
});
}
}
}
}

View File

@@ -0,0 +1,21 @@
@using Orchard.DynamicForms.Elements
@using Orchard.Layouts.Helpers
@{
var element = (UrlField)Model.Element;
var tagBuilder = TagBuilderExtensions.CreateElementTagBuilder(Model, "input");
tagBuilder.AddCssClass("text design");
tagBuilder.Attributes["type"] = "url";
tagBuilder.Attributes["value"] = element.Value;
tagBuilder.Attributes["name"] = element.Name;
}
@if (element.ShowLabel) {
<div>
<label for="@element.HtmlId">@element.Label</label>
@tagBuilder.ToHtmlString(TagRenderMode.SelfClosing)
</div>
}
else {
@tagBuilder.ToHtmlString(TagRenderMode.SelfClosing)
}

View File

@@ -0,0 +1,25 @@
@using Orchard.DisplayManagement.Shapes
@using Orchard.DynamicForms.Elements
@using Orchard.Layouts.Helpers
@{
var element = (UrlField)Model.Element;
var tagBuilder = (OrchardTagBuilder)TagBuilderExtensions.CreateElementTagBuilder(Model, "input");
tagBuilder.AddCssClass("text");
tagBuilder.Attributes["type"] = "url";
tagBuilder.Attributes["value"] = Model.ProcessedValue;
tagBuilder.Attributes["name"] = Model.ProcessedName;
tagBuilder.AddClientValidationAttributes((IDictionary<string, string>)Model.ClientValidationAttributes);
if (!ViewData.ModelState.IsValidField(Model.ProcessedName)) {
tagBuilder.AddCssClass("input-validation-error");
}
}
@if (element.ShowLabel) {
<label for="@element.HtmlId">@Model.ProcessedLabel</label>
}
@tagBuilder.ToHtmlString(TagRenderMode.SelfClosing)
@if (element.ValidationSettings.ShowValidationMessage == true) {
@Html.ValidationMessage((string)Model.ProcessedName)
}

View File

@@ -237,7 +237,10 @@ namespace Orchard.Indexing.Services {
// skip items from types which are not indexed
var settings = GetTypeIndexingSettings(item.ContentItem);
if (settings.List.Contains(indexName)) {
documentIndex = ExtractDocumentIndex(item.ContentItem);
if (item.ContentItem.HasPublished()) {
var published = _contentManager.Get(item.Id, VersionOptions.Published);
documentIndex = ExtractDocumentIndex(published);
}
}
else if (settings.List.Contains(indexName + ":latest")) {
var latest = _contentManager.Get(item.Id, VersionOptions.Latest);

View File

@@ -169,8 +169,8 @@
break;
case "save":
{
var frameDoc = self.frame.getDocument();
var form = frameDoc.find("form:first");
var frameWindow = self.frame.getWindow();
var form = frameWindow.$("form:first");
form.submit();
}
break;

View File

@@ -380,7 +380,11 @@ namespace Orchard.Lists.Controllers {
[HttpPost, ActionName("List")]
[FormValueRequired("listViewName")]
public ActionResult ChangeListView(int containerId, string listViewName, PagerParameters pagerParameters) {
var container = _containerService.Get(containerId);
var container = _containerService.Get(containerId, VersionOptions.Latest);
if (container == null || !container.Has<ContainerPart>()) {
return HttpNotFound();
}
container.Record.AdminListViewName = listViewName;
return RedirectToAction("List", new { containerId, page = pagerParameters.Page, pageSize = pagerParameters.PageSize });
}

View File

@@ -156,10 +156,10 @@ namespace Orchard.MediaLibrary.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media")))
return new HttpUnauthorizedResult();
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder().MediaPath;
var mediaParts = _mediaLibraryService.GetMediaContentItems(rootMediaFolder, skip, count, order, mediaType);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(rootMediaFolder, mediaType);
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
var rootMediaFolderPath = rootMediaFolder == null ? null : rootMediaFolder.MediaPath;
var mediaParts = _mediaLibraryService.GetMediaContentItems(rootMediaFolderPath, skip, count, order, mediaType);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(rootMediaFolderPath, mediaType);
var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel {
@@ -256,4 +256,4 @@ namespace Orchard.MediaLibrary.Controllers {
return new FolderHierarchy(root) {Children = _mediaLibraryService.GetMediaFolders(root.MediaPath).Select(GetFolderHierarchy)};
}
}
}
}

View File

@@ -31,7 +31,7 @@ namespace Orchard.MediaLibrary {
},
new PermissionStereotype {
Name = "Author",
Permissions = new[] {ManageMediaContent}
Permissions = new[] {ManageOwnMedia}
},
new PermissionStereotype {
Name = "Contributor",

View File

@@ -71,8 +71,11 @@ $(function () {
var listWidth = $('#media-library-main-list').width();
var listHeight = $('#media-library-main-list').height();
var itemWidth = $('.thumbnail').first().width();
var itemHeight = $('.thumbnail').first().height();
var itemWidth = $('#media-library-main-list li').first().width();
var itemHeight = $('#media-library-main-list li').first().height();
var defaultDimension = $(window).width() < 1420 ? 120 : 200;
if (itemHeight == 0 || itemHeight == null) itemHeight = defaultDimension;
if (itemWidth == 0 || itemWidth == null) itemWidth = defaultDimension;
var draftText = $("#media-library").data("draft-text");
var itemsPerRow = Math.floor(listWidth / itemWidth);

View File

@@ -1,4 +1,4 @@
.zone-content, #content, #main, #layout-content, #layout-main {
.zone-content, #content, #main, #layout-content, #layout-main {
height: 100%;
display: block;
min-height: 400px;
@@ -155,6 +155,10 @@
background-position: center;
}
#media-library-main-list.pending li {
opacity:.3;
}
/* Remove the space for the editor, and the scrollbar in the import page */
#media-library-import #media-library-main-list {
overflow-y: hidden;
@@ -499,4 +503,4 @@ padding-right: 16px;
.dir-rtl .media-library-main-list-overlay p {
padding-right:inherit;
padding-left:5px;
}
}

View File

@@ -18,7 +18,7 @@ html.dyn #main ul.features button { display:none; }
height:6em;
margin:0 .5% 1% .5%;
position:relative;
width:32.2%;
width:32%;
}
.features.summary-view .missingDependencies{
@@ -223,4 +223,4 @@ h2.recentlyInstalledModule {padding:0 0 0 40px;}
.dir-rtl .manage {
float: left;
}
}

View File

@@ -14,5 +14,7 @@
$allCheckboxes.prop("checked", false);
}
});
$('input[name=DataProvider]:checked').click();
});
})(jQuery);

View File

@@ -4,18 +4,19 @@
Layout.Title = T("Add New Tenant").ToString();
Script.Require("jQuery").AtFoot();
Script.Include(Url.Content("~/Themes/TheAdmin/Scripts/admin.js")).AtFoot();
Script.Require("ShapesBase").AtFoot();
Script.Include(Url.Content("~/Themes/TheAdmin/Scripts/admin.js")).AtFoot();
Script.Include("multi-tenancy.admin.js").AtFoot();
}
@using (Html.BeginFormAntiForgeryPost()) {
@using (Html.BeginFormAntiForgeryPost()) {
@Html.ValidationSummary()
<fieldset>
<div>
<label for="@Html.FieldIdFor(m => m.Name)">@T("Name")</label>
@Html.TextBoxFor(m => m.Name, new { @class = "text" })
<span class="hint">@T("The name of the tenant as it will be displayed in the admin.")</span>
</div>
</div>
<div>
<label for="@Html.FieldIdFor(m => m.RequestUrlHost)">@T("Host")</label>
@Html.TextBoxFor(m => m.RequestUrlHost, new { @class = "text medium" })
@@ -30,7 +31,7 @@
</fieldset>
<fieldset>
<legend>@T("Database Setup")</legend>
<div>
<div>
@Html.RadioButtonFor(svm => svm.DataProvider, "", new { id = "tenantDatabaseOption" })
<label for="tenantDatabaseOption" class="forcheckbox">@T("Allow the tenant to set up the database")</label>
</div>
@@ -48,18 +49,18 @@
<span class="hint">@T("Example:") @T("Data Source=sqlServerName;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password")</span>
</span>
<span data-controllerid="sqlDatabaseOption">
<label for="DatabaseTablePrefix">@T("Database Table Prefix")</label>
<label for="DatabaseTablePrefix">@T("Database table prefix")</label>
@Html.EditorFor(svm => svm.DatabaseTablePrefix)
</span>
</div>
</div>
</fieldset>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Themes)">@T("Available Themes")</label>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Themes)">@T("Available Themes")</label>
<div>
<span class="hint">@T("Select the Themes which should be available for this tenant. If none is selected, they will all be available.")</span>
<ol>
<li>
<input type="checkbox" class="select-all" id="select-all-themes" />
@@ -79,11 +80,11 @@
}
</ol>
</div>
</div>
</fieldset>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Modules)">@T("Available Modules")</label>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Modules)">@T("Available Modules")</label>
<div>
<span class="hint">@T("Select the Modules which should be available for this tenant. If none is selected, they will all be available.")</span>
@@ -94,21 +95,21 @@
</li>
@for (var i = 0; i < Model.Modules.Count; i++) {
<li>
@{
var theme = Model.Modules[i];
@Html.CheckBox(Html.FieldNameFor(m => m.Modules[i].Checked), Model.Modules[i].Checked, new { id = Html.FieldIdFor(x => x.Modules[i]) })
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Modules[i])">@Model.Modules[i].ModuleName</label>
@Html.HiddenFor(m => m.Modules[i].ModuleId)
@Html.HiddenFor(m => m.Modules[i].ModuleName)
}
</li>
<li>
@{
var theme = Model.Modules[i];
@Html.CheckBox(Html.FieldNameFor(m => m.Modules[i].Checked), Model.Modules[i].Checked, new { id = Html.FieldIdFor(x => x.Modules[i]) })
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Modules[i])">@Model.Modules[i].ModuleName</label>
@Html.HiddenFor(m => m.Modules[i].ModuleId)
@Html.HiddenFor(m => m.Modules[i].ModuleName)
}
</li>
}
</ol>
</div>
</fieldset>
</div>
</fieldset>
<fieldset>
<button class="primaryAction" type="submit">@T("Save")</button>
</fieldset>
}
}

View File

@@ -5,11 +5,12 @@
Layout.Title = T("Edit Tenant").ToString();
Script.Require("jQuery").AtFoot();
Script.Include(Url.Content("~/Themes/TheAdmin/Scripts/admin.js")).AtFoot();
Script.Require("ShapesBase").AtFoot();
Script.Include(Url.Content("~/Themes/TheAdmin/Scripts/admin.js")).AtFoot();
Script.Include("multi-tenancy.admin.js").AtFoot();
}
@using (Html.BeginFormAntiForgeryPost()) {
@using (Html.BeginFormAntiForgeryPost()) {
@Html.ValidationSummary()
<fieldset>
<div>
@@ -24,19 +25,19 @@
<label for="@Html.FieldIdFor(m => m.RequestUrlPrefix)">@T("URL prefix")</label>
@Html.TextBoxFor(m => m.RequestUrlPrefix, new { @class = "text medium" })
<span class="hint">@T("(Optional) Example: If prefix is \"site1\", the tenant URL prefix is \"http://orchardproject.net/site1\"")</span>
</div>
</div>
</fieldset>
<fieldset>
<legend>@T("Database Setup")</legend>
@if (Model.State != TenantState.Uninitialized) {
<div class="warning message">@T("Warning: If you don't know what you're doing you *will* (likely) send this tenant into a downward spiral of irrecoverable disrepair. Have a nice day.")</div>
@if (Model.State != TenantState.Uninitialized) {
<div class="message message-Warning">@T("Warning: If you don't know what you're doing you *will* (likely) send this tenant into a downward spiral of irrecoverable disrepair. Have a nice day.")</div>
}
else {
<div>
else {
<div>
@Html.RadioButtonFor(svm => svm.DataProvider, "", new { id = "tenantDatabaseOption" })
<label for="tenantDatabaseOption" class="forcheckbox">@T("Allow the tenant to set up the database")</label>
</div>
}
}
<div>
@Html.RadioButtonFor(svm => svm.DataProvider, "SqlCe", new { id = "builtinDatabaseOption" })
<label for="builtinDatabaseOption" class="forcheckbox">@T("Use built-in data storage (SQL Server Compact)")</label>
@@ -44,23 +45,25 @@
<div>
@Html.RadioButtonFor(svm => svm.DataProvider, "SqlServer", new { id = "sqlDatabaseOption" })
<label for="sqlDatabaseOption" class="forcheckbox">@T("Use an existing SQL Server (or SQL Express) database")</label>
<span data-controllerid="sqlDatabaseOption">
<label for="DatabaseConnectionString">@T("Connection string")</label>
@Html.TextBoxFor(svm => svm.DatabaseConnectionString, new { @class = "text large" })
<span class="hint">@T("Example:")<br />@T("Data Source=sqlServerName;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password")</span>
</span>
<span data-controllerid="sqlDatabaseOption">
<label for="DatabaseTablePrefix">@T("Database Table Prefix")</label>
@Html.EditorFor(svm => svm.DatabaseTablePrefix)
</span>
<div class="options">
<span data-controllerid="sqlDatabaseOption">
<label for="DatabaseConnectionString">@T("Connection string")</label>
@Html.TextBoxFor(svm => svm.DatabaseConnectionString)
<span class="hint">@T("Example:") @T("Data Source=sqlServerName;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password")</span>
</span>
<span data-controllerid="sqlDatabaseOption">
<label for="DatabaseTablePrefix">@T("Database table prefix")</label>
@Html.EditorFor(svm => svm.DatabaseTablePrefix)
</span>
</div>
</div>
</fieldset>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Themes)">@T("Available Themes")</label>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Themes)">@T("Available Themes")</label>
<div>
<span class="hint">@T("Select the Themes which should be available for this tenant. If none is selected, they will all be available.")</span>
<ol>
<li>
<input type="checkbox" class="select-all" id="select-all-themes" />
@@ -80,11 +83,11 @@
}
</ol>
</div>
</div>
</fieldset>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Modules)">@T("Available Modules")</label>
<fieldset class="available-extensions">
<label for="@Html.FieldIdFor(m => m.Modules)">@T("Available Modules")</label>
<div>
<span class="hint">@T("Select the Modules which should be available for this tenant. If none is selected, they will all be available.")</span>
@@ -95,21 +98,21 @@
</li>
@for (var i = 0; i < Model.Modules.Count; i++) {
<li>
@{
var theme = Model.Modules[i];
@Html.CheckBox(Html.FieldNameFor(m => m.Modules[i].Checked), Model.Modules[i].Checked, new { id = Html.FieldIdFor(x => x.Modules[i]) })
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Modules[i])">@Model.Modules[i].ModuleName</label>
@Html.HiddenFor(m => m.Modules[i].ModuleId)
@Html.HiddenFor(m => m.Modules[i].ModuleName)
}
</li>
<li>
@{
var theme = Model.Modules[i];
@Html.CheckBox(Html.FieldNameFor(m => m.Modules[i].Checked), Model.Modules[i].Checked, new { id = Html.FieldIdFor(x => x.Modules[i]) })
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Modules[i])">@Model.Modules[i].ModuleName</label>
@Html.HiddenFor(m => m.Modules[i].ModuleId)
@Html.HiddenFor(m => m.Modules[i].ModuleName)
}
</li>
}
</ol>
</div>
</fieldset>
</div>
</fieldset>
<fieldset>
<button class="primaryAction" type="submit">@T("Save")</button>
</fieldset>
}
}

View File

@@ -58,7 +58,7 @@ namespace Orchard.Redis.Caching {
}
public void Clear() {
Database.KeyDeleteWithPrefix(GetLocalizedKey("*"));
_connectionMultiplexer.KeyDeleteWithPrefix(GetLocalizedKey("*"));
}
private string GetLocalizedKey(string key) {

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using StackExchange.Redis;
namespace Orchard.Redis.Extensions {
public static class RedisConnectionExtensions {
public static void KeyDeleteWithPrefix(this IConnectionMultiplexer connection, string prefix) {
var keys = GetKeys(connection, prefix);
var database = connection.GetDatabase();
database.KeyDelete(keys.Select(key => (RedisKey)key).ToArray());
}
public static int KeyCount(this IConnectionMultiplexer connection, string prefix) {
return GetKeys(connection, prefix).Count();
}
// CYCLES EACH ENDPOINT FOR A CONNECTION SO KEYS ARE FETECHED IN A REDIS CLUSTER CONFIGURATION
// STACKEXCHANGECLIENT .KEYS WILL PERFORM SCAN ON REDIS SERVERS THAT SUPPORT IT
public static IEnumerable<string> GetKeys(this IConnectionMultiplexer connection, string prefix) {
if (connection == null) {
throw new ArgumentException("Connection cannot be null", "connection");
}
if (string.IsNullOrWhiteSpace(prefix)) {
throw new ArgumentException("Prefix cannot be empty", "database");
}
var keys = new List<string>();
var databaseId = connection.GetDatabase().Database;
foreach (var endPoint in connection.GetEndPoints()) {
var server = connection.GetServer(endPoint);
keys.AddRange(server.Keys(pattern: prefix, database: databaseId).Select(x => x.ToString()));
}
return keys.Distinct();
}
}
}

View File

@@ -1,41 +0,0 @@
using System;
using StackExchange.Redis;
namespace Orchard.Redis.Extensions {
public static class RedisDatabaseExtensions {
public static void KeyDeleteWithPrefix(this IDatabase database, string prefix) {
if (database == null) {
throw new ArgumentException("Database cannot be null", "database");
}
if (string.IsNullOrWhiteSpace(prefix)) {
throw new ArgumentException("Prefix cannot be empty", "database");
}
database.ScriptEvaluate(@"
local keys = redis.call('keys', ARGV[1])
for i=1,#keys,5000 do
redis.call('del', unpack(keys, i, math.min(i+4999, #keys)))
end", values: new RedisValue[] { prefix });
}
public static int KeyCount(this IDatabase database, string prefix) {
if (database == null) {
throw new ArgumentException("Database cannot be null", "database");
}
if (string.IsNullOrWhiteSpace(prefix)) {
throw new ArgumentException("Prefix cannot be empty", "database");
}
var retVal = database.ScriptEvaluate("return table.getn(redis.call('keys', ARGV[1]))", values: new RedisValue[] { prefix });
if (retVal.IsNull) {
return 0;
}
return (int)retVal;
}
}
}

View File

@@ -107,7 +107,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Caching\RedisCacheStorageProvider.cs" />
<Compile Include="Extensions\RedisDatabaseExtensions.cs" />
<Compile Include="Extensions\RedisConnectionExtensions.cs" />
<Compile Include="Configuration\IRedisConnectionProvider.cs" />
<Compile Include="Configuration\RedisConnectionProvider.cs" />
<Compile Include="MessageBus\RedisMessageBusBroker.cs" />

View File

@@ -54,7 +54,7 @@ namespace Orchard.Redis.OutputCache {
}
public void Set(string key, CacheItem cacheItem) {
if(cacheItem == null) {
if (cacheItem == null) {
throw new ArgumentNullException("cacheItem");
}
@@ -74,7 +74,7 @@ namespace Orchard.Redis.OutputCache {
}
public void RemoveAll() {
Database.KeyDeleteWithPrefix(GetLocalizedKey("*"));
Database.KeyDelete(GetPrefixedKeys().Select(key => (RedisKey)key).ToArray());
}
public CacheItem GetCacheItem(string key) {
@@ -85,11 +85,11 @@ namespace Orchard.Redis.OutputCache {
}
using (var compressedStream = new MemoryStream(value)) {
if(compressedStream.Length == 0) {
if (compressedStream.Length == 0) {
return null;
}
using(var decompressedStream = Decompress(compressedStream)) {
using (var decompressedStream = Decompress(compressedStream)) {
return Deserialize(decompressedStream);
}
}
@@ -106,7 +106,7 @@ namespace Orchard.Redis.OutputCache {
}
public int GetCacheItemsCount() {
return Database.KeyCount(GetLocalizedKey("*"));
return GetPrefixedKeys().Count();
}
/// <summary>
@@ -123,19 +123,19 @@ namespace Orchard.Redis.OutputCache {
/// </summary>
/// <returns>The keys for the current tenant.</returns>
private IEnumerable<string> GetAllKeys() {
var prefix = GetLocalizedKey("");
return GetPrefixedKeys().Select(x => x.Substring(prefix.Length));
}
private IEnumerable<string> GetPrefixedKeys() {
// prevent the same request from computing the list twice (count + list)
if (_keysCache == null) {
_keysCache = new HashSet<string>();
var prefix = GetLocalizedKey("");
foreach (var endPoint in _connectionMultiplexer.GetEndPoints()) {
var server = _connectionMultiplexer.GetServer(endPoint);
foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) {
_keysCache.Add(key.ToString().Substring(prefix.Length));
}
var keys = _connectionMultiplexer.GetKeys(GetLocalizedKey("*"));
foreach (var key in keys) {
_keysCache.Add(key);
}
}
return _keysCache;
}

View File

@@ -68,11 +68,7 @@ namespace Orchard.Search {
}
public int Create() {
_indexManager.GetSearchIndexProvider().CreateIndex("Admin");
ContentDefinitionManager.AlterTypeDefinition("Page", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Page:latest"));
return 1;
}
}

View File

@@ -1,4 +1,6 @@
@{
Script.Require("SelectableContentTab");
var pageTitle = T("Search Content");
Layout.Title = pageTitle;
}
@@ -11,10 +13,18 @@
<button type="submit">@T("Search")</button>
</fieldset>
if (Model.ContentItems.Items.Count > 0)
{
<label for="selectAll">@T("Select All")</label>
<input name="selectAll" type="checkbox" class="content-picker-SelectAll" />
}
<fieldset class="contentItems bulk-items">
@Display(Model.ContentItems)
@Display(Model.ContentItems)
</fieldset>
if (Model.ContentItems.Items.Count > 0)
{
@Html.Link(T("Add Selected").Text, "#", new { @class = "button addSelected"})
}
@Display(Model.Pager)
}

View File

@@ -58,28 +58,7 @@ namespace Orchard.Taxonomies.Drivers {
}
protected override DriverResult Editor(ContentPart part, TaxonomyField field, dynamic shapeHelper) {
return ContentShape("Fields_TaxonomyField_Edit", GetDifferentiator(field, part), () => {
var settings = field.PartFieldDefinition.Settings.GetModel<TaxonomyFieldSettings>();
var appliedTerms = GetAppliedTerms(part, field, VersionOptions.Latest).ToDictionary(t => t.Id, t => t);
var taxonomy = _taxonomyService.GetTaxonomyByName(settings.Taxonomy);
var terms = taxonomy != null
? _taxonomyService.GetTerms(taxonomy.Id).Where(t => !string.IsNullOrWhiteSpace(t.Name)).Select(t => t.CreateTermEntry()).ToList()
: new List<TermEntry>(0);
terms.ForEach(t => t.IsChecked = appliedTerms.ContainsKey(t.Id));
var viewModel = new TaxonomyFieldViewModel {
DisplayName = field.DisplayName,
Name = field.Name,
Terms = terms,
Settings = settings,
SingleTermId = terms.Where(t => t.IsChecked).Select(t => t.Id).FirstOrDefault(),
TaxonomyId = taxonomy != null ? taxonomy.Id : 0
};
var templateName = settings.Autocomplete ? "Fields/TaxonomyField.Autocomplete" : "Fields/TaxonomyField";
return shapeHelper.EditorTemplate(TemplateName: templateName, Model: viewModel, Prefix: GetPrefix(field, part));
});
return BuildEditorShape(part, field, shapeHelper);
}
protected override DriverResult Editor(ContentPart part, TaxonomyField field, IUpdateModel updater, dynamic shapeHelper) {
@@ -103,7 +82,38 @@ namespace Orchard.Taxonomies.Drivers {
_taxonomyService.UpdateTerms(part.ContentItem, checkedTerms, field.Name);
}
return Editor(part, field, shapeHelper);
return BuildEditorShape(part, field, shapeHelper, viewModel);
}
private ContentShapeResult BuildEditorShape(ContentPart part, TaxonomyField field, dynamic shapeHelper, TaxonomyFieldViewModel appliedViewModel = null) {
return ContentShape("Fields_TaxonomyField_Edit", GetDifferentiator(field, part), () => {
var settings = field.PartFieldDefinition.Settings.GetModel<TaxonomyFieldSettings>();
var taxonomy = _taxonomyService.GetTaxonomyByName(settings.Taxonomy);
var terms = taxonomy != null
? _taxonomyService.GetTerms(taxonomy.Id).Where(t => !string.IsNullOrWhiteSpace(t.Name)).Select(t => t.CreateTermEntry()).ToList()
: new List<TermEntry>(0);
// Ensure the modified taxonomy items are not lost if a model validation error occurs
if (appliedViewModel != null) {
terms.ForEach(t => t.IsChecked = appliedViewModel.Terms.Any(at => at.Id == t.Id && at.IsChecked) || t.Id == appliedViewModel.SingleTermId);
}
else {
var appliedTerms = GetAppliedTerms(part, field, VersionOptions.Latest).ToDictionary(t => t.Id, t => t);
terms.ForEach(t => t.IsChecked = appliedTerms.ContainsKey(t.Id));
}
var viewModel = new TaxonomyFieldViewModel {
DisplayName = field.DisplayName,
Name = field.Name,
Terms = terms,
Settings = settings,
SingleTermId = terms.Where(t => t.IsChecked).Select(t => t.Id).FirstOrDefault(),
TaxonomyId = taxonomy != null ? taxonomy.Id : 0
};
var templateName = settings.Autocomplete ? "Fields/TaxonomyField.Autocomplete" : "Fields/TaxonomyField";
return shapeHelper.EditorTemplate(TemplateName: templateName, Model: viewModel, Prefix: GetPrefix(field, part));
});
}
protected override void Exporting(ContentPart part, TaxonomyField field, ExportContentContext context) {

View File

@@ -17,6 +17,8 @@ namespace Orchard.Taxonomies.Handlers {
public class TermsPartHandler : ContentHandler {
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IContentManager _contentManager;
private readonly HashSet<int> _processedTermParts = new HashSet<int>();
public TermsPartHandler(
IContentDefinitionManager contentDefinitionManager,
@@ -88,12 +90,17 @@ namespace Orchard.Taxonomies.Handlers {
});
}
// Fires off a processing engine task to run the count processing after the request so it's non-blocking.
// Fires off a processing engine task to run the count processing after the request so it's non-blocking.
private void RecalculateCount(IProcessingEngine processingEngine, ShellSettings shellSettings, IShellDescriptorManager shellDescriptorManager, TermsPart part) {
var termPartRecordIds = part.Terms.Select(t => t.TermRecord.Id).ToArray();
processingEngine.AddTask(shellSettings, shellDescriptorManager.GetShellDescriptor(), "ITermCountProcessor.Process", new Dictionary<string, object> { { "termPartRecordIds", termPartRecordIds } });
if (termPartRecordIds.Any()) {
if (!_processedTermParts.Any()) {
processingEngine.AddTask(shellSettings, shellDescriptorManager.GetShellDescriptor(), "ITermCountProcessor.Process", new Dictionary<string, object> { { "termPartRecordIds", _processedTermParts } });
}
foreach (var termPartRecordId in termPartRecordIds) {
_processedTermParts.Add(termPartRecordId);
}
}
}
protected override void Activating(ActivatingContentContext context) {
@@ -113,4 +120,4 @@ namespace Orchard.Taxonomies.Handlers {
}
}
}
}
}

View File

@@ -7,6 +7,6 @@ using Orchard.Events;
namespace Orchard.Taxonomies.Services {
public interface ITermCountProcessor : IEventHandler {
void Process(params int[] termPartRecordIds);
void Process(IEnumerable<int> termPartRecordIds);
}
}

View File

@@ -30,6 +30,7 @@ namespace Orchard.Taxonomies.Services {
private readonly ShellSettings _shellSettings;
private readonly IShellDescriptorManager _shellDescriptorManager;
private readonly HashSet<int> _processedTermParts = new HashSet<int>();
public TaxonomyService(
IRepository<TermContentItem> termContentItemRepository,
@@ -266,9 +267,14 @@ namespace Orchard.Taxonomies.Services {
}
var termPartRecordIds = termList.Select(t => t.Term.TermRecord.Id).ToArray();
_processingEngine.AddTask(_shellSettings, _shellDescriptorManager.GetShellDescriptor(), "ITermCountProcessor.Process", new Dictionary<string, object> { { "termPartRecordIds", termPartRecordIds } });
if (termPartRecordIds.Any()) {
if (!_processedTermParts.Any()) {
_processingEngine.AddTask(_shellSettings, _shellDescriptorManager.GetShellDescriptor(), "ITermCountProcessor.Process", new Dictionary<string, object> { { "termPartRecordIds", _processedTermParts } });
}
foreach (var termPartRecordId in termPartRecordIds) {
_processedTermParts.Add(termPartRecordId);
}
}
}
public IContentQuery<TermsPart, TermsPartRecord> GetContentItemsQuery(TermPart term, string fieldName = null) {

View File

@@ -1,3 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement;
using Orchard.Taxonomies.Models;
@@ -9,20 +13,31 @@ namespace Orchard.Taxonomies.Services {
_taxonomyService = taxonomyService;
}
public void Process(params int[] termPartRecordIds) {
public void Process(IEnumerable<int> termPartRecordIds)
{
var processedTermPartRecordIds = new List<int>();
foreach (var id in termPartRecordIds) {
var termPart = _taxonomyService.GetTerm(id);
while (termPart != null) {
termPart.Count = (int)_taxonomyService.GetContentItemsCount(termPart);
// compute count for the hierarchy too
if (termPart.Container != null) {
var parentTerm = termPart.Container.As<TermPart>();
termPart = parentTerm;
if (!processedTermPartRecordIds.Contains(id)) {
var termPart = _taxonomyService.GetTerm(id);
if (termPart != null) {
ProcessTerm(termPart, processedTermPartRecordIds);
}
}
}
}
private void ProcessTerm(TermPart termPart, ICollection<int> processedTermPartRecordIds)
{
termPart.Count = (int)_taxonomyService.GetContentItemsCount(termPart);
processedTermPartRecordIds.Add(termPart.Id);
// Look for a parent term that has not yet been processed
if (termPart.Container != null) {
var parentTerm = termPart.Container.As<TermPart>();
if (parentTerm != null && !processedTermPartRecordIds.Contains(parentTerm.Id)) {
ProcessTerm(parentTerm, processedTermPartRecordIds);
}
}
}
}
}

View File

@@ -185,7 +185,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-5.0.2.0" newVersion="5.0.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31BF3856AD364E35" culture="neutral"/>