--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-12-10 12:03:27 -08:00
56 changed files with 507 additions and 172 deletions

View File

@@ -11,20 +11,29 @@ using Orchard.Themes;
using Orchard.UI.Navigation;
namespace Orchard.Core.Containers.Controllers {
using Orchard.Settings;
public class ItemController : Controller {
private readonly IContentManager _contentManager;
private readonly IContainersPathConstraint _containersPathConstraint;
private readonly ISiteService _siteService;
public ItemController(
IContentManager contentManager,
IContainersPathConstraint containersPathConstraint,
IShapeFactory shapeFactory,
ISiteService siteService) {
public ItemController(IContentManager contentManager, IContainersPathConstraint containersPathConstraint, IShapeFactory shapeFactory) {
_contentManager = contentManager;
_containersPathConstraint = containersPathConstraint;
_siteService = siteService;
Shape = shapeFactory;
}
dynamic Shape { get; set; }
[Themed]
public ActionResult Display(string path, Pager pager) {
public ActionResult Display(string path, PagerParameters pagerParameters) {
var matchedPath = _containersPathConstraint.FindPath(path);
if (string.IsNullOrEmpty(matchedPath)) {
throw new ApplicationException("404 - should not have passed path constraint");
@@ -51,7 +60,8 @@ namespace Orchard.Core.Containers.Controllers {
var descendingOrder = container.As<ContainerPart>().Record.OrderByDirection == (int) OrderByDirection.Descending;
query = query.OrderBy(container.As<ContainerPart>().Record.OrderByProperty, descendingOrder);
pager.PageSize = pager.PageSize != Pager.PageSizeDefault && container.As<ContainerPart>().Record.Paginated
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
pager.PageSize = pagerParameters.PageSize != null && container.As<ContainerPart>().Record.Paginated
? pager.PageSize
: container.As<ContainerPart>().Record.PageSize;
var pagerShape = Shape.Pager(pager).TotalItemCount(query.Count());

View File

@@ -17,6 +17,7 @@ using Orchard.Localization;
using Orchard.Logging;
using Orchard.UI.Navigation;
using Orchard.UI.Notify;
using Orchard.Settings;
namespace Orchard.Core.Contents.Controllers {
[ValidateInput(false)]
@@ -24,17 +25,20 @@ namespace Orchard.Core.Contents.Controllers {
private readonly IContentManager _contentManager;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly ITransactionManager _transactionManager;
private readonly ISiteService _siteService;
public AdminController(
IOrchardServices orchardServices,
IContentManager contentManager,
IContentDefinitionManager contentDefinitionManager,
ITransactionManager transactionManager,
ISiteService siteService,
IShapeFactory shapeFactory) {
Services = orchardServices;
_contentManager = contentManager;
_contentDefinitionManager = contentDefinitionManager;
_transactionManager = transactionManager;
_siteService = siteService;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
Shape = shapeFactory;
@@ -45,7 +49,8 @@ namespace Orchard.Core.Contents.Controllers {
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public ActionResult List(ListContentsViewModel model, Pager pager) {
public ActionResult List(ListContentsViewModel model, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
if (model.ContainerId != null && _contentManager.GetLatest((int)model.ContainerId) == null)
return HttpNotFound();

View File

@@ -104,6 +104,7 @@
<Compile Include="Contents\Shapes.cs" />
<Compile Include="Contents\ViewModels\PublishContentViewModel.cs" />
<Compile Include="Navigation\Services\MainMenuNavigationProvider.cs" />
<Compile Include="Routable\Events\ISlugEventHandler.cs" />
<Compile Include="Routable\ResourceManifest.cs" />
<Compile Include="Routable\Services\RoutableHomePageProvider.cs" />
<Compile Include="Contents\ViewModels\ListContentsViewModel.cs" />

View File

@@ -0,0 +1,17 @@
using Orchard.Events;
namespace Orchard.Core.Routable.Events {
public interface ISlugEventHandler : IEventHandler {
void FillingSlugFromTitle(FillSlugContext context);
void FilledSlugFromTitle(FillSlugContext context);
}
public class FillSlugContext {
public FillSlugContext(string slug) {
Slug = slug;
}
public string Slug { get; set; }
public bool Adjusted { get; set; }
}
}

View File

@@ -1,18 +1,23 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Events;
using Orchard.Core.Routable.Models;
namespace Orchard.Core.Routable.Services {
public class RoutableService : IRoutableService {
private readonly IContentManager _contentManager;
private readonly IEnumerable<ISlugEventHandler> _slugEventHandlers;
public RoutableService(IContentManager contentManager) {
public RoutableService(IContentManager contentManager, IEnumerable<ISlugEventHandler> slugEventHandlers) {
_contentManager = contentManager;
_slugEventHandlers = slugEventHandlers;
}
public void FixContainedPaths(IRoutableAspect part) {
@@ -27,23 +32,47 @@ namespace Orchard.Core.Routable.Services {
}
}
public static string RemoveDiacritics(string slug) {
string stFormD = slug.Normalize(NormalizationForm.FormD);
StringBuilder sb = new StringBuilder();
for (int ich = 0; ich < stFormD.Length; ich++) {
UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);
if (uc != UnicodeCategory.NonSpacingMark) {
sb.Append(stFormD[ich]);
}
}
return (sb.ToString().Normalize(NormalizationForm.FormC));
}
public void FillSlugFromTitle<TModel>(TModel model) where TModel : IRoutableAspect {
if (!string.IsNullOrEmpty(model.Slug) || string.IsNullOrEmpty(model.Title))
return;
var slug = model.Title;
var dissallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s\""\<\>]+");
FillSlugContext slugContext = new FillSlugContext(model.Title);
slug = dissallowed.Replace(slug, "-");
slug = slug.Trim('-');
foreach(ISlugEventHandler slugEventHandler in _slugEventHandlers) {
slugEventHandler.FillingSlugFromTitle(slugContext);
}
if (slug.Length > 1000)
slug = slug.Substring(0, 1000);
if (!slugContext.Adjusted) {
var disallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s\""\<\>]+");
// dots are not allowed at the begin and the end of routes
slug = slug.Trim('.');
slugContext.Slug = disallowed.Replace(slugContext.Slug, "-").Trim('-');
model.Slug = slug.ToLowerInvariant();
if (slugContext.Slug.Length > 1000)
slugContext.Slug = slugContext.Slug.Substring(0, 1000);
// dots are not allowed at the begin and the end of routes
slugContext.Slug = RemoveDiacritics(slugContext.Slug.Trim('.').ToLower());
}
foreach (ISlugEventHandler slugEventHandler in _slugEventHandlers) {
slugEventHandler.FilledSlugFromTitle(slugContext);
}
model.Slug = slugContext.Slug;
}
public string GenerateUniqueSlug(IRoutableAspect part, IEnumerable<string> existingPaths) {

View File

@@ -90,6 +90,7 @@ namespace Orchard.Core.Settings {
.Column<string>("HomePage")
.Column<string>("SiteCulture")
.Column<string>("ResourceDebugMode", c => c.WithDefault("FromAppSetting"))
.Column<int>("PageSize")
);
return 1;

View File

@@ -8,28 +8,39 @@ namespace Orchard.Core.Settings.Models {
get { return Record.PageTitleSeparator; }
set { Record.PageTitleSeparator = value; }
}
public string SiteName {
get { return Record.SiteName; }
set { Record.SiteName = value; }
}
public string SiteSalt {
get { return Record.SiteSalt; }
}
public string SuperUser {
get { return Record.SuperUser; }
set { Record.SuperUser = value; }
}
public string HomePage {
get { return Record.HomePage; }
set { Record.HomePage = value; }
}
public string SiteCulture {
get { return Record.SiteCulture; }
set { Record.SiteCulture = value; }
}
public ResourceDebugMode ResourceDebugMode {
get { return Record.ResourceDebugMode; }
set { Record.ResourceDebugMode = value; }
}
public int PageSize {
get { return Record.PageSize; }
set { Record.PageSize = value; }
}
}
}

View File

@@ -3,12 +3,26 @@ using Orchard.Settings;
namespace Orchard.Core.Settings.Models {
public class SiteSettingsPartRecord : ContentPartRecord {
public const int DefaultPageSize = 10;
public SiteSettingsPartRecord() {
PageSize = DefaultPageSize;
}
public virtual string SiteSalt { get; set; }
public virtual string SiteName { get; set; }
public virtual string SuperUser { get; set; }
public virtual string PageTitleSeparator { get; set; }
public virtual string HomePage { get; set; }
public virtual string SiteCulture { get; set; }
public virtual ResourceDebugMode ResourceDebugMode { get; set; }
public virtual int PageSize { get; set; }
}
}

View File

@@ -15,8 +15,7 @@ namespace Orchard.Core.Settings.ViewModels {
get { return Site.ContentItem.Id; }
}
public string PageTitleSeparator
{
public string PageTitleSeparator {
get { return Site.Record.PageTitleSeparator; }
set { Site.Record.PageTitleSeparator = value; }
}
@@ -40,5 +39,10 @@ namespace Orchard.Core.Settings.ViewModels {
get { return Site.As<SiteSettingsPart>().ResourceDebugMode; }
set { Site.As<SiteSettingsPart>().ResourceDebugMode = value; }
}
public int PageSize {
get { return Site.As<SiteSettingsPart>().PageSize; }
set { Site.As<SiteSettingsPart>().PageSize = value; }
}
}
}

View File

@@ -36,4 +36,9 @@
@Html.DropDownList("ResourceDebugMode", resourceDebugMode)
<span class="hint">@T("Determines whether scripts and stylesheets load in their debuggable or minified form.")</span>
</div>
<div>
<label for="DefaultPageSize">@T("Default number of items per page")</label>
@Html.TextBoxFor(m => m.PageSize, new { @class = "textMedium" })
<span class="hint">@T("Determines the default number of items that are shown per page.")</span>
</div>
</fieldset>

View File

@@ -25,7 +25,7 @@ namespace Orchard.Blogs {
var singleBlog = blogCount == 1 ? blogs.ElementAt(0) : null;
if (blogCount > 0 && singleBlog == null) {
menu.Add(T("List"), "3",
menu.Add(T("Manage Blogs"), "3",
item => item.Action("List", "BlogAdmin", new {area = "Orchard.Blogs"}).Permission(Permissions.MetaListOwnBlogs));
}
else if (singleBlog != null)

View File

@@ -15,6 +15,8 @@ using Orchard.UI.Navigation;
using Orchard.UI.Notify;
namespace Orchard.Blogs.Controllers {
using Orchard.Settings;
[ValidateInput(false), Admin]
public class BlogAdminController : Controller, IUpdateModel {
private readonly IBlogService _blogService;
@@ -22,6 +24,7 @@ namespace Orchard.Blogs.Controllers {
private readonly IContentManager _contentManager;
private readonly ITransactionManager _transactionManager;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly ISiteService _siteService;
public BlogAdminController(
IOrchardServices services,
@@ -30,6 +33,7 @@ namespace Orchard.Blogs.Controllers {
IContentManager contentManager,
ITransactionManager transactionManager,
IBlogSlugConstraint blogSlugConstraint,
ISiteService siteService,
IShapeFactory shapeFactory) {
Services = services;
_blogService = blogService;
@@ -37,6 +41,7 @@ namespace Orchard.Blogs.Controllers {
_contentManager = contentManager;
_transactionManager = transactionManager;
_blogSlugConstraint = blogSlugConstraint;
_siteService = siteService;
T = NullLocalizer.Instance;
Shape = shapeFactory;
}
@@ -147,7 +152,8 @@ namespace Orchard.Blogs.Controllers {
return View((object)viewModel);
}
public ActionResult Item(int blogId, Pager pager) {
public ActionResult Item(int blogId, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
BlogPart blogPart = _blogService.Get(blogId, VersionOptions.Latest).As<BlogPart>();
if (blogPart == null)

View File

@@ -13,6 +13,8 @@ using Orchard.Themes;
using Orchard.UI.Navigation;
namespace Orchard.Blogs.Controllers {
using Orchard.Settings;
[Themed]
public class BlogController : Controller {
private readonly IOrchardServices _services;
@@ -22,6 +24,7 @@ namespace Orchard.Blogs.Controllers {
private readonly IFeedManager _feedManager;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IHomePageProvider _routableHomePageProvider;
private readonly ISiteService _siteService;
public BlogController(
IOrchardServices services,
@@ -31,13 +34,15 @@ namespace Orchard.Blogs.Controllers {
IFeedManager feedManager,
IShapeFactory shapeFactory,
IWorkContextAccessor workContextAccessor,
IEnumerable<IHomePageProvider> homePageProviders) {
IEnumerable<IHomePageProvider> homePageProviders,
ISiteService siteService) {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_blogSlugConstraint = blogSlugConstraint;
_feedManager = feedManager;
_workContextAccessor = workContextAccessor;
_siteService = siteService;
_routableHomePageProvider = homePageProviders.SingleOrDefault(p => p.GetProviderName() == RoutableHomePageProvider.Name);
Logger = NullLogger.Instance;
Shape = shapeFactory;
@@ -59,7 +64,8 @@ namespace Orchard.Blogs.Controllers {
return View((object)viewModel);
}
public ActionResult Item(string blogSlug, Pager pager) {
public ActionResult Item(string blogSlug, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var correctedSlug = _blogSlugConstraint.FindSlug(blogSlug);
if (correctedSlug == null)
return HttpNotFound();

View File

@@ -9,6 +9,8 @@ using Orchard.ContentManagement.Aspects;
using Orchard.Core.Contents.Settings;
using Orchard.Localization;
using Orchard.Mvc.AntiForgery;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
@@ -84,9 +86,6 @@ namespace Orchard.Blogs.Controllers {
//todo: the content shape template has extra bits that the core contents module does not (remove draft functionality)
//todo: - move this extra functionality there or somewhere else that's appropriate?
public ActionResult Edit(int blogId, int postId) {
if (!Services.Authorizer.Authorize(Permissions.EditOwnBlogPost, T("Couldn't edit blog post")))
return new HttpUnauthorizedResult();
var blog = _blogService.Get(blogId, VersionOptions.Latest);
if (blog == null)
return HttpNotFound();
@@ -95,6 +94,9 @@ namespace Orchard.Blogs.Controllers {
if (post == null)
return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.EditOthersBlogPost, post.ContentItem, T("Couldn't edit blog post")))
return new HttpUnauthorizedResult();
dynamic model = Services.ContentManager.BuildEditor(post);
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);

View File

@@ -5,7 +5,7 @@ namespace Orchard.Blogs {
public class Migrations : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("BlogPartArchiveRecord",
SchemaBuilder.CreateTable("BlogPartArchiveRecord",
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<int>("Year")
@@ -14,21 +14,21 @@ namespace Orchard.Blogs {
.Column<int>("BlogPart_id")
);
SchemaBuilder.CreateTable("BlogPartRecord",
SchemaBuilder.CreateTable("BlogPartRecord",
table => table
.ContentPartRecord()
.Column<string>("Description", c => c.Unlimited())
.Column<int>("PostCount")
);
SchemaBuilder.CreateTable("RecentBlogPostsPartRecord",
SchemaBuilder.CreateTable("RecentBlogPostsPartRecord",
table => table
.ContentPartRecord()
.Column<string>("BlogSlug")
.Column<int>("Count")
);
SchemaBuilder.CreateTable("BlogArchivesPartRecord",
SchemaBuilder.CreateTable("BlogArchivesPartRecord",
table => table
.ContentPartRecord()
.Column<string>("BlogSlug", c => c.WithLength(255))

View File

@@ -82,6 +82,7 @@
<Compile Include="Routing\IsArchiveConstraint.cs" />
<Compile Include="Routing\BlogSlugConstraint.cs" />
<Compile Include="Routing\BlogSlugConstraintUpdator.cs" />
<Compile Include="Security\BlogAuthorizationEventHandler.cs" />
<Compile Include="Services\BlogService.cs" />
<Compile Include="Controllers\BlogController.cs" />
<Compile Include="Models\BlogPart.cs" />

View File

@@ -0,0 +1,49 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Security;
using Orchard.Security.Permissions;
namespace Orchard.Blogs.Security {
[UsedImplicitly]
public class BlogAuthorizationEventHandler : IAuthorizationServiceEventHandler {
public void Checking(CheckAccessContext context) { }
public void Complete(CheckAccessContext context) { }
public void Adjust(CheckAccessContext context) {
if (!context.Granted &&
context.Content.Is<ICommonPart>()) {
if (OwnerVariationExists(context.Permission) &&
HasOwnership(context.User, context.Content)) {
context.Adjusted = true;
context.Permission = GetOwnerVariation(context.Permission);
}
}
}
private static bool HasOwnership(IUser user, IContent content) {
if (user == null || content == null)
return false;
var common = content.As<ICommonPart>();
if (common == null || common.Owner == null)
return false;
return user.Id == common.Owner.Id;
}
private static bool OwnerVariationExists(Permission permission) {
return GetOwnerVariation(permission) != null;
}
private static Permission GetOwnerVariation(Permission permission) {
if (permission.Name == Permissions.PublishOthersBlogPost.Name)
return Permissions.PublishOwnBlogPost;
if (permission.Name == Permissions.EditOthersBlogPost.Name)
return Permissions.EditOwnBlogPost;
if (permission.Name == Permissions.DeleteOthersBlogPost.Name)
return Permissions.DeleteOwnBlogPost;
return null;
}
}
}

View File

@@ -123,7 +123,7 @@ namespace Orchard.Blogs.Services {
string password) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
_authorizationService.CheckAccess(Permissions.EditOthersBlogPost, user, null);
var array = new XRpcArray();
foreach (var blog in _blogService.Get()) {
@@ -144,7 +144,7 @@ namespace Orchard.Blogs.Services {
int numberOfPosts) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
_authorizationService.CheckAccess(Permissions.EditOthersBlogPost, user, null);
var blog = _contentManager.Get<BlogPart>(Convert.ToInt32(blogId));
if (blog == null)
@@ -166,7 +166,7 @@ namespace Orchard.Blogs.Services {
IEnumerable<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(Permissions.EditOwnBlogPost, user, null);
_authorizationService.CheckAccess(publish ? Permissions.PublishOthersBlogPost : Permissions.EditOthersBlogPost, user, null);
var blog = _contentManager.Get<BlogPart>(Convert.ToInt32(blogId));
if (blog == null)
@@ -216,7 +216,7 @@ namespace Orchard.Blogs.Services {
IEnumerable<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
_authorizationService.CheckAccess(Permissions.EditOthersBlogPost, user, null);
var blogPost = _blogPostService.Get(postId, VersionOptions.Latest);
if (blogPost == null)
@@ -231,15 +231,13 @@ namespace Orchard.Blogs.Services {
}
private bool MetaWeblogEditPost(int postId, string userName, string password, XRpcStruct content, bool publish, IEnumerable<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
_authorizationService.CheckAccess(publish ? Permissions.PublishOthersBlogPost : Permissions.EditOthersBlogPost, user, null);
var blogPost = _blogPostService.Get(postId, VersionOptions.DraftRequired);
if (blogPost == null)
throw new ArgumentException();
var title = content.Optional<string>("title");
var description = content.Optional<string>("description");
var slug = content.Optional<string>("wp_slug");
@@ -259,7 +257,7 @@ namespace Orchard.Blogs.Services {
private bool MetaWeblogDeletePost(string appkey, string postId, string userName, string password, bool publish, IEnumerable<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
_authorizationService.CheckAccess(Permissions.DeleteOthersBlogPost, user, null);
var blogPost = _blogPostService.Get(Convert.ToInt32(postId), VersionOptions.Latest);
if (blogPost == null)

View File

@@ -14,12 +14,20 @@ using Orchard.Comments.ViewModels;
using Orchard.Comments.Services;
namespace Orchard.Comments.Controllers {
using Orchard.Settings;
[ValidateInput(false)]
public class AdminController : Controller {
private readonly ICommentService _commentService;
private readonly ISiteService _siteService;
public AdminController(IOrchardServices services, ICommentService commentService, IShapeFactory shapeFactory) {
public AdminController(
IOrchardServices services,
ICommentService commentService,
ISiteService siteService,
IShapeFactory shapeFactory) {
_commentService = commentService;
_siteService = siteService;
Services = services;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
@@ -31,7 +39,9 @@ namespace Orchard.Comments.Controllers {
public Localizer T { get; set; }
dynamic Shape { get; set; }
public ActionResult Index(CommentIndexOptions options, Pager pager) {
public ActionResult Index(CommentIndexOptions options, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
// Default options
if (options == null)
options = new CommentIndexOptions();

View File

@@ -2,7 +2,7 @@
white-space:nowrap;
}
table.items tr {
background:#f7f7f7;
background:#fff;
}
table.items tr.anonymous {
background:#fff;

View File

@@ -36,7 +36,7 @@ namespace Orchard.ContentTypes.Services {
public Localizer T { get; set; }
public IEnumerable<EditTypeViewModel> GetTypes() {
return _contentDefinitionManager.ListTypeDefinitions().Select(ctd => new EditTypeViewModel(ctd));
return _contentDefinitionManager.ListTypeDefinitions().Select(ctd => new EditTypeViewModel(ctd)).OrderBy(m => m.DisplayName);
}
public EditTypeViewModel GetType(string name) {

View File

@@ -1,5 +1,6 @@
.orchard-contenttypes #main h2 {
margin:1.5em 0 0;
border-bottom:1px solid #ccc;
}
#main .properties p {

View File

@@ -1,6 +1,7 @@
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.UI.Navigation;
using Orchard.Security;
namespace Orchard.Packaging {
[OrchardFeature("Gallery")]
@@ -12,11 +13,14 @@ namespace Orchard.Packaging {
public void GetNavigation(NavigationBuilder builder) {
builder.Add(T("Gallery"), "30", menu => menu
.Add(T("Modules"), "1.0", item => item
.Action("Modules", "Gallery", new { area = "Orchard.Packaging" }))
.Action("Modules", "Gallery", new { area = "Orchard.Packaging" })
.Permission(StandardPermissions.SiteOwner))
.Add(T("Themes"), "2.0", item => item
.Action("Themes", "Gallery", new { area = "Orchard.Packaging" }))
.Action("Themes", "Gallery", new { area = "Orchard.Packaging" })
.Permission(StandardPermissions.SiteOwner))
.Add(T("Feeds"), "3.0", item => item
.Action("Sources", "Gallery", new { area = "Orchard.Packaging" })));
.Action("Sources", "Gallery", new { area = "Orchard.Packaging" })
.Permission(StandardPermissions.SiteOwner)));
}
}
}

View File

@@ -9,6 +9,7 @@ using Orchard.Localization;
using Orchard.Logging;
using Orchard.Packaging.Services;
using Orchard.Packaging.ViewModels;
using Orchard.Security;
using Orchard.Themes;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
@@ -26,36 +27,51 @@ namespace Orchard.Packaging.Controllers {
public GalleryController(
IPackageManager packageManager,
IPackagingSourceManager packagingSourceManager,
INotifier notifier) {
INotifier notifier,
IOrchardServices services) {
_packageManager = packageManager;
_packagingSourceManager = packagingSourceManager;
_notifier = notifier;
Services = services;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
}
public IOrchardServices Services { get; set; }
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public ActionResult Sources() {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list sources")))
return new HttpUnauthorizedResult();
return View(new PackagingSourcesViewModel {
Sources = _packagingSourceManager.GetSources(),
});
}
public ActionResult Remove(int id) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove sources")))
return new HttpUnauthorizedResult();
_packagingSourceManager.RemoveSource(id);
_notifier.Information(T("The feed has been removed successfully."));
return RedirectToAction("Sources");
}
public ActionResult AddSource() {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add sources")))
return new HttpUnauthorizedResult();
return View(new PackagingAddSourceViewModel());
}
[HttpPost]
public ActionResult AddSource(string url) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add sources")))
return new HttpUnauthorizedResult();
try {
if (!String.IsNullOrEmpty(url)) {
if (!url.StartsWith("http")) {
@@ -96,6 +112,9 @@ namespace Orchard.Packaging.Controllers {
}
public ActionResult Modules(int? sourceId) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list modules")))
return new HttpUnauthorizedResult();
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
var sources = selectedSource != null
@@ -123,6 +142,9 @@ namespace Orchard.Packaging.Controllers {
}
public ActionResult Themes(int? sourceId) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list themes")))
return new HttpUnauthorizedResult();
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
var sources = selectedSource != null
@@ -138,6 +160,9 @@ namespace Orchard.Packaging.Controllers {
}
public ActionResult Install(string packageId, string version, int sourceId, string redirectTo) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to install packages")))
return new HttpUnauthorizedResult();
var source = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
if (source == null) {

View File

@@ -8,6 +8,7 @@ using Orchard.Environment.Extensions;
using Orchard.FileSystems.AppData;
using Orchard.Localization;
using Orchard.Packaging.Services;
using Orchard.Security;
using Orchard.Themes;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
@@ -25,40 +26,61 @@ namespace Orchard.Packaging.Controllers {
public PackagingServicesController(
IPackageManager packageManager,
INotifier notifier,
IAppDataFolderRoot appDataFolderRoot) {
IAppDataFolderRoot appDataFolderRoot,
IOrchardServices services) {
_packageManager = packageManager;
_notifier = notifier;
_appDataFolderRoot = appDataFolderRoot;
Services = services;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public IOrchardServices Services { get; set; }
public ActionResult AddTheme(string returnUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add themes")))
return new HttpUnauthorizedResult();
return View();
}
[HttpPost, ActionName("AddTheme")]
public ActionResult AddThemePOST(string returnUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add themes")))
return new HttpUnauthorizedResult();
return InstallPackage(returnUrl, Request.RawUrl);
}
[HttpPost, ActionName("RemoveTheme")]
public ActionResult RemoveThemePOST(string themeId, string returnUrl, string retryUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove themes")))
return new HttpUnauthorizedResult();
return UninstallPackage(PackagingSourceManager.ThemesPrefix + themeId, returnUrl, retryUrl);
}
public ActionResult AddModule(string returnUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add modules")))
return new HttpUnauthorizedResult();
return View();
}
[HttpPost, ActionName("AddModule")]
public ActionResult AddModulePOST(string returnUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add modules")))
return new HttpUnauthorizedResult();
return InstallPackage(returnUrl, Request.RawUrl);
}
public ActionResult InstallPackage(string returnUrl, string retryUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to install packages")))
return new HttpUnauthorizedResult();
try {
if (Request.Files != null &&
Request.Files.Count > 0 &&
@@ -90,6 +112,9 @@ namespace Orchard.Packaging.Controllers {
}
public ActionResult UninstallPackage(string id, string returnUrl, string retryUrl) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to uninstall packages")))
return new HttpUnauthorizedResult();
try {
_packageManager.Uninstall(id, HostingEnvironment.MapPath("~/"));

View File

@@ -2,6 +2,7 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Services;
using Orchard.Mvc;
using Orchard.PublishLater.Models;
using Orchard.PublishLater.Services;
using Orchard.PublishLater.ViewModels;
@@ -58,22 +59,24 @@ namespace Orchard.PublishLater.Drivers {
updater.TryUpdateModel(model, Prefix, null, null);
if (!string.IsNullOrWhiteSpace(model.ScheduledPublishDate) && !string.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
DateTime scheduled;
string parseDateTime = String.Concat(model.ScheduledPublishDate, " ", model.ScheduledPublishTime);
if (Services.WorkContext.Resolve<IHttpContextAccessor>().Current().Request.Form["submit.Save"] == "submit.PublishLater") {
if (!string.IsNullOrWhiteSpace(model.ScheduledPublishDate) && !string.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
DateTime scheduled;
string parseDateTime = String.Concat(model.ScheduledPublishDate, " ", model.ScheduledPublishTime);
// use an english culture as it is the one used by jQuery.datepicker by default
if (DateTime.TryParse(parseDateTime, CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.AssumeLocal, out scheduled)) {
model.ScheduledPublishUtc = part.ScheduledPublishUtc.Value = scheduled.ToUniversalTime();
_publishLaterService.Publish(model.ContentItem, model.ScheduledPublishUtc.Value);
// use an english culture as it is the one used by jQuery.datepicker by default
if (DateTime.TryParse(parseDateTime, CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.AssumeLocal, out scheduled)) {
model.ScheduledPublishUtc = part.ScheduledPublishUtc.Value = scheduled.ToUniversalTime();
_publishLaterService.Publish(model.ContentItem, model.ScheduledPublishUtc.Value);
}
else {
updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime));
}
}
else {
updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime));
else if (!string.IsNullOrWhiteSpace(model.ScheduledPublishDate) || !string.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then click Save or Publish Now."));
}
}
else if (!string.IsNullOrWhiteSpace(model.ScheduledPublishDate) || !string.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then clear both the date and time fields."));
}
return ContentShape("Parts_PublishLater_Edit",
() => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));

View File

@@ -7,7 +7,7 @@
-->
<!-- edit shape just get default placement -->
<!-- edit "shape" -->
<Place Parts_PublishLater_Edit="Sidebar:22"/><!-- immediately following the contents module's save button -->
<Place Parts_PublishLater_Edit="Sidebar:25"/><!-- immediately following the contents module's Publish Now button -->
<!-- default positioning -->
<Match DisplayType="SummaryAdmin">
<Place Parts_PublishLater_Metadata_SummaryAdmin="Meta:1"/>

View File

@@ -6,9 +6,25 @@ html.dyn input.hinted {
color:#ccc;
font-style:italic;
}
fieldset.publish-later-datetime {
float:left;
clear:none;
white-space: nowrap;
vertical-align: middle;
}
fieldset.publish-later-datetime legend {
display:none;
}
fieldset.publish-later-datetime input {
padding:1px;
text-align:center;
color:#666;
}
input#PublishLater_ScheduledPublishDate {
width:49%;
width:39%;
}
input#PublishLater_ScheduledPublishTime {
width:43%;
}
width:33%;
}

View File

@@ -12,6 +12,7 @@
@Html.EditorFor(m => m.ScheduledPublishDate)
<label class="forpicker" for="@ViewData.TemplateInfo.GetFullHtmlFieldId("ScheduledPublishTime")">@T("Time")</label>
@Html.EditorFor(m => m.ScheduledPublishTime)
<button type="submit" name="submit.Save" value="submit.PublishLater">@T("Publish Later")</button>
</fieldset>
@using(Script.Foot()) {
<script type="text/javascript">

View File

@@ -15,19 +15,24 @@ using Orchard.Collections;
using Orchard.Themes;
namespace Orchard.Search.Controllers {
using Orchard.Settings;
[ValidateInput(false), Themed]
public class SearchController : Controller {
private readonly ISearchService _searchService;
private readonly IContentManager _contentManager;
private readonly ISiteService _siteService;
public SearchController(
IOrchardServices services,
ISearchService searchService,
IContentManager contentManager,
ISearchService searchService,
IContentManager contentManager,
ISiteService siteService,
IShapeFactory shapeFactory) {
Services = services;
_searchService = searchService;
_contentManager = contentManager;
_siteService = siteService;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
@@ -39,7 +44,8 @@ namespace Orchard.Search.Controllers {
public ILogger Logger { get; set; }
dynamic Shape { get; set; }
public ActionResult Index(Pager pager, string q = "") {
public ActionResult Index(PagerParameters pagerParameters, string q = "") {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var searchFields = Services.WorkContext.CurrentSite.As<SearchSettingsPart>().SearchedFields;
IPageOfItems<ISearchHit> searchHits = new PageOfItems<ISearchHit>(new ISearchHit[] { });

View File

@@ -7,17 +7,12 @@
Model.ContentItems.Classes.Add("search-results");
}
<h1>@Html.TitleForPage(T("Search").Text)</h1>
@using(Html.BeginForm("index", "search", new { area = "Orchard.Search" }, FormMethod.Get, new { @class = "search group" })) {
<fieldset>
@Html.TextBox("q", Model.Query)
<button type="submit">@T("Search")</button>
</fieldset>
}
@if (HasText(Model.Query)) {
if (searchResults.Count() == 0) {
<p class="search-summary">@T.Plural("the <em>one</em> result", "<em>zero</em> results", searchResults.Count())</p>
<p class="search-summary">@T.Plural("There is <em>one</em> result", "<em>zero</em> results", searchResults.Count())</p>
} else {
<p class="search-summary">@T.Plural("the <em>one</em> result", "<em>{1} - {2}</em> of <em>{0}</em> results", Model.TotalItemCount, Model.StartPosition, Model.EndPosition)</p>
<p class="search-summary">@T.Plural("There is <em>one</em> result", "<em>{1} - {2}</em> of <em>{0}</em> results", Model.TotalItemCount, Model.StartPosition, Model.EndPosition)</p>
}
}
@if (searchResults != null && searchResults.Count() > 0) {

View File

@@ -8,6 +8,7 @@ using Orchard.Commands.Builtin;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Core.Settings.Models;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Providers;
using Orchard.Data.Migration;
@@ -172,6 +173,11 @@ namespace Orchard.Setup {
get { return ResourceDebugMode.FromAppSetting; }
set { throw new NotImplementedException(); }
}
public int PageSize {
get { return SiteSettingsPartRecord.DefaultPageSize; }
set { throw new NotImplementedException(); }
}
}
}
}

View File

@@ -4,23 +4,28 @@ using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Settings;
using Orchard.Tags.Services;
using Orchard.Tags.ViewModels;
using Orchard.Themes;
using Orchard.UI.Navigation;
namespace Orchard.Tags.Controllers {
[ValidateInput(false), Themed]
public class HomeController : Controller {
private readonly ITagService _tagService;
private readonly IContentManager _contentManager;
private readonly ISiteService _siteService;
private readonly dynamic _shapeFactory;
public HomeController(
ITagService tagService,
IContentManager contentManager,
ITagService tagService,
IContentManager contentManager,
ISiteService siteService,
IShapeFactory shapeFactory) {
_tagService = tagService;
_contentManager = contentManager;
_siteService = siteService;
_shapeFactory = shapeFactory;
T = NullLocalizer.Instance;
}
@@ -34,21 +39,26 @@ namespace Orchard.Tags.Controllers {
return View(model);
}
public ActionResult Search(string tagName) {
public ActionResult Search(string tagName, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var tag = _tagService.GetTagByName(tagName);
if (tag == null) {
return RedirectToAction("Index");
}
var list = _shapeFactory.List();
foreach (var taggedContentItem in _tagService.GetTaggedContentItems(tag.Id)) {
list.Add(_contentManager.BuildDisplay(taggedContentItem, "Summary"));
}
var taggedItems = _tagService.GetTaggedContentItems(tag.Id, pager.GetStartIndex(), pager.PageSize)
.Select(item => _contentManager.BuildDisplay(item, "Summary"));
var list = _shapeFactory.List();
list.AddRange(taggedItems);
var totalItemCount = _tagService.GetTaggedContentItemCount(tag.Id);
var viewModel = new TagsSearchViewModel {
TagName = tag.TagName,
List = list
List = list,
Pager = _shapeFactory.Pager(pager).TotalItemCount(totalItemCount)
};
return View(viewModel);

View File

@@ -9,6 +9,10 @@ namespace Orchard.Tags.Services {
TagRecord GetTagByName(string tagName);
IEnumerable<IContent> GetTaggedContentItems(int tagId);
IEnumerable<IContent> GetTaggedContentItems(int tagId, VersionOptions options);
IEnumerable<IContent> GetTaggedContentItems(int tagId, int skip, int count);
IEnumerable<IContent> GetTaggedContentItems(int tagId, int skip, int count, VersionOptions versionOptions);
int GetTaggedContentItemCount(int tagId);
int GetTaggedContentItemCount(int tagId, VersionOptions versionOptions);
TagRecord CreateTag(string tagName);

View File

@@ -119,6 +119,27 @@ namespace Orchard.Tags.Services {
.Where(c => c != null);
}
public IEnumerable<IContent> GetTaggedContentItems(int tagId, int skip, int take) {
return GetTaggedContentItems(tagId, skip, take, VersionOptions.Published);
}
public IEnumerable<IContent> GetTaggedContentItems(int tagId, int skip, int take, VersionOptions options) {
return _contentTagRepository
.Fetch(x => x.TagRecord.Id == tagId)
.Skip(skip)
.Take(take)
.Select(t => _orchardServices.ContentManager.Get(t.TagsPartRecord.Id, options))
.Where(c => c != null);
}
public int GetTaggedContentItemCount(int tagId) {
return GetTaggedContentItemCount(tagId, VersionOptions.Published);
}
public int GetTaggedContentItemCount(int tagId, VersionOptions options) {
return GetTaggedContentItems(tagId, options).Count();
}
private void TagContentItem(TagsPartRecord tagsPartRecord, string tagName) {
var tagRecord = GetTagByName(tagName);
var tagsContentItems = new ContentTagRecord { TagsPartRecord = tagsPartRecord, TagRecord = tagRecord };

View File

@@ -2,5 +2,6 @@
public class TagsSearchViewModel {
public string TagName { get; set; }
public dynamic List { get; set; }
public dynamic Pager { get; set; }
}
}

View File

@@ -1,11 +1,10 @@
@model Orchard.Tags.ViewModels.TagsSearchViewModel
@{
Html.AddTitleParts(T("Tags").ToString());
Html.AddTitleParts(T("Contents tagged with {0}", Model.TagName).ToString());
Model.List.Classes.Add("tagged-posts");
Model.List.Classes.Add("content-items");
}
<h1 class="page-title">@T("Contents tagged with <span>{0}</span>", Model.TagName)</h1>
@Display(Model.List)
@Display(Model.Pager)

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement;
@@ -27,8 +28,16 @@ namespace Orchard.Widgets.Drivers {
public Localizer T { get; set; }
protected override DriverResult Editor(LayerPart layerPart, dynamic shapeHelper) {
return ContentShape("Parts_Widgets_LayerPart",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Widgets.LayerPart", Model: layerPart, Prefix: Prefix));
var results = new List<DriverResult> {
ContentShape("Parts_Widgets_LayerPart",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Widgets.LayerPart", Model: layerPart, Prefix: Prefix))
};
if (layerPart.Id > 0)
results.Add(ContentShape("Widget_DeleteButton",
deleteButton => deleteButton));
return Combined(results.ToArray());
}
protected override DriverResult Editor(LayerPart layerPart, IUpdateModel updater, dynamic shapeHelper) {

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Widgets.Models;
@@ -18,8 +19,16 @@ namespace Orchard.Widgets.Drivers {
widgetPart.AvailableZones = _widgetsService.GetZones();
widgetPart.AvailableLayers = _widgetsService.GetLayers();
return ContentShape("Parts_Widgets_WidgetPart",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Widgets.WidgetPart", Model: widgetPart, Prefix: Prefix));
var results = new List<DriverResult> {
ContentShape("Parts_Widgets_WidgetPart",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Widgets.WidgetPart", Model: widgetPart, Prefix: Prefix))
};
if (widgetPart.Id > 0)
results.Add(ContentShape("Widget_DeleteButton",
deleteButton => deleteButton));
return Combined(results.ToArray());
}
protected override DriverResult Editor(WidgetPart widgetPart, IUpdateModel updater, dynamic shapeHelper) {

View File

@@ -130,6 +130,9 @@
<Content Include="Views\EditorTemplates\Parts.Widgets.LayerPart.cshtml" />
<Content Include="Views\EditorTemplates\Parts.Widgets.WidgetPart.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Widget.DeleteButton.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -1,4 +1,5 @@
<Placement>
<Place Widget_DeleteButton="Sidebar:25"/>
<Place Parts_Widgets_LayerPart="Content:1"/>
<Place Parts_Widgets_WidgetPart="Content:1"/>
<Place Parts_Widgets_WidegetBagPart="Content:5"/>

View File

@@ -2,8 +2,4 @@
@using (Html.BeginFormAntiForgeryPost()) {
@Html.ValidationSummary()
@Display(Model)
<fieldset>
<button type="submit" name="submit.Delete" value="@T("Delete")">@T("Delete")</button>
</fieldset>
}

View File

@@ -2,8 +2,4 @@
@using (Html.BeginFormAntiForgeryPost()) {
@Html.ValidationSummary()
@Display(Model)
<fieldset>
<button type="submit" name="submit.Delete" value="@T("Delete")">@T("Delete")</button>
</fieldset>
}

View File

@@ -0,0 +1,3 @@
<fieldset class="delete-button">
<button type="submit" name="submit.Delete" value="@T("Delete")">@T("Delete")</button>
</fieldset>

View File

@@ -732,7 +732,6 @@ table.items th, table.items td {
border-spacing:0px;
display:table-cell;
padding:8px 12px;
vertical-align:middle;
}
/* Content item lists
@@ -748,6 +747,7 @@ table.items th, table.items td {
margin:0;
overflow:hidden;
padding:0 1.4em .8em;
border-bottom:1px solid #eaeaea;
}
.contentItems li.last {
border-bottom:none;
@@ -859,51 +859,28 @@ table.items th, table.items td {
}
/* Core Contents and Orchard.PublishLater */
.edit-item-sidebar
{
border:1px solid #d3d3d3;
padding:8px;
/*CSS3 properties*/
filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr='#f7f7f7', endColorstr='#f5f5f5');
background: -webkit-gradient(linear, 0 0, 0 100%, from(#f7f7f7), to(#f5f5f5));
background: -moz-linear-gradient(top, #f7f7f7, #f5f5f5);
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
.edit-item-sidebar fieldset {
margin:0;
padding:0;
}
fieldset.publish-button {
fieldset.publish-button, fieldset.delete-button, fieldset.save-button {
clear:none;
float:left;
}
fieldset.save-button {
clear:left;
}
fieldset.publish-button {
margin: 0 12px;
padding: 0 12px;
border-left:1px solid #ccc;
}
fieldset.save-button {
clear:none;
float:left;
padding-right:0;
width:auto;
}
fieldset.publish-later-datetime {
float:left;
}
fieldset.publish-later-datetime legend {
display:none;
}
fieldset.publish-later-datetime input {
padding:1px;
text-align:center;
color:#666;
fieldset.delete-button {
margin: 0 0 0 12px;
}
/* Fields
***************************************************************/
/* TextField */