Merge remote-tracking branch 'origin/dev-v7' into dev-v7.7
# Conflicts: # build/UmbracoVersion.txt # src/SolutionInfo.cs # src/Umbraco.Core/Configuration/UmbracoVersion.cs # src/Umbraco.Web.UI/Umbraco.Web.UI.csproj # src/Umbraco.Web/Umbraco.Web.csproj
This commit is contained in:
@@ -19,6 +19,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
private ShadowWrapper _macroPartialFileSystem;
|
||||
private ShadowWrapper _partialViewsFileSystem;
|
||||
private ShadowWrapper _macroScriptsFileSystem;
|
||||
private ShadowWrapper _userControlsFileSystem;
|
||||
private ShadowWrapper _stylesheetsFileSystem;
|
||||
private ShadowWrapper _scriptsFileSystem;
|
||||
private ShadowWrapper _xsltFileSystem;
|
||||
@@ -61,6 +63,8 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
var macroPartialFileSystem = new PhysicalFileSystem(SystemDirectories.MacroPartials);
|
||||
var partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews);
|
||||
var macroScriptsFileSystem = new PhysicalFileSystem(SystemDirectories.MacroScripts);
|
||||
var userControlsFileSystem = new PhysicalFileSystem(SystemDirectories.UserControls);
|
||||
var stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css);
|
||||
var scriptsFileSystem = new PhysicalFileSystem(SystemDirectories.Scripts);
|
||||
var xsltFileSystem = new PhysicalFileSystem(SystemDirectories.Xslt);
|
||||
@@ -69,6 +73,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", ScopeProvider);
|
||||
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", ScopeProvider);
|
||||
_macroScriptsFileSystem = new ShadowWrapper(macroScriptsFileSystem, "macroScripts", ScopeProvider);
|
||||
_userControlsFileSystem = new ShadowWrapper(userControlsFileSystem, "usercontrols", ScopeProvider);
|
||||
_stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", ScopeProvider);
|
||||
_scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", ScopeProvider);
|
||||
_xsltFileSystem = new ShadowWrapper(xsltFileSystem, "xslt", ScopeProvider);
|
||||
@@ -85,6 +91,10 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public IFileSystem2 MacroPartialsFileSystem { get { return _macroPartialFileSystem; } }
|
||||
public IFileSystem2 PartialViewsFileSystem { get { return _partialViewsFileSystem; } }
|
||||
// Legacy /macroScripts folder
|
||||
public IFileSystem2 MacroScriptsFileSystem { get { return _macroScriptsFileSystem; } }
|
||||
// Legacy /usercontrols folder
|
||||
public IFileSystem2 UserControlsFileSystem { get { return _userControlsFileSystem; } }
|
||||
public IFileSystem2 StylesheetsFileSystem { get { return _stylesheetsFileSystem; } }
|
||||
public IFileSystem2 ScriptsFileSystem { get { return _scriptsFileSystem; } }
|
||||
public IFileSystem2 XsltFileSystem { get { return _xsltFileSystem; } }
|
||||
@@ -252,13 +262,15 @@ namespace Umbraco.Core.IO
|
||||
internal ICompletable Shadow(Guid id)
|
||||
{
|
||||
var typed = _wrappers.ToArray();
|
||||
var wrappers = new ShadowWrapper[typed.Length + 7];
|
||||
var wrappers = new ShadowWrapper[typed.Length + 9];
|
||||
var i = 0;
|
||||
while (i < typed.Length) wrappers[i] = typed[i++];
|
||||
wrappers[i++] = _macroPartialFileSystem;
|
||||
wrappers[i++] = _macroScriptsFileSystem;
|
||||
wrappers[i++] = _partialViewsFileSystem;
|
||||
wrappers[i++] = _stylesheetsFileSystem;
|
||||
wrappers[i++] = _scriptsFileSystem;
|
||||
wrappers[i++] = _userControlsFileSystem;
|
||||
wrappers[i++] = _xsltFileSystem;
|
||||
wrappers[i++] = _masterPagesFileSystem;
|
||||
wrappers[i] = _mvcViewsFileSystem;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IUserControl : IFile
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
{
|
||||
Unknown = 0, // default
|
||||
PartialView = 1,
|
||||
PartialViewMacro = 2
|
||||
PartialViewMacro = 2,
|
||||
MacroScript = 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a UserControl file
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class UserControl : File, IUserControl
|
||||
{
|
||||
public UserControl(string path)
|
||||
: this(path, (Func<File, string>)null)
|
||||
{ }
|
||||
|
||||
internal UserControl(string path, Func<File, string> getFileContent)
|
||||
: base(path, getFileContent)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity has an identity, which in this case is a path/name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Overrides the default Entity identity check.
|
||||
/// </remarks>
|
||||
public override bool HasIdentity
|
||||
{
|
||||
get { return string.IsNullOrEmpty(Path) == false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-21
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
@@ -11,15 +10,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
|
||||
{
|
||||
public UpdateUniqueIdToHaveCorrectIndexType(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
//see: http://issues.umbraco.org/issue/U4-6188, http://issues.umbraco.org/issue/U4-6187
|
||||
public override void Up()
|
||||
{
|
||||
|
||||
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
var indexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
@@ -28,24 +23,19 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
|
||||
//must be non-nullable
|
||||
// drop the index if it exists
|
||||
if (indexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID")))
|
||||
Delete.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode");
|
||||
|
||||
// set uniqueID to be non-nullable
|
||||
// the index *must* be dropped else 'one or more objects access this column' exception
|
||||
Alter.Table("umbracoNode").AlterColumn("uniqueID").AsGuid().NotNullable();
|
||||
|
||||
//make sure it already exists
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID")))
|
||||
{
|
||||
Delete.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode");
|
||||
}
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNode_uniqueID")) == false)
|
||||
{
|
||||
//must be a uniqe index
|
||||
Create.Index("IX_umbracoNode_uniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Unique();
|
||||
}
|
||||
// create the index
|
||||
Create.Index("IX_umbracoNode_uniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Unique();
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
}
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.IO;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IUserControlRepository : IRepository<string, UserControl>
|
||||
{
|
||||
bool ValidateUserControl(UserControl userControl);
|
||||
Stream GetFileContentStream(string filepath);
|
||||
void SetFileContent(string filepath, Stream content);
|
||||
long GetFileSize(string filepath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class MacroScriptRepository : PartialViewRepository
|
||||
{
|
||||
public MacroScriptRepository(IUnitOfWork work, IFileSystem fileSystem)
|
||||
: base(work, fileSystem)
|
||||
{ }
|
||||
|
||||
protected override PartialViewType ViewType { get { return PartialViewType.MacroScript; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the UserControl Repository
|
||||
/// </summary>
|
||||
internal class UserControlRepository : FileRepository<string, UserControl>, IUserControlRepository
|
||||
{
|
||||
public UserControlRepository(IUnitOfWork work, IFileSystem fileSystem)
|
||||
: base(work, fileSystem)
|
||||
{
|
||||
}
|
||||
|
||||
public override UserControl Get(string id)
|
||||
{
|
||||
var path = FileSystem.GetRelativePath(id);
|
||||
|
||||
path = path.EnsureEndsWith(".ascx");
|
||||
|
||||
if (FileSystem.FileExists(path) == false)
|
||||
return null;
|
||||
|
||||
var created = FileSystem.GetCreated(path).UtcDateTime;
|
||||
var updated = FileSystem.GetLastModified(path).UtcDateTime;
|
||||
|
||||
var userControl = new UserControl(path, file => GetFileContent(file.OriginalPath))
|
||||
{
|
||||
Key = path.EncodeAsGuid(),
|
||||
CreateDate = created,
|
||||
UpdateDate = updated,
|
||||
Id = path.GetHashCode(),
|
||||
VirtualPath = FileSystem.GetUrl(path)
|
||||
};
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
userControl.ResetDirtyProperties(false);
|
||||
|
||||
return userControl;
|
||||
}
|
||||
|
||||
public override void AddOrUpdate(UserControl entity)
|
||||
{
|
||||
base.AddOrUpdate(entity);
|
||||
|
||||
// ensure that from now on, content is lazy-loaded
|
||||
if (entity.GetFileContent == null)
|
||||
entity.GetFileContent = file => GetFileContent(file.OriginalPath);
|
||||
}
|
||||
|
||||
public override IEnumerable<UserControl> GetAll(params string[] ids)
|
||||
{
|
||||
ids = ids
|
||||
.Select(x => StringExtensions.EnsureEndsWith(x, ".ascx"))
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
foreach (var id in ids)
|
||||
{
|
||||
yield return Get(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var files = FindAllFiles("", "*.ascx");
|
||||
foreach (var file in files)
|
||||
{
|
||||
yield return Get(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all <see cref="UserControl"/> that exist at the relative path specified.
|
||||
/// </summary>
|
||||
/// <param name="rootPath">
|
||||
/// If null or not specified, will return the UserControl files at the root path relative to the IFileSystem
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<UserControl> GetUserControlsAtPath(string rootPath = null)
|
||||
{
|
||||
return FileSystem.GetFiles(rootPath ?? string.Empty, "*.ascx").Select(Get);
|
||||
}
|
||||
|
||||
private static readonly List<string> ValidExtensions = new List<string> { "ascx" };
|
||||
|
||||
public bool ValidateUserControl(UserControl userControl)
|
||||
{
|
||||
// get full path
|
||||
string fullPath;
|
||||
try
|
||||
{
|
||||
// may throw for security reasons
|
||||
fullPath = FileSystem.GetFullPath(userControl.Path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate path and extension
|
||||
var validDir = SystemDirectories.UserControls;
|
||||
var isValidPath = IOHelper.VerifyEditPath(fullPath, validDir);
|
||||
var isValidExtension = IOHelper.VerifyFileExtension(userControl.Path, ValidExtensions);
|
||||
return isValidPath && isValidExtension;
|
||||
}
|
||||
|
||||
public Stream GetFileContentStream(string filepath)
|
||||
{
|
||||
if (FileSystem.FileExists(filepath) == false) return null;
|
||||
|
||||
try
|
||||
{
|
||||
return FileSystem.OpenFile(filepath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null; // deal with race conds
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFileContent(string filepath, Stream content)
|
||||
{
|
||||
FileSystem.AddFile(filepath, content, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,6 +248,18 @@ namespace Umbraco.Core.Persistence
|
||||
return new PartialViewMacroRepository(uow, FileSystemProviderManager.Current.MacroPartialsFileSystem);
|
||||
}
|
||||
|
||||
[Obsolete("MacroScripts are obsolete - this is for backwards compatibility with upgraded sites.")]
|
||||
internal virtual IPartialViewRepository CreateMacroScriptRepository(IUnitOfWork uow)
|
||||
{
|
||||
return new MacroScriptRepository(uow, FileSystemProviderManager.Current.MacroScriptsFileSystem);
|
||||
}
|
||||
|
||||
[Obsolete("UserControls are obsolete - this is for backwards compatibility with upgraded sites.")]
|
||||
internal virtual IUserControlRepository CreateUserControlRepository(IUnitOfWork uow)
|
||||
{
|
||||
return new UserControlRepository(uow, FileSystemProviderManager.Current.UserControlsFileSystem);
|
||||
}
|
||||
|
||||
public virtual IStylesheetRepository CreateStylesheetRepository(IUnitOfWork uow)
|
||||
{
|
||||
return new StylesheetRepository(uow, FileSystemProviderManager.Current.StylesheetsFileSystem);
|
||||
|
||||
@@ -621,6 +621,34 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetMacroScriptFileContentStream(string filepath)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMacroScriptRepository(uow);
|
||||
return repository.GetFileContentStream(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMacroScriptFileContent(string filepath, Stream content)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMacroScriptRepository(uow);
|
||||
repository.SetFileContent(filepath, content);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetMacroScriptFileSize(string filepath)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMacroScriptRepository(uow);
|
||||
return repository.GetFileSize(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Stream GetStylesheetFileContentStream(string filepath)
|
||||
@@ -679,6 +707,34 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetUserControlFileContentStream(string filepath)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateUserControlRepository(uow);
|
||||
return repository.GetFileContentStream(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUserControlFileContent(string filepath, Stream content)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateUserControlRepository(uow);
|
||||
repository.SetFileContent(filepath, content);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetUserControlFileSize(string filepath)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateUserControlRepository(uow);
|
||||
return repository.GetFileSize(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetXsltFileContentStream(string filepath)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
@@ -783,6 +839,26 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("MacroScripts are obsolete - this is for backwards compatibility with upgraded sites.")]
|
||||
public IPartialView GetMacroScript(string path)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMacroScriptRepository(uow);
|
||||
return repository.Get(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("UserControls are obsolete - this is for backwards compatibility with upgraded sites.")]
|
||||
public IUserControl GetUserControl(string path)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateUserControlRepository(uow);
|
||||
return repository.Get(path);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IPartialView> GetPartialViewMacros(params string[] names)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
|
||||
@@ -17,6 +17,10 @@ namespace Umbraco.Core.Services
|
||||
void DeletePartialViewMacroFolder(string folderPath);
|
||||
IPartialView GetPartialView(string path);
|
||||
IPartialView GetPartialViewMacro(string path);
|
||||
[Obsolete("MacroScripts are obsolete - this is for backwards compatibility with upgraded sites.")]
|
||||
IPartialView GetMacroScript(string path);
|
||||
[Obsolete("UserControls are obsolete - this is for backwards compatibility with upgraded sites.")]
|
||||
IUserControl GetUserControl(string path);
|
||||
IEnumerable<IPartialView> GetPartialViewMacros(params string[] names);
|
||||
IXsltFile GetXsltFile(string path);
|
||||
IEnumerable<IXsltFile> GetXsltFiles(params string[] names);
|
||||
@@ -263,6 +267,27 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>The size of the template.</returns>
|
||||
long GetTemplateFileSize(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of a macroscript as a stream.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the macroscript.</param>
|
||||
/// <returns>The content of the macroscript.</returns>
|
||||
Stream GetMacroScriptFileContentStream(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the content of a macroscript.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the macroscript.</param>
|
||||
/// <param name="content">The content of the macroscript.</param>
|
||||
void SetMacroScriptFileContent(string filepath, Stream content);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of a macroscript.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the macroscript.</param>
|
||||
/// <returns>The size of the macroscript.</returns>
|
||||
long GetMacroScriptFileSize(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of a stylesheet as a stream.
|
||||
/// </summary>
|
||||
@@ -305,6 +330,27 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>The size of the script file.</returns>
|
||||
long GetScriptFileSize(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of a usercontrol as a stream.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the usercontrol.</param>
|
||||
/// <returns>The content of the usercontrol.</returns>
|
||||
Stream GetUserControlFileContentStream(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the content of a usercontrol.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the usercontrol.</param>
|
||||
/// <param name="content">The content of the usercontrol.</param>
|
||||
void SetUserControlFileContent(string filepath, Stream content);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of a usercontrol.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the usercontrol.</param>
|
||||
/// <returns>The size of the usercontrol.</returns>
|
||||
long GetUserControlFileSize(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of a XSLT file as a stream.
|
||||
/// </summary>
|
||||
|
||||
@@ -73,6 +73,10 @@ namespace Umbraco.Core
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string AnyString = "any-string"; // that one is for tests
|
||||
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Language = "language";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string MacroScript = "macroscript";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string MediaFile = "media-file";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
@@ -86,9 +90,9 @@ namespace Umbraco.Core
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string PartialViewMacro = "partial-view-macro";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Xslt = "xslt";
|
||||
public const string UserControl = "usercontrol";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Language = "language";
|
||||
public const string Xslt = "xslt";
|
||||
|
||||
public static string FromUmbracoObjectType(UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
|
||||
@@ -190,6 +190,17 @@ namespace Umbraco.Core
|
||||
return new GuidUdi(Constants.UdiEntityType.Macro, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity.</param>
|
||||
/// <returns>The entity identifier of the entity.</returns>
|
||||
public static StringUdi GetUdi(this IUserControl entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new StringUdi(Constants.UdiEntityType.UserControl, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity identifier of the entity.
|
||||
/// </summary>
|
||||
|
||||
@@ -344,7 +344,9 @@
|
||||
<Compile Include="HashCodeHelper.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
|
||||
<Compile Include="Models\IUserControl.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentTypeConverter.cs" />
|
||||
<Compile Include="Models\UserControl.cs" />
|
||||
<Compile Include="OrderedHashSet.cs" />
|
||||
<Compile Include="Events\UninstallPackageEventArgs.cs" />
|
||||
<Compile Include="Models\GridValue.cs" />
|
||||
@@ -578,12 +580,15 @@
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IRedirectUrlRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IServerRegistrationRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IDeleteMediaFilesRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IUserControlRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IXsltFileRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\ITaskRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\ITaskTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\MacroScriptRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\MigrationEntryRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\PublicAccessRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\RedirectUrlRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\UserControlRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\XsltFileRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskTypeRepository.cs" />
|
||||
|
||||
@@ -269,12 +269,12 @@
|
||||
var isSelected = false;
|
||||
for (var i = 0; selection.length > i; i++) {
|
||||
var selectedItem = selection[i];
|
||||
if (item.id === selectedItem.id) {
|
||||
if (item.id === selectedItem.id || item.key === selectedItem.key) {
|
||||
isSelected = true;
|
||||
}
|
||||
}
|
||||
if (!isSelected) {
|
||||
selection.push({ id: item.id });
|
||||
selection.push({ id: item.id, key: item.key });
|
||||
item.selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,35 @@
|
||||
angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseController", function($scope, $http, installerService){
|
||||
|
||||
$scope.checking = false;
|
||||
$scope.invalidDbDns = false;
|
||||
|
||||
$scope.dbs = [
|
||||
{name: 'Microsoft SQL Server Compact (SQL CE)', id: 0},
|
||||
{name: 'Microsoft SQL Server', id: 1},
|
||||
{ name: 'Microsoft SQL Azure', id: 3 },
|
||||
{ name: 'MySQL', id: 2 },
|
||||
{name: 'Custom connection string', id: -1}];
|
||||
{ name: 'Microsoft SQL Server Compact (SQL CE)', id: 0},
|
||||
{ name: 'Microsoft SQL Server', id: 1},
|
||||
{ name: 'Microsoft SQL Azure', id: 3 },
|
||||
{ name: 'MySQL', id: 2 },
|
||||
{ name: 'Custom connection string', id: -1}
|
||||
];
|
||||
|
||||
if(installerService.status.current.model.dbType === undefined){
|
||||
if ( installerService.status.current.model.dbType === undefined ) {
|
||||
installerService.status.current.model.dbType = 0;
|
||||
}
|
||||
|
||||
$scope.validateAndForward = function(){
|
||||
if(!$scope.checking && this.myForm.$valid){
|
||||
$scope.validateAndForward = function(){
|
||||
if ( !$scope.checking && this.myForm.$valid ) {
|
||||
$scope.checking = true;
|
||||
$scope.invalidDbDns = false;
|
||||
|
||||
var model = installerService.status.current.model;
|
||||
|
||||
$http.post(Umbraco.Sys.ServerVariables.installApiBaseUrl + "PostValidateDatabaseConnection",
|
||||
model).then(function(response){
|
||||
$http.post(
|
||||
Umbraco.Sys.ServerVariables.installApiBaseUrl + "PostValidateDatabaseConnection",
|
||||
model ).then( function( response ) {
|
||||
|
||||
if(response.data === "true"){
|
||||
if ( response.data === "true" ) {
|
||||
installerService.forward();
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
$scope.invalidDbDns = true;
|
||||
}
|
||||
|
||||
@@ -33,4 +40,4 @@ angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseControll
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
<div ng-controller="Umbraco.Installer.PackagesController" id="starterKits">
|
||||
<h1>Would you like to learn or demo Umbraco?</h1>
|
||||
<h1>Install a starter website</h1>
|
||||
|
||||
<p>
|
||||
Installing a starter website helps you learn how Umbraco works, and gives you a solid
|
||||
and simple foundation to build on top of.
|
||||
</p>
|
||||
|
||||
<small ng-if="!packages || packages.length == 0">Loading...</small>
|
||||
|
||||
<ul class="thumbnails">
|
||||
<li class="span3" ng-repeat="pck in packages">
|
||||
<a href ng-click="setPackageAndContinue(pck.id)" class="thumbnail">
|
||||
<small>Loading...</small>
|
||||
<img ng-src="http://our.umbraco.org{{pck.thumbnail}}?width=170" alt="{{pck.name}}">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<span style="float: left; margin: 0 15px 50px 0; background-color: #efefef; width: 350px; height: 167px;"><img ng-src="http://our.umbraco.org{{packages[0].thumbnail}}?width=350" style="width: 350px;" alt="{{pck.name}}" /></span>
|
||||
<p>The Starter Kit is a great way to experience some of the ways you can use Umbraco. It's a complete website with textpages, landing pages, blog, product listings and more that's easy to get started with Umbraco.
|
||||
</p>
|
||||
<p>
|
||||
It's also a great way to learn Umbraco as the Starter Kit comes with a set of Lessons that'll teach you how to implement and extend Umbraco using short 5-15 minute tasks.
|
||||
</p>
|
||||
<p>
|
||||
<a href ng-click="setPackageAndContinue(packages[0].id)" class="btn btn-success">Yes, I'd like a Starter Kit</a>
|
||||
|
||||
<a href ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')" class="btn btn-link btn-link-reverse">
|
||||
No thanks
|
||||
No thanks, I do not want to install a starter website
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,8 +66,9 @@ label.control-label, .control-label {
|
||||
}
|
||||
.form-search .icon, .form-search .icon-search {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 6px;
|
||||
left: 4px;
|
||||
left: 6px;
|
||||
color: @gray-8;
|
||||
}
|
||||
|
||||
@@ -86,6 +87,9 @@ label.control-label, .control-label {
|
||||
background: @white
|
||||
}
|
||||
|
||||
.form-search .icon-search + .search-input {
|
||||
padding-left: 25px !important;
|
||||
}
|
||||
|
||||
.form-search .search-input {
|
||||
font-weight: bold;
|
||||
@@ -191,7 +195,7 @@ input[type="tel"],
|
||||
input[type="color"],
|
||||
.uneditable-input {
|
||||
display: inline-block;
|
||||
height: 30px;
|
||||
height: @inputHeight;
|
||||
padding: 4px 6px;
|
||||
margin-bottom: @baseLineHeight / 2;
|
||||
font-size: @baseFontSize;
|
||||
@@ -206,7 +210,6 @@ input.-full-width-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 6px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
// Reset appearance properties for textual inputs and textarea
|
||||
@@ -579,9 +582,9 @@ input[type="checkbox"][readonly] {
|
||||
.add-on {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
height: @baseLineHeight;
|
||||
min-width: 16px;
|
||||
padding: 4px 5px;
|
||||
height: 22px;
|
||||
min-width: 18px;
|
||||
padding: 4px 6px;
|
||||
font-size: @baseFontSize;
|
||||
font-weight: normal;
|
||||
line-height: @baseLineHeight;
|
||||
@@ -653,29 +656,21 @@ input.search-query {
|
||||
padding-left: 14px;
|
||||
padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */
|
||||
margin: 0; // Remove the default margin on all inputs
|
||||
.border-radius(0px);
|
||||
}
|
||||
|
||||
/* Allow for input prepend/append in search forms */
|
||||
.form-search .input-append .search-query,
|
||||
.form-search .input-prepend .search-query {
|
||||
.border-radius(0); // Override due to specificity
|
||||
.form-search {
|
||||
.input-prepend {
|
||||
.btn {
|
||||
.border-radius(0 @borderRadiusSmall @borderRadiusSmall 0);
|
||||
}
|
||||
}
|
||||
.input-append {
|
||||
.btn {
|
||||
.border-radius(0 @borderRadiusSmall @borderRadiusSmall 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-search .input-append .search-query {
|
||||
.border-radius(14px 0 0 14px);
|
||||
}
|
||||
.form-search .input-append .btn {
|
||||
.border-radius(0 14px 14px 0);
|
||||
}
|
||||
.form-search .input-prepend .search-query {
|
||||
.border-radius(0 14px 14px 0);
|
||||
}
|
||||
.form-search .input-prepend .btn {
|
||||
.border-radius(14px 0 0 14px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// HORIZONTAL & VERTICAL FORMS
|
||||
// ---------------------------
|
||||
|
||||
@@ -47,10 +47,25 @@ h5.-black {
|
||||
background: none;
|
||||
border: none
|
||||
}
|
||||
.datepicker td.active,
|
||||
.datepicker td span.active {
|
||||
background: @turquoise !important;
|
||||
.bootstrap-datetimepicker-widget {
|
||||
td {
|
||||
&.active, span.active {
|
||||
background: @turquoise !important;
|
||||
}
|
||||
&.today:not(.active):before {
|
||||
border-bottom-color: @purple-l1 !important;
|
||||
}
|
||||
a[data-action] {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.timepicker-hour,
|
||||
.timepicker-minute,
|
||||
.timepicker-second {
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.umb-datetime-picker div.info {
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
@@ -446,8 +446,8 @@ input.umb-panel-header-name-input {
|
||||
margin-bottom: 0;
|
||||
font-weight: bold;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
width: 100%;
|
||||
&:hover {
|
||||
background: @white;
|
||||
|
||||
@@ -7,7 +7,7 @@ ul.sections {
|
||||
background: @purple;
|
||||
height: 100%;
|
||||
width: 80px;
|
||||
border-right: 1px solid @purple;
|
||||
border-right: 1px solid @purple-d1;
|
||||
}
|
||||
|
||||
ul.sections li {
|
||||
@@ -22,13 +22,16 @@ ul.sections li [class^="icon-"],
|
||||
ul.sections li [class*=" icon-"],
|
||||
ul.sections li img.icon-section {
|
||||
font-size: 30px;
|
||||
line-height: 20px; /* set line-height to ensure all icons use same line-height */
|
||||
display: inline-block;
|
||||
margin: 1px 0 0 0;
|
||||
color: @purple-l2;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
|
||||
&, &:before {
|
||||
line-height: 20px !important; /* set line-height to ensure all icons use same line-height */
|
||||
}
|
||||
}
|
||||
|
||||
ul.sections:hover li [class^="icon-"],
|
||||
@@ -168,7 +171,7 @@ ul.sections-tray {
|
||||
width: 80px;
|
||||
|
||||
& > li:first-child > a {
|
||||
border-top: 1px solid @purple;
|
||||
border-top: 1px solid @purple-d1;
|
||||
}
|
||||
|
||||
& > li {
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
@inputBorderRadius: 0;
|
||||
@inputDisabledBackground: @gray-10;
|
||||
@formActionsBackground: @gray-9;
|
||||
@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border
|
||||
@inputHeight: @baseLineHeight + 12px; // base line-height + 8px vertical padding + 2px top/bottom border
|
||||
@controlRequiredColor: @red;
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<div class="umb-panel">
|
||||
<div class="umb-panel-body no-header with-footer">
|
||||
<umb-pane>
|
||||
<umb-control-group label="Url">
|
||||
<umb-control-group label="@general_url">
|
||||
<input id="url" class="umb-editor input-block-level" type="text" ng-model="form.url" ng-keyup="$event.keyCode == 13 ? showPreview() : null" required />
|
||||
<input type="button" ng-click="showPreview()" class="btn" value="Retrieve" />
|
||||
<input type="button" ng-click="showPreview()" class="btn" localize="value" value="@general_retrieve" />
|
||||
</umb-control-group>
|
||||
|
||||
<div ng-show="form.supportsDimensions">
|
||||
<umb-control-group label="Size">
|
||||
<umb-control-group label="@general_size">
|
||||
<input type="text" ng-model="form.width" on-blur="changeSize('width')" style="width:50px"/> x <input type="text" ng-model="form.height" on-blur="changeSize('height')" style="width:50px"/>
|
||||
|
||||
<label for="constrain" style="display:inline"><localize key="general_constrain">Constrain</localize>:</label>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<form ng-controller="Umbraco.Overlays.EmbedOverlay as vm">
|
||||
|
||||
<umb-control-group label="Url">
|
||||
<umb-control-group label="@general_url">
|
||||
<input id="url" class="umb-editor input-block-level" type="text" style="margin-bottom: 10px;" ng-model="model.embed.url" ng-keyup="$event.keyCode == 13 ? vm.showPreview() : null" required />
|
||||
<input type="button" ng-click="vm.showPreview()" class="btn" value="Retrieve" />
|
||||
<input type="button" ng-click="vm.showPreview()" class="btn" localize="value" value="@general_retrieve" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group>
|
||||
@@ -11,15 +11,15 @@
|
||||
</umb-control-group>
|
||||
|
||||
<div ng-show="model.embed.supportsDimensions">
|
||||
<umb-control-group label="Width">
|
||||
<umb-control-group label="@general_width">
|
||||
<input type="text" ng-model="model.embed.width" on-blur="vm.changeSize('width')" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="Height">
|
||||
<umb-control-group label="@general_height">
|
||||
<input type="text" ng-model="model.embed.height" on-blur="vm.changeSize('height')" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="Constrain:">
|
||||
<umb-control-group label="@general_constrain">
|
||||
<input id="constrain" type="checkbox" ng-model="model.embed.constrain" />
|
||||
</umb-control-group>
|
||||
</div>
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
<div class="upload-button">
|
||||
<umb-button
|
||||
type="button"
|
||||
key="general_upload"
|
||||
label="Upload"
|
||||
label-key="general_upload"
|
||||
action="upload()"
|
||||
disabled="disabled">
|
||||
</umb-button>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" >
|
||||
<button type="button" class="btn btn-info" ng-click="nav.hideDialog()">
|
||||
<button type="button" class="btn btn-info" ng-click="nav.hideDialog(true)">
|
||||
<localize key="buttons_somethingElse">Do something else</localize>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
ng-model="renderModel">
|
||||
<li ng-repeat="node in renderModel">
|
||||
|
||||
<i class="icon icon-delete red hover-show pull-right" ng-click="remove($index)"></i>
|
||||
<i class="icon icon-delete red hover-show pull-right" style="cursor:pointer;" ng-click="remove($index); $event.stopPropagation();"></i>
|
||||
|
||||
<i class="icon {{node.icon}} hover-hide"></i>
|
||||
<a href prevent-default ng-click="openContentPicker()" >{{node.name}}</a>
|
||||
|
||||
@@ -20,8 +20,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
|
||||
getListResultsCallback = contentResource.getPagedResults;
|
||||
deleteItemCallback = contentResource.deleteByKey;
|
||||
getIdCallback = function (selected) {
|
||||
var selectedKey = getItemKey(selected.id);
|
||||
return selectedKey;
|
||||
return selected.key;
|
||||
};
|
||||
createEditUrlCallback = function (item) {
|
||||
return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.key + "?page=" + $scope.options.pageNumber + "&listName=" + $scope.contentId;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
function textAreaController($rootScope, $scope, $log) {
|
||||
$scope.model.maxlength = false;
|
||||
if($scope.model.config.maxChars) {
|
||||
$scope.model.maxlength = true;
|
||||
if($scope.model.value == undefined) {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1);
|
||||
} else {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1) - $scope.model.value.length;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.model.change = function() {
|
||||
if($scope.model.config.maxChars) {
|
||||
if($scope.model.value == undefined) {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1);
|
||||
} else {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1) - $scope.model.value.length;
|
||||
}
|
||||
if($scope.model.count < 0) {
|
||||
$scope.model.value = $scope.model.value.substring(0, ($scope.model.config.maxChars * 1));
|
||||
$scope.model.count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.textAreaController", textAreaController);
|
||||
@@ -1,3 +1,9 @@
|
||||
<textarea ng-model="model.value" id="{{model.alias}}" name="textarea" rows="10" class="umb-editor umb-textarea textstring" val-server="value" ng-required="model.validation.mandatory"></textarea>
|
||||
<span class="help-inline" val-msg-for="textarea" val-toggle-msg="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" val-msg-for="textarea" val-toggle-msg="valServer"></span>
|
||||
<div ng-controller="Umbraco.PropertyEditors.textAreaController">
|
||||
<textarea ng-model="model.value" id="{{model.alias}}" name="textarea" rows="10" class="umb-editor umb-textarea textstring" val-server="value" ng-keyup="model.change()"></textarea>
|
||||
<span class="help-inline" val-msg-for="textarea" val-toggle-msg="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" val-msg-for="textarea" val-toggle-msg="valServer"></span>
|
||||
<div class="help" ng-if="model.maxlength">
|
||||
<strong>{{model.count}}</strong>
|
||||
<localize key="textbox_characters_left">characters left</localize>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
function textboxController($rootScope, $scope, $log) {
|
||||
$scope.model.maxlength = false;
|
||||
if($scope.model.config.maxChars) {
|
||||
$scope.model.maxlength = true;
|
||||
if($scope.model.value == undefined) {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1);
|
||||
} else {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1) - $scope.model.value.length;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.model.change = function() {
|
||||
if($scope.model.config.maxChars) {
|
||||
if($scope.model.value == undefined) {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1);
|
||||
} else {
|
||||
$scope.model.count = ($scope.model.config.maxChars * 1) - $scope.model.value.length;
|
||||
}
|
||||
if($scope.model.count < 0) {
|
||||
$scope.model.value = $scope.model.value.substring(0, ($scope.model.config.maxChars * 1));
|
||||
$scope.model.count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.textboxController", textboxController);
|
||||
@@ -1,9 +1,14 @@
|
||||
<div>
|
||||
<div ng-controller="Umbraco.PropertyEditors.textboxController">
|
||||
<input type="text" name="textbox" ng-model="model.value" id="{{model.alias}}"
|
||||
class="umb-editor umb-textstring textstring"
|
||||
val-server="value"
|
||||
ng-required="model.validation.mandatory"
|
||||
ng-trim="false" />
|
||||
ng-trim="false"
|
||||
ng-keyup="model.change()" />
|
||||
<span class="help-inline" val-msg-for="textbox" val-toggle-msg="valServer"></span>
|
||||
<span class="help-inline" val-msg-for="textbox" val-toggle-msg="required"><localize key="general_required">Required</localize></span>
|
||||
</div>
|
||||
<div class="help" ng-if="model.maxlength">
|
||||
<strong>{{model.count}}</strong>
|
||||
<localize key="textbox_characters_left">characters left</localize>
|
||||
</div>
|
||||
</div>
|
||||
@@ -568,6 +568,7 @@
|
||||
<Content Include="Config\Lang\zh-CN.user.xml" />
|
||||
<Content Include="Umbraco\Config\Lang\cs.xml" />
|
||||
<Content Include="Umbraco\ClientRedirect.aspx" />
|
||||
<Content Include="Umbraco\Config\Lang\tr.xml" />
|
||||
<Content Include="Umbraco\Config\Lang\zh_tw.xml" />
|
||||
<Content Include="Umbraco\create.aspx" />
|
||||
<Content Include="Umbraco\Developer\Packages\installer.aspx" />
|
||||
|
||||
@@ -1291,4 +1291,7 @@ Mange hilsner fra Umbraco robotten
|
||||
<key alias="enabledConfirm">URL tracker er nu slået fra.</key>
|
||||
<key alias="enableError">Der opstod en fejl under forsøget på at slå URL trackeren til, der findes mere information i logfilen.</key>
|
||||
</area>
|
||||
<area alias="textbox">
|
||||
<key alias="characters_left">Karakterer tilbage</key>
|
||||
</area>
|
||||
</language>
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
<key alias="rename">Rename</key>
|
||||
<key alias="renew">Renew</key>
|
||||
<key alias="required" version="7.0">Required</key>
|
||||
<key alias="retrieve">Retrieve</key>
|
||||
<key alias="retry">Retry</key>
|
||||
<key alias="rights">Permissions</key>
|
||||
<key alias="search">Search</key>
|
||||
@@ -1556,8 +1557,10 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="xmlDataIntegrityCheckMedia">Media - Total XML: %0%, Total: %1%, Total invalid: %2%</key>
|
||||
<key alias="xmlDataIntegrityCheckContent">Content - Total XML: %0%, Total published: %1%, Total invalid: %2%</key>
|
||||
|
||||
<key alias="httpsCheckValidCertificate">Your site certificate was marked as valid.</key>
|
||||
<key alias="httpsCheckValidCertificate">Your website's certificate is valid.</key>
|
||||
<key alias="httpsCheckInvalidCertificate">Certificate validation error: '%0%'</key>
|
||||
<key alias="httpsCheckExpiredCertificate">Your website's SSL certificate has expired.</key>
|
||||
<key alias="httpsCheckExpiringCertificate">Your website's SSL certificate is expiring in %0% days.</key>
|
||||
<key alias="httpsCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
|
||||
<key alias="httpsCheckIsCurrentSchemeHttps">You are currently %0% viewing the site using the HTTPS scheme.</key>
|
||||
<key alias="httpsCheckConfigurationRectifyNotPossible">The appSetting 'umbracoUseSSL' is set to 'false' in your web.config file. Once you access this site using the HTTPS scheme, that should be set to 'true'.</key>
|
||||
@@ -1637,4 +1640,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<area alias="emptyStates">
|
||||
<key alias="emptyDictionaryTree">No Dictionary items to choose from</key>
|
||||
</area>
|
||||
</language>
|
||||
<area alias="textbox">
|
||||
<key alias="characters_left">characters left</key>
|
||||
</area>
|
||||
</language>
|
||||
@@ -515,6 +515,7 @@
|
||||
<key alias="rename">Rename</key>
|
||||
<key alias="renew">Renew</key>
|
||||
<key alias="required" version="7.0">Required</key>
|
||||
<key alias="retrieve">Retrieve</key>
|
||||
<key alias="retry">Retry</key>
|
||||
<key alias="rights">Permissions</key>
|
||||
<key alias="search">Search</key>
|
||||
@@ -1543,8 +1544,10 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="xmlDataIntegrityCheckMedia">Media - Total XML: %0%, Total: %1%, Total invalid: %2%</key>
|
||||
<key alias="xmlDataIntegrityCheckContent">Content - Total XML: %0%, Total published: %1%, Total invalid: %2%</key>
|
||||
|
||||
<key alias="httpsCheckValidCertificate">Your site certificate was marked as valid.</key>
|
||||
<key alias="httpsCheckValidCertificate">Your website's certificate is valid.</key>
|
||||
<key alias="httpsCheckInvalidCertificate">Certificate validation error: '%0%'</key>
|
||||
<key alias="httpsCheckExpiredCertificate">Your website's SSL certificate has expired.</key>
|
||||
<key alias="httpsCheckExpiringCertificate">Your website's SSL certificate is expiring in %0% days.</key>
|
||||
<key alias="httpsCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
|
||||
<key alias="httpsCheckIsCurrentSchemeHttps">You are currently %0% viewing the site using the HTTPS scheme.</key>
|
||||
<key alias="httpsCheckConfigurationRectifyNotPossible">The appSetting 'umbracoUseSSL' is set to 'false' in your web.config file. Once you access this site using the HTTPS scheme, that should be set to 'true'.</key>
|
||||
@@ -1624,4 +1627,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<area alias="emptyStates">
|
||||
<key alias="emptyDictionaryTree">No Dictionary items to choose from</key>
|
||||
</area>
|
||||
<area alias="textbox">
|
||||
<key alias="characters_left">characters left</key>
|
||||
</area>
|
||||
</language>
|
||||
|
||||
@@ -356,7 +356,8 @@
|
||||
<key alias="theFriendliestCommunity">Самое дружелюбное сообщество</key>
|
||||
<key alias="linkToPage">Ссылка на страницу</key>
|
||||
<key alias="openInNewWindow">Открывать ссылку в новом окне или вкладке браузера</key>
|
||||
<key alias="linkToMedia">Ссылка на медиа-файл</key>
|
||||
<key alias="linkToMedia">Ссылка на медиа-элемент</key>
|
||||
<key alias="linkToFile">Ссылка на файл</key>
|
||||
<key alias="selectMedia">Выбрать медиа</key>
|
||||
<key alias="selectIcon">Выбрать значок</key>
|
||||
<key alias="selectItem">Выбрать элемент</key>
|
||||
@@ -366,7 +367,7 @@
|
||||
<key alias="selectMember">Выбрать участника</key>
|
||||
<key alias="selectMemberGroup">Выбрать группу участников</key>
|
||||
<key alias="noMacroParams">Это макрос без параметров</key>
|
||||
<key alias="noMacros">Нет макросов доступных для вставки в редактор</key>
|
||||
<key alias="noMacros">Нет макросов, доступных для вставки в редактор</key>
|
||||
<key alias="externalLoginProviders">Провайдеры аутентификации</key>
|
||||
<key alias="exceptionDetail">Подробное сообщение об ошибке</key>
|
||||
<key alias="stacktrace">Трассировка стека</key>
|
||||
@@ -487,6 +488,7 @@
|
||||
<key alias="closewindow">Закрыть окно</key>
|
||||
<key alias="comment">Примечание</key>
|
||||
<key alias="confirm">Подтвердить</key>
|
||||
<key alias="constrain">Сохранять пропорции</key>
|
||||
<key alias="constrainProportions">Сохранять пропорции</key>
|
||||
<key alias="continue">Далее</key>
|
||||
<key alias="copy">Копировать</key>
|
||||
@@ -554,6 +556,7 @@
|
||||
<key alias="rename">Переименовать</key>
|
||||
<key alias="renew">Обновить</key>
|
||||
<key alias="required" version="7.0">Обязательное</key>
|
||||
<key alias="retrieve">Получить</key>
|
||||
<key alias="retry">Повторить</key>
|
||||
<key alias="rights">Разрешения</key>
|
||||
<key alias="search">Поиск</key>
|
||||
@@ -571,7 +574,7 @@
|
||||
<key alias="update">Обновить</key>
|
||||
<key alias="upgrade">Обновление</key>
|
||||
<key alias="upload">Загрузить</key>
|
||||
<key alias="url">URL</key>
|
||||
<key alias="url">Интернет-ссылка</key>
|
||||
<key alias="user">Пользователь</key>
|
||||
<key alias="username">Имя пользователя</key>
|
||||
<key alias="value">Значение</key>
|
||||
@@ -990,7 +993,7 @@
|
||||
<key alias="dropHere">Перетащите сюда</key>
|
||||
<key alias="orClickHereToUpload">или нажмите здесь для выбора файла пакета</key>
|
||||
<key alias="uploadPackage">Загрузить пакет</key>
|
||||
<key alias="localPackageDescr">Установите локальный пакет из файла, расположенного на Вашем компьютере. Остерегайтесь устанавливать пакеты из непроверенных источников!</key>
|
||||
<key alias="localPackageDescription">Установите локальный пакет из файла, расположенного на Вашем компьютере. Остерегайтесь устанавливать пакеты из непроверенных источников!</key>
|
||||
<key alias="uploadAnother">Загрузить еще один пакет</key>
|
||||
<key alias="cancelAndUploadAnother">Отменить и загрузить другой пакет</key>
|
||||
<key alias="packageLicense">Лицензия</key>
|
||||
@@ -1422,12 +1425,15 @@
|
||||
</area>
|
||||
<area alias="templateEditor">
|
||||
<key alias="addFallbackField">Добавить поле замены</key>
|
||||
<key alias="fallbackField">Поле замены</key>
|
||||
<key alias="addDefaultValue">Добавить значение по-умолчанию</key>
|
||||
<key alias="defaultValue">Значение по-умолчанию</key>
|
||||
<key alias="alternativeField">Альтернативное поле</key>
|
||||
<key alias="alternativeText">Текст по-умолчанию</key>
|
||||
<key alias="casing">Регистр</key>
|
||||
<key alias="chooseField">Выбрать поле</key>
|
||||
<key alias="convertLineBreaks">Преобразовать переводы строк</key>
|
||||
<key alias="convertLineBreaksDescription">Да, преобразовывать</key>
|
||||
<key alias="convertLineBreaksHelp">Заменяет переводы строк на тэг html 'br'</key>
|
||||
<key alias="customFields">Пользовательские</key>
|
||||
<key alias="dateOnly">Только дата</key>
|
||||
@@ -1526,6 +1532,8 @@
|
||||
<key alias="documentTypes">Типы документов</key>
|
||||
<key alias="packager">Пакеты дополнений</key>
|
||||
<key alias="packages">Пакеты дополнений</key>
|
||||
<key alias="partialViews">Частичные представления</key>
|
||||
<key alias="partialViewMacros">Файлы макросов</key>
|
||||
<key alias="python">Скрипты Python</key>
|
||||
<key alias="relationTypes">Типы связей</key>
|
||||
<key alias="repositories">Установить из репозитория</key>
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Umbraco.Web.Cache
|
||||
}
|
||||
|
||||
TagsValueConverter.ClearCaches();
|
||||
MultipleMediaPickerPropertyConverter.ClearCaches();
|
||||
LegacyMediaPickerPropertyConverter.ClearCaches();
|
||||
SliderValueConverter.ClearCaches();
|
||||
MediaPickerPropertyConverter.ClearCaches();
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Web.Editors
|
||||
basic.Description = TranslateItem(basic.Description);
|
||||
}
|
||||
|
||||
return basics;
|
||||
return basics.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Web;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -53,7 +54,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
|
||||
private HealthCheckStatus CheckForValidCertificate()
|
||||
{
|
||||
var message = string.Empty;
|
||||
var success = false;
|
||||
StatusResultType result;
|
||||
var url = HealthCheckContext.HttpContext.Request.Url;
|
||||
|
||||
// Attempt to access the site over HTTPS to see if it HTTPS is supported
|
||||
@@ -65,7 +66,37 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
|
||||
try
|
||||
{
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
success = response.StatusCode == HttpStatusCode.OK;
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
// Got a valid response, check now for if certificate expiring within 14 days
|
||||
// Hat-tip: https://stackoverflow.com/a/15343898/489433
|
||||
const int NumberOfDaysForExpiryWarning = 14;
|
||||
var cert = request.ServicePoint.Certificate;
|
||||
var cert2 = new X509Certificate2(cert);
|
||||
var expirationDate = cert2.NotAfter;
|
||||
|
||||
var daysToExpiry = (int)Math.Floor((cert2.NotAfter - DateTime.Now).TotalDays);
|
||||
if (daysToExpiry <= 0)
|
||||
{
|
||||
result = StatusResultType.Error;
|
||||
message = _textService.Localize("healthcheck/httpsCheckExpiredCertificate");
|
||||
}
|
||||
else if (daysToExpiry < NumberOfDaysForExpiryWarning)
|
||||
{
|
||||
result = StatusResultType.Warning;
|
||||
message = _textService.Localize("healthcheck/httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() });
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StatusResultType.Success;
|
||||
message = _textService.Localize("healthcheck/httpsCheckValidCertificate");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StatusResultType.Error;
|
||||
message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { address, response.StatusDescription });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -80,17 +111,16 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
|
||||
{
|
||||
message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { address, ex.Message });
|
||||
}
|
||||
|
||||
result = StatusResultType.Error;
|
||||
}
|
||||
|
||||
var actions = new List<HealthCheckAction>();
|
||||
|
||||
if (success)
|
||||
message = _textService.Localize("healthcheck/httpsCheckValidCertificate");
|
||||
|
||||
return
|
||||
new HealthCheckStatus(message)
|
||||
{
|
||||
ResultType = success ? StatusResultType.Success : StatusResultType.Error,
|
||||
ResultType = result,
|
||||
Actions = actions
|
||||
};
|
||||
}
|
||||
|
||||
@@ -165,12 +165,20 @@ namespace Umbraco.Web.Models.Mapping
|
||||
var listViewTab = new Tab<ContentPropertyDisplay>();
|
||||
listViewTab.Alias = Constants.Conventions.PropertyGroups.ListViewGroupName;
|
||||
listViewTab.Label = localizedTextService.Localize("content/childItems");
|
||||
listViewTab.Id = 25;
|
||||
listViewTab.Id = display.Tabs.Count() + 1;
|
||||
listViewTab.IsActive = true;
|
||||
|
||||
var listViewConfig = editor.PreValueEditor.ConvertDbToEditor(editor.DefaultPreValues, preVals);
|
||||
//add the entity type to the config
|
||||
listViewConfig["entityType"] = entityType;
|
||||
listViewConfig["entityType"] = entityType;
|
||||
|
||||
//Override Tab Label if tabName is provided
|
||||
if (listViewConfig.ContainsKey("tabName"))
|
||||
{
|
||||
var configTabName = listViewConfig["tabName"];
|
||||
if (configTabName != null && string.IsNullOrWhiteSpace(configTabName.ToString()) == false)
|
||||
listViewTab.Label = configTabName.ToString();
|
||||
}
|
||||
|
||||
var listViewProperties = new List<ContentPropertyDisplay>();
|
||||
listViewProperties.Add(new ContentPropertyDisplay
|
||||
|
||||
@@ -50,7 +50,10 @@ namespace Umbraco.Web.PropertyEditors
|
||||
}
|
||||
|
||||
internal class ListViewPreValueEditor : PreValueEditor
|
||||
{
|
||||
{
|
||||
[PreValueField("tabName", "Tab Name", "textstring", Description = "The name of the listview tab (default if empty: 'Child Items')")]
|
||||
public int TabName { get; set; }
|
||||
|
||||
[PreValueField("displayAtTabNumber", "Display At Tab Number", "number", Description = "Which tab position that the list of child items will be displayed")]
|
||||
public int DisplayAtTabNumber { get; set; }
|
||||
|
||||
|
||||
@@ -6,5 +6,15 @@ namespace Umbraco.Web.PropertyEditors
|
||||
[PropertyEditor(Constants.PropertyEditors.TextboxMultipleAlias, "Textarea", "textarea", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.Text, Icon="icon-application-window-alt")]
|
||||
public class TextAreaPropertyEditor : PropertyEditor
|
||||
{
|
||||
protected override PreValueEditor CreatePreValueEditor()
|
||||
{
|
||||
return new TextAreaPreValueEditor();
|
||||
}
|
||||
|
||||
internal class TextAreaPreValueEditor : PreValueEditor
|
||||
{
|
||||
[PreValueField("maxChars", "Maximum allowed characters", "number", Description = "If empty - no character limit")]
|
||||
public bool MaxChars { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,19 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[PropertyEditor(Constants.PropertyEditors.TextboxAlias, "Textbox", "textbox", IsParameterEditor = true, Group = "Common")]
|
||||
public class TextboxPropertyEditor : PropertyEditor
|
||||
{
|
||||
{
|
||||
|
||||
|
||||
protected override PreValueEditor CreatePreValueEditor()
|
||||
{
|
||||
return new TextboxPreValueEditor();
|
||||
}
|
||||
|
||||
internal class TextboxPreValueEditor : PreValueEditor
|
||||
{
|
||||
[PreValueField("maxChars", "Maximum allowed characters", "number", Description = "If empty - no character limit")]
|
||||
public bool MaxChars { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+12
-6
@@ -1,5 +1,5 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="MultipleMediaPickerPropertyConverter.cs" company="Umbraco">
|
||||
// <copyright file="LegacyMediaPickerPropertyConverter.cs" company="Umbraco">
|
||||
// Umbraco
|
||||
// </copyright>
|
||||
// <summary>
|
||||
@@ -24,20 +24,20 @@ using Umbraco.Core.Services;
|
||||
namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// The multiple media picker property value converter.
|
||||
/// The multiple media picker and double legacy media picker property value converter, should be deleted for v8
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter(typeof(MustBeStringValueConverter))]
|
||||
public class MultipleMediaPickerPropertyConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
|
||||
public class LegacyMediaPickerPropertyConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
|
||||
{
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
|
||||
//TODO: Remove this ctor in v8 since the other one will use IoC
|
||||
public MultipleMediaPickerPropertyConverter()
|
||||
public LegacyMediaPickerPropertyConverter()
|
||||
: this(ApplicationContext.Current.Services.DataTypeService)
|
||||
{
|
||||
}
|
||||
|
||||
public MultipleMediaPickerPropertyConverter(IDataTypeService dataTypeService)
|
||||
public LegacyMediaPickerPropertyConverter(IDataTypeService dataTypeService)
|
||||
{
|
||||
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
|
||||
_dataTypeService = dataTypeService;
|
||||
@@ -58,6 +58,12 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
{
|
||||
return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.MultipleMediaPickerAlias);
|
||||
}
|
||||
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
|
||||
{
|
||||
// this is the double legacy media picker, it can pick only single media items
|
||||
return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.MediaPickerAlias);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,7 +115,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
ApplicationContext.Current.Services.DataTypeService.GetDataTypeDefinitionById(
|
||||
propertyType.DataTypeId).Name);
|
||||
|
||||
LogHelper.Warn<MultipleMediaPickerPropertyConverter>(error);
|
||||
LogHelper.Warn<LegacyMediaPickerPropertyConverter>(error);
|
||||
throw new Exception(error);
|
||||
}
|
||||
}
|
||||
@@ -126,10 +126,6 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
if (propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.MediaPicker2Alias))
|
||||
return true;
|
||||
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
|
||||
{
|
||||
return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.MediaPickerAlias);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -640,14 +640,10 @@ namespace Umbraco.Web
|
||||
private static bool IsDocumentTypeRecursive(IPublishedContent content, string docTypeAlias)
|
||||
{
|
||||
var contentTypeService = UmbracoContext.Current.Application.Services.ContentTypeService;
|
||||
var type = contentTypeService.GetContentType(content.DocumentTypeAlias);
|
||||
while (type != null && type.ParentId > 0)
|
||||
{
|
||||
type = contentTypeService.GetContentType(type.ParentId);
|
||||
if (type.Alias.InvariantEquals(docTypeAlias))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
var type = contentTypeService.GetContentType(content.DocumentTypeAlias);
|
||||
if (type.Alias.InvariantEquals(docTypeAlias) || content.IsComposedOf(docTypeAlias))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsNull(this IPublishedContent content, string alias, bool recurse)
|
||||
@@ -918,14 +914,14 @@ namespace Umbraco.Web
|
||||
|
||||
#region Axes: ancestors, ancestors-or-self
|
||||
|
||||
// as per XPath 1.0 specs §2.2,
|
||||
// as per XPath 1.0 specs §2.2,
|
||||
// - the ancestor axis contains the ancestors of the context node; the ancestors of the context node consist
|
||||
// of the parent of context node and the parent's parent and so on; thus, the ancestor axis will always
|
||||
// include the root node, unless the context node is the root node.
|
||||
// - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus,
|
||||
// the ancestor axis will always include the root node.
|
||||
//
|
||||
// as per XPath 2.0 specs §3.2.1.1,
|
||||
// as per XPath 2.0 specs §3.2.1.1,
|
||||
// - the ancestor axis is defined as the transitive closure of the parent axis; it contains the ancestors
|
||||
// of the context node (the parent, the parent of the parent, and so on) - The ancestor axis includes the
|
||||
// root node of the tree in which the context node is found, unless the context node is the root node.
|
||||
@@ -935,7 +931,7 @@ namespace Umbraco.Web
|
||||
// the ancestor and ancestor-or-self axis are reverse axes ie they contain the context node or nodes that
|
||||
// are before the context node in document order.
|
||||
//
|
||||
// document order is defined by §2.4.1 as:
|
||||
// document order is defined by §2.4.1 as:
|
||||
// - the root node is the first node.
|
||||
// - every node occurs before all of its children and descendants.
|
||||
// - the relative order of siblings is the order in which they occur in the children property of their parent node.
|
||||
@@ -1246,12 +1242,12 @@ namespace Umbraco.Web
|
||||
}
|
||||
|
||||
|
||||
// as per XPath 1.0 specs §2.2,
|
||||
// as per XPath 1.0 specs §2.2,
|
||||
// - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus
|
||||
// the descendant axis never contains attribute or namespace nodes.
|
||||
// - the descendant-or-self axis contains the context node and the descendants of the context node.
|
||||
//
|
||||
// as per XPath 2.0 specs §3.2.1.1,
|
||||
// as per XPath 2.0 specs §3.2.1.1,
|
||||
// - the descendant axis is defined as the transitive closure of the child axis; it contains the descendants of the context node (the
|
||||
// children, the children of the children, and so on).
|
||||
// - the descendant-or-self axis contains the context node and the descendants of the context node.
|
||||
@@ -1259,7 +1255,7 @@ namespace Umbraco.Web
|
||||
// the descendant and descendant-or-self axis are forward axes ie they contain the context node or nodes that are after the context
|
||||
// node in document order.
|
||||
//
|
||||
// document order is defined by §2.4.1 as:
|
||||
// document order is defined by §2.4.1 as:
|
||||
// - the root node is the first node.
|
||||
// - every node occurs before all of its children and descendants.
|
||||
// - the relative order of siblings is the order in which they occur in the children property of their parent node.
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
public abstract class FileSystemTreeController : TreeController
|
||||
{
|
||||
protected abstract IFileSystem2 FileSystem { get; }
|
||||
protected abstract string[] Extensions { get; }
|
||||
protected abstract string FileIcon { get; }
|
||||
protected abstract string FilePath { get; }
|
||||
protected abstract string FileSearchPattern { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Inheritors can override this method to modify the file node that is created.
|
||||
@@ -31,43 +28,67 @@ namespace Umbraco.Web.Trees
|
||||
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
|
||||
? HttpUtility.UrlDecode(id).TrimStart("/")
|
||||
: "";
|
||||
var orgPath = "";
|
||||
string path;
|
||||
if (string.IsNullOrEmpty(id) == false && id != "-1")
|
||||
{
|
||||
orgPath = id;
|
||||
path = IOHelper.MapPath(FilePath + "/" + orgPath);
|
||||
orgPath += "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = IOHelper.MapPath(FilePath);
|
||||
}
|
||||
|
||||
var directories = FileSystem.GetDirectories(path);
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
var dirInfos = dirInfo.GetDirectories();
|
||||
|
||||
var nodes = new TreeNodeCollection();
|
||||
foreach (var directory in directories)
|
||||
foreach (var dir in dirInfos)
|
||||
{
|
||||
var hasChildren = FileSystem.GetFiles(directory).Any() || FileSystem.GetDirectories(directory).Any();
|
||||
if ((dir.Attributes & FileAttributes.Hidden) != 0)
|
||||
continue;
|
||||
|
||||
var hasChildren = dir.GetFiles().Length > 0 || dir.GetDirectories().Length > 0;
|
||||
var node = CreateTreeNode(orgPath + dir.Name, orgPath, queryStrings, dir.Name, "icon-folder", hasChildren);
|
||||
|
||||
var name = Path.GetFileName(directory);
|
||||
var node = CreateTreeNode(HttpUtility.UrlEncode(directory), path, queryStrings, name, "icon-folder", hasChildren);
|
||||
OnRenderFolderNode(ref node);
|
||||
if(node != null)
|
||||
if (node != null)
|
||||
nodes.Add(node);
|
||||
}
|
||||
|
||||
//this is a hack to enable file system tree to support multiple file extension look-up
|
||||
//so the pattern both support *.* *.xml and xml,js,vb for lookups
|
||||
var files = FileSystem.GetFiles(path).Where(x =>
|
||||
{
|
||||
var extension = Path.GetExtension(x);
|
||||
return extension != null && Extensions.Contains(extension.Trim('.'), StringComparer.InvariantCultureIgnoreCase);
|
||||
});
|
||||
var allowedExtensions = new string[0];
|
||||
var filterByMultipleExtensions = FileSearchPattern.Contains(",");
|
||||
FileInfo[] fileInfo;
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var withoutExt = Path.GetFileNameWithoutExtension(file);
|
||||
if (withoutExt.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var name = Path.GetFileName(file);
|
||||
var node = CreateTreeNode(HttpUtility.UrlEncode(file), path, queryStrings, name, FileIcon, false);
|
||||
OnRenderFileNode(ref node);
|
||||
if (node != null)
|
||||
nodes.Add(node);
|
||||
}
|
||||
if (filterByMultipleExtensions)
|
||||
{
|
||||
fileInfo = dirInfo.GetFiles();
|
||||
allowedExtensions = FileSearchPattern.ToLower().Split(',');
|
||||
}
|
||||
else
|
||||
fileInfo = dirInfo.GetFiles(FileSearchPattern);
|
||||
|
||||
foreach (var file in fileInfo)
|
||||
{
|
||||
if ((file.Attributes & FileAttributes.Hidden) != 0)
|
||||
continue;
|
||||
|
||||
if (filterByMultipleExtensions && Array.IndexOf(allowedExtensions, file.Extension.ToLower().Trim('.')) < 0)
|
||||
continue;
|
||||
|
||||
var withoutExt = Path.GetFileNameWithoutExtension(file.Name);
|
||||
if (withoutExt.IsNullOrWhiteSpace())
|
||||
continue;
|
||||
|
||||
var node = CreateTreeNode(orgPath + file.Name, orgPath, queryStrings, file.Name, "icon-file", false);
|
||||
|
||||
OnRenderFileNode(ref node);
|
||||
if (node != null)
|
||||
nodes.Add(node);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
@@ -90,22 +111,27 @@ namespace Umbraco.Web.Trees
|
||||
return menu;
|
||||
}
|
||||
|
||||
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
|
||||
? System.Web.HttpUtility.UrlDecode(id).TrimStart("/")
|
||||
: "";
|
||||
string path;
|
||||
if (string.IsNullOrEmpty(id) == false)
|
||||
{
|
||||
var orgPath = System.Web.HttpUtility.UrlDecode(id);
|
||||
path = IOHelper.MapPath(FilePath + "/" + orgPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = IOHelper.MapPath(FilePath);
|
||||
}
|
||||
|
||||
var isFile = FileSystem.FileExists(path);
|
||||
var isDirectory = FileSystem.DirectoryExists(path);
|
||||
|
||||
if (isDirectory)
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
//check if it's a directory
|
||||
if (dirInfo.Attributes == FileAttributes.Directory)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any();
|
||||
|
||||
|
||||
var hasChildren = dirInfo.GetFiles().Length > 0 || dirInfo.GetDirectories().Length > 0;
|
||||
//We can only delete folders if it doesn't have any children (folders or files)
|
||||
if (hasChildren == false)
|
||||
{
|
||||
@@ -116,9 +142,10 @@ namespace Umbraco.Web.Trees
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
}
|
||||
else if (isFile)
|
||||
//if it's not a directory then we only allow to delete the item
|
||||
else
|
||||
{
|
||||
//if it's not a directory then we only allow to delete the item
|
||||
//delete action
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
public abstract class FileSystemTreeController2 : TreeController
|
||||
{
|
||||
protected abstract IFileSystem2 FileSystem { get; }
|
||||
protected abstract string[] Extensions { get; }
|
||||
protected abstract string FileIcon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Inheritors can override this method to modify the file node that is created.
|
||||
/// </summary>
|
||||
/// <param name="treeNode"></param>
|
||||
protected virtual void OnRenderFileNode(ref TreeNode treeNode) { }
|
||||
|
||||
/// <summary>
|
||||
/// Inheritors can override this method to modify the folder node that is created.
|
||||
/// </summary>
|
||||
/// <param name="treeNode"></param>
|
||||
protected virtual void OnRenderFolderNode(ref TreeNode treeNode) { }
|
||||
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
|
||||
? HttpUtility.UrlDecode(id).TrimStart("/")
|
||||
: "";
|
||||
|
||||
var directories = FileSystem.GetDirectories(path);
|
||||
|
||||
var nodes = new TreeNodeCollection();
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
var hasChildren = FileSystem.GetFiles(directory).Any() || FileSystem.GetDirectories(directory).Any();
|
||||
|
||||
var name = Path.GetFileName(directory);
|
||||
var node = CreateTreeNode(HttpUtility.UrlEncode(directory), path, queryStrings, name, "icon-folder", hasChildren);
|
||||
OnRenderFolderNode(ref node);
|
||||
if(node != null)
|
||||
nodes.Add(node);
|
||||
}
|
||||
|
||||
//this is a hack to enable file system tree to support multiple file extension look-up
|
||||
//so the pattern both support *.* *.xml and xml,js,vb for lookups
|
||||
var files = FileSystem.GetFiles(path).Where(x =>
|
||||
{
|
||||
var extension = Path.GetExtension(x);
|
||||
return extension != null && Extensions.Contains(extension.Trim('.'), StringComparer.InvariantCultureIgnoreCase);
|
||||
});
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var withoutExt = Path.GetFileNameWithoutExtension(file);
|
||||
if (withoutExt.IsNullOrWhiteSpace()) continue;
|
||||
|
||||
var name = Path.GetFileName(file);
|
||||
var node = CreateTreeNode(HttpUtility.UrlEncode(file), path, queryStrings, name, FileIcon, false);
|
||||
OnRenderFileNode(ref node);
|
||||
if (node != null)
|
||||
nodes.Add(node);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
//if root node no need to visit the filesystem so lets just create the menu and return it
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
|
||||
? HttpUtility.UrlDecode(id).TrimStart("/")
|
||||
: "";
|
||||
|
||||
var isFile = FileSystem.FileExists(path);
|
||||
var isDirectory = FileSystem.DirectoryExists(path);
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any();
|
||||
|
||||
//We can only delete folders if it doesn't have any children (folders or files)
|
||||
if (hasChildren == false)
|
||||
{
|
||||
//delete action
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
|
||||
}
|
||||
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
}
|
||||
else if (isFile)
|
||||
{
|
||||
//if it's not a directory then we only allow to delete the item
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@ namespace Umbraco.Web.Trees
|
||||
/// Tree for displaying partial view macros in the developer app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Developer, "partialViewMacros", null, sortOrder: 6)]
|
||||
public class PartialViewMacrosTreeController : FileSystemTreeController
|
||||
public class PartialViewMacrosTreeController : FileSystemTreeController2
|
||||
{
|
||||
protected override IFileSystem2 FileSystem
|
||||
{
|
||||
get { return FileSystemProviderManager.Current.MacroPartialsFileSystem; }
|
||||
}
|
||||
|
||||
private static readonly string[] ExtensionsStatic = { "cshtml" };
|
||||
private static readonly string[] ExtensionsStatic = {"cshtml"};
|
||||
|
||||
protected override string[] Extensions
|
||||
{
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace Umbraco.Web.Trees
|
||||
/// Tree for displaying partial views in the settings app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Settings, "partialViews", null, sortOrder: 2)]
|
||||
public class PartialViewsTreeController : FileSystemTreeController
|
||||
public class PartialViewsTreeController : FileSystemTreeController2
|
||||
{
|
||||
protected override IFileSystem2 FileSystem
|
||||
{
|
||||
get { return FileSystemProviderManager.Current.PartialViewsFileSystem; }
|
||||
}
|
||||
protected override IFileSystem2 FileSystem
|
||||
{
|
||||
get { return FileSystemProviderManager.Current.PartialViewsFileSystem; }
|
||||
}
|
||||
|
||||
private static readonly string[] ExtensionsStatic = { "cshtml" };
|
||||
private static readonly string[] ExtensionsStatic = {"cshtml"};
|
||||
|
||||
protected override string[] Extensions
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Web.Models.Trees;
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
[Tree(Constants.Applications.Settings, "scripts", null, sortOrder: 4)]
|
||||
public class ScriptTreeController : FileSystemTreeController
|
||||
public class ScriptTreeController : FileSystemTreeController2
|
||||
{
|
||||
protected override IFileSystem2 FileSystem
|
||||
{
|
||||
|
||||
@@ -439,7 +439,7 @@
|
||||
<Compile Include="PropertyEditors\ValueConverters\MediaPickerPropertyConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MemberPickerPropertyConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MultiNodeTreePickerPropertyConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MultipleMediaPickerPropertyConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\LegacyMediaPickerPropertyConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\NestedContentSingleValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\NestedContentManyValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\NestedContentPublishedPropertyTypeExtensions.cs" />
|
||||
@@ -467,6 +467,7 @@
|
||||
<Compile Include="SingletonHttpContextAccessor.cs" />
|
||||
<Compile Include="Trees\ContentBlueprintTreeController.cs" />
|
||||
<Compile Include="Trees\ContentTypeTreeController.cs" />
|
||||
<Compile Include="Trees\FileSystemTreeController.cs" />
|
||||
<Compile Include="Trees\PackagesTreeController.cs" />
|
||||
<Compile Include="Trees\MediaTypeTreeController.cs" />
|
||||
<Compile Include="Trees\MemberTypeTreeController.cs" />
|
||||
@@ -721,7 +722,7 @@
|
||||
<Compile Include="TagQuery.cs" />
|
||||
<Compile Include="Trees\CoreTreeAttribute.cs" />
|
||||
<Compile Include="Trees\DataTypeTreeController.cs" />
|
||||
<Compile Include="Trees\FileSystemTreeController.cs" />
|
||||
<Compile Include="Trees\FileSystemTreeController2.cs" />
|
||||
<Compile Include="Trees\LanguageTreeController.cs" />
|
||||
<Compile Include="Trees\LegacyBaseTreeAttribute.cs" />
|
||||
<Compile Include="Trees\MemberTreeController.cs" />
|
||||
|
||||
@@ -1393,15 +1393,25 @@ namespace umbraco
|
||||
/// <returns>An XpathNodeIterator containing the current page as Xml.</returns>
|
||||
public static XPathNodeIterator GetXmlNodeCurrent()
|
||||
{
|
||||
var pageId = "";
|
||||
|
||||
try
|
||||
{
|
||||
var nav = Umbraco.Web.UmbracoContext.Current.ContentCache.GetXPathNavigator();
|
||||
nav.MoveToId(HttpContext.Current.Items["pageID"].ToString());
|
||||
var pageIdItem = HttpContext.Current.Items["pageID"];
|
||||
|
||||
if (pageIdItem == null)
|
||||
{
|
||||
throw new NullReferenceException("pageID not found in the current HTTP context");
|
||||
}
|
||||
|
||||
pageId = pageIdItem.ToString();
|
||||
nav.MoveToId(pageId);
|
||||
return nav.Select(".");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<library>("Could not retrieve current xml node", ex);
|
||||
LogHelper.Error<library>(string.Concat("Could not retrieve current xml node for page Id ",pageId), ex);
|
||||
}
|
||||
|
||||
XmlDocument xd = new XmlDocument();
|
||||
|
||||
@@ -46,6 +46,7 @@ using System.Linq;
|
||||
using File = System.IO.File;
|
||||
using MacroTypes = umbraco.cms.businesslogic.macro.MacroTypes;
|
||||
using Member = umbraco.cms.businesslogic.member.Member;
|
||||
using UserControl = System.Web.UI.UserControl;
|
||||
|
||||
namespace umbraco
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using umbraco.BusinessLogic;
|
||||
using System.Collections.Generic;
|
||||
using MacroProperty = umbraco.cms.businesslogic.macro.MacroProperty;
|
||||
using UserControl = System.Web.UI.UserControl;
|
||||
|
||||
namespace umbraco.developer
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user