Compare commits
180 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd2fe1939a | |||
| 81e56bed9e | |||
| 52457fea21 | |||
| 07ec9aa813 | |||
| ba89aec34f | |||
| 29533820ab | |||
| 4366500fad | |||
| ee6e1a9d8b | |||
| 3b95184f04 | |||
| 9da7e108da | |||
| cb491d45ab | |||
| 344b880ba7 | |||
| c958f12bc1 | |||
| 9a973d0ccc | |||
| b170053e87 | |||
| db4509de2b | |||
| 5c91b822e3 | |||
| e6ddf63e56 | |||
| 84ac029372 | |||
| 5d59741612 | |||
| 2ffd0413e8 | |||
| dc4e6ee01c | |||
| 1d8e217c6f | |||
| e59768dda0 | |||
| 0b114c88f0 | |||
| 0b3136cf20 | |||
| b0e96b256a | |||
| 72a966b0fa | |||
| bf222f26cd | |||
| be9f4b70e2 | |||
| d9374c34d1 | |||
| 2b7526ab2e | |||
| 2fde10494c | |||
| 0da4879400 | |||
| 07172067ab | |||
| 681a3e3046 | |||
| 0060f0019e | |||
| 632cd221d9 | |||
| 46d5215d9e | |||
| aa43656cb9 | |||
| e5dea8e4be | |||
| 087dd1fe9e | |||
| 37afe6dd29 | |||
| 338a125eaa | |||
| 18fc6ccc99 | |||
| 8a1db41fc4 | |||
| d2119c17c1 | |||
| 9d4afbd007 | |||
| c4f764d5fc | |||
| db3d86aeca | |||
| c17e60f709 | |||
| 68860b6c54 | |||
| 5834757476 | |||
| e4837d1962 | |||
| 40868d7cd2 | |||
| 0fde3f7b5d | |||
| 76f0eac5f8 | |||
| 2352d258b9 | |||
| 2dc38a29cf | |||
| 91ddbff990 | |||
| 5fd1d7c9e5 | |||
| 32cfdbe968 | |||
| a754cecaf7 | |||
| 1aa162e255 | |||
| 8ccb06c91d | |||
| d8e35ffc08 | |||
| 34dcde645c | |||
| 342999a678 | |||
| 0474605d36 | |||
| 4dd3f2f8ac | |||
| d7a0447e2e | |||
| cbe23663e3 | |||
| bff415a4c6 | |||
| caa59f2c80 | |||
| 2ff1c973e0 | |||
| f056d3fae7 | |||
| 41a455c9ac | |||
| f834155763 | |||
| 15cc3d19c1 | |||
| 3bb563ec55 | |||
| b5282244f0 | |||
| aa5b5708b2 | |||
| ec0d6959a9 | |||
| 320df6706e | |||
| 519dd8b476 | |||
| 0434b3e5bd | |||
| ff42a1b79c | |||
| 4e433becd6 | |||
| 8aafc583de | |||
| d6b0ed2d40 | |||
| ebbbd80bb3 | |||
| 7b33eca014 | |||
| f8e06e54de | |||
| 23d9ef624b | |||
| cdb5b0470d | |||
| b43f39a0cb | |||
| d0cb27d1c1 | |||
| e8990eb6b2 | |||
| 05524c643e | |||
| ed989079b4 | |||
| 5cb210c7b6 | |||
| feed5c5e51 | |||
| b80ab20cb4 | |||
| 754a6e327e | |||
| 650fb94057 | |||
| 0af19fa442 | |||
| bac6e71e7f | |||
| 9a36d74418 | |||
| 5b17bc6d5f | |||
| 06a1f790dd | |||
| 39eaa4a15e | |||
| 2fdf040f73 | |||
| aec956dd2e | |||
| e7994d077e | |||
| f55f9edb71 | |||
| 65bb1e1e20 | |||
| 3dabd73ec2 | |||
| df3bc873df | |||
| d1c5ddc03d | |||
| f11d209177 | |||
| ea32776174 | |||
| 90e5440518 | |||
| 7cfd2d6593 | |||
| 6382515258 | |||
| fd2b9ce67d | |||
| 1284417a58 | |||
| b57642003c | |||
| 9ee59e8e38 | |||
| a5f81ae6c2 | |||
| 08cc608dc8 | |||
| 71839d53a6 | |||
| 7508613d13 | |||
| 9626e91c83 | |||
| 83b6375f04 | |||
| 52cd44a700 | |||
| 0c8ff187aa | |||
| 3af74bd4fd | |||
| c9e2e1e116 | |||
| c27f73e54a | |||
| cede13d180 | |||
| 3ffb2772b6 | |||
| e6f0d4e056 | |||
| 23c7eafaf5 | |||
| 90892ce818 | |||
| e62d1559b1 | |||
| 81934c47d2 | |||
| 80379e116d | |||
| 89081b86af | |||
| 216e2255f2 | |||
| 9db3dbd730 | |||
| 8a1dd96294 | |||
| 67bebd0d2d | |||
| 4f34fbd2c8 | |||
| 8cda6e4062 | |||
| d8209efefa | |||
| 00180d2120 | |||
| 66e768afee | |||
| bba109cb28 | |||
| 39ede8c47a | |||
| fec84b8ce3 | |||
| a00e5d54aa | |||
| 331813e370 | |||
| 6c36f43276 | |||
| e8f4e7663f | |||
| 9f116c00d5 | |||
| 7e61b25746 | |||
| 482750ab6a | |||
| 40d1099fbd | |||
| 2d050a0c88 | |||
| 103f4f33bd | |||
| 727f9355a0 | |||
| e269a0b9bb | |||
| 861b1cefe5 | |||
| 23301817bf | |||
| f5842c82a6 | |||
| 4baf3ed99a | |||
| 3c09cd7674 | |||
| 6fae57c5e9 | |||
| beb1979b46 | |||
| 672672d0aa |
@@ -78,6 +78,12 @@ src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
|
||||
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.panel.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.palettes.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.loader.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.front.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.config.js
|
||||
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ IF NOT EXIST UmbracoVersion.txt (
|
||||
GOTO :showerror
|
||||
)
|
||||
SET /p release=<UmbracoVersion.txt
|
||||
SET comment=
|
||||
SET comment=alpha
|
||||
SET version=%release%
|
||||
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
|
||||
@@ -1 +1 @@
|
||||
7.1.4
|
||||
7.2.0
|
||||
@@ -77,6 +77,7 @@
|
||||
<Compile Include="SqlCEUtility.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.1.4");
|
||||
private static readonly Version Version = new Version("7.2.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
public static string CurrentComment { get { return "alpha"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -70,6 +70,11 @@
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
|
||||
/// <summary>
|
||||
/// alias for the media tree.
|
||||
/// </summary>
|
||||
public const string Templates = "template";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,6 +130,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string FolderBrowserAlias = "Umbraco.FolderBrowser";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the grid datatype.
|
||||
/// </summary>
|
||||
public const string GridAlias = "Umbraco.Grid";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Image Cropper datatype.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
internal class ManifestWatcher : DisposableObject
|
||||
{
|
||||
private readonly List<FileSystemWatcher> _fws = new List<FileSystemWatcher>();
|
||||
|
||||
public void Start(params string[] packageFolders)
|
||||
{
|
||||
foreach (var packageFolder in packageFolders)
|
||||
{
|
||||
if (Directory.Exists(packageFolder) && File.Exists(Path.Combine(packageFolder, "package.manifest")))
|
||||
{
|
||||
//NOTE: for some reason *.manifest doesn't work!
|
||||
var fsw = new FileSystemWatcher(packageFolder, "*package.*")
|
||||
{
|
||||
IncludeSubdirectories = false,
|
||||
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
|
||||
};
|
||||
_fws.Add(fsw);
|
||||
fsw.Changed += FswChanged;
|
||||
fsw.EnableRaisingEvents = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FswChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
if (e.Name.InvariantContains("package.manifest"))
|
||||
{
|
||||
LogHelper.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
|
||||
HttpRuntime.UnloadAppDomain();
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
foreach (var fw in _fws)
|
||||
{
|
||||
fw.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,14 +44,18 @@ namespace Umbraco.Core.Media
|
||||
|
||||
var result = new List<ResizedImage>();
|
||||
|
||||
var allSizes = new List<int> {100, 500};
|
||||
var allSizesDictionary = new Dictionary<int,string> {{100,"thumb"}, {500,"big-thumb"}};
|
||||
var allSizes = allSizesDictionary.Select(kv => kv.Key).ToList();
|
||||
allSizes.AddRange(additionalThumbSizes.Where(x => x > 0).Distinct());
|
||||
var sizesDictionary = allSizes.ToDictionary(s => s, s => allSizesDictionary.ContainsKey(s) ? allSizesDictionary[s]: "");
|
||||
|
||||
foreach (var s in allSizes)
|
||||
foreach (var s in sizesDictionary)
|
||||
{
|
||||
if (originalImage.Width >= s && originalImage.Height >= s)
|
||||
var size = s.Key;
|
||||
var name = s.Value;
|
||||
if (originalImage.Width >= size && originalImage.Height >= size)
|
||||
{
|
||||
result.Add(Resize(fs, fileName, extension, s, "thumb", originalImage));
|
||||
result.Add(Resize(fs, fileName, extension, size, name, originalImage));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,8 +93,17 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
var contentTypeComposition = ContentTypeComposition.FirstOrDefault(x => x.Alias == alias);
|
||||
if (contentTypeComposition == null)//You can't remove a composition from another composition
|
||||
return false;
|
||||
|
||||
RemovedContentTypeKeyTracker.Add(contentTypeComposition.Id);
|
||||
|
||||
//If the ContentType we are removing has Compositions of its own these needs to be removed as well
|
||||
var compositionIdsToRemove = contentTypeComposition.CompositionIds().ToList();
|
||||
if(compositionIdsToRemove.Any())
|
||||
RemovedContentTypeKeyTracker.AddRange(compositionIdsToRemove);
|
||||
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
return _contentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,14 @@ namespace Umbraco.Core.Models
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//check if the item's sort order is already in use
|
||||
if (this.Any(x => x.SortOrder == item.SortOrder))
|
||||
{
|
||||
//make it the next iteration
|
||||
item.SortOrder = this.Max(x => x.SortOrder) + 1;
|
||||
}
|
||||
|
||||
base.Add(item);
|
||||
OnAdd.IfNotNull(x => x.Invoke());//Could this not be replaced by a Mandate/Contract for ensuring item is not null
|
||||
|
||||
|
||||
@@ -222,19 +222,38 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var converterMeta = _converter as IPropertyValueConverterMeta;
|
||||
|
||||
// get the cache levels, quietely fixing the inconsistencies (no need to throw, really)
|
||||
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
if (converterMeta != null)
|
||||
{
|
||||
_sourceCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
}
|
||||
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
|
||||
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
|
||||
|
||||
// get the CLR type of the converted value
|
||||
if (_converter != null)
|
||||
{
|
||||
var attr = _converter.GetType().GetCustomAttribute<PropertyValueTypeAttribute>(false);
|
||||
if (attr != null)
|
||||
_clrType = attr.Type;
|
||||
if (converterMeta != null)
|
||||
{
|
||||
_clrType = converterMeta.GetPropertyValueType(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
var attr = _converter.GetType().GetCustomAttribute<PropertyValueTypeAttribute>(false);
|
||||
if (attr != null)
|
||||
_clrType = attr.Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
var nodeId = contentDto.NodeId;
|
||||
var propertyTypeId = propertyType.Id;
|
||||
var propertySql = new Sql().Select("*")
|
||||
var propertySql = new Sql().Select("cmsPropertyData.id")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyDataDto, PropertyTypeDto>(
|
||||
@@ -249,7 +249,7 @@ AND umbracoNode.id <> @id",
|
||||
.Where<PropertyTypeDto>(x => x.Id == propertyTypeId);
|
||||
|
||||
//Finally delete the properties that match our criteria for removing a ContentType from the composition
|
||||
Database.Delete<PropertyDataDto>(propertySql);
|
||||
Database.Delete<PropertyDataDto>(new Sql("WHERE id IN (" + propertySql.SQL + ")", propertySql.Arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,7 +285,8 @@ AND umbracoNode.id <> @id",
|
||||
}
|
||||
}
|
||||
|
||||
if (((ICanBeDirty) entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") ||
|
||||
entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete Tabs/Groups by excepting entries from db with entries from collections
|
||||
var dbPropertyGroups =
|
||||
@@ -346,6 +347,25 @@ AND umbracoNode.id <> @id",
|
||||
if (propertyType.HasIdentity == false)
|
||||
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
|
||||
}
|
||||
|
||||
//If a Composition is removed we need to update/reset references to the PropertyGroups on that ContentType
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("ContentTypeComposition") &&
|
||||
compositionBase != null &&
|
||||
compositionBase.RemovedContentTypeKeyTracker != null &&
|
||||
compositionBase.RemovedContentTypeKeyTracker.Any())
|
||||
{
|
||||
foreach (var compositionId in compositionBase.RemovedContentTypeKeyTracker)
|
||||
{
|
||||
var dbPropertyGroups =
|
||||
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = compositionId })
|
||||
.Select(x => x.Id);
|
||||
foreach (var propertyGroup in dbPropertyGroups)
|
||||
{
|
||||
Database.Update<PropertyTypeGroupDto>("SET parentGroupId = NULL WHERE parentGroupId = @TabId AND contenttypeNodeId = @ContentTypeNodeId",
|
||||
new { TabId = propertyGroup, ContentTypeNodeId = entity.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
|
||||
@@ -371,7 +371,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//template.CreateDate = _viewsFileSystem.GetCreated(path).UtcDateTime;
|
||||
//template.Key = new FileInfo(path).Name.EncodeAsGuid();
|
||||
|
||||
template.Path = path;
|
||||
template.Content = content;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,9 +82,16 @@ namespace Umbraco.Core.Profiling
|
||||
return false;
|
||||
|
||||
var request = TryGetRequest(sender);
|
||||
if (request.Success == false || request.Result.Url.IsClientSideRequest() || string.IsNullOrEmpty(request.Result["umbDebug"]))
|
||||
|
||||
if (request.Success == false || request.Result.Url.IsClientSideRequest())
|
||||
return false;
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(request.Result["umbDebug"]))
|
||||
return true;
|
||||
|
||||
if (request.Result.Url.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -97,7 +104,7 @@ namespace Umbraco.Core.Profiling
|
||||
/// </remarks>
|
||||
public string Render()
|
||||
{
|
||||
return MiniProfiler.RenderIncludes().ToString();
|
||||
return MiniProfiler.RenderIncludes(RenderPosition.Right).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides published content properties converter meta data.
|
||||
/// </summary>
|
||||
public interface IPropertyValueConverterMeta : IPropertyValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of values returned by the converter.
|
||||
/// </summary>
|
||||
/// <param name="propertyType">The property type.</param>
|
||||
/// <returns>The CLR type of values returned by the converter.</returns>
|
||||
Type GetPropertyValueType(PublishedPropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property cache level of a specified value.
|
||||
/// </summary>
|
||||
/// <param name="propertyType">The property type.</param>
|
||||
/// <param name="cacheValue">The property value.</param>
|
||||
/// <returns>The property cache level of the specified value.</returns>
|
||||
PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue);
|
||||
}
|
||||
}
|
||||
@@ -367,8 +367,8 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
var sql = new Sql().Select("nodeObjectType").From<NodeDto>().Where<NodeDto>(x => x.NodeId == id);
|
||||
var nodeObjectTypeId = uow.Database.ExecuteScalar<string>(sql);
|
||||
var objectTypeId = new Guid(nodeObjectTypeId);
|
||||
var nodeObjectTypeId = uow.Database.ExecuteScalar<Guid>(sql);
|
||||
var objectTypeId = nodeObjectTypeId;
|
||||
return UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
}
|
||||
}
|
||||
@@ -383,8 +383,8 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
var sql = new Sql().Select("nodeObjectType").From<NodeDto>().Where<NodeDto>(x => x.UniqueId == key);
|
||||
var nodeObjectTypeId = uow.Database.ExecuteScalar<string>(sql);
|
||||
var objectTypeId = new Guid(nodeObjectTypeId);
|
||||
var nodeObjectTypeId = uow.Database.ExecuteScalar<Guid>(sql);
|
||||
var objectTypeId = nodeObjectTypeId;
|
||||
return UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Script.Serialization;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -520,7 +521,7 @@ namespace Umbraco.Core.Sync
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IAsyncResult> GetAsyncResults(List<IAsyncResult> asyncResultsList, out List<WaitHandle> waitHandlesList)
|
||||
internal IEnumerable<IAsyncResult> GetAsyncResults(List<IAsyncResult> asyncResultsList, out List<WaitHandle> waitHandlesList)
|
||||
{
|
||||
var asyncResults = asyncResultsList.ToArray();
|
||||
waitHandlesList = new List<WaitHandle>();
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
[Serializable]
|
||||
public class RefreshInstruction
|
||||
{
|
||||
public RefreshMethodType RefreshType { get; set; }
|
||||
public Guid RefresherId { get; set; }
|
||||
public Guid GuidId { get; set; }
|
||||
public int IntId { get; set; }
|
||||
public string JsonIds { get; set; }
|
||||
public string JsonPayload { get; set; }
|
||||
|
||||
[Serializable]
|
||||
public enum RefreshMethodType
|
||||
{
|
||||
RefreshAll,
|
||||
RefreshByGuid,
|
||||
RefreshById,
|
||||
RefreshByIds,
|
||||
RefreshByJson,
|
||||
RemoveById
|
||||
}
|
||||
|
||||
protected bool Equals(RefreshInstruction other)
|
||||
{
|
||||
return RefreshType == other.RefreshType && RefresherId.Equals(other.RefresherId) && GuidId.Equals(other.GuidId) && IntId == other.IntId && string.Equals(JsonIds, other.JsonIds) && string.Equals(JsonPayload, other.JsonPayload);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((RefreshInstruction) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = (int) RefreshType;
|
||||
hashCode = (hashCode*397) ^ RefresherId.GetHashCode();
|
||||
hashCode = (hashCode*397) ^ GuidId.GetHashCode();
|
||||
hashCode = (hashCode*397) ^ IntId;
|
||||
hashCode = (hashCode*397) ^ (JsonIds != null ? JsonIds.GetHashCode() : 0);
|
||||
hashCode = (hashCode*397) ^ (JsonPayload != null ? JsonPayload.GetHashCode() : 0);
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(RefreshInstruction left, RefreshInstruction right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(RefreshInstruction left, RefreshInstruction right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The client Soap service for making distrubuted cache calls between servers
|
||||
/// </summary>
|
||||
@@ -21,6 +20,31 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/BulkRefresh", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void BulkRefresh(RefreshInstruction[] instructions, string login, string password)
|
||||
{
|
||||
this.Invoke("BulkRefresh", new object[] {
|
||||
instructions,
|
||||
login,
|
||||
password});
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginBulkRefresh(RefreshInstruction[] instructions, string login, string password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("BulkRefresh", new object[] {
|
||||
instructions,
|
||||
login,
|
||||
password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public void EndBulkRefresh(System.IAsyncResult asyncResult)
|
||||
{
|
||||
this.EndInvoke(asyncResult);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshAll", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void RefreshAll(System.Guid uniqueIdentifier, string Login, string Password)
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MiniProfiler">
|
||||
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data">
|
||||
@@ -315,6 +316,7 @@
|
||||
<Compile Include="Manifest\ManifestBuilder.cs" />
|
||||
<Compile Include="Manifest\ManifestParser.cs" />
|
||||
<Compile Include="Manifest\ManifestValidatorConverter.cs" />
|
||||
<Compile Include="Manifest\ManifestWatcher.cs" />
|
||||
<Compile Include="Manifest\PackageManifest.cs" />
|
||||
<Compile Include="Manifest\ParameterEditorConverter.cs" />
|
||||
<Compile Include="Manifest\PreValueFieldConverter.cs" />
|
||||
@@ -405,6 +407,7 @@
|
||||
<Compile Include="PropertyEditors\TagPropertyDefinition.cs" />
|
||||
<Compile Include="PropertyEditors\TagValueType.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\IntegerValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\IPropertyValueConverterMeta.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\JsonValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MultipleTextStringValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MarkdownEditorValueConverter.cs" />
|
||||
@@ -1063,6 +1066,7 @@
|
||||
<Compile Include="Standalone\StandaloneCoreBootManager.cs" />
|
||||
<Compile Include="Strings\ContentBaseExtensions.cs" />
|
||||
<Compile Include="Strings\Diff.cs" />
|
||||
<Compile Include="Sync\RefreshInstruction.cs" />
|
||||
<Compile Include="TopologicalSorter.cs" />
|
||||
<Compile Include="Strings\DefaultUrlSegmentProvider.cs" />
|
||||
<Compile Include="Strings\IUrlSegmentProvider.cs" />
|
||||
@@ -1159,6 +1163,7 @@
|
||||
<Compile Include="Xml\XPathVariable.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -9,8 +9,8 @@
|
||||
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
|
||||
<package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
|
||||
<package id="MiniProfiler" version="2.1.0" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="6.0.2" targetFramework="net45" />
|
||||
<package id="MiniProfiler" version="2.1.0" targetFramework="net45" />
|
||||
<package id="MySql.Data" version="6.6.5" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="6.0.2" targetFramework="net45" />
|
||||
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
|
||||
</packages>
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
|
||||
<sectionGroup name="umbracoConfiguration">
|
||||
<section name="FileSystemProviders" type="Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core" requirePermission="false"/>
|
||||
<section name="FileSystemProviders" type="Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
|
||||
</configSections>
|
||||
@@ -12,69 +12,69 @@
|
||||
<FileSystemProviders>
|
||||
<Provider alias="media" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
|
||||
<Parameters>
|
||||
<add key="rootPath" value="\Media\"/>
|
||||
<add key="rootUrl" value="/Media/"/>
|
||||
<add key="rootPath" value="\Media\" />
|
||||
<add key="rootUrl" value="/Media/" />
|
||||
</Parameters>
|
||||
</Provider>
|
||||
<!-- Macros -->
|
||||
<Provider alias="macros" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
|
||||
<Parameters>
|
||||
<add key="rootPath" value="\App_Data\Macros"/>
|
||||
<add key="rootUrl" value="/Macros/"/>
|
||||
<add key="rootPath" value="\App_Data\Macros" />
|
||||
<add key="rootUrl" value="/Macros/" />
|
||||
</Parameters>
|
||||
</Provider>
|
||||
<!-- Scripts -->
|
||||
<Provider alias="scripts" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
|
||||
<Parameters>
|
||||
<add key="rootPath" value="\scripts\"/>
|
||||
<add key="rootUrl" value="/scripts/"/>
|
||||
<add key="rootPath" value="\scripts\" />
|
||||
<add key="rootUrl" value="/scripts/" />
|
||||
</Parameters>
|
||||
</Provider>
|
||||
<!-- Stylesheets -->
|
||||
<Provider alias="stylesheets" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
|
||||
<Parameters>
|
||||
<add key="rootPath" value="\css\"/>
|
||||
<add key="rootUrl" value="/css/"/>
|
||||
<add key="rootPath" value="\css\" />
|
||||
<add key="rootUrl" value="/css/" />
|
||||
</Parameters>
|
||||
</Provider>
|
||||
<!-- Templates -->
|
||||
<Provider alias="masterpages" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
|
||||
<Parameters>
|
||||
<add key="rootPath" value="\masterpages\"/>
|
||||
<add key="rootUrl" value="/masterpages/"/>
|
||||
<add key="rootPath" value="\masterpages\" />
|
||||
<add key="rootUrl" value="/masterpages/" />
|
||||
</Parameters>
|
||||
</Provider>
|
||||
<Provider alias="views" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
|
||||
<Parameters>
|
||||
<add key="rootPath" value="\views\"/>
|
||||
<add key="rootUrl" value="/views/"/>
|
||||
<add key="rootPath" value="\views\" />
|
||||
<add key="rootUrl" value="/views/" />
|
||||
</Parameters>
|
||||
</Provider>
|
||||
</FileSystemProviders>
|
||||
</umbracoConfiguration>
|
||||
|
||||
<appSettings>
|
||||
<add key="umbracoConfigurationStatus" value="6.0.0"/>
|
||||
<add key="umbracoReservedUrls" value="~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd"/>
|
||||
<add key="umbracoReservedPaths" value="~/umbraco,~/install/"/>
|
||||
<add key="umbracoPath" value="~/umbraco"/>
|
||||
<add key="umbracoHideTopLevelNodeFromPath" value="true"/>
|
||||
<add key="umbracoUseDirectoryUrls" value="false"/>
|
||||
<add key="umbracoTimeOutInMinutes" value="20"/>
|
||||
<add key="umbracoDefaultUILanguage" value="en"/>
|
||||
<add key="umbracoUseSSL" value="false"/>
|
||||
<add key="umbracoConfigurationStatus" value="6.0.0" />
|
||||
<add key="umbracoReservedUrls" value="~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd" />
|
||||
<add key="umbracoReservedPaths" value="~/umbraco,~/install/" />
|
||||
<add key="umbracoPath" value="~/umbraco" />
|
||||
<add key="umbracoHideTopLevelNodeFromPath" value="true" />
|
||||
<add key="umbracoUseDirectoryUrls" value="false" />
|
||||
<add key="umbracoTimeOutInMinutes" value="20" />
|
||||
<add key="umbracoDefaultUILanguage" value="en" />
|
||||
<add key="umbracoUseSSL" value="false" />
|
||||
</appSettings>
|
||||
|
||||
<connectionStrings>
|
||||
<add name="umbracoDbDSN" connectionString="Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;" providerName="System.Data.SqlServerCe.4.0"/>
|
||||
<add name="umbracoDbDSN" connectionString="Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;" providerName="System.Data.SqlServerCe.4.0" />
|
||||
</connectionStrings>
|
||||
|
||||
<system.data>
|
||||
<DbProviderFactories>
|
||||
<remove invariant="System.Data.SqlServerCe.4.0" />
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
|
||||
<remove invariant="MySql.Data.MySqlClient" />
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/>
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
|
||||
</DbProviderFactories>
|
||||
</system.data>
|
||||
|
||||
@@ -85,13 +85,13 @@
|
||||
<!-- Sitemap provider-->
|
||||
<siteMap defaultProvider="UmbracoSiteMapProvider" enabled="true">
|
||||
<providers>
|
||||
<clear/>
|
||||
<add name="UmbracoSiteMapProvider" type="umbraco.presentation.nodeFactory.UmbracoSiteMapProvider" defaultDescriptionAlias="description" securityTrimmingEnabled="true"/>
|
||||
<clear />
|
||||
<add name="UmbracoSiteMapProvider" type="umbraco.presentation.nodeFactory.UmbracoSiteMapProvider" defaultDescriptionAlias="description" securityTrimmingEnabled="true" />
|
||||
</providers>
|
||||
</siteMap>
|
||||
</system.web>
|
||||
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></startup>
|
||||
<runtime>
|
||||
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
@@ -128,6 +128,14 @@
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
<dependentAssembly>
|
||||
|
||||
<assemblyIdentity name="MiniProfiler" publicKeyToken="b44f9351044011a3" culture="neutral" />
|
||||
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
</assemblyBinding>
|
||||
|
||||
</runtime>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@@ -31,7 +32,50 @@ namespace Umbraco.Tests.PublishedContent
|
||||
return GetNode(id).AsDynamic();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test]
|
||||
public void FirstChild()
|
||||
{
|
||||
var content = GetDynamicNode(1173);
|
||||
|
||||
var x = content.FirstChild();
|
||||
Assert.IsNotNull(x);
|
||||
Assert.IsInstanceOf<DynamicPublishedContent>(x);
|
||||
Assert.AreEqual(1174, x.Id);
|
||||
|
||||
x = content.FirstChild("CustomDocument");
|
||||
Assert.IsNotNull(x);
|
||||
Assert.IsInstanceOf<DynamicPublishedContent>(x);
|
||||
Assert.AreEqual(1177, x.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Children()
|
||||
{
|
||||
var content = GetDynamicNode(1173);
|
||||
|
||||
var l = content.Children;
|
||||
Assert.AreEqual(4, l.Count());
|
||||
|
||||
// works - but not by calling the extension method
|
||||
// because the binder will in fact re-route to the property first
|
||||
l = content.Children();
|
||||
Assert.AreEqual(4, l.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildrenOfType()
|
||||
{
|
||||
var content = GetDynamicNode(1173);
|
||||
|
||||
var l = content.Children;
|
||||
Assert.AreEqual(4, l.Count());
|
||||
|
||||
// fails - because it fails to find extension methods?
|
||||
l = content.Children("CustomDocument");
|
||||
Assert.AreEqual(2, l.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Custom_Extension_Methods()
|
||||
{
|
||||
var asDynamic = GetDynamicNode(1173);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
@@ -11,30 +11,30 @@ using Umbraco.Tests.TestHelpers.Entities;
|
||||
namespace Umbraco.Tests.Services
|
||||
{
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
[TestFixture, RequiresSTA]
|
||||
public class ContentTypeServiceTests : BaseServiceTest
|
||||
{
|
||||
[SetUp]
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
}
|
||||
[TestFixture, RequiresSTA]
|
||||
public class ContentTypeServiceTests : BaseServiceTest
|
||||
{
|
||||
[SetUp]
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Deleting_PropertyType_Removes_The_Property_From_Content()
|
||||
{
|
||||
[Test]
|
||||
public void Deleting_PropertyType_Removes_The_Property_From_Content()
|
||||
{
|
||||
IContentType contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "Test1");
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
IContent contentItem = MockedContent.CreateTextpageContent(contentType1, "Testing", -1);
|
||||
ServiceContext.ContentService.SaveAndPublish(contentItem);
|
||||
var initProps = contentItem.Properties.Count;
|
||||
var initPropTypes = contentItem.PropertyTypes.Count();
|
||||
IContent contentItem = MockedContent.CreateTextpageContent(contentType1, "Testing", -1);
|
||||
ServiceContext.ContentService.SaveAndPublishWithStatus(contentItem);
|
||||
var initProps = contentItem.Properties.Count;
|
||||
var initPropTypes = contentItem.PropertyTypes.Count();
|
||||
|
||||
//remove a property
|
||||
contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias);
|
||||
@@ -44,30 +44,31 @@ namespace Umbraco.Tests.Services
|
||||
contentItem = ServiceContext.ContentService.GetById(contentItem.Id);
|
||||
|
||||
Assert.AreEqual(initPropTypes - 1, contentItem.PropertyTypes.Count());
|
||||
Assert.AreEqual(initProps -1, contentItem.Properties.Count);
|
||||
}
|
||||
Assert.AreEqual(initProps - 1, contentItem.Properties.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Rebuild_Content_Xml_On_Alias_Change()
|
||||
[Test]
|
||||
public void Rebuild_Content_Xml_On_Alias_Change()
|
||||
{
|
||||
var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "Test1");
|
||||
var contentType2 = MockedContentTypes.CreateTextpageContentType("test2", "Test2");
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
ServiceContext.ContentTypeService.Save(contentType2);
|
||||
var contentItems1 = MockedContent.CreateTextpageContent(contentType1, -1, 10).ToArray();
|
||||
contentItems1.ForEach(x => ServiceContext.ContentService.SaveAndPublish(x));
|
||||
var contentItems1 = MockedContent.CreateTextpageContent(contentType1, -1, 10).ToArray();
|
||||
contentItems1.ForEach(x => ServiceContext.ContentService.SaveAndPublishWithStatus(x));
|
||||
var contentItems2 = MockedContent.CreateTextpageContent(contentType2, -1, 5).ToArray();
|
||||
contentItems2.ForEach(x => ServiceContext.ContentService.SaveAndPublish(x));
|
||||
contentItems2.ForEach(x => ServiceContext.ContentService.SaveAndPublishWithStatus(x));
|
||||
//only update the contentType1 alias which will force an xml rebuild for all content of that type
|
||||
contentType1.Alias = "newAlias";
|
||||
contentType1.Alias = "newAlias";
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
|
||||
|
||||
foreach (var c in contentItems1)
|
||||
{
|
||||
var xml = DatabaseContext.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = c.Id });
|
||||
Assert.IsNotNull(xml);
|
||||
Assert.IsTrue(xml.Xml.StartsWith("<newAlias"));
|
||||
}
|
||||
|
||||
foreach (var c in contentItems2)
|
||||
{
|
||||
var xml = DatabaseContext.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = c.Id });
|
||||
@@ -79,19 +80,20 @@ namespace Umbraco.Tests.Services
|
||||
[Test]
|
||||
public void Rebuild_Content_Xml_On_Property_Removal()
|
||||
{
|
||||
var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "Test1");
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "Test1");
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
var contentItems1 = MockedContent.CreateTextpageContent(contentType1, -1, 10).ToArray();
|
||||
contentItems1.ForEach(x => ServiceContext.ContentService.SaveAndPublish(x));
|
||||
contentItems1.ForEach(x => ServiceContext.ContentService.SaveAndPublishWithStatus(x));
|
||||
var alias = contentType1.PropertyTypes.First().Alias;
|
||||
var elementToMatch = "<" + alias + ">";
|
||||
|
||||
foreach (var c in contentItems1)
|
||||
{
|
||||
var xml = DatabaseContext.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = c.Id });
|
||||
Assert.IsNotNull(xml);
|
||||
Assert.IsTrue(xml.Xml.Contains(elementToMatch)); //verify that it is there before we remove the property
|
||||
}
|
||||
|
||||
|
||||
//remove a property
|
||||
contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias);
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
@@ -107,21 +109,21 @@ namespace Umbraco.Tests.Services
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Descendants()
|
||||
{
|
||||
// Arrange
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var hierarchy = CreateContentTypeHierarchy();
|
||||
[Test]
|
||||
public void Get_Descendants()
|
||||
{
|
||||
// Arrange
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var hierarchy = CreateContentTypeHierarchy();
|
||||
contentTypeService.Save(hierarchy, 0); //ensure they are saved!
|
||||
var master = hierarchy.First();
|
||||
|
||||
//Act
|
||||
var descendants = master.Descendants();
|
||||
var descendants = master.Descendants();
|
||||
|
||||
//Assert
|
||||
Assert.AreEqual(10, descendants.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Descendants_And_Self()
|
||||
@@ -139,67 +141,97 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreEqual(11, descendants.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Bulk_Save_New_Hierarchy_Content_Types()
|
||||
{
|
||||
// Arrange
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var hierarchy = CreateContentTypeHierarchy();
|
||||
[Test]
|
||||
public void Can_Bulk_Save_New_Hierarchy_Content_Types()
|
||||
{
|
||||
// Arrange
|
||||
var contentTypeService = ServiceContext.ContentTypeService;
|
||||
var hierarchy = CreateContentTypeHierarchy();
|
||||
|
||||
// Act
|
||||
contentTypeService.Save(hierarchy, 0);
|
||||
// Act
|
||||
contentTypeService.Save(hierarchy, 0);
|
||||
|
||||
Assert.That(hierarchy.Any(), Is.True);
|
||||
Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False);
|
||||
//all parent id's should be ok, they are lazy and if they equal zero an exception will be thrown
|
||||
Assert.DoesNotThrow(() => hierarchy.Any(x => x.ParentId != 0));
|
||||
for (var i = 0; i < hierarchy.Count(); i++)
|
||||
{
|
||||
if (i == 0) continue;
|
||||
Assert.AreEqual(hierarchy.ElementAt(i).ParentId, hierarchy.ElementAt(i - 1).Id);
|
||||
}
|
||||
}
|
||||
Assert.That(hierarchy.Any(), Is.True);
|
||||
Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False);
|
||||
//all parent id's should be ok, they are lazy and if they equal zero an exception will be thrown
|
||||
Assert.DoesNotThrow(() => hierarchy.Any(x => x.ParentId != 0));
|
||||
for (var i = 0; i < hierarchy.Count(); i++)
|
||||
{
|
||||
if (i == 0) continue;
|
||||
Assert.AreEqual(hierarchy.ElementAt(i).ParentId, hierarchy.ElementAt(i - 1).Id);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Save_ContentType_Structure_And_Create_Content_Based_On_It()
|
||||
{
|
||||
// Arrange
|
||||
var cs = ServiceContext.ContentService;
|
||||
var cts = ServiceContext.ContentTypeService;
|
||||
var dtdYesNo = ServiceContext.DataTypeService.GetDataTypeDefinitionById(-49);
|
||||
var ctBase = new ContentType(-1) {Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png"};
|
||||
ctBase.AddPropertyType(new PropertyType(dtdYesNo)
|
||||
{
|
||||
Name = "Hide From Navigation",
|
||||
Alias = Constants.Conventions.Content.NaviHide
|
||||
}
|
||||
/*,"Navigation"*/);
|
||||
cts.Save(ctBase);
|
||||
[Test]
|
||||
public void Can_Save_ContentType_Structure_And_Create_Content_Based_On_It()
|
||||
{
|
||||
// Arrange
|
||||
var cs = ServiceContext.ContentService;
|
||||
var cts = ServiceContext.ContentTypeService;
|
||||
var dtdYesNo = ServiceContext.DataTypeService.GetDataTypeDefinitionById(-49);
|
||||
var ctBase = new ContentType(-1) { Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png" };
|
||||
ctBase.AddPropertyType(new PropertyType(dtdYesNo)
|
||||
{
|
||||
Name = "Hide From Navigation",
|
||||
Alias = Constants.Conventions.Content.NaviHide
|
||||
}
|
||||
/*,"Navigation"*/);
|
||||
cts.Save(ctBase);
|
||||
|
||||
var ctHomePage = new ContentType(ctBase)
|
||||
{
|
||||
Name = "Home Page",
|
||||
Alias = "HomePage",
|
||||
Icon = "settingDomain.gif",
|
||||
Thumbnail = "folder.png",
|
||||
AllowedAsRoot = true
|
||||
};
|
||||
ctHomePage.AddPropertyType(new PropertyType(dtdYesNo) {Name = "Some property", Alias = "someProperty"}
|
||||
/*,"Navigation"*/);
|
||||
cts.Save(ctHomePage);
|
||||
var ctHomePage = new ContentType(ctBase)
|
||||
{
|
||||
Name = "Home Page",
|
||||
Alias = "HomePage",
|
||||
Icon = "settingDomain.gif",
|
||||
Thumbnail = "folder.png",
|
||||
AllowedAsRoot = true
|
||||
};
|
||||
ctHomePage.AddPropertyType(new PropertyType(dtdYesNo) { Name = "Some property", Alias = "someProperty" }
|
||||
/*,"Navigation"*/);
|
||||
cts.Save(ctHomePage);
|
||||
|
||||
// Act
|
||||
var homeDoc = cs.CreateContent("Home Page", -1, "HomePage");
|
||||
cs.SaveAndPublish(homeDoc);
|
||||
// Act
|
||||
var homeDoc = cs.CreateContent("Home Page", -1, "HomePage");
|
||||
cs.SaveAndPublishWithStatus(homeDoc);
|
||||
|
||||
// Assert
|
||||
Assert.That(ctBase.HasIdentity, Is.True);
|
||||
Assert.That(ctHomePage.HasIdentity, Is.True);
|
||||
Assert.That(homeDoc.HasIdentity, Is.True);
|
||||
Assert.That(homeDoc.ContentTypeId, Is.EqualTo(ctHomePage.Id));
|
||||
}
|
||||
// Assert
|
||||
Assert.That(ctBase.HasIdentity, Is.True);
|
||||
Assert.That(ctHomePage.HasIdentity, Is.True);
|
||||
Assert.That(homeDoc.HasIdentity, Is.True);
|
||||
Assert.That(homeDoc.ContentTypeId, Is.EqualTo(ctHomePage.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test]
|
||||
public void Create_Content_Type_Ensures_Sort_Orders()
|
||||
{
|
||||
var service = ServiceContext.ContentTypeService;
|
||||
|
||||
var contentType = new ContentType(-1)
|
||||
{
|
||||
Alias = "test",
|
||||
Name = "Test",
|
||||
Description = "ContentType used for simple text pages",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc2.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
|
||||
contentType.AddPropertyType(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, DataTypeDefinitionId = -88 });
|
||||
contentType.AddPropertyType(new PropertyType(Constants.PropertyEditors.TinyMCEAlias, DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, DataTypeDefinitionId = -87 });
|
||||
contentType.AddPropertyType(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", Mandatory = false, DataTypeDefinitionId = -88 });
|
||||
|
||||
service.Save(contentType);
|
||||
|
||||
var sortOrders = contentType.PropertyTypes.Select(x => x.SortOrder).ToArray();
|
||||
|
||||
Assert.AreEqual(1, sortOrders.Count(x => x == 0));
|
||||
Assert.AreEqual(1, sortOrders.Count(x => x == 1));
|
||||
Assert.AreEqual(1, sortOrders.Count(x => x == 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_And_Save_ContentType_Composition()
|
||||
{
|
||||
/*
|
||||
@@ -266,9 +298,9 @@ namespace Umbraco.Tests.Services
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Copy_ContentType_By_Performing_Clone()
|
||||
{
|
||||
// Arrange
|
||||
public void Can_Copy_ContentType_By_Performing_Clone()
|
||||
{
|
||||
// Arrange
|
||||
var service = ServiceContext.ContentTypeService;
|
||||
var metaContentType = MockedContentTypes.CreateMetaContentType();
|
||||
service.Save(metaContentType);
|
||||
@@ -278,7 +310,7 @@ namespace Umbraco.Tests.Services
|
||||
var categoryId = simpleContentType.Id;
|
||||
|
||||
// Act
|
||||
var sut = simpleContentType.Clone("newcategory");
|
||||
var sut = simpleContentType.DeepCloneWithResetIdentities("newcategory");
|
||||
service.Save(sut);
|
||||
|
||||
// Assert
|
||||
@@ -297,25 +329,24 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreNotEqual(contentType.SortOrder, category.SortOrder);
|
||||
Assert.AreNotEqual(contentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, category.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
|
||||
Assert.AreNotEqual(contentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, category.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Copy_ContentType_To_New_Parent_By_Performing_Clone()
|
||||
{
|
||||
// Arrange
|
||||
var service = ServiceContext.ContentTypeService;
|
||||
|
||||
|
||||
var parentContentType1 = MockedContentTypes.CreateSimpleContentType("parent1", "Parent1");
|
||||
service.Save(parentContentType1);
|
||||
var parentContentType2 = MockedContentTypes.CreateSimpleContentType("parent2", "Parent2");
|
||||
service.Save(parentContentType2);
|
||||
|
||||
|
||||
var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1);
|
||||
service.Save(simpleContentType);
|
||||
|
||||
// Act
|
||||
var clone = simpleContentType.Clone("newcategory");
|
||||
var clone = simpleContentType.DeepCloneWithResetIdentities("newcategory");
|
||||
clone.RemoveContentType("parent1");
|
||||
clone.AddContentType(parentContentType2);
|
||||
clone.ParentId = parentContentType2.Id;
|
||||
@@ -332,7 +363,7 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
Assert.AreEqual(clonedContentType.Path, "-1," + parentContentType2.Id + "," + clonedContentType.Id);
|
||||
Assert.AreEqual(clonedContentType.PropertyTypes.Count(), originalContentType.PropertyTypes.Count());
|
||||
|
||||
|
||||
Assert.AreNotEqual(clonedContentType.ParentId, originalContentType.ParentId);
|
||||
Assert.AreEqual(clonedContentType.ParentId, parentContentType2.Id);
|
||||
|
||||
@@ -342,7 +373,6 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
Assert.AreNotEqual(clonedContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, originalContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
|
||||
Assert.AreNotEqual(clonedContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, originalContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -366,12 +396,12 @@ namespace Umbraco.Tests.Services
|
||||
var cloned = service.GetContentType(clone.Id);
|
||||
var original = service.GetContentType(categoryId);
|
||||
|
||||
|
||||
Assert.That(cloned.CompositionAliases().Any(x => x.Equals("meta")), Is.False); //it's been copied to root
|
||||
Assert.AreEqual(cloned.ParentId, -1);
|
||||
Assert.AreEqual(cloned.Level, 1);
|
||||
Assert.AreEqual(cloned.PropertyTypes.Count(), original.PropertyTypes.Count());
|
||||
Assert.AreEqual(cloned.PropertyGroups.Count(), original.PropertyGroups.Count());
|
||||
|
||||
for (int i = 0; i < cloned.PropertyGroups.Count; i++)
|
||||
{
|
||||
Assert.AreEqual(cloned.PropertyGroups[i].PropertyTypes.Count, original.PropertyGroups[i].PropertyTypes.Count);
|
||||
@@ -380,17 +410,18 @@ namespace Umbraco.Tests.Services
|
||||
Assert.IsTrue(propertyType.HasIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyType in cloned.PropertyTypes)
|
||||
{
|
||||
Assert.IsTrue(propertyType.HasIdentity);
|
||||
}
|
||||
|
||||
Assert.AreNotEqual(cloned.Id, original.Id);
|
||||
Assert.AreNotEqual(cloned.Key, original.Key);
|
||||
Assert.AreNotEqual(cloned.Path, original.Path);
|
||||
Assert.AreNotEqual(cloned.SortOrder, original.SortOrder);
|
||||
Assert.AreNotEqual(cloned.PropertyTypes.First(x => x.Alias.Equals("title")).Id, original.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
|
||||
Assert.AreNotEqual(cloned.PropertyGroups.First(x => x.Name.Equals("Content")).Id, original.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -431,22 +462,21 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
Assert.AreNotEqual(clonedContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, originalContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
|
||||
Assert.AreNotEqual(clonedContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, originalContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
|
||||
|
||||
}
|
||||
|
||||
private ContentType CreateComponent()
|
||||
{
|
||||
var component = new ContentType(-1)
|
||||
{
|
||||
Alias = "component",
|
||||
Name = "Component",
|
||||
Description = "ContentType used for Component grouping",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
{
|
||||
Alias = "component",
|
||||
Name = "Component",
|
||||
Description = "ContentType used for Component grouping",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
|
||||
var contentCollection = new PropertyTypeCollection();
|
||||
contentCollection.Add(new PropertyType("test", DataTypeDatabaseType.Ntext) { Alias = "componentGroup", Name = "Component Group", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
|
||||
@@ -458,27 +488,26 @@ namespace Umbraco.Tests.Services
|
||||
private ContentType CreateBannerComponent(ContentType parent)
|
||||
{
|
||||
var banner = new ContentType(parent)
|
||||
{
|
||||
Alias = "banner",
|
||||
Name = "Banner Component",
|
||||
Description = "ContentType used for Banner Component",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
{
|
||||
Alias = "banner",
|
||||
Name = "Banner Component",
|
||||
Description = "ContentType used for Banner Component",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
|
||||
var propertyType = new PropertyType("test", DataTypeDatabaseType.Ntext)
|
||||
{
|
||||
Alias = "bannerName",
|
||||
Name = "Banner Name",
|
||||
Description = "",
|
||||
HelpText = "",
|
||||
Mandatory = false,
|
||||
SortOrder = 2,
|
||||
DataTypeDefinitionId = -88
|
||||
};
|
||||
{
|
||||
Alias = "bannerName",
|
||||
Name = "Banner Name",
|
||||
Description = "",
|
||||
Mandatory = false,
|
||||
SortOrder = 2,
|
||||
DataTypeDefinitionId = -88
|
||||
};
|
||||
banner.AddPropertyType(propertyType, "Component");
|
||||
return banner;
|
||||
}
|
||||
@@ -486,16 +515,16 @@ namespace Umbraco.Tests.Services
|
||||
private ContentType CreateSite()
|
||||
{
|
||||
var site = new ContentType(-1)
|
||||
{
|
||||
Alias = "site",
|
||||
Name = "Site",
|
||||
Description = "ContentType used for Site inheritence",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 2,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
{
|
||||
Alias = "site",
|
||||
Name = "Site",
|
||||
Description = "ContentType used for Site inheritence",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 2,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
|
||||
var contentCollection = new PropertyTypeCollection();
|
||||
contentCollection.Add(new PropertyType("test", DataTypeDatabaseType.Ntext) { Alias = "hostname", Name = "Hostname", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
|
||||
@@ -507,16 +536,16 @@ namespace Umbraco.Tests.Services
|
||||
private ContentType CreateHomepage(ContentType parent)
|
||||
{
|
||||
var contentType = new ContentType(parent)
|
||||
{
|
||||
Alias = "homepage",
|
||||
Name = "Homepage",
|
||||
Description = "ContentType used for the Homepage",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
{
|
||||
Alias = "homepage",
|
||||
Name = "Homepage",
|
||||
Description = "ContentType used for the Homepage",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
|
||||
var contentCollection = new PropertyTypeCollection();
|
||||
contentCollection.Add(new PropertyType("test", DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
|
||||
@@ -528,26 +557,26 @@ namespace Umbraco.Tests.Services
|
||||
return contentType;
|
||||
}
|
||||
|
||||
private IContentType[] CreateContentTypeHierarchy()
|
||||
{
|
||||
//create the master type
|
||||
var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType");
|
||||
masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE");
|
||||
ServiceContext.ContentTypeService.Save(masterContentType);
|
||||
private IContentType[] CreateContentTypeHierarchy()
|
||||
{
|
||||
//create the master type
|
||||
var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType");
|
||||
masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE");
|
||||
ServiceContext.ContentTypeService.Save(masterContentType);
|
||||
|
||||
//add the one we just created
|
||||
var list = new List<IContentType> {masterContentType};
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i,
|
||||
//make the last entry in the list, this one's parent
|
||||
list.Last());
|
||||
//add the one we just created
|
||||
var list = new List<IContentType> { masterContentType };
|
||||
|
||||
list.Add(contentType);
|
||||
}
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i,
|
||||
//make the last entry in the list, this one's parent
|
||||
list.Last());
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
||||
list.Add(contentType);
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,6 +138,16 @@ namespace Umbraco.Tests.Services
|
||||
&& ((UmbracoEntity.EntityProperty)y.Value).PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias)), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_ObjectType()
|
||||
{
|
||||
var service = ServiceContext.EntityService;
|
||||
var mediaObjectType = service.GetObjectType(1031);
|
||||
|
||||
Assert.NotNull(mediaObjectType);
|
||||
Assert.AreEqual(mediaObjectType, UmbracoObjectTypes.MediaType);
|
||||
}
|
||||
|
||||
private static bool _isSetup = false;
|
||||
|
||||
public override void CreateTestData()
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Services
|
||||
@@ -8,10 +12,17 @@ namespace Umbraco.Tests.Services
|
||||
/// This is more of an integration test as it involves multiple layers
|
||||
/// as well as configuration.
|
||||
/// </summary>
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerFixture)]
|
||||
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
|
||||
[TestFixture, RequiresSTA]
|
||||
public class LocalizationServiceTests : BaseServiceTest
|
||||
{
|
||||
private Guid _parentItemGuidId;
|
||||
private int _parentItemIntId;
|
||||
private Guid _childItemGuidId;
|
||||
private int _childItemIntId;
|
||||
private int _danishLangId;
|
||||
private int _englishLangId;
|
||||
|
||||
[SetUp]
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -23,5 +34,194 @@ namespace Umbraco.Tests.Services
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_Root_Dictionary_Items()
|
||||
{
|
||||
var rootItems = ServiceContext.LocalizationService.GetRootDictionaryItems();
|
||||
|
||||
Assert.NotNull(rootItems);
|
||||
Assert.IsTrue(rootItems.Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Determint_If_DictionaryItem_Exists()
|
||||
{
|
||||
var exists = ServiceContext.LocalizationService.DictionaryItemExists("Parent");
|
||||
Assert.IsTrue(exists);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_All_Languages()
|
||||
{
|
||||
var languages = ServiceContext.LocalizationService.GetAllLanguages();
|
||||
Assert.NotNull(languages);
|
||||
Assert.IsTrue(languages.Any());
|
||||
Assert.That(languages.Count(), Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_Dictionary_Item_By_Int_Id()
|
||||
{
|
||||
var parentItem = ServiceContext.LocalizationService.GetDictionaryItemById(_parentItemIntId);
|
||||
Assert.NotNull(parentItem);
|
||||
|
||||
var childItem = ServiceContext.LocalizationService.GetDictionaryItemById(_childItemIntId);
|
||||
Assert.NotNull(childItem);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_Dictionary_Item_By_Guid_Id()
|
||||
{
|
||||
var parentItem = ServiceContext.LocalizationService.GetDictionaryItemById(_parentItemGuidId);
|
||||
Assert.NotNull(parentItem);
|
||||
|
||||
var childItem = ServiceContext.LocalizationService.GetDictionaryItemById(_childItemGuidId);
|
||||
Assert.NotNull(childItem);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_Dictionary_Item_By_Key()
|
||||
{
|
||||
var parentItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Parent");
|
||||
Assert.NotNull(parentItem);
|
||||
|
||||
var childItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child");
|
||||
Assert.NotNull(childItem);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_Dictionary_Item_Children()
|
||||
{
|
||||
var item = ServiceContext.LocalizationService.GetDictionaryItemChildren(_parentItemGuidId);
|
||||
Assert.NotNull(item);
|
||||
Assert.That(item.Count(), Is.EqualTo(1));
|
||||
|
||||
foreach (var dictionaryItem in item)
|
||||
{
|
||||
Assert.IsFalse(string.IsNullOrEmpty(dictionaryItem.ItemKey));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Get_Language_By_Culture_Code()
|
||||
{
|
||||
var danish = ServiceContext.LocalizationService.GetLanguageByCultureCode("Danish");
|
||||
var english = ServiceContext.LocalizationService.GetLanguageByCultureCode("English");
|
||||
Assert.NotNull(danish);
|
||||
Assert.NotNull(english);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_GetLanguageById()
|
||||
{
|
||||
var danish = ServiceContext.LocalizationService.GetLanguageById(_danishLangId);
|
||||
var english = ServiceContext.LocalizationService.GetLanguageById(_englishLangId);
|
||||
Assert.NotNull(danish);
|
||||
Assert.NotNull(english);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_GetLanguageByIsoCode()
|
||||
{
|
||||
var danish = ServiceContext.LocalizationService.GetLanguageByIsoCode("da-DK");
|
||||
var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-GB");
|
||||
Assert.NotNull(danish);
|
||||
Assert.NotNull(english);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Does_Not_Fail_When_Language_Doesnt_Exist()
|
||||
{
|
||||
var language = ServiceContext.LocalizationService.GetLanguageByIsoCode("sv-SE");
|
||||
Assert.Null(language);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Does_Not_Fail_When_DictionaryItem_Doesnt_Exist()
|
||||
{
|
||||
var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("RandomKey");
|
||||
Assert.Null(item);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Delete_Language()
|
||||
{
|
||||
var norwegian = new Language("nb-NO") { CultureName = "Norwegian" };
|
||||
ServiceContext.LocalizationService.Save(norwegian, 0);
|
||||
Assert.That(norwegian.HasIdentity, Is.True);
|
||||
var languageId = norwegian.Id;
|
||||
|
||||
ServiceContext.LocalizationService.Delete(norwegian);
|
||||
|
||||
var language = ServiceContext.LocalizationService.GetLanguageById(languageId);
|
||||
Assert.Null(language);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Delete_DictionaryItem()
|
||||
{
|
||||
var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child");
|
||||
Assert.NotNull(item);
|
||||
|
||||
ServiceContext.LocalizationService.Delete(item);
|
||||
|
||||
var deletedItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child");
|
||||
Assert.Null(deletedItem);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LocalizationService_Can_Update_Existing_DictionaryItem()
|
||||
{
|
||||
var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child");
|
||||
foreach (var translation in item.Translations)
|
||||
{
|
||||
translation.Value = translation.Value + "UPDATED";
|
||||
}
|
||||
|
||||
ServiceContext.LocalizationService.Save(item);
|
||||
|
||||
var updatedItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child");
|
||||
Assert.NotNull(updatedItem);
|
||||
|
||||
foreach (var translation in updatedItem.Translations)
|
||||
{
|
||||
Assert.That(translation.Value.EndsWith("UPDATED"), Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
public override void CreateTestData()
|
||||
{
|
||||
var danish = new Language("da-DK") { CultureName = "Danish" };
|
||||
var english = new Language("en-GB") { CultureName = "English"};
|
||||
ServiceContext.LocalizationService.Save(danish, 0);
|
||||
ServiceContext.LocalizationService.Save(english, 0);
|
||||
_danishLangId = danish.Id;
|
||||
_englishLangId = english.Id;
|
||||
|
||||
var parentItem = new DictionaryItem("Parent")
|
||||
{
|
||||
Translations = new List<IDictionaryTranslation>
|
||||
{
|
||||
new DictionaryTranslation(english, "ParentValue"),
|
||||
new DictionaryTranslation(danish, "ForældreVærdi")
|
||||
}
|
||||
};
|
||||
ServiceContext.LocalizationService.Save(parentItem);
|
||||
_parentItemGuidId = parentItem.Key;
|
||||
_parentItemIntId = parentItem.Id;
|
||||
|
||||
var childItem = new DictionaryItem(parentItem.Key, "Child")
|
||||
{
|
||||
Translations = new List<IDictionaryTranslation>
|
||||
{
|
||||
new DictionaryTranslation(english, "ChildValue"),
|
||||
new DictionaryTranslation(danish, "BørnVærdi")
|
||||
}
|
||||
};
|
||||
ServiceContext.LocalizationService.Save(childItem);
|
||||
_childItemGuidId = childItem.Key;
|
||||
_childItemIntId = childItem.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"typeahead.js": "~0.10.2"
|
||||
"typeahead.js": "~0.10.2",
|
||||
"ace-builds": "~1.1.3",
|
||||
"rgrove-lazyload": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ module.exports = function (grunt) {
|
||||
grunt.registerTask('dev', ['jshint:dev', 'build', 'webserver', 'open:dev', 'watch']);
|
||||
|
||||
//run by the watch task
|
||||
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:vs','karma:unit']);
|
||||
grunt.registerTask('watch-less', ['recess:build','recess:installer','copy:assets','copy:vs']);
|
||||
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:tuning','copy:vs','karma:unit']);
|
||||
grunt.registerTask('watch-less', ['recess:build', 'recess:installer', 'recess:tuning','copy:tuning', 'copy:assets', 'copy:vs']);
|
||||
grunt.registerTask('watch-html', ['copy:views', 'copy:vs']);
|
||||
grunt.registerTask('watch-packages', ['copy:packages']);
|
||||
grunt.registerTask('watch-installer', ['concat:install','concat:installJs','copy:installer', 'copy:vs']);
|
||||
grunt.registerTask('watch-installer', ['concat:install', 'concat:installJs', 'copy:installer', 'copy:vs']);
|
||||
grunt.registerTask('watch-tuning', ['copy:tuning', 'concat:tuningJs', 'copy:vs']);
|
||||
grunt.registerTask('watch-test', ['jshint:dev', 'karma:unit']);
|
||||
|
||||
//triggered from grunt dev or grunt
|
||||
grunt.registerTask('build', ['clean','concat','recess:min','recess:installer','copy']);
|
||||
grunt.registerTask('build', ['clean', 'concat', 'recess:min', 'recess:installer', 'recess:tuning', 'bower', 'copy']);
|
||||
|
||||
//utillity tasks
|
||||
grunt.registerTask('docs', ['ngdocs']);
|
||||
@@ -109,23 +110,48 @@ module.exports = function (grunt) {
|
||||
clean: ['<%= distdir %>/*'],
|
||||
|
||||
copy: {
|
||||
|
||||
/* Copies over the files downloaded by bower
|
||||
bower: {
|
||||
files: [
|
||||
{ dest: '<%= distdir %>/lib/typeahead/typeahead.bundle.min.js', src: '<%= bowerfiles %>/typeahead.js/dist/typeahead.bundle.min.js' }
|
||||
]
|
||||
},
|
||||
*/
|
||||
|
||||
assets: {
|
||||
files: [{ dest: '<%= distdir %>/assets', src : '**', expand: true, cwd: 'src/assets/' }]
|
||||
},
|
||||
|
||||
|
||||
// Copies over the files downloaded by bower
|
||||
bower: {
|
||||
files: [
|
||||
{
|
||||
dest: '<%= distdir %>/lib/typeahead/typeahead.bundle.min.js',
|
||||
src: 'bower_components/typeahead.js/dist/typeahead.bundle.min.js'
|
||||
},
|
||||
{
|
||||
dest: '<%= distdir %>/lib/lazyload/lazyload.min.js',
|
||||
src: 'bower_components/rgrove-lazyload/lazyload.js'
|
||||
},
|
||||
{
|
||||
dest: '<%= distdir %>/lib/ace/',
|
||||
src: '**',
|
||||
expand: true,
|
||||
cwd: 'bower_components/ace-builds/src-min-noconflict/'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
installer: {
|
||||
files: [{ dest: '<%= distdir %>/views/install', src : '**/*.html', expand: true, cwd: 'src/installer/steps' }]
|
||||
},
|
||||
|
||||
tuning: {
|
||||
files: [
|
||||
{ dest: '<%= distdir %>/preview', src: '**/*.html', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/assets/css', src: 'tuning.defaultStyle.css', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/assets/less', src: 'tuning.defaultStyle.less', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/assets/less', src: 'tuning.gridRowStyle.less', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/js', src: 'tuning.config.js', expand: true, cwd: 'src/tuning/config' },
|
||||
{ dest: '<%= distdir %>/js', src: 'tuning.palettes.js', expand: true, cwd: 'src/tuning/config' },
|
||||
{ dest: '<%= distdir %>/js', src: 'tuning.front.js', expand: true, cwd: 'src/tuning' }
|
||||
]
|
||||
},
|
||||
|
||||
vendor: {
|
||||
files: [{ dest: '<%= distdir %>/lib', src : '**', expand: true, cwd: 'lib/' }]
|
||||
},
|
||||
@@ -147,7 +173,8 @@ module.exports = function (grunt) {
|
||||
{ dest: '<%= vsdir %>/assets', src: '**', expand: true, cwd: '<%= distdir %>/assets' },
|
||||
{ dest: '<%= vsdir %>/js', src: '**', expand: true, cwd: '<%= distdir %>/js' },
|
||||
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' },
|
||||
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' }
|
||||
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' },
|
||||
{ dest: '<%= vsdir %>/preview', src: '**', expand: true, cwd: '<%= distdir %>/preview' }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -186,6 +213,10 @@ module.exports = function (grunt) {
|
||||
footer: "\n\n})();"
|
||||
}
|
||||
},
|
||||
tuningJs: {
|
||||
src: ['src/tuning/tuning.global.js', 'src/tuning/tuning.controller.js', 'src/tuning/lib/slider.directive.js', 'src/tuning/lib/spectrum.directive.js'],
|
||||
dest: '<%= distdir %>/js/tuning.panel.js'
|
||||
},
|
||||
controllers: {
|
||||
src:['src/controllers/**/*.controller.js','src/views/**/*.controller.js'],
|
||||
dest: '<%= distdir %>/js/umbraco.controllers.js',
|
||||
@@ -272,6 +303,15 @@ module.exports = function (grunt) {
|
||||
compile: true
|
||||
}
|
||||
},
|
||||
tuning: {
|
||||
files: {
|
||||
'<%= distdir %>/assets/css/tuning.panelStyles.css':
|
||||
['src/less/tuning.panelStyles.less', 'src/less/helveticons.less']
|
||||
},
|
||||
options: {
|
||||
compile: true
|
||||
}
|
||||
},
|
||||
min: {
|
||||
files: {
|
||||
'<%= distdir %>/assets/css/<%= pkg.name %>.css': ['<%= src.less %>']
|
||||
@@ -304,6 +344,10 @@ module.exports = function (grunt) {
|
||||
files: ['src/installer/**/*.*'],
|
||||
tasks: ['watch-installer', 'timestamp'],
|
||||
},
|
||||
tuning: {
|
||||
files: ['src/tuning/**/*.*'],
|
||||
tasks: ['watch-tuning', 'timestamp'],
|
||||
},
|
||||
html: {
|
||||
files: ['src/views/**/*.html', 'src/*.html'],
|
||||
tasks:['watch-html','timestamp']
|
||||
|
||||
+9
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
|
||||
// Inline and block code styles
|
||||
code,
|
||||
pre {
|
||||
pre.code {
|
||||
padding: 0 3px 2px;
|
||||
#font > #family > .monospace;
|
||||
font-size: @baseFontSize - 2;
|
||||
@@ -23,7 +23,7 @@ code {
|
||||
}
|
||||
|
||||
// Blocks of code
|
||||
pre {
|
||||
pre.code {
|
||||
display: block;
|
||||
padding: (@baseLineHeight - 1) / 2;
|
||||
margin: 0 0 @baseLineHeight / 2;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +0,0 @@
|
||||
LazyLoad=function(x,h){function r(b,a){var c=h.createElement(b),d;for(d in a)a.hasOwnProperty(d)&&c.setAttribute(d,a[d]);return c}function k(b){var a=i[b],c,d;if(a){c=a.callback;d=a.urls;d.shift();l=0;if(!d.length){c&&c.call(a.context,a.obj);i[b]=null;j[b].length&&m(b)}}}function w(){if(!e){var b=navigator.userAgent;e={async:h.createElement("script").async===true};(e.webkit=/AppleWebKit\//.test(b))||(e.ie=/MSIE/.test(b))||(e.opera=/Opera/.test(b))||(e.gecko=/Gecko\//.test(b))||(e.unknown=true)}}function m(b,
|
||||
a,c,d,s){var n=function(){k(b)},o=b==="css",f,g,p;w();if(a){a=typeof a==="string"?[a]:a.concat();if(o||e.async||e.gecko||e.opera)j[b].push({urls:a,callback:c,obj:d,context:s});else{f=0;for(g=a.length;f<g;++f)j[b].push({urls:[a[f]],callback:f===g-1?c:null,obj:d,context:s})}}if(!(i[b]||!(p=i[b]=j[b].shift()))){q||(q=h.head||h.getElementsByTagName("head")[0]);a=p.urls;f=0;for(g=a.length;f<g;++f){c=a[f];if(o)c=r("link",{charset:"utf-8","class":"lazyload",href:c,rel:"stylesheet",type:"text/css"});else{c=
|
||||
r("script",{charset:"utf-8","class":"lazyload",src:c});c.async=false}if(e.ie)c.onreadystatechange=function(){var t=this.readyState;if(t==="loaded"||t==="complete"){this.onreadystatechange=null;n()}};else if(o&&(e.gecko||e.webkit))if(e.webkit){p.urls[f]=c.href;u()}else setTimeout(n,50*g);else c.onload=c.onerror=n;q.appendChild(c)}}}function u(){var b=i.css,a;if(b){for(a=v.length;a&&--a;)if(v[a].href===b.urls[0]){k("css");break}l+=1;if(b)l<200?setTimeout(u,50):k("css")}}var e,q,i={},l=0,j={css:[],js:[]},
|
||||
v=h.styleSheets;return{css:function(b,a,c,d){m("css",b,a,c,d)},js:function(b,a,c,d){m("js",b,a,c,d)}}}(this,this.document);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -335,6 +335,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
|
||||
this._modal.push(dialog);
|
||||
return dialog;
|
||||
},
|
||||
rootScope : function(){
|
||||
return getRootScope();
|
||||
},
|
||||
|
||||
closeModalWindow: function(rVal) {
|
||||
|
||||
//get our angular navigation service
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 763 KiB After Width: | Height: | Size: 116 KiB |
@@ -0,0 +1,269 @@
|
||||
angular.module('umbraco')
|
||||
.constant('uiAceConfig', {})
|
||||
.directive('uiAce', ['uiAceConfig', function (uiAceConfig) {
|
||||
|
||||
if (angular.isUndefined(window.ace)) {
|
||||
throw new Error('ui-ace need ace to work... (o rly?)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets editor options such as the wrapping mode or the syntax checker.
|
||||
*
|
||||
* The supported options are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>showGutter</li>
|
||||
* <li>useWrapMode</li>
|
||||
* <li>onLoad</li>
|
||||
* <li>theme</li>
|
||||
* <li>mode</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param acee
|
||||
* @param session ACE editor session
|
||||
* @param {object} opts Options to be set
|
||||
*/
|
||||
var setOptions = function(acee, session, opts) {
|
||||
|
||||
// Boolean options
|
||||
if (angular.isDefined(opts.showGutter)) {
|
||||
acee.renderer.setShowGutter(opts.showGutter);
|
||||
}
|
||||
if (angular.isDefined(opts.useWrapMode)) {
|
||||
session.setUseWrapMode(opts.useWrapMode);
|
||||
}
|
||||
if (angular.isDefined(opts.showInvisibles)) {
|
||||
acee.renderer.setShowInvisibles(opts.showInvisibles);
|
||||
}
|
||||
if (angular.isDefined(opts.showIndentGuides)) {
|
||||
acee.renderer.setDisplayIndentGuides(opts.showIndentGuides);
|
||||
}
|
||||
if (angular.isDefined(opts.useSoftTabs)) {
|
||||
session.setUseSoftTabs(opts.useSoftTabs);
|
||||
}
|
||||
|
||||
// commands
|
||||
if (angular.isDefined(opts.disableSearch) && opts.disableSearch) {
|
||||
acee.commands.addCommands([
|
||||
{
|
||||
name: 'unfind',
|
||||
bindKey: {
|
||||
win: 'Ctrl-F',
|
||||
mac: 'Command-F'
|
||||
},
|
||||
exec: function () {
|
||||
return false;
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// onLoad callback
|
||||
if (angular.isFunction(opts.onLoad)) {
|
||||
opts.onLoad(acee);
|
||||
}
|
||||
|
||||
// Basic options
|
||||
if (angular.isString(opts.theme)) {
|
||||
acee.setTheme('ace/theme/' + opts.theme);
|
||||
}
|
||||
if (angular.isString(opts.mode)) {
|
||||
session.setMode('ace/mode/' + opts.mode);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
require: '?ngModel',
|
||||
link: function (scope, elm, attrs, ngModel) {
|
||||
|
||||
/**
|
||||
* Corresponds the uiAceConfig ACE configuration.
|
||||
* @type object
|
||||
*/
|
||||
var options = uiAceConfig.ace || {};
|
||||
|
||||
/**
|
||||
* uiAceConfig merged with user options via json in attribute or data binding
|
||||
* @type object
|
||||
*/
|
||||
var opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
|
||||
|
||||
/**
|
||||
* ACE editor
|
||||
* @type object
|
||||
*/
|
||||
var acee = window.ace.edit(elm[0]);
|
||||
|
||||
/**
|
||||
* ACE editor session.
|
||||
* @type object
|
||||
* @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
|
||||
*/
|
||||
var session = acee.getSession();
|
||||
|
||||
/**
|
||||
* Reference to a change listener created by the listener factory.
|
||||
* @function
|
||||
* @see listenerFactory.onChange
|
||||
*/
|
||||
var onChangeListener;
|
||||
|
||||
/**
|
||||
* Reference to a blur listener created by the listener factory.
|
||||
* @function
|
||||
* @see listenerFactory.onBlur
|
||||
*/
|
||||
var onBlurListener;
|
||||
|
||||
/**
|
||||
* Calls a callback by checking its existing. The argument list
|
||||
* is variable and thus this function is relying on the arguments
|
||||
* object.
|
||||
* @throws {Error} If the callback isn't a function
|
||||
*/
|
||||
var executeUserCallback = function () {
|
||||
|
||||
/**
|
||||
* The callback function grabbed from the array-like arguments
|
||||
* object. The first argument should always be the callback.
|
||||
*
|
||||
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
|
||||
* @type {*}
|
||||
*/
|
||||
var callback = arguments[0];
|
||||
|
||||
/**
|
||||
* Arguments to be passed to the callback. These are taken
|
||||
* from the array-like arguments object. The first argument
|
||||
* is stripped because that should be the callback function.
|
||||
*
|
||||
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
|
||||
* @type {Array}
|
||||
*/
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
if (angular.isDefined(callback)) {
|
||||
scope.$apply(function () {
|
||||
if (angular.isFunction(callback)) {
|
||||
callback(args);
|
||||
} else {
|
||||
throw new Error('ui-ace use a function as callback.');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listener factory. Until now only change listeners can be created.
|
||||
* @type object
|
||||
*/
|
||||
var listenerFactory = {
|
||||
/**
|
||||
* Creates a change listener which propagates the change event
|
||||
* and the editor session to the callback from the user option
|
||||
* onChange. It might be exchanged during runtime, if this
|
||||
* happens the old listener will be unbound.
|
||||
*
|
||||
* @param callback callback function defined in the user options
|
||||
* @see onChangeListener
|
||||
*/
|
||||
onChange: function (callback) {
|
||||
return function (e) {
|
||||
var newValue = session.getValue();
|
||||
if (newValue !== scope.$eval(attrs.value) && !scope.$$phase && !scope.$root.$$phase) {
|
||||
if (angular.isDefined(ngModel)) {
|
||||
scope.$apply(function () {
|
||||
ngModel.$setViewValue(newValue);
|
||||
});
|
||||
}
|
||||
executeUserCallback(callback, e, acee);
|
||||
}
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Creates a blur listener which propagates the editor session
|
||||
* to the callback from the user option onBlur. It might be
|
||||
* exchanged during runtime, if this happens the old listener
|
||||
* will be unbound.
|
||||
*
|
||||
* @param callback callback function defined in the user options
|
||||
* @see onBlurListener
|
||||
*/
|
||||
onBlur: function (callback) {
|
||||
return function () {
|
||||
executeUserCallback(callback, acee);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
attrs.$observe('readonly', function (value) {
|
||||
acee.setReadOnly(value === 'true');
|
||||
});
|
||||
|
||||
// Value Blind
|
||||
if (angular.isDefined(ngModel)) {
|
||||
ngModel.$formatters.push(function (value) {
|
||||
if (angular.isUndefined(value) || value === null) {
|
||||
return '';
|
||||
}
|
||||
else if (angular.isObject(value) || angular.isArray(value)) {
|
||||
throw new Error('ui-ace cannot use an object or an array as a model');
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
ngModel.$render = function () {
|
||||
session.setValue(ngModel.$viewValue);
|
||||
};
|
||||
}
|
||||
|
||||
// set the options here, even if we try to watch later, if this
|
||||
// line is missing things go wrong (and the tests will also fail)
|
||||
setOptions(acee, session, opts);
|
||||
|
||||
// Listen for option updates
|
||||
scope.$watch( attrs.uiAce, function() {
|
||||
opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
|
||||
|
||||
// unbind old change listener
|
||||
session.removeListener('change', onChangeListener);
|
||||
|
||||
// bind new change listener
|
||||
onChangeListener = listenerFactory.onChange(opts.onChange);
|
||||
session.on('change', onChangeListener);
|
||||
|
||||
// unbind old blur listener
|
||||
//session.removeListener('blur', onBlurListener);
|
||||
acee.removeListener('blur', onBlurListener);
|
||||
|
||||
// bind new blur listener
|
||||
onBlurListener = listenerFactory.onBlur(opts.onBlur);
|
||||
acee.on('blur', onBlurListener);
|
||||
|
||||
setOptions(acee, session, opts);
|
||||
}, /* deep watch */ true );
|
||||
|
||||
// EVENTS
|
||||
onChangeListener = listenerFactory.onChange(opts.onChange);
|
||||
session.on('change', onChangeListener);
|
||||
|
||||
onBlurListener = listenerFactory.onBlur(opts.onBlur);
|
||||
acee.on('blur', onBlurListener);
|
||||
|
||||
elm.on('$destroy', function () {
|
||||
acee.session.$stopWorker();
|
||||
acee.destroy();
|
||||
});
|
||||
|
||||
scope.$watch(function() {
|
||||
return [elm[0].offsetWidth, elm[0].offsetHeight];
|
||||
}, function() {
|
||||
acee.resize();
|
||||
acee.renderer.updateFull();
|
||||
}, true);
|
||||
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -26,6 +26,41 @@ angular.module("umbraco.directives")
|
||||
scope.placeholder = value;
|
||||
});
|
||||
}
|
||||
|
||||
(function () {
|
||||
|
||||
var mX, mY, distance;
|
||||
|
||||
function calculateDistance(elem, mouseX, mouseY) {
|
||||
|
||||
var cx = Math.max(Math.min(mouseX, elem.offset().left + elem.width()), elem.offset().left);
|
||||
var cy = Math.max(Math.min(mouseY, elem.offset().top + elem.height()), elem.offset().top);
|
||||
return Math.sqrt((mouseX - cx) * (mouseX - cx) + (mouseY - cy) * (mouseY - cy));
|
||||
}
|
||||
|
||||
var mouseMoveDebounce = _.throttle(function (e) {
|
||||
mX = e.pageX;
|
||||
mY = e.pageY;
|
||||
// not focused and not over element
|
||||
if (!inputElement.is(":focus") && !inputElement.hasClass("ng-invalid")) {
|
||||
// on page
|
||||
if (mX >= inputElement.offset().left) {
|
||||
distance = calculateDistance(inputElement, mX, mY);
|
||||
if (distance <= 155) {
|
||||
|
||||
distance = 1 - (100 / 150 * distance / 100);
|
||||
inputElement.css("border", "1px solid rgba(175,175,175, " + distance + ")");
|
||||
inputElement.css("background-color", "rgba(255,255,255, " + distance + ")");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, 15);
|
||||
|
||||
$(document).mousemove(mouseMoveDebounce);
|
||||
|
||||
})();
|
||||
|
||||
$timeout(function(){
|
||||
if(!scope.model){
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
angular.module("umbraco")
|
||||
.directive('gridRte', function (tinyMceService, stylesheetResource, angularHelper, assetsService, $q, $timeout) {
|
||||
return {
|
||||
scope: {
|
||||
uniqueId: '=',
|
||||
value: '=',
|
||||
onClick: '&',
|
||||
onFocus: '&',
|
||||
onBlur: '&',
|
||||
configuration:"="
|
||||
},
|
||||
template: "<textarea ng-model=\"value\" rows=\"10\" class=\"mceNoEditor\" id=\"{{uniqueId}}\"></textarea>",
|
||||
replace: true,
|
||||
link: function (scope, element, attrs) {
|
||||
|
||||
var initTiny = function () {
|
||||
|
||||
//we always fetch the default one, and then override parts with our own
|
||||
tinyMceService.configuration().then(function (tinyMceConfig) {
|
||||
|
||||
|
||||
|
||||
//config value from general tinymce.config file
|
||||
var validElements = tinyMceConfig.validElements;
|
||||
var fallbackStyles = [{title: "Page header", block: "h2"}, {title: "Section header", block: "h3"}, {title: "Paragraph header", block: "h4"}, {title: "Normal", block: "p"}, {title: "Quote", block: "blockquote"}, {title: "Code", block: "code"}];
|
||||
|
||||
//These are absolutely required in order for the macros to render inline
|
||||
//we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce
|
||||
var extendedValidElements = "@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align]";
|
||||
|
||||
var invalidElements = tinyMceConfig.inValidElements;
|
||||
var plugins = _.map(tinyMceConfig.plugins, function (plugin) {
|
||||
if (plugin.useOnFrontend) {
|
||||
return plugin.name;
|
||||
}
|
||||
}).join(" ") + " autoresize";
|
||||
|
||||
//config value on the data type
|
||||
var toolbar = ["code", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbembeddialog"].join(" | ");
|
||||
var stylesheets = [];
|
||||
|
||||
var styleFormats = [];
|
||||
var await = [];
|
||||
|
||||
//queue file loading
|
||||
if (typeof (tinymce) === "undefined") {
|
||||
await.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope));
|
||||
}
|
||||
|
||||
|
||||
if(scope.configuration && scope.configuration.toolbar){
|
||||
toolbar = scope.configuration.toolbar.join(' | ');
|
||||
}
|
||||
|
||||
|
||||
if(scope.configuration && scope.configuration.stylesheets){
|
||||
angular.forEach(scope.configuration.stylesheets, function(stylesheet, key){
|
||||
|
||||
stylesheets.push("/css/" + stylesheet + ".css");
|
||||
await.push(stylesheetResource.getRulesByName(stylesheet).then(function (rules) {
|
||||
angular.forEach(rules, function (rule) {
|
||||
var r = {};
|
||||
r.title = rule.name;
|
||||
if (rule.selector[0] === ".") {
|
||||
r.inline = "span";
|
||||
r.classes = rule.selector.substring(1);
|
||||
}else if (rule.selector[0] === "#") {
|
||||
r.inline = "span";
|
||||
r.attributes = { id: rule.selector.substring(1) };
|
||||
}else {
|
||||
r.block = rule.selector;
|
||||
}
|
||||
styleFormats.push(r);
|
||||
});
|
||||
}));
|
||||
});
|
||||
}else{
|
||||
stylesheets.push("views/propertyeditors/grid/config/grid.default.rtestyles.css");
|
||||
styleFormats = fallbackStyles;
|
||||
}
|
||||
|
||||
//stores a reference to the editor
|
||||
var tinyMceEditor = null;
|
||||
$q.all(await).then(function () {
|
||||
|
||||
var uniqueId = scope.uniqueId;
|
||||
|
||||
//create a baseline Config to exten upon
|
||||
var baseLineConfigObj = {
|
||||
mode: "exact",
|
||||
skin: "umbraco",
|
||||
plugins: plugins,
|
||||
valid_elements: validElements,
|
||||
invalid_elements: invalidElements,
|
||||
extended_valid_elements: extendedValidElements,
|
||||
menubar: false,
|
||||
statusbar: false,
|
||||
relative_urls: false,
|
||||
autoresize_min_height: 30,
|
||||
toolbar: toolbar,
|
||||
content_css: stylesheets.join(','),
|
||||
style_formats: styleFormats
|
||||
};
|
||||
|
||||
|
||||
if (tinyMceConfig.customConfig) {
|
||||
angular.extend(baseLineConfigObj, tinyMceConfig.customConfig);
|
||||
}
|
||||
|
||||
//set all the things that user configs should not be able to override
|
||||
baseLineConfigObj.elements = uniqueId;
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
|
||||
//set the reference
|
||||
tinyMceEditor = editor;
|
||||
|
||||
|
||||
//enable browser based spell checking
|
||||
editor.on('init', function (e) {
|
||||
editor.getBody().setAttribute('spellcheck', true);
|
||||
|
||||
//hide toolbar by default
|
||||
$(editor.editorContainer)
|
||||
.find(".mce-toolbar")
|
||||
.css("visibility", "hidden");
|
||||
|
||||
$timeout(function(){
|
||||
if(scope.value === null){
|
||||
editor.focus();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
});
|
||||
|
||||
//when we leave the editor (maybe)
|
||||
editor.on('blur', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
|
||||
var _toolbar = $(editor.editorContainer)
|
||||
.find(".mce-toolbar");
|
||||
|
||||
if(scope.onBlur){
|
||||
scope.onBlur();
|
||||
}
|
||||
|
||||
_toolbar.css("visibility", "hidden");
|
||||
});
|
||||
});
|
||||
|
||||
// Focus on editor
|
||||
editor.on('focus', function (e) {
|
||||
angularHelper.safeApply(scope, function () {
|
||||
|
||||
var _toolbar = $(editor.editorContainer)
|
||||
.find(".mce-toolbar");
|
||||
|
||||
if(scope.onFocus){
|
||||
scope.onFocus();
|
||||
}
|
||||
|
||||
var toolbarHeight = -_toolbar.height() - 2;
|
||||
_toolbar
|
||||
.css("visibility", "visible")
|
||||
.css("margin-top", toolbarHeight + "px");
|
||||
});
|
||||
});
|
||||
|
||||
// Click on editor
|
||||
editor.on('click', function (e) {
|
||||
angularHelper.safeApply(scope, function () {
|
||||
|
||||
var _toolbar = $(editor.editorContainer)
|
||||
.find(".mce-toolbar");
|
||||
|
||||
if(scope.onClick){
|
||||
scope.onClick();
|
||||
}
|
||||
|
||||
var toolbarHeight = -_toolbar.height() - 2;
|
||||
_toolbar
|
||||
.css("visibility", "visible")
|
||||
.css("margin-top", toolbarHeight + "px");
|
||||
});
|
||||
});
|
||||
|
||||
//when buttons modify content
|
||||
editor.on('ExecCommand', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
|
||||
// Update model on keypress
|
||||
editor.on('KeyUp', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
|
||||
// Update model on change, i.e. copy/pasted text, plugins altering content
|
||||
editor.on('SetContent', function (e) {
|
||||
if (!e.initial) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('ObjectResized', function (e) {
|
||||
var qs = "?width=" + e.width + "px&height=" + e.height + "px";
|
||||
var srcAttr = $(e.target).attr("src");
|
||||
var path = srcAttr.split("?")[0];
|
||||
$(e.target).attr("data-mce-src", path + qs);
|
||||
});
|
||||
|
||||
|
||||
//Create the insert media plugin
|
||||
tinyMceService.createMediaPicker(editor, scope);
|
||||
|
||||
//Create the embedded plugin
|
||||
tinyMceService.createInsertEmbeddedMedia(editor, scope);
|
||||
|
||||
//Create the insert link plugin
|
||||
//tinyMceService.createLinkPicker(editor, scope);
|
||||
|
||||
//Create the insert macro plugin
|
||||
tinyMceService.createInsertMacro(editor, scope);
|
||||
|
||||
};
|
||||
|
||||
/** Loads in the editor */
|
||||
function loadTinyMce() {
|
||||
|
||||
//we need to add a timeout here, to force a redraw so TinyMCE can find
|
||||
//the elements needed
|
||||
$timeout(function () {
|
||||
tinymce.DOM.events.domLoaded = true;
|
||||
tinymce.init(baseLineConfigObj);
|
||||
}, 150, false);
|
||||
}
|
||||
|
||||
loadTinyMce();
|
||||
|
||||
//here we declare a special method which will be called whenever the value has changed from the server
|
||||
//this is instead of doing a watch on the model.value = faster
|
||||
//scope.model.onValueChanged = function (newVal, oldVal) {
|
||||
// //update the display val again if it has changed from the server;
|
||||
// tinyMceEditor.setContent(newVal, { format: 'raw' });
|
||||
// //we need to manually fire this event since it is only ever fired based on loading from the DOM, this
|
||||
// // is required for our plugins listening to this event to execute
|
||||
// tinyMceEditor.fire('LoadContent', null);
|
||||
//};
|
||||
|
||||
//listen for formSubmitting event (the result is callback used to remove the event subscription)
|
||||
var unsubscribe = scope.$on("formSubmitting", function () {
|
||||
//TODO: Here we should parse out the macro rendered content so we can save on a lot of bytes in data xfer
|
||||
// we do parse it out on the server side but would be nice to do that on the client side before as well.
|
||||
scope.value = tinyMceEditor.getContent();
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise if this is part of a modal, the listener still exists because the dom
|
||||
// element might still be there even after the modal has been hidden.
|
||||
scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
initTiny();
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
* @name umbraco.directives.directive:umbSections
|
||||
* @restrict E
|
||||
**/
|
||||
function sectionsDirective($timeout, $window, navigationService, treeService, sectionResource, appState, eventsService) {
|
||||
function sectionsDirective($timeout, $window, navigationService, treeService, sectionResource, appState, eventsService, $location) {
|
||||
return {
|
||||
restrict: "E", // restrict to an element
|
||||
replace: true, // replace the html element with the template
|
||||
@@ -84,7 +84,8 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
|
||||
scope.sectionClick = function (section) {
|
||||
navigationService.hideSearch();
|
||||
navigationService.showTree(section.alias);
|
||||
navigationService.showTree(section.alias);
|
||||
$location.path("/" + section.alias);
|
||||
};
|
||||
|
||||
scope.sectionDblClick = function(section){
|
||||
|
||||
@@ -36,7 +36,7 @@ angular.module("umbraco.directives")
|
||||
'<ins ng-hide="node.hasChildren" style="width:18px;"></ins>' +
|
||||
'<ins ng-show="node.hasChildren" ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(node)"></ins>' +
|
||||
'<i title="#{{node.routePath}}" class="{{node.cssClass}}"></i>' +
|
||||
'<a href ng-click="select(this, node, $event)" on-right-click="altSelect(this, node, $event)">{{node.name}}</a>' +
|
||||
'<a href ng-click="select(this, node, $event)" on-right-click="altSelect(this, node, $event)" ng-bind-html="node.name"></a>' +
|
||||
'<a href class="umb-options" ng-hide="!node.menuUrl" ng-click="options(this, node, $event)"><i></i><i></i><i></i></a>' +
|
||||
'<div ng-show="node.loading" class="l"><div></div></div>' +
|
||||
'</div>' +
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
angular.module('umbraco.directives')
|
||||
.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
|
||||
// contains
|
||||
function contains(arr, item) {
|
||||
if (angular.isArray(arr)) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (angular.equals(arr[i], item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// add
|
||||
function add(arr, item) {
|
||||
arr = angular.isArray(arr) ? arr : [];
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (angular.equals(arr[i], item)) {
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
arr.push(item);
|
||||
return arr;
|
||||
}
|
||||
|
||||
// remove
|
||||
function remove(arr, item) {
|
||||
if (angular.isArray(arr)) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (angular.equals(arr[i], item)) {
|
||||
arr.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/19228302/1458162
|
||||
function postLinkFn(scope, elem, attrs) {
|
||||
// compile with `ng-model` pointing to `checked`
|
||||
$compile(elem)(scope);
|
||||
|
||||
// getter / setter for original model
|
||||
var getter = $parse(attrs.checklistModel);
|
||||
var setter = getter.assign;
|
||||
|
||||
// value added to list
|
||||
var value = $parse(attrs.checklistValue)(scope.$parent);
|
||||
|
||||
// watch UI checked change
|
||||
scope.$watch('checked', function(newValue, oldValue) {
|
||||
if (newValue === oldValue) {
|
||||
return;
|
||||
}
|
||||
var current = getter(scope.$parent);
|
||||
if (newValue === true) {
|
||||
setter(scope.$parent, add(current, value));
|
||||
} else {
|
||||
setter(scope.$parent, remove(current, value));
|
||||
}
|
||||
});
|
||||
|
||||
// watch original model change
|
||||
scope.$parent.$watch(attrs.checklistModel, function(newArr, oldArr) {
|
||||
scope.checked = contains(newArr, value);
|
||||
}, true);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
priority: 1000,
|
||||
terminal: true,
|
||||
scope: true,
|
||||
compile: function(tElement, tAttrs) {
|
||||
if (tElement[0].tagName !== 'INPUT' || !tElement.attr('type', 'checkbox')) {
|
||||
throw 'checklist-model should be applied to `input[type="checkbox"]`.';
|
||||
}
|
||||
|
||||
if (!tAttrs.checklistValue) {
|
||||
throw 'You should provide `checklist-value`.';
|
||||
}
|
||||
|
||||
// exclude recursion
|
||||
tElement.removeAttr('checklist-model');
|
||||
|
||||
// local scope var storing individual checkbox model
|
||||
tElement.attr('ng-model', 'checked');
|
||||
|
||||
return postLinkFn;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -124,6 +124,7 @@ angular.module('umbraco.mocks').
|
||||
"content_itemChanged": "This item has been changed after publication",
|
||||
"content_itemNotPublished": "This item is not published",
|
||||
"content_lastPublished": "Last published",
|
||||
"content_listViewNoItems": "There are no items show in the list.",
|
||||
"content_mediatype": "Media Type",
|
||||
"content_mediaLinks": "Link to media item(s)",
|
||||
"content_membergroup": "Member Group",
|
||||
@@ -425,14 +426,14 @@ angular.module('umbraco.mocks').
|
||||
"language_displayName": "Culture Name",
|
||||
"lockout_lockoutWillOccur": "You've been idle and logout will automatically occur in",
|
||||
"lockout_renewSession": "Renew now to save your work",
|
||||
"login_greeting1": "Happy super sunday",
|
||||
"login_greeting2": "Happy manic monday ",
|
||||
"login_greeting3": "Happy tremendous tuesday",
|
||||
"login_greeting4": "Happy wonderfull wednesday",
|
||||
"login_greeting5": "Happy thunder thursday",
|
||||
"login_greeting6": "Happy friendly friday",
|
||||
"login_greeting7": "Happy shiny saturday",
|
||||
"login_instruction": "log in below:",
|
||||
"login_greeting1": "Happy super Sunday",
|
||||
"login_greeting2": "Happy manic Monday ",
|
||||
"login_greeting3": "Happy tremendous Tuesday",
|
||||
"login_greeting4": "Happy wonderful Wednesday",
|
||||
"login_greeting5": "Happy thunderous Thursday",
|
||||
"login_greeting6": "Happy friendly Friday",
|
||||
"login_greeting7": "Happy shiny Saturday",
|
||||
"login_instruction": "Log in below:",
|
||||
"login_bottomText": "<p style='text-align:right;'>© 2001 - %0% <br /><a href='http://umbraco.org' style='text-decoration: none' target='_blank'>umbraco.org</a></p> ",
|
||||
"main_dashboard": "Dashboard",
|
||||
"main_sections": "Sections",
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.resources.stylesheetResource
|
||||
* @description service to retrieve available stylesheets
|
||||
*
|
||||
*
|
||||
**/
|
||||
function templateResource($q, $http, umbRequestHelper) {
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.stylesheetResource#getAll
|
||||
* @methodOf umbraco.resources.stylesheetResource
|
||||
*
|
||||
* @description
|
||||
* Gets all registered stylesheets
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* stylesheetResource.getAll()
|
||||
* .then(function(stylesheets) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @returns {Promise} resourcePromise object containing the stylesheets.
|
||||
*
|
||||
*/
|
||||
getAll: function () {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"GetAll")),
|
||||
'Failed to retrieve stylesheets ');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.stylesheetResource#getRulesByName
|
||||
* @methodOf umbraco.resources.stylesheetResource
|
||||
*
|
||||
* @description
|
||||
* Returns all defined child rules for a stylesheet with a given name
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* stylesheetResource.getRulesByName("ie7stylesheet")
|
||||
* .then(function(rules) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @returns {Promise} resourcePromise object containing the rules.
|
||||
*
|
||||
*/
|
||||
getById: function (id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"GetById",
|
||||
[{ id: id }])),
|
||||
'Failed to retreive template ');
|
||||
},
|
||||
|
||||
saveAndRender: function(html, templateId, pageId){
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"PostSaveAndRender"),
|
||||
{templateId: templateId, pageId: pageId, html: html }),
|
||||
'Failed to retreive template ');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.resources').factory('templateResource', templateResource);
|
||||
@@ -0,0 +1,14 @@
|
||||
angular.module('umbraco.services')
|
||||
.factory('gridService', function ($http, $q){
|
||||
|
||||
var configPath = "views/propertyeditors/grid/config/grid.editors.config.js";
|
||||
|
||||
var service = {
|
||||
getGridEditors: function () {
|
||||
return $http.get(configPath);
|
||||
}
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
});
|
||||
@@ -31,7 +31,7 @@ angular.module("umbraco.install").factory('installerService', function($rootScop
|
||||
"'Umbraco' is the danish name for an allen key",
|
||||
"Umbraco has been around since 2005, that's a looong time in IT",
|
||||
"More than 400 people from all over the world meet each year in Denmark in June for our annual conference <a target='_blank' href='http://codegarden14.com'>CodeGarden</a>",
|
||||
"While you install Umbraco someone else on the other side of the planet probably does it too",
|
||||
"While you are installing Umbraco someone else on the other side of the planet is probably doing it too",
|
||||
"You can extend Umbraco without modifying the source code and using either JavaScript or C#"
|
||||
];
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<a href ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')" class="btn btn-link">
|
||||
<a href ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')" class="btn btn-link btn-link-reverse">
|
||||
No thanks, I do not want to install a starter website
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="name">Name</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="name" placeholder="Full name" required
|
||||
ng-model="installer.current.model.name" />
|
||||
<input type="text" id="name" name="name" placeholder="Full name" required ng-model="installer.current.model.name" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="email">Email</label>
|
||||
<div class="controls">
|
||||
<input type="email" name="email" placeholder="you@example.com" required ng-model="installer.current.model.email" />
|
||||
<input type="email" id="email" name="email" placeholder="you@example.com" required ng-model="installer.current.model.email" />
|
||||
<small class="inline-help">Your email will be used as your login</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,7 +33,7 @@
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
required
|
||||
ng-model="installer.current.model.password" />
|
||||
ng-model="installer.current.model.password" id="password" />
|
||||
<small class="inline-help">At least {{installer.current.model.minCharLength}} characters long</small>
|
||||
|
||||
<small ng-if="installer.current.model.minNonAlphaNumericLength > 0" class="inline-help">
|
||||
@@ -47,7 +46,7 @@
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox" for="subscribeToNewsLetter">
|
||||
<input type="checkbox" name="subscribeToNewsLetter"
|
||||
<input type="checkbox" id="subscribeToNewsLetter" name="subscribeToNewsLetter"
|
||||
ng-model="installer.current.model.subscribeToNewsLetter" /> Keep me updated on Umbraco Versions, Security Bulletins and Community News</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,7 +56,7 @@
|
||||
|
||||
<input type="submit" ng-disabled="myForm.$invalid" value="Install" class="btn btn-success" />
|
||||
|
||||
<a href class="btn btn-link" ng-disabled="myForm.$invalid" ng-click="validateAndForward()">Customize</a>
|
||||
<a href class="btn btn-neutral control-customize" ng-disabled="myForm.$invalid" ng-click="validateAndForward()">Customize</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -64,8 +64,6 @@
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.btn-group>.btn+.dropdown-toggle {
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow:none;
|
||||
@@ -163,7 +161,8 @@ input[type="button"] {
|
||||
.btn-danger.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-inverse.active {
|
||||
.btn-inverse.active,
|
||||
.btn-neutral.active {
|
||||
color: rgba(255,255,255,.75);
|
||||
}
|
||||
|
||||
@@ -192,7 +191,23 @@ input[type="button"] {
|
||||
.btn-inverse {
|
||||
.buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight);
|
||||
}
|
||||
// Neutral appears as lighter gray
|
||||
.btn-neutral {
|
||||
.buttonBackground(@btnNeutralBackground, @btnNeutralBackgroundHighlight);
|
||||
color: #656565;
|
||||
// Hover/focus state
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #656565;
|
||||
}
|
||||
|
||||
&.disabled,
|
||||
&[disabled] {
|
||||
color:#656565;
|
||||
.opacity(65);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Cross-browser Jank
|
||||
// --------------------------------------------------
|
||||
@@ -253,3 +268,12 @@ input[type="submit"].btn {
|
||||
color: @grayDark;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
// Make a reverse type of a button link
|
||||
.btn-link-reverse{
|
||||
text-decoration:underline;
|
||||
&:hover,
|
||||
&:focus{
|
||||
text-decoration:none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,585 @@
|
||||
// Gridview
|
||||
// -------------------------
|
||||
|
||||
.editor {
|
||||
border: 1px solid #cdcdcd;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
position: relative;
|
||||
-webkit-transition: all 500ms ease-in-out;
|
||||
-moz-transition: all 500ms ease-in-out;
|
||||
-ms-transition: all 500ms ease-in-out;
|
||||
-o-transition: all 500ms ease-in-out;
|
||||
transition: all 500ms ease-in-out;
|
||||
margin: 0 0 1.5% 0
|
||||
|
||||
|
||||
|
||||
// Sortabel
|
||||
// -------------------------
|
||||
.usky-grid .ui-sortable-helper {
|
||||
border: dashed 1px #000;
|
||||
background: #ccc;
|
||||
opacity: 0.4;
|
||||
height: 50px !important;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-helper *{
|
||||
border: none !important;
|
||||
background: none !important;
|
||||
color: #999 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-helper .cell-tools{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-placeholder{
|
||||
border: 2px dashed @grayLight;
|
||||
padding: 20px;
|
||||
font-family: icomoon;
|
||||
text-align: center;
|
||||
font-size: 85px;
|
||||
line-height: 65px;
|
||||
color: @grayLighter;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-placeholder:hover{
|
||||
border-color: @gray;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-placeholder:before{
|
||||
content: "\e1bd";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// utils
|
||||
// -------------------------
|
||||
.usky-grid-width {
|
||||
margin: 0 auto;
|
||||
width:100%;
|
||||
}
|
||||
.usky-grid .right {
|
||||
float:right;
|
||||
}
|
||||
|
||||
// general layout components
|
||||
// -------------------------
|
||||
.usky-grid .tb {
|
||||
display:table;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
.usky-grid .td {
|
||||
display:table-cell;
|
||||
vertical-align:top;
|
||||
border-right:1px dashed rgba(182, 182, 182, 0.0);
|
||||
}
|
||||
.usky-grid .tb:hover .td{
|
||||
border-right:1px dashed rgba(182, 182, 182, 0.3);
|
||||
}
|
||||
.usky-grid .td.last {
|
||||
border-right:1px dashed rgba(182, 182, 182, 0.0) !important;
|
||||
}
|
||||
.usky-grid .tr {
|
||||
display:table-row;
|
||||
}
|
||||
.usky-grid .td2{
|
||||
width: 50%;
|
||||
}
|
||||
.usky-grid .td3{
|
||||
width: 33.33%;
|
||||
}
|
||||
.usky-grid .td4{
|
||||
width: 25%;
|
||||
}
|
||||
.usky-grid .td5{
|
||||
width: 20%;
|
||||
}
|
||||
.usky-grid .td6{
|
||||
width: 16.6%;
|
||||
}
|
||||
.usky-grid .middle {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.usky-grid .mainTb {
|
||||
border-collapse: separate;
|
||||
}
|
||||
.usky-grid .mainTd {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// COLUMN
|
||||
// -------------------------
|
||||
.usky-grid .usky-column {
|
||||
|
||||
}
|
||||
.usky-grid .usky-column.last {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ROW
|
||||
// -------------------------
|
||||
.usky-grid .usky-row{
|
||||
position: relative;
|
||||
border: 1px dashed rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.editor:hover {
|
||||
border-color: #000
|
||||
|
||||
|
||||
|
||||
// CELL
|
||||
// -------------------------
|
||||
.usky-grid .usky-cell{
|
||||
position: relative;
|
||||
border: 1px dashed rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.editor:hover i {
|
||||
opacity: 1
|
||||
.usky-grid .cell-tools {
|
||||
transition: all .20s ease-in-out;
|
||||
-moz-transition: all .20s ease-in-out;
|
||||
-webkit-transition: all .20s ease-in-out;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.editor i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
font-size: 20px;
|
||||
color: @white;
|
||||
background: @black;
|
||||
padding: 10px;
|
||||
-webkit-transition: all 500ms ease-in-out;
|
||||
-moz-transition: all 500ms ease-in-out;
|
||||
-ms-transition: all 500ms ease-in-out;
|
||||
-o-transition: all 500ms ease-in-out;
|
||||
transition: all 500ms ease-in-out;
|
||||
opacity: 0
|
||||
.usky-grid .cell-tools-add {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
bottom: -20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 500;
|
||||
}
|
||||
|
||||
.editor i:hover {
|
||||
.usky-grid .cell-tools-add-single i{
|
||||
font-size: 85px;
|
||||
color: @grayLight;
|
||||
display: block;
|
||||
line-height: 55px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.editor i.icon-move {
|
||||
left: 0;
|
||||
cursor: move
|
||||
}
|
||||
.usky-grid .cell-tools-add-single a:hover i{color: @gray;}
|
||||
|
||||
.editor i.icon-edit {
|
||||
right: 36px;
|
||||
cursor: pointer
|
||||
.usky-grid .cell-tools-add-single a{text-decoration: none;}
|
||||
|
||||
.usky-grid .cell-tools-add-single p{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.editor i.icon-trash {
|
||||
right: 0;
|
||||
cursor: pointer
|
||||
}
|
||||
.usky-grid .single-editor-rte p{
|
||||
display: block;
|
||||
}
|
||||
.usky-grid .single-editor-rte i, .usky-grid .single-editor-rte div{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.usky-grid .cell-tools-remove {
|
||||
display:inline-block;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
right: -20px;
|
||||
text-align: right;
|
||||
z-index: 500;
|
||||
}
|
||||
|
||||
.usky-grid .cell-tools-remove .iconBox:hover, .usky-grid .cell-tools-remove .iconBox:hover *{
|
||||
background: @red !important;
|
||||
border-color: @red !important;
|
||||
}
|
||||
|
||||
.usky-grid .cell-tools-move {
|
||||
display:inline-block;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: -20px;
|
||||
z-index: 500;
|
||||
cursor: move
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CONTROL
|
||||
// -------------------------
|
||||
.usky-grid .usky-control {
|
||||
transition: all .20s ease-in-out;
|
||||
-moz-transition: all .20s ease-in-out;
|
||||
-webkit-transition: all .20s ease-in-out;
|
||||
position:relative;
|
||||
display:block;
|
||||
|
||||
border: 1px dashed rgba(255, 0, 0, .0);
|
||||
border-bottom-width: 2px;
|
||||
|
||||
-webkit-background-clip: padding-box; /* for Safari */
|
||||
background-clip: padding-box; /* for IE9+, Firefox 4+, Opera, Chrome */
|
||||
}
|
||||
|
||||
.usky-grid .usky-control:hover{
|
||||
border-bottom:2px solid rgba(182, 182, 182, 0.3);
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-placeholder:hover{
|
||||
border-bottom:2px solid rgba(182, 182, 182, 0.0) !important;
|
||||
}
|
||||
|
||||
.usky-grid .removingControl{
|
||||
border: 1px dashed @red !important;
|
||||
}
|
||||
|
||||
.usky-grid .movingControl{
|
||||
border: 1px dashed @blue !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// CONTROL PLACEHOLDER
|
||||
// -------------------------
|
||||
.usky-grid .usky-control-placeholder {
|
||||
min-height: 100px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
text-align: -moz-center;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-placeholder .placeholder{
|
||||
font-size: 14px; opacity: 0.7; text-align: left;
|
||||
padding: 5px;
|
||||
border:1px solid rgba(182, 182, 182, 0.3);
|
||||
height: 50px;
|
||||
}
|
||||
.usky-grid .usky-control-placeholder:hover .placeholder{
|
||||
border:1px solid rgba(182, 182, 182, 0.8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// EDITOR PLACEHOLDER
|
||||
// -------------------------
|
||||
.usky-grid .usky-editor-placeholder{
|
||||
min-height: 65px;
|
||||
padding: 20px;
|
||||
padding-bottom: 30px;
|
||||
position: relative;
|
||||
background-color: white;
|
||||
border: 4px dashed @grayLight;
|
||||
text-align: center;
|
||||
text-align: -moz-center;
|
||||
}
|
||||
.usky-grid .usky-editor-placeholder i{
|
||||
color: @grayLight;
|
||||
font-size: 85px;
|
||||
line-height: 85px;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Form elements
|
||||
// -------------------------
|
||||
.usky-grid textarea.textstring{
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background: #fff;
|
||||
outline: none;
|
||||
width: 99%;
|
||||
resize: none;
|
||||
color: @gray;
|
||||
}
|
||||
|
||||
.usky-grid .usky-cell-rte textarea{
|
||||
display: none !important
|
||||
}
|
||||
|
||||
.usky-grid .usky-cell-media .caption{
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background: #fff;
|
||||
outline: none;
|
||||
width: 99%;
|
||||
resize: none;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.usky-grid .cellPanelRte {
|
||||
min-height:60px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ICONS
|
||||
// -------------------------
|
||||
.usky-grid .iconBox {
|
||||
padding: 4px 7px 4px 7px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
border-radius: 200px;
|
||||
background: rgba(255,255,255, 1);
|
||||
border:1px solid rgb(182, 182, 182);
|
||||
margin: 2px;
|
||||
}
|
||||
.usky-grid .iconBox:hover, .usky-grid .iconBox:hover *{
|
||||
background: @blue !important;
|
||||
color: white !important;
|
||||
border-color: @blue !important;
|
||||
}
|
||||
|
||||
.usky-grid .iconBox a:hover {
|
||||
text-decoration:none;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.usky-grid .iconBox.selected {
|
||||
-webkit-appearance: none;
|
||||
background-image: -moz-linear-gradient(top,#e6e6e6,#bfbfbf);
|
||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#bfbfbf));
|
||||
background-image: -webkit-linear-gradient(top,#e6e6e6,#bfbfbf);
|
||||
background-image: -o-linear-gradient(top,#e6e6e6,#bfbfbf);
|
||||
background-image: linear-gradient(to bottom,#e6e6e6,#bfbfbf);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffbfbfbf',GradientType=0);
|
||||
zoom: 1;
|
||||
border-color: #bfbfbf #bfbfbf #999;
|
||||
border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
|
||||
-webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.usky-grid .iconBox i {
|
||||
font-size:16px !important;
|
||||
color: #5F5F5F;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.usky-grid ul {
|
||||
display:inline-block;
|
||||
list-style:none;
|
||||
padding:0;
|
||||
margin: 10px 0 0 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.usky-grid .help-text {
|
||||
background: @grayLighter;
|
||||
color: @gray;
|
||||
font-size: 14px;
|
||||
padding: 10px 20px 10px 20px;
|
||||
border-radius: 15px;
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.usky-grid ul li {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
margin: 8px 8px 0px 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TINYMCE EDITOR
|
||||
// -------------------------
|
||||
.usky-grid .mce-panel {
|
||||
border:none !important;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.usky-grid .mce-btn button {
|
||||
padding: 8px 6px;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.usky-grid .mce-toolbar {
|
||||
border: 1px solid rgba(207, 207, 207, 0.7);
|
||||
background-color: rgba(250, 250, 250, 1);
|
||||
z-index: 100;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
padding: -1px;
|
||||
position: absolute;
|
||||
margin: -1px -1px 0 -1px;
|
||||
-webkit-box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14);
|
||||
-moz-box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14);
|
||||
box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14);
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
.mce-flow-layout-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.usky-grid .mce-panel {
|
||||
background: transparent !important;
|
||||
}
|
||||
.usky-grid .mce-floatpanel {
|
||||
background-color: #F7F7F7 !important;
|
||||
}
|
||||
|
||||
|
||||
// MEDIA EDITOR
|
||||
// -------------------------
|
||||
.usky-grid .fullSizeImage {
|
||||
width:100%
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* Width */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .boxWidth {
|
||||
text-align:right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.usky-grid .boxWidth input {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.usky-grid .boxWidth label {
|
||||
font-size: 10px;
|
||||
padding: 0;
|
||||
margin: 5px 5px 0 0;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* Margin control */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .usky-cell{
|
||||
|
||||
}
|
||||
|
||||
.usky-grid .usky-row{
|
||||
|
||||
}
|
||||
|
||||
.usky-grid .usky-control{
|
||||
margin: 30px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.usky-grid .usky-templates-columns{
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* template */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .uSky-templates {
|
||||
text-align:center;
|
||||
overflow:hidden;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template {
|
||||
display:inline-block;
|
||||
width:100px;
|
||||
padding-right: 30px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb:hover {
|
||||
border:5px solid @blue;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb {
|
||||
width:100%;
|
||||
height:150px;
|
||||
padding:10px;
|
||||
background-color: @grayLighter;
|
||||
border: 5px solid @grayLight;
|
||||
cursor:pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tr {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb .uSky-templates-column {
|
||||
height:100%;
|
||||
border: 1px dashed @grayLight;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb .uSky-templates-column.last {
|
||||
border-right: 1px dashed @grayLight !important;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* template column */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .usky-templates-columns .td{
|
||||
border: none !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.usky-grid .usky-templates-columns .td i{
|
||||
color: @gray;
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
|
||||
.usky-grid .mainTbpt:hover {
|
||||
border-color:@blue;
|
||||
}
|
||||
|
||||
.usky-grid .mainTbpt {
|
||||
cursor:pointer;
|
||||
border-spacing: 5px;
|
||||
border-collapse: separate;
|
||||
height: 35px;
|
||||
border: 2px solid @grayLight;
|
||||
margin:0px;
|
||||
background-color: @grayLighter;
|
||||
}
|
||||
.usky-grid .mainTdpt {
|
||||
height: 35px;
|
||||
border: 1px dashed @grayLight;
|
||||
margin:0px;
|
||||
background-color: rgba(228, 228, 228, 0.41);
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
/*wft ms?*/
|
||||
*{ -ms-touch-action: none;}
|
||||
|
||||
.ace_editor { height: 200px; }
|
||||
|
||||
.nounderline {text-decoration: none !important}
|
||||
.nounderline:hover {text-decoration: underline !important}
|
||||
.nounderline * {text-decoration: none !important; border: none}
|
||||
|
||||
@@ -288,4 +288,8 @@ select {
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
border:none;
|
||||
}
|
||||
|
||||
.control-customize{
|
||||
margin:2px 0 0 0;
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
.umb-modalcolumn-header {
|
||||
background: @grayLighter;
|
||||
border-bottom: 1px solid @grayLight;
|
||||
height: 79px;
|
||||
padding: 20px 20px 0px 20px;
|
||||
height: 94px;
|
||||
padding: 5px 20px 0px 20px;
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
|
||||
@@ -38,18 +38,19 @@
|
||||
}
|
||||
|
||||
.umb-panel-header .umb-headline, .umb-panel-header h1 {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
background: none;
|
||||
margin: 25px 0 0 20px;
|
||||
padding: 0;
|
||||
margin: 15px 0 0 20px;
|
||||
padding: 3px 5px;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
border: 1px solid @grayLighter;
|
||||
}
|
||||
|
||||
.umb-panel-header .umb-headline:hover,.umb-panel-header .umb-headline:active {
|
||||
border-bottom: 1px dotted @grayLight;
|
||||
color: @black
|
||||
.umb-panel-header .umb-headline:focus,.umb-panel-header .umb-headline:active {
|
||||
border: 1px solid @grayLight;
|
||||
background-color: @white;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper{
|
||||
@@ -94,9 +95,9 @@
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper input.ng-invalid::-webkit-input-placeholder {color: @red;}
|
||||
.umb-headline-editor-wrapper input.ng-invalid::-moz-placeholder {color: @red;}
|
||||
.umb-headline-editor-wrapper input.ng-invalid:-ms-input-placeholder {color: @red;}
|
||||
.umb-headline-editor-wrapper input.ng-invalid::-webkit-input-placeholder {color: @red; line-height: 22px;}
|
||||
.umb-headline-editor-wrapper input.ng-invalid::-moz-placeholder {color: @red; line-height: 22px;}
|
||||
.umb-headline-editor-wrapper input.ng-invalid:-ms-input-placeholder {color: @red; line-height: 22px;}
|
||||
|
||||
.umb-panel-header i {
|
||||
font-size: 13px;
|
||||
@@ -109,7 +110,7 @@
|
||||
|
||||
.umb-panel-header .umb-btn-toolbar {
|
||||
float: right;
|
||||
padding: 20px 20px 0 0;
|
||||
padding: 5px 20px 0 0;
|
||||
}
|
||||
|
||||
.umb-panel-footer {
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.umb-tree li .file-ext {
|
||||
color: @grayLight;
|
||||
}
|
||||
|
||||
.umb-tree li.root > div h5 {
|
||||
margin-top: 10px;
|
||||
|
||||
@@ -0,0 +1,784 @@
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #EEEEEE;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
}
|
||||
|
||||
body.open {
|
||||
padding-left:275px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-left: 10px;
|
||||
font-size: 14px;
|
||||
color: #d9d9d9;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tuning #TuningBg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
width: 275px;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin-left: -275px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
background: #1D1D1D;
|
||||
-webkit-box-shadow: 0 0 14px rgba(0, 0, 0, 0);
|
||||
-moz-box-shadow: 0 0 14px rgba(0, 0, 0, 0);
|
||||
box-shadow: 0 0 14px rgba(0, 0, 0, 0);
|
||||
-webkit-transition: all 0.2s ease-in-out;
|
||||
-moz-transition: all 0.2s ease-in-out;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.wait {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.tuning .tuning-wrapper {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tuning .wrapper-pading {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tuning #TuningBg.open {
|
||||
margin-left: 0;
|
||||
-webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.tuning .colpick {
|
||||
z-index: 99999999;
|
||||
}
|
||||
|
||||
.tuning .nav {
|
||||
padding: 0 10px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 30px;
|
||||
text-transform: uppercase;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a {
|
||||
color: #d9d9d9 !important;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li.active > a,
|
||||
.tuning .nav-tabs > li.active > a:hover,
|
||||
.tuning .nav-tabs > li.active > a:focus {
|
||||
color: #d9d9d9;
|
||||
cursor: default;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none;
|
||||
border-bottom: 3px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a:hover {
|
||||
color: #d9d9d9 !important;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none !important;
|
||||
border-bottom: 3px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.tuning .nav > li > a:hover,
|
||||
.tuning .nav > li > a:focus {
|
||||
color: #d9d9d9 !important;
|
||||
text-decoration: none !important;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none !important;
|
||||
border-bottom: 3px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a {
|
||||
border-bottom: 3px solid transparent;
|
||||
/*border-radius: 2px 2px 0 0;*/
|
||||
|
||||
}
|
||||
|
||||
.nav-tabs > li {
|
||||
float: left;
|
||||
margin-top: 1px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a {
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .nav > li > a {
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
.tuning .panel-title > a span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tuning .panel-title > a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* .panel-heading */
|
||||
|
||||
.tab-pane {
|
||||
border-bottom: 1px solid #343434;
|
||||
}
|
||||
|
||||
.tuning .panel-heading {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default > .panel-heading {
|
||||
color: #d9d9d9;
|
||||
background-color: #1D1D1D;
|
||||
border-left: 4px transparent solid;
|
||||
border-color: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default > .panel-heading:hover,
|
||||
.tuning .panel-default.selected > .panel-heading {
|
||||
color: #d9d9d9;
|
||||
text-decoration: none;
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
border-left: 4px #f57020 solid;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
}
|
||||
|
||||
.tuning .panel-title > a {
|
||||
display: block;
|
||||
padding: 5px 0 5px 17px;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
color: #d9d9d9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .panel-default > .panel-heading h4 {
|
||||
margin: 0 0 0 -4px;
|
||||
border-top: 1px solid #343434;
|
||||
}
|
||||
|
||||
.panel-group .panel + .panel {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default.selected {
|
||||
margin: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default.selected > .panel-heading h4 {
|
||||
margin: 0 0 0 0;
|
||||
color: #d9d9d9;
|
||||
border-top: none;
|
||||
border-bottom: 1px solid #6D6D6D;
|
||||
}
|
||||
|
||||
.tuning .panel-default.selected > .panel-heading h4 a {
|
||||
padding: 5px 0 5px 13px;
|
||||
}
|
||||
|
||||
/* panel */
|
||||
|
||||
.tuning .panel-default {
|
||||
background-color: #1D1D1D;
|
||||
border: 0 solid rgba(217, 217, 217, 0.5);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-group .panel {
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.panel-collapse {
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
border-left: 4px #f57020 solid;
|
||||
}
|
||||
|
||||
.tuning .btn-default-save,
|
||||
.tuning .btn-default-save:focus {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
margin-right: 20px;
|
||||
color: #fff;
|
||||
background-color: #53a93f;
|
||||
border-color: #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.tuning .btn-default-save:hover {
|
||||
color: #fff;
|
||||
background-color: rgba(83, 169, 63, 0.81);
|
||||
}
|
||||
|
||||
.tuning .btn-default-delete,
|
||||
.tuning .btn-default-delete:focus {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
margin-right: 10px;
|
||||
color: #343434;
|
||||
background: #e4e4e4;
|
||||
border-color: #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.tuning .btn-default-delete:hover {
|
||||
color: #343434;
|
||||
background-color: rgba(228, 228, 228, 0.65);
|
||||
}
|
||||
|
||||
.tuning .field-title {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
font-size: 11px;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .div-field {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tuning .sp-replacer {
|
||||
float: left;
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
background: none;
|
||||
border: solid 1px #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .panel-body {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
.tuning select {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.tuning .sp-dd {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tuning .sp-preview {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
margin-right: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tuning .box-slider {
|
||||
padding: 7px 2px 12px 2px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tuning .ui-widget-content {
|
||||
background: rgba(255, 255, 255, 0.09) !important;
|
||||
border: 0px solid #fff !important;
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
|
||||
.tuning .ui-slider-horizontal {
|
||||
float: left;
|
||||
width: 155px;
|
||||
height: .3em !important;
|
||||
}
|
||||
|
||||
.tuning .ui-slider .ui-slider-handle {
|
||||
top: -0.3em;
|
||||
width: 0.3em !important;
|
||||
height: 0.9em !important;
|
||||
margin-left: 0;
|
||||
color: #d9d9d9 !important;
|
||||
cursor: pointer;
|
||||
border-top-right-radius: 1px;
|
||||
border-bottom-right-radius: 1px;
|
||||
border-bottom-left-radius: 1px;
|
||||
border-top-left-radius: 1px;
|
||||
}
|
||||
|
||||
.tuning .ui-slider .ui-slider-handle:hover,
|
||||
.tuning .ui-slider .ui-slider-handle:focus {
|
||||
color: #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.tuning .slider-input {
|
||||
float: right;
|
||||
width: 25px;
|
||||
padding: 0;
|
||||
margin-top: -9px;
|
||||
margin-right: 1px;
|
||||
font-size: 11px;
|
||||
color: #d9d9d9;
|
||||
text-align: right;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tuning .slider-span {
|
||||
float: right;
|
||||
margin: -9px 0 0 0;
|
||||
font-size: 11px;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
.tuning .slider-input {
|
||||
margin-top: -6px;
|
||||
}
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreviewContainer {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreview {
|
||||
float: left;
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
clear: both;
|
||||
color: rgba(217, 217, 217, 0.5);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
border: 1px solid rgba(217, 217, 217, 0.5);
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreview:hover {
|
||||
color: #d9d9d9;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreview i {
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .colorPickerDelete {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
margin-left: 3px;
|
||||
font-size: 10px;
|
||||
color: rgba(217, 217, 217, 0.5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .colorPickerDelete:hover {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .tuning-tools {
|
||||
position: absolute;
|
||||
right: -28px;
|
||||
margin: 25px 0 0 0;
|
||||
}
|
||||
|
||||
.tuning #TuningBg.open .tuning-tools {
|
||||
right: -33px;
|
||||
}
|
||||
|
||||
.tuning .tuning-tools div {
|
||||
display: block;
|
||||
padding: 8px 8px 8px 9px;
|
||||
margin: 5px 0 0 0;
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
background: #353535;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
-webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.tuning .tuning-tools div:hover,
|
||||
.tuning .tuning-tools div.selected {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background: #1D1D1D;
|
||||
}
|
||||
|
||||
/* image picker */
|
||||
|
||||
.tuningImagePicker {
|
||||
height: 500px;
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
overflow: auto;
|
||||
text-align: left;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tuningImagePicker ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-left: 17px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tuningImagePicker li {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tuningImagePicker ul.media-items li {
|
||||
margin-right: 17px;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 110px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
border: 2px solid #F3F2F2;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview .folder {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-size: 40px;
|
||||
color: gainsboro;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview .folder-name {
|
||||
margin-top: -5px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 0;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview:hover,
|
||||
.media-preview.selected {
|
||||
border: 2px solid #84B8F0;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker {
|
||||
padding: 10px 20px 0 15px;
|
||||
}
|
||||
|
||||
.tuningImagePicker .modal-dialog {
|
||||
width: 618px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb > li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb > li a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb input {
|
||||
padding: 0;
|
||||
margin: -4px -4px;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .fileinput-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker input.input-media {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
font-size: 23px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
filter: alpha(opacity=0);
|
||||
transform: translate(-300px, 0) scale(4);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb a.disabled,
|
||||
.bodyTuningImagePicker .breadcrumb a.disabled:hover {
|
||||
color: grey;
|
||||
text-decoration: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.tuningImagePicker h3 {
|
||||
font-size: 18px;
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
/* font picker */
|
||||
|
||||
.tuning-fontfamilypicker .show {
|
||||
margin-top: 10px;
|
||||
font-size: 32px;
|
||||
line-height: 34px;
|
||||
color: #242424;
|
||||
}
|
||||
|
||||
.tuning .fontFamilyPickerPreview {
|
||||
float: left;
|
||||
width: 90%;
|
||||
min-height: 50px;
|
||||
padding: 8px;
|
||||
margin-top: 4px;
|
||||
clear: both;
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.28);
|
||||
border: 1px solid rgba(217, 217, 217, 0.5);
|
||||
}
|
||||
|
||||
.tuning .fontFamilyPickerPreview span {
|
||||
font-size: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.tuning .fontFamilyPickerPreview:hover {
|
||||
color: #d9d9d9;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning-fontfamilypicker {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.tuning .palette {
|
||||
padding: 0;
|
||||
margin: 20px 0 20px 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tuning .palette li {
|
||||
margin: 10px 0 0 0;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.tuning .palette div {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
border: 1px solid rgba(255, 255, 255, 0.61);
|
||||
}
|
||||
|
||||
.tuning .palette li:hover {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.tuning .palette li:hover div {
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
.tuning .palette li:hover p {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tuning .palette div span {
|
||||
display: table-cell;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0 0 0 0;
|
||||
margin: 0;
|
||||
border: 1px solid rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.tuning .palette p {
|
||||
float: left;
|
||||
margin: 7px 0 0 10px;
|
||||
color: rgba(255, 255, 255, 0.57);
|
||||
}
|
||||
|
||||
/******* IFRAME *******/
|
||||
|
||||
.desktop {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.laptop {
|
||||
width: 1366px;
|
||||
height: 768px;
|
||||
}
|
||||
|
||||
.iPad-portrait {
|
||||
width: 769px;
|
||||
height: 929px;
|
||||
}
|
||||
|
||||
.iPad-landscape {
|
||||
width: 1024px;
|
||||
height: 675px;
|
||||
}
|
||||
|
||||
.smartphone-portrait {
|
||||
width: 320px;
|
||||
height: 504px;
|
||||
}
|
||||
|
||||
.smartphone-landscape {
|
||||
width: 480px;
|
||||
height: 256px;
|
||||
}
|
||||
|
||||
.border {
|
||||
margin: 75px auto;
|
||||
background-color: #ffffff;
|
||||
border-radius: 10px;
|
||||
opacity: 1.0;
|
||||
box-shadow: 0 0 0 29px #fff, 0 0 0 30px #dee0e3;
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
iframe {
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.flip:before {
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/******* preview-device *******/
|
||||
|
||||
ul.preview-device {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
border-top: 1px solid #343434;
|
||||
}
|
||||
|
||||
ul.preview-device li {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-left: 4px solid transparent;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
}
|
||||
|
||||
ul.preview-device li div {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #343434;
|
||||
}
|
||||
|
||||
ul.preview-device li:hover,
|
||||
ul.preview-device li.selected {
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
border-left: 4px #f57020 solid;
|
||||
}
|
||||
|
||||
ul.preview-device li i {
|
||||
font-size: 80px;
|
||||
line-height: 80px;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
ul.preview-device li span {
|
||||
display: block;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
/******* font-face *******/
|
||||
|
||||
#speechbubble {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 40px;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
margin-left: 300px;
|
||||
text-align: left;
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#speechbubble p {
|
||||
position: relative;
|
||||
padding: 8px 30px 8px 20px;
|
||||
margin: auto;
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
text-shadow: none;
|
||||
background-color: #46a546;
|
||||
border: none;
|
||||
border-color: transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/******* font-face *******/
|
||||
|
||||
@font-face {
|
||||
src: url('/Umbraco/assets/fonts/helveticons/helveticons.eot') !important;
|
||||
src: url('/Umbraco/assets/fonts/helveticons/helveticons.eot?#iefix') format('embedded-opentype'), url('/Umbraco/assets/fonts/helveticons/helveticons.ttf') format('truetype'), url('/Umbraco/assets/fonts/helveticons/helveticons.svg#icomoon') format('svg') !important;
|
||||
}
|
||||
@@ -102,8 +102,6 @@
|
||||
@btnBackgroundHighlight: #e4e4e4;
|
||||
@btnBorder: #ccc;
|
||||
|
||||
//@btnPrimaryBackground: #297aff;
|
||||
//@btnPrimaryBackgroundHighlight: #297aff;
|
||||
@btnPrimaryBackground: #53a93f;
|
||||
@btnPrimaryBackgroundHighlight: #53a93f;
|
||||
|
||||
@@ -122,6 +120,9 @@
|
||||
@btnInverseBackground: #444;
|
||||
@btnInverseBackgroundHighlight: @grayDarker;
|
||||
|
||||
@btnNeutralBackground: #f5f5f5;
|
||||
@btnNeutralBackgroundHighlight: #f5f5f5;
|
||||
|
||||
|
||||
// Forms
|
||||
// -------------------------
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
LazyLoad.js([
|
||||
'/Umbraco/lib/jquery/jquery-2.0.3.min.js',
|
||||
'/Umbraco/lib/jquery/jquery-ui-1.10.4.custom.min.js',
|
||||
'/Umbraco/lib/angular/1.1.5/angular.min.js',
|
||||
'/Umbraco/lib/underscore/underscore.js',
|
||||
'/Umbraco/js/app.js',
|
||||
'/Umbraco/js/umbraco.resources.js',
|
||||
'/Umbraco/js/umbraco.services.js',
|
||||
'/Umbraco/js/umbraco.security.js',
|
||||
'/Umbraco/ServerVariables',
|
||||
'/Umbraco/lib/angular-bootstrap/ui-bootstrap-tpls-0.10.0.min.js',
|
||||
'/Umbraco/lib/spectrum/spectrum.js',
|
||||
'http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
|
||||
'/Umbraco/js/tuning.config.js',
|
||||
'/Umbraco/js/tuning.palettes.js',
|
||||
'/umbraco/js/tuning.panel.js'
|
||||
], function () {
|
||||
jQuery(document).ready(function () {
|
||||
angular.bootstrap(document, ['umbraco.tuning']);
|
||||
});
|
||||
}
|
||||
);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,238 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link href="/Umbraco/lib/bootstrap/css/bootstrap.min.3.0.1.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/assets/css/tuning.panelStyles.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/lib/spectrum/spectrum.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/lib/jquery/jquery-ui-1.10.4.custom.min.css" type="text/css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body id="tuningPanel" ng-class="{open:isOpen}" ng-controller="Umbraco.tuningController">
|
||||
|
||||
<div class="wait" ng-show="!frameLoaded">Loading ...</div>
|
||||
|
||||
<div id="demo-iframe-wrapper" ng-show="frameLoaded" class="{{previewDevice.css}}">
|
||||
<iframe id="resultFrame" ng-src="{{pageId}}" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
<div class="tuning">
|
||||
|
||||
<div id="TuningBg" ng-class="{open:isOpen}" style="display: block;">
|
||||
|
||||
<div class="tuning-tools">
|
||||
|
||||
<div ng-click="togglePanel()">
|
||||
<i ng-if="isOpen" class="icon icon-left-double-arrow"></i>
|
||||
<i ng-if="!isOpen" class="icon icon-right-double-arrow"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('previewDevice')" ng-class="{selected:settingIsOpen=='previewDevice', show:frameLoaded}" style="display:none">
|
||||
<i class="icon icon-display"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('setting')" ng-class="{selected:settingIsOpen=='setting', show:enableTuning > 0}" style="display:none">
|
||||
<i class="icon icon-paint-roller"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('presetColors')" ng-class="{selected:settingIsOpen=='presetColors', show:enableTuning > 0}" style="display:none">
|
||||
<i class="icon icon-palette"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tuning-wrapper">
|
||||
|
||||
<div ng-show="settingIsOpen == 'previewDevice'">
|
||||
|
||||
<h2>DEVICES</h2>
|
||||
<ul class="preview-device">
|
||||
<li ng-repeat="device in devices" ng-class=" { selected:previewDevice==device }" ng-click="updatePreviewDevice(device)">
|
||||
<div><i class="icon {{device.icon}}"></i><span>{{device.name}}</span></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="settingIsOpen == 'setting'">
|
||||
|
||||
<tabset vertical="false">
|
||||
|
||||
<tab ng-repeat="category in tuningModel.categories" active="category.active">
|
||||
|
||||
<tab-heading>
|
||||
<span>{{category.name}}</span>
|
||||
</tab-heading>
|
||||
|
||||
<div ng-repeat="section in category.sections">
|
||||
|
||||
<accordion close-others="true">
|
||||
|
||||
<accordion-group ng-repeat="subSection in section.subSections"
|
||||
ng-class="{true:'selected', false:''}[isOpen]"
|
||||
is-open="(schemaFocus != '' && schemaFocus == subSection.name.toLowerCase())">
|
||||
|
||||
<accordion-heading>
|
||||
<span ng-click="accordionOpened(subSection.name)" ng-mouseover="accordionWillBeOpened(subSection.schema)">
|
||||
{{subSection.name}}
|
||||
</span>
|
||||
</accordion-heading>
|
||||
|
||||
<div ng-mouseover="accordionWillBeOpened(subSection.schema)">
|
||||
<div class="div-field" ng-repeat="field in subSection.fields">
|
||||
|
||||
<span class="field-title">{{field.name}}:</span>
|
||||
|
||||
<div ng-if="field.type == 'colorPicker'">
|
||||
<spectrum colorselected="field.value"></spectrum>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="icon icon-delete colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgImagePicker'" class="imagePickerPreviewContainer">
|
||||
<div class="imagePickerPreview" ng-click="open(field)" style="background-image:{{ field.value }}">
|
||||
<i class="icon icon-add"></i>
|
||||
</div>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="icon icon-delete colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgPositionPicker'">
|
||||
<select ng-options="BackgroundPosition for BackgroundPosition in BackgroundPositions" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgRepeatPicker'">
|
||||
<select ng-options="BackgroundRepeat for BackgroundRepeat in BackgroundRepeats" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgAttachmentPicker'">
|
||||
<select ng-options="BackgroundAttachment for BackgroundAttachment in BackgroundAttachments" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'layoutPicker'">
|
||||
<select ng-options="Layout for Layout in Layouts" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div class="box-slider" ng-if="field.type == 'slider'">
|
||||
<div ui-slider min="{{field.min}}" max="{{field.max}}" step="1" ng-model="field.value"></div>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'checkbox'">
|
||||
<input type="checkbox" ng-checked="field.value == 'true'" ng-model="field.value">
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'displayPicker'">
|
||||
<select ng-options="display for display in displays" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'optionHomePicker'">
|
||||
<select ng-options="optionHome for optionHome in optionHomes" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'fontFamilyPicker'">
|
||||
<div class="fontFamilyPickerPreview" ng-click="openFontFamilyPickerModal(field)" style="font-family:{{ field.value }}">
|
||||
<span>Aa</span>
|
||||
{{ field.value }}
|
||||
</div>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="fa fa-times colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</accordion-group>
|
||||
</accordion>
|
||||
|
||||
</div>
|
||||
|
||||
</tab>
|
||||
|
||||
</tabset>
|
||||
|
||||
<button class="btn btn-default btn-default-save" ng-click="saveLessParameters()">save</button>
|
||||
<button class="btn btn-default btn-default-delete" ng-click="deleteTuning()">reset</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="settingIsOpen == 'presetColors'">
|
||||
|
||||
<h2>PALETTE COLORS</h2>
|
||||
<ul class="palette">
|
||||
<li ng-click="refreshtuningByPalette(palette)" ng-repeat="palette in tuningPalette">
|
||||
<div>
|
||||
<span style="background-color: {{ palette.mainColor }}"></span>
|
||||
</div>
|
||||
<p>{{ palette.name }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="btn btn-default btn-default-save" style="display:none" ng-click="saveLessParameters()">save</button>
|
||||
<button class="btn btn-default btn-default-save" ng-click="makePreset()">make it !</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="myModalContent.html">
|
||||
<div class="modal-header bodyTuningImagePicker ng-scope">
|
||||
<ul class="breadcrumb">
|
||||
<li ng-if="startNodeId == -1">
|
||||
<a href="" ng-click="gotoFolder()">Media</a>
|
||||
</li>
|
||||
|
||||
<!-- ngRepeat: item in path -->
|
||||
<li ng-repeat="item in currentPath" class="ng-scope">
|
||||
<a ng-if="currentFolder.id == item.id" href="" ng-class="{disabled:currentFolder.id == item.id}">{{ item.name }}</a>
|
||||
<a ng-if="currentFolder.id != item.id" ng-click="gotoFolder(item)">{{ item.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-body bodyTuningImagePicker">
|
||||
<ul class="tuningImagePicker">
|
||||
<li>
|
||||
<ul class="media-items">
|
||||
<li ng-repeat="child in currentFolder.children | orderBy:'isFolder':true">
|
||||
<div ng-if="!child.isFolder" class=" media-preview" ng-class="{selected:selectedMedia.id == child.id}" ng-click="selectMedia(child)" style="background-image: url({{ child.thumbnail }})"></div>
|
||||
<div ng-if="child.isFolder" class=" media-preview" ng-click="selectMedia(child)">
|
||||
<i class="icon icon-folder folder"><p class="folder-name">{{child.name}}</p></i>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" ng-click="ok()">OK</button>
|
||||
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="fontFamilyPickerModel.html">
|
||||
|
||||
<div class="modal-header tuning-fontfamilypicker">
|
||||
<select ng-model="selectedFont" ng-change="showFontPreview(selectedFont)" ng-options="font as font.fontFamily group by font.fontType for font in fonts"></select>
|
||||
<select ng-model="selectedFont.variant" ng-change="showFontPreview(selectedFont)" ng-options="variant for variant in selectedFont.variants" />
|
||||
</div>
|
||||
|
||||
<div class="modal-body tuning-fontfamilypicker">
|
||||
<span class="show" ng-style="setStyleVariant()">Aa Bb Cc 1 2 3 4… <br />The quick brown fox jumps over the lazy dog…</span>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer tuning-fontfamilypicker">
|
||||
<button class="btn btn-primary" ng-click="ok()">OK</button>
|
||||
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="speechbubble">
|
||||
<p>Styles saved and visible at the website</p>
|
||||
</div>
|
||||
|
||||
<script src="/umbraco/lib/lazyload/lazyload.min.js"></script>
|
||||
<script src="/umbraco/js/tuning.loader.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,148 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* jQuery UI Slider plugin wrapper */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
angular.module('ui.slider', []).value('uiSliderConfig', {}).directive('uiSlider', ['uiSliderConfig', '$timeout', function (uiSliderConfig, $timeout) {
|
||||
uiSliderConfig = uiSliderConfig || {};
|
||||
return {
|
||||
require: 'ngModel',
|
||||
template: '<div><div class="slider" /><span class="slider-span">px</span><input class="slider-input" ng-model="value"></div>',
|
||||
replace: true,
|
||||
compile: function () {
|
||||
return function (scope, elm, attrs, ngModel) {
|
||||
|
||||
scope.value = ngModel.$viewValue;
|
||||
|
||||
function parseNumber(n, decimals) {
|
||||
return (decimals) ? parseFloat(n) : parseInt(n);
|
||||
};
|
||||
|
||||
var options = angular.extend(scope.$eval(attrs.uiSlider) || {}, uiSliderConfig);
|
||||
// Object holding range values
|
||||
var prevRangeValues = {
|
||||
min: null,
|
||||
max: null
|
||||
};
|
||||
|
||||
// convenience properties
|
||||
var properties = ['min', 'max', 'step'];
|
||||
var useDecimals = (!angular.isUndefined(attrs.useDecimals)) ? true : false;
|
||||
|
||||
var init = function () {
|
||||
// When ngModel is assigned an array of values then range is expected to be true.
|
||||
// Warn user and change range to true else an error occurs when trying to drag handle
|
||||
if (angular.isArray(ngModel.$viewValue) && options.range !== true) {
|
||||
console.warn('Change your range option of ui-slider. When assigning ngModel an array of values then the range option should be set to true.');
|
||||
options.range = true;
|
||||
}
|
||||
|
||||
// Ensure the convenience properties are passed as options if they're defined
|
||||
// This avoids init ordering issues where the slider's initial state (eg handle
|
||||
// position) is calculated using widget defaults
|
||||
// Note the properties take precedence over any duplicates in options
|
||||
angular.forEach(properties, function (property) {
|
||||
if (angular.isDefined(attrs[property])) {
|
||||
options[property] = parseNumber(attrs[property], useDecimals);
|
||||
}
|
||||
});
|
||||
|
||||
elm.find(".slider").slider(options);
|
||||
init = angular.noop;
|
||||
};
|
||||
|
||||
// Find out if decimals are to be used for slider
|
||||
angular.forEach(properties, function (property) {
|
||||
// support {{}} and watch for updates
|
||||
attrs.$observe(property, function (newVal) {
|
||||
if (!!newVal) {
|
||||
init();
|
||||
elm.find(".slider").slider('option', property, parseNumber(newVal, useDecimals));
|
||||
}
|
||||
});
|
||||
});
|
||||
attrs.$observe('disabled', function (newVal) {
|
||||
init();
|
||||
elm.find(".slider").slider('option', 'disabled', !!newVal);
|
||||
});
|
||||
|
||||
// Watch ui-slider (byVal) for changes and update
|
||||
scope.$watch(attrs.uiSlider, function (newVal) {
|
||||
init();
|
||||
if (newVal != undefined) {
|
||||
elm.find(".slider").slider('option', newVal);
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Late-bind to prevent compiler clobbering
|
||||
$timeout(init, 0, true);
|
||||
|
||||
// Update model value from slider
|
||||
elm.find(".slider").bind('slidestop', function (event, ui) {
|
||||
ngModel.$setViewValue(ui.values || ui.value);
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
elm.bind('slide', function (event, ui) {
|
||||
event.stopPropagation();
|
||||
elm.find(".slider-input").val(ui.value);
|
||||
});
|
||||
|
||||
// Update slider from model value
|
||||
ngModel.$render = function () {
|
||||
init();
|
||||
var method = options.range === true ? 'values' : 'value';
|
||||
|
||||
if (isNaN(ngModel.$viewValue) && !(ngModel.$viewValue instanceof Array))
|
||||
ngModel.$viewValue = 0;
|
||||
|
||||
scope.value = ngModel.$viewValue;
|
||||
|
||||
// Do some sanity check of range values
|
||||
if (options.range === true) {
|
||||
|
||||
// Check outer bounds for min and max values
|
||||
if (angular.isDefined(options.min) && options.min > ngModel.$viewValue[0]) {
|
||||
ngModel.$viewValue[0] = options.min;
|
||||
}
|
||||
if (angular.isDefined(options.max) && options.max < ngModel.$viewValue[1]) {
|
||||
ngModel.$viewValue[1] = options.max;
|
||||
}
|
||||
|
||||
// Check min and max range values
|
||||
if (ngModel.$viewValue[0] >= ngModel.$viewValue[1]) {
|
||||
// Min value should be less to equal to max value
|
||||
if (prevRangeValues.min >= ngModel.$viewValue[1])
|
||||
ngModel.$viewValue[0] = prevRangeValues.min;
|
||||
// Max value should be less to equal to min value
|
||||
if (prevRangeValues.max <= ngModel.$viewValue[0])
|
||||
ngModel.$viewValue[1] = prevRangeValues.max;
|
||||
}
|
||||
|
||||
// Store values for later user
|
||||
prevRangeValues.min = ngModel.$viewValue[0];
|
||||
prevRangeValues.max = ngModel.$viewValue[1];
|
||||
|
||||
}
|
||||
elm.find(".slider").slider(method, ngModel.$viewValue);
|
||||
};
|
||||
|
||||
scope.$watch("value", function () {
|
||||
ngModel.$setViewValue(scope.value);
|
||||
}, true);
|
||||
|
||||
scope.$watch(attrs.ngModel, function () {
|
||||
if (options.range === true) {
|
||||
ngModel.$render();
|
||||
}
|
||||
}, true);
|
||||
|
||||
function destroy() {
|
||||
elm.find(".slider").slider('destroy');
|
||||
}
|
||||
elm.find(".slider").bind('$destroy', destroy);
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* spectrum color picker directive */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
angular.module('spectrumcolorpicker', [])
|
||||
.directive('spectrum', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
scope: {
|
||||
colorselected: '='
|
||||
},
|
||||
link: function (scope, $element) {
|
||||
|
||||
var initColor;
|
||||
|
||||
$element.find("input").spectrum({
|
||||
color: scope.colorselected,
|
||||
preferredFormat: "rgb",
|
||||
showAlpha: true,
|
||||
showInput: true,
|
||||
change: function (color) {
|
||||
scope.colorselected = color.toRgbString();
|
||||
scope.$apply();
|
||||
},
|
||||
move: function (color) {
|
||||
scope.colorselected = color.toRgbString();
|
||||
scope.$apply();
|
||||
},
|
||||
beforeShow: function (color) {
|
||||
initColor = angular.copy(scope.colorselected);
|
||||
$(this).spectrum("container").find(".sp-cancel").click(function (e) {
|
||||
scope.colorselected = initColor;
|
||||
scope.$apply();
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
scope.$watch('colorselected', function () {
|
||||
$element.find("input").spectrum("set", scope.colorselected);
|
||||
}, true);
|
||||
|
||||
},
|
||||
template:
|
||||
'<div><input type=\'text\' ng-model=\'colorselected\' /></div>',
|
||||
replace: true
|
||||
};
|
||||
})
|
||||
@@ -0,0 +1,758 @@
|
||||
/*********************************************************************************************************/
|
||||
/* tuning panel app and controller */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
// tuning main app
|
||||
angular.module("umbraco.tuning", ['ui.bootstrap', 'spectrumcolorpicker', 'ui.slider', 'umbraco.resources', 'umbraco.services'])
|
||||
|
||||
// panel main controller
|
||||
.controller("Umbraco.tuningController", function ($scope, $modal, $http, $window, $timeout, $location) {
|
||||
|
||||
$scope.isOpen = false;
|
||||
$scope.frameLoaded = false;
|
||||
$scope.enableTuning = 0;
|
||||
$scope.tuningParameterUrl = "";
|
||||
$scope.tuningGridList = "";
|
||||
$scope.schemaFocus = "body";
|
||||
$scope.settingIsOpen = 'previewDevice';
|
||||
$scope.BackgroundPositions = ['center', 'left', 'right', 'bottom center', 'bottom left', 'bottom right', 'top center', 'top left', 'top right'];
|
||||
$scope.BackgroundRepeats = ['no-repeat', 'repeat', 'repeat-x', 'repeat-y'];
|
||||
$scope.BackgroundAttachments = ['scroll', 'fixed'];
|
||||
$scope.Layouts = ['boxed', 'wide', 'full'];
|
||||
$scope.displays = ['float-left', 'float-right', 'block-left', 'block-right', 'none'];
|
||||
$scope.optionHomes = ['icon', 'text', 'none'];
|
||||
$scope.googleFontFamilies = {};
|
||||
$scope.pageId = "../dialogs/Preview.aspx?id=" + $location.search().id;
|
||||
$scope.devices = [
|
||||
{ name: "desktop", css: "desktop", icon: "icon-display" },
|
||||
{ name: "laptop - 1366px", css: "laptop border", icon: "icon-laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait border", icon: "icon-ipad" },
|
||||
{ name: "iPad landscape - 1024px", css: "iPad-landscape border", icon: "icon-ipad flip" },
|
||||
{ name: "smartphone portrait - 480px", css: "smartphone-portrait border", icon: "icon-iphone" },
|
||||
{ name: "smartphone landscape - 320px", css: "smartphone-landscape border", icon: "icon-iphone flip" }
|
||||
];
|
||||
$scope.previewDevice = $scope.devices[0];
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preview devices */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Set preview device
|
||||
$scope.updatePreviewDevice = function (device) {
|
||||
$scope.previewDevice = device;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* UI designer managment */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Update all tuningConfig's values from data
|
||||
var updateConfigValue = function (data) {
|
||||
|
||||
var fonts = [];
|
||||
$.each(tuningConfig.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
try {
|
||||
|
||||
// value
|
||||
var newValue = eval("data." + field.alias.replace("@", ""));
|
||||
if (newValue != undefined) {
|
||||
field.value = newValue;
|
||||
if (field.value == "''") { field.value = ""; }
|
||||
}
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
|
||||
var fontWeight = eval("data." + field.alias.replace("@", "") + "_weight");
|
||||
var fontStyle = eval("data." + field.alias.replace("@", "") + "_style");
|
||||
var fontType = eval("data." + field.alias.replace("@", "") + "_type");
|
||||
|
||||
if (fontWeight != undefined) {
|
||||
field.fontWeight = fontWeight;
|
||||
if (field.fontWeight == "''") { field.fontWeight = ""; }
|
||||
}
|
||||
|
||||
if (fontStyle != undefined) {
|
||||
field.fontStyle = fontStyle;
|
||||
if (field.fontStyle == "''") { field.fontStyle = ""; }
|
||||
}
|
||||
|
||||
if (fontType != undefined) {
|
||||
field.fontType = fontType;
|
||||
if (field.fontType == "''") { field.fontType = ""; }
|
||||
}
|
||||
|
||||
if (fontType == 'google' && field.value + field.fontWeight && $.inArray(field.value + ":" + field.fontWeight, fonts) < 0) {
|
||||
fonts.splice(0, 0, field.value + ":" + field.fontWeight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
console.info("Style parameter not found " + field.alias);
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// Load google font
|
||||
$.each(fonts, function (indexFont, font) {
|
||||
loadGoogleFont(font);
|
||||
loadGoogleFontInFront(font);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Load parameters from GetLessParameters and init data of the tuning config
|
||||
var initTuning = function () {
|
||||
|
||||
$http.get('/Umbraco/Api/tuning/Load', { params: { tuningStyleUrl: $scope.tuningParameterUrl, pageId: $location.search().id } })
|
||||
.success(function (data) {
|
||||
|
||||
updateConfigValue(data);
|
||||
|
||||
$scope.tuningModel = tuningConfig;
|
||||
$scope.tuningPalette = tuningPalette;
|
||||
|
||||
if ($scope.settingIsOpen == "setting") {
|
||||
openIntelTuning();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Add Less parameters for each grid row
|
||||
var initGridConfig = function () {
|
||||
|
||||
if ($scope.tuningGridList) {
|
||||
|
||||
$.each($scope.tuningGridList, function (index, row) {
|
||||
|
||||
var stylingSubSection = tuningConfig.categories[1].sections[0].subSections
|
||||
var newIndex = stylingSubSection.length + 1;
|
||||
var rowFieldModel = angular.copy(rowModel);
|
||||
|
||||
var rowNumber = index + 1;
|
||||
rowFieldModel.name = "Grid Row " + rowNumber;
|
||||
stylingSubSection.splice(newIndex + 1, 0, rowFieldModel);
|
||||
stylingSubSection[newIndex - 1].schema = "." + row;
|
||||
|
||||
$.each(stylingSubSection[newIndex - 1].fields, function (indexField, field) {
|
||||
field.alias = field.alias + "__" + row;
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Refresh all less parameters for every changes watching tuningModel
|
||||
var refreshtuning = function () {
|
||||
var parameters = [];
|
||||
|
||||
if ($scope.tuningModel) {
|
||||
$.each($scope.tuningModel.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
// value
|
||||
parameters.splice(parameters.length + 1, 0, "'@" + field.alias + "':'" + field.value + "'");
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
parameters.splice(parameters.length + 1, 0, "'@" + field.alias + "_weight':'" + field.fontWeight + "'");
|
||||
parameters.splice(parameters.length + 1, 0, "'@" + field.alias + "_Style':'" + field.fontStyle + "'");
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// Refrech page style
|
||||
refreshFrontStyles(parameters);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Save all parameter in tuningParameters.less file
|
||||
$scope.saveLessParameters = function () {
|
||||
|
||||
var parameters = [];
|
||||
var parametersGrid = [];
|
||||
$.each($scope.tuningModel.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
if (subSection.schema && subSection.schema.indexOf("gridrow_") >= 0) {
|
||||
var value = (field.value != 0 && (field.value == undefined || field.value == "")) ? "''" : field.value;
|
||||
parametersGrid.splice(parametersGrid.length + 1, 0, "@" + field.alias + ":" + value + ";");
|
||||
}
|
||||
else {
|
||||
// value
|
||||
var value = (field.value != 0 && (field.value == undefined || field.value == "")) ? "''" : field.value;
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + ":" + value + ";");
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
if (field.fontType == "google" && value != "''") {
|
||||
var variant = field.fontWeight != "" || field.fontStyle != "" ? ":" + field.fontWeight + field.fontStyle : "";
|
||||
var gimport = "@import url('http://fonts.googleapis.com/css?family=" + value + variant + "');";
|
||||
if ($.inArray(gimport, parameters) < 0) {
|
||||
parameters.splice(0, 0, gimport);
|
||||
}
|
||||
}
|
||||
var fontWeight = (field.fontWeight != 0 && (field.fontWeight == undefined || field.fontWeight == "")) ? "''" : field.fontWeight;
|
||||
var fontStyle = (field.fontStyle != 0 && (field.fontStyle == undefined || field.fontStyle == "")) ? "''" : field.fontStyle;
|
||||
var fontType = (field.fontType != 0 && (field.fontType == undefined || field.fontType == "")) ? "''" : field.fontType;
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + "_weight:" + fontWeight + ";");
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + "_style:" + fontStyle + ";");
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + "_type:" + fontType + ";");
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
var resultParameters = { parameters: parameters.join(""), parametersGrid: parametersGrid.join(""), pageId: $location.search().id };
|
||||
var transform = function (result) {
|
||||
return $.param(result);
|
||||
}
|
||||
|
||||
$('.btn-default-save').attr("disabled", true);
|
||||
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
|
||||
$http.post('/Umbraco/Api/tuning/Save', resultParameters, {
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
transformRequest: transform
|
||||
})
|
||||
.success(function (data) {
|
||||
$('.btn-default-save').attr("disabled", false);
|
||||
$('#speechbubble').fadeIn('slow').delay(5000).fadeOut('slow');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Delete current page tuning
|
||||
$scope.deleteTuning = function () {
|
||||
$('.btn-default-delete').attr("disabled", true);
|
||||
$http.get('/Umbraco/Api/tuning/Delete', { params: { pageId: $location.search().id } })
|
||||
.success(function (data) {
|
||||
$scope.enableTuning++;
|
||||
$scope.pageId = $scope.pageId + "&n=123456";
|
||||
$('.btn-default-delete').attr("disabled", false);
|
||||
})
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preset design */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Refresh with selected tuning palette
|
||||
$scope.refreshtuningByPalette = function (palette) {
|
||||
updateConfigValue(palette.colors);
|
||||
refreshtuning();
|
||||
}
|
||||
|
||||
// Hidden botton to make preset from the current settings
|
||||
$scope.makePreset = function () {
|
||||
|
||||
var parameters = [];
|
||||
$.each($scope.tuningModel.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
if (!subSection.schema || subSection.schema.indexOf("gridrow_") < 0) {
|
||||
|
||||
// value
|
||||
var value = (field.value != 0 && (field.value == undefined || field.value == "")) ? "''" : field.value;
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "\":" + " \"" + value + "\"");
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
var fontWeight = (field.fontWeight != 0 && (field.fontWeight == undefined || field.fontWeight == "")) ? "''" : field.fontWeight;
|
||||
var fontStyle = (field.fontStyle != 0 && (field.fontStyle == undefined || field.fontStyle == "")) ? "''" : field.fontStyle;
|
||||
var fontType = (field.fontType != 0 && (field.fontType == undefined || field.fontType == "")) ? "''" : field.fontType;
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "_weight" + "\":" + " \"" + fontWeight + "\"");
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "_style" + "\":" + " \"" + fontStyle + "\"");
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "_type" + "\":" + " \"" + fontType + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
$("body").append("<textarea>{name:\"\", mainColor:\"\", colors:{" + parameters.join(",") + "}}</textarea>");
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Panel managment */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Toggle panel
|
||||
$scope.togglePanel = function () {
|
||||
if ($scope.isOpen) {
|
||||
$scope.isOpen = false;
|
||||
closeIntelTuning();
|
||||
}
|
||||
else {
|
||||
$scope.isOpen = true;
|
||||
$scope.settingOpen($scope.settingIsOpen);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle setting
|
||||
$scope.settingOpen = function (a) {
|
||||
|
||||
if ($scope.settingIsOpen == "setting" && a != "setting") {
|
||||
closeIntelTuning();
|
||||
}
|
||||
|
||||
if (a == "setting") {
|
||||
openIntelTuning();
|
||||
}
|
||||
|
||||
$scope.settingIsOpen = a;
|
||||
}
|
||||
|
||||
// Remove value from field
|
||||
$scope.removeField = function (field) {
|
||||
field.value = "";
|
||||
}
|
||||
|
||||
// Open image picker modal
|
||||
$scope.open = function (field) {
|
||||
$scope.data = {
|
||||
newFolder: "",
|
||||
modalField: field
|
||||
};
|
||||
|
||||
var modalInstance = $modal.open({
|
||||
scope: $scope,
|
||||
templateUrl: 'myModalContent.html',
|
||||
controller: 'tuning.mediapickercontroller',
|
||||
resolve: {
|
||||
items: function () {
|
||||
return field.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function (selectedItem) {
|
||||
field.value = selectedItem;
|
||||
});
|
||||
};
|
||||
|
||||
// Open font family picker modal
|
||||
$scope.openFontFamilyPickerModal = function (field) {
|
||||
$scope.data = {
|
||||
modalField: field
|
||||
};
|
||||
var modalInstance = $modal.open({
|
||||
scope: $scope,
|
||||
templateUrl: 'fontFamilyPickerModel.html',
|
||||
controller: 'tuning.fontfamilypickercontroller',
|
||||
resolve: {
|
||||
googleFontFamilies: function () {
|
||||
return $scope.googleFontFamilies;
|
||||
},
|
||||
item: function () {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function (selectedItem) {
|
||||
field.value = selectedItem.fontFamily;
|
||||
field.fontType = selectedItem.fontType;
|
||||
field.fontWeight = selectedItem.fontWeight;
|
||||
field.fontStyle = selectedItem.fontStyle;
|
||||
});
|
||||
};
|
||||
|
||||
// Accordion open event
|
||||
$scope.accordionOpened = function (schema) {
|
||||
$scope.schemaFocus = schema;
|
||||
}
|
||||
|
||||
// Focus schema in front
|
||||
$scope.accordionWillBeOpened = function (schema) {
|
||||
if (schema) {
|
||||
setSelectedSchema(schema);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Call function into the front-end */
|
||||
/*****************************************************************************/
|
||||
|
||||
var openIntelTuning = function () {
|
||||
if (document.getElementById("resultFrame").contentWindow.initIntelTuning)
|
||||
document.getElementById("resultFrame").contentWindow.initIntelTuning($scope.tuningModel);
|
||||
}
|
||||
|
||||
var closeIntelTuning = function () {
|
||||
if (document.getElementById("resultFrame").contentWindow.closeIntelTuning)
|
||||
document.getElementById("resultFrame").contentWindow.closeIntelTuning($scope.tuningModel);
|
||||
}
|
||||
|
||||
var loadGoogleFontInFront = function (font) {
|
||||
if (document.getElementById("resultFrame").contentWindow.getFont)
|
||||
document.getElementById("resultFrame").contentWindow.getFont(font);
|
||||
}
|
||||
|
||||
var setSelectedSchema = function (schema) {
|
||||
if (document.getElementById("resultFrame").contentWindow.setSelectedSchema)
|
||||
document.getElementById("resultFrame").contentWindow.setSelectedSchema(schema);
|
||||
}
|
||||
|
||||
var refreshFrontStyles = function (parameters) {
|
||||
if (document.getElementById("resultFrame").contentWindow.refrechLayout)
|
||||
document.getElementById("resultFrame").contentWindow.refrechLayout(parameters);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Google font loader, TODO: put together from directive, front and back */
|
||||
/*****************************************************************************/
|
||||
|
||||
var webFontScriptLoaded = false;
|
||||
var loadGoogleFont = function (font) {
|
||||
if (!webFontScriptLoaded) {
|
||||
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
.done(function () {
|
||||
webFontScriptLoaded = true;
|
||||
// Recursively call once webfont script is available.
|
||||
loadGoogleFont(font);
|
||||
})
|
||||
.fail(function () {
|
||||
console.log('error loading webfont');
|
||||
});
|
||||
}
|
||||
else {
|
||||
WebFont.load({
|
||||
google: {
|
||||
families: [font]
|
||||
},
|
||||
loading: function () {
|
||||
console.log('loading font' + font + ' in UI designer');
|
||||
},
|
||||
active: function () {
|
||||
console.log('loaded font ' + font + ' in UI designer');
|
||||
},
|
||||
inactive: function () {
|
||||
console.log('error loading font ' + font + ' in UI designer');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Init */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Preload of the google font
|
||||
$http.get('/Umbraco/Api/tuning/GetGoogleFont').success(function (data) {
|
||||
$scope.googleFontFamilies = data;
|
||||
})
|
||||
|
||||
// watch framLoaded, only if iframe page have EnableTuning()
|
||||
$scope.$watch("enableTuning", function () {
|
||||
if ($scope.enableTuning > 0) {
|
||||
if ($scope.enableTuning == 1) {
|
||||
initGridConfig();
|
||||
}
|
||||
initTuning();
|
||||
$scope.$watch('tuningModel', function () {
|
||||
refreshtuning();
|
||||
}, true);
|
||||
}
|
||||
}, true)
|
||||
|
||||
// First default load
|
||||
$timeout(function () {
|
||||
// toggle panel
|
||||
$scope.frameLoaded = true;
|
||||
//$timeout(function () { 1000, $scope.togglePanel(); });
|
||||
}, 1000);
|
||||
|
||||
})
|
||||
|
||||
// Image picker controller
|
||||
.controller('tuning.mediapickercontroller', function ($scope, $modalInstance, items, $http, mediaResource, umbRequestHelper, entityResource, mediaHelper) {
|
||||
|
||||
if (mediaHelper && mediaHelper.registerFileResolver) {
|
||||
mediaHelper.registerFileResolver("Umbraco.UploadField", function (property, entity, thumbnail) {
|
||||
if (thumbnail) {
|
||||
|
||||
if (mediaHelper.detectIfImageByExtension(property.value)) {
|
||||
var thumbnailUrl = umbRequestHelper.getApiUrl(
|
||||
"imagesApiBaseUrl",
|
||||
"GetBigThumbnail",
|
||||
[{ originalImagePath: property.value }]);
|
||||
|
||||
return thumbnailUrl;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return property.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var modalFieldvalue = $scope.data.modalField.value;
|
||||
|
||||
$scope.currentFolder = {};
|
||||
$scope.currentFolder.children = [];
|
||||
$scope.currentPath = [];
|
||||
$scope.startNodeId = -1;
|
||||
|
||||
$scope.options = {
|
||||
url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"),
|
||||
formData: {
|
||||
currentFolder: $scope.startNodeId
|
||||
}
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
$scope.selectedMedia = undefined;
|
||||
|
||||
$scope.submitFolder = function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
$scope.$parent.data.showFolderInput = false;
|
||||
|
||||
if ($scope.$parent.data.newFolder && $scope.$parent.data.newFolder != "") {
|
||||
mediaResource
|
||||
.addFolder($scope.$parent.data.newFolder, $scope.currentFolder.id)
|
||||
.then(function (data) {
|
||||
$scope.$parent.data.newFolder = undefined;
|
||||
$scope.gotoFolder(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.gotoFolder = function (folder) {
|
||||
|
||||
if (!folder) {
|
||||
folder = { id: $scope.startNodeId, name: "Media", icon: "icon-folder" };
|
||||
}
|
||||
|
||||
if (folder.id > 0) {
|
||||
var matches = _.filter($scope.currentPath, function (value, index) {
|
||||
if (value.id == folder.id) {
|
||||
value.indexInPath = index;
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
if (matches && matches.length > 0) {
|
||||
$scope.currentPath = $scope.currentPath.slice(0, matches[0].indexInPath + 1);
|
||||
}
|
||||
else {
|
||||
$scope.currentPath.push(folder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$scope.currentPath = [];
|
||||
}
|
||||
|
||||
//mediaResource.rootMedia()
|
||||
mediaResource.getChildren(folder.id)
|
||||
.then(function (data) {
|
||||
folder.children = data.items ? data.items : [];
|
||||
|
||||
angular.forEach(folder.children, function (child) {
|
||||
child.isFolder = child.contentTypeAlias == "Folder" ? true : false;
|
||||
|
||||
if (!child.isFolder) {
|
||||
child.thumbnail = mediaHelper.resolveFile(child, true);
|
||||
child.image = mediaHelper.resolveFile(child, false);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.options.formData.currentFolder = folder.id;
|
||||
$scope.currentFolder = folder;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.iconFolder = "glyphicons-icon folder-open"
|
||||
|
||||
$scope.selectMedia = function (media) {
|
||||
|
||||
if (!media.isFolder) {
|
||||
//we have 3 options add to collection (if multi) show details, or submit it right back to the callback
|
||||
$scope.selectedMedia = media;
|
||||
$scope.data.modalField.value = "url(" + $scope.selectedMedia.image + ")";
|
||||
}
|
||||
else {
|
||||
$scope.gotoFolder(media);
|
||||
}
|
||||
};
|
||||
|
||||
//default root item
|
||||
if (!$scope.selectedMedia) {
|
||||
$scope.gotoFolder();
|
||||
}
|
||||
|
||||
$scope.ok = function () {
|
||||
$modalInstance.close($scope.data.modalField.value);
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
$scope.data.modalField.value = modalFieldvalue;
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
})
|
||||
|
||||
// Font picker controller
|
||||
.controller('tuning.fontfamilypickercontroller', function ($scope, $modalInstance, item, googleFontFamilies, $http) {
|
||||
|
||||
$scope.safeFonts = ["Arial, Helvetica", "Impact", "Lucida Sans Unicode", "Tahoma", "Trebuchet MS", "Verdana", "Georgia", "Times New Roman", "Courier New, Courier"];
|
||||
$scope.fonts = [];
|
||||
$scope.selectedFont = {};
|
||||
|
||||
var originalFont = {};
|
||||
originalFont.fontFamily = $scope.data.modalField.value;
|
||||
originalFont.fontType = $scope.data.modalField.fontType;
|
||||
originalFont.fontWeight = $scope.data.modalField.fontWeight;
|
||||
originalFont.fontStyle = $scope.data.modalField.fontStyle;
|
||||
|
||||
var googleGetWeight = function (googleVariant) {
|
||||
return (googleVariant != undefined && googleVariant != "") ? googleVariant.replace("italic", "") : "";
|
||||
};
|
||||
|
||||
var googleGetStyle = function (googleVariant) {
|
||||
var variantStyle = "";
|
||||
if (googleVariant != undefined && googleVariant != "" && googleVariant.indexOf("italic") >= 0) {
|
||||
variantWeight = googleVariant.replace("italic", "");
|
||||
variantStyle = "italic";
|
||||
}
|
||||
return variantStyle;
|
||||
};
|
||||
|
||||
angular.forEach($scope.safeFonts, function (value, key) {
|
||||
$scope.fonts.push({
|
||||
groupName: "Safe fonts",
|
||||
fontType: "safe",
|
||||
fontFamily: value,
|
||||
fontWeight: "normal",
|
||||
fontStyle: "normal",
|
||||
});
|
||||
});
|
||||
|
||||
angular.forEach(googleFontFamilies.items, function (value, key) {
|
||||
var variants = value.variants;
|
||||
var variant = value.variants.length > 0 ? value.variants[0] : "";
|
||||
var fontWeight = googleGetWeight(variant);
|
||||
var fontStyle = googleGetStyle(variant);
|
||||
$scope.fonts.push({
|
||||
groupName: "Google fonts",
|
||||
fontType: "google",
|
||||
fontFamily: value.family,
|
||||
variants: value.variants,
|
||||
variant: variant,
|
||||
fontWeight: fontWeight,
|
||||
fontStyle: fontStyle
|
||||
});
|
||||
});
|
||||
|
||||
$scope.setStyleVariant = function () {
|
||||
if ($scope.selectedFont != undefined) {
|
||||
return {
|
||||
'font-family': $scope.selectedFont.fontFamily,
|
||||
'font-weight': $scope.selectedFont.fontWeight,
|
||||
'font-style': $scope.selectedFont.fontStyle
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showFontPreview = function (font) {
|
||||
if (font != undefined && font.fontFamily != "" && font.fontType == "google") {
|
||||
|
||||
// Font needs to be independently loaded in the iframe for live preview to work.
|
||||
document.getElementById("resultFrame").contentWindow.getFont(font.fontFamily + ":" + font.variant);
|
||||
|
||||
WebFont.load({
|
||||
google: {
|
||||
families: [font.fontFamily + ":" + font.variant]
|
||||
},
|
||||
loading: function () {
|
||||
console.log('loading');
|
||||
},
|
||||
active: function () {
|
||||
// If $apply isn't called, the new font family isn't applied until the next user click.
|
||||
$scope.$apply(function () {
|
||||
$scope.selectedFont = font;
|
||||
$scope.selectedFont.fontWeight = googleGetWeight($scope.selectedFont.variant);
|
||||
$scope.selectedFont.fontStyle = googleGetStyle($scope.selectedFont.variant);
|
||||
// Apply to the page content as a preview.
|
||||
$scope.data.modalField.value = $scope.selectedFont.fontFamily;
|
||||
$scope.data.modalField.fontType = $scope.selectedFont.fontType;
|
||||
$scope.data.modalField.fontWeight = $scope.selectedFont.fontWeight;
|
||||
$scope.data.modalField.fontStyle = $scope.selectedFont.fontStyle;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Font is available, apply it immediately in modal preview.
|
||||
$scope.selectedFont = font;
|
||||
// And to page content.
|
||||
$scope.data.modalField.value = $scope.selectedFont.fontFamily;
|
||||
$scope.data.modalField.fontType = $scope.selectedFont.fontType;
|
||||
$scope.data.modalField.fontWeight = $scope.selectedFont.fontWeight;
|
||||
$scope.data.modalField.fontStyle = $scope.selectedFont.fontStyle;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.ok = function () {
|
||||
$modalInstance.close({
|
||||
fontFamily: $scope.selectedFont.fontFamily,
|
||||
fontType: $scope.selectedFont.fontType,
|
||||
fontWeight: $scope.selectedFont.fontWeight,
|
||||
fontStyle: $scope.selectedFont.fontStyle,
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
// Discard font change.
|
||||
$modalInstance.close({
|
||||
fontFamily: originalFont.fontFamily,
|
||||
fontType: originalFont.fontType,
|
||||
fontWeight: originalFont.fontWeight,
|
||||
fontStyle: originalFont.fontStyle,
|
||||
});
|
||||
};
|
||||
|
||||
if (item != undefined) {
|
||||
angular.forEach($scope.fonts, function (value, key) {
|
||||
if (value.fontFamily == item.value) {
|
||||
$scope.selectedFont = value;
|
||||
$scope.selectedFont.variant = item.fontWeight + item.fontStyle;
|
||||
$scope.selectedFont.fontWeight = item.fontWeight;
|
||||
$scope.selectedFont.fontStyle = item.fontStyle;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,230 @@
|
||||
/*********************************************************************************************************/
|
||||
/* Global function and variable for panel/page com */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
var refrechLayout = function (parameters) {
|
||||
|
||||
// hide preview badget
|
||||
$("#umbracoPreviewBadge").hide();
|
||||
|
||||
var string = "less.modifyVars({" + parameters.join(",") + "})";
|
||||
eval(string);
|
||||
}
|
||||
|
||||
|
||||
/* Fonts loaded in the tuning panel need to be loaded independently in
|
||||
* the content iframe to allow live previewing.
|
||||
*/
|
||||
var webFontScriptLoaded = false;
|
||||
var getFont = function (font) {
|
||||
if (!webFontScriptLoaded) {
|
||||
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
.done(function () {
|
||||
webFontScriptLoaded = true;
|
||||
// Recursively call once webfont script is available.
|
||||
getFont(font);
|
||||
})
|
||||
.fail(function () {
|
||||
console.log('error loading webfont');
|
||||
});
|
||||
}
|
||||
else {
|
||||
WebFont.load({
|
||||
google: {
|
||||
families: [font]
|
||||
},
|
||||
loading: function () {
|
||||
console.log('loading font' + font + ' in iframe');
|
||||
},
|
||||
active: function () {
|
||||
console.log('loaded font ' + font + ' in iframe');
|
||||
},
|
||||
inactive: function () {
|
||||
console.log('error loading font ' + font + ' in iframe');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var setSelectedSchema = function (schema) {
|
||||
outlinePosition($(schema));
|
||||
}
|
||||
|
||||
var closeIntelTuning = function (tuningModel) {
|
||||
|
||||
if (tuningModel) {
|
||||
|
||||
$("[tuning-over]").css('outline', 'none');
|
||||
$.each(tuningModel.categories, function (key, category) {
|
||||
$.each(category.sections, function (key, section) {
|
||||
$.each(section.subSections, function (key, subSection) {
|
||||
if (subSection.schema) {
|
||||
$(subSection.schema).unbind();
|
||||
$(subSection.schema).removeAttr("tuning-over");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var initIntelTuning = function (tuningModel) {
|
||||
|
||||
if (tuningModel) {
|
||||
|
||||
// Add tuning-over attr for each schema from config
|
||||
$.each(tuningModel.categories, function (key, category) {
|
||||
$.each(category.sections, function (key, section) {
|
||||
$.each(section.subSections, function (key, subSection) {
|
||||
if (subSection.schema) {
|
||||
$(subSection.schema).attr("tuning-over", subSection.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Outline tuning-over
|
||||
$(document).mousemove(function (e) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
var target = $(e.target);
|
||||
while (target.length > 0 && (target.attr('tuning-over') == undefined || target.attr('tuning-over') == '')) {
|
||||
target = target.parent();
|
||||
}
|
||||
|
||||
if (target.attr('tuning-over') != undefined && target.attr('tuning-over') != '') {
|
||||
target.unbind();
|
||||
|
||||
outlinePosition(target);
|
||||
|
||||
target.click(function (e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
console.info(target.attr('tuning-over'));
|
||||
parent.refrechIntelTuning(target.attr('tuning-over'));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
outlineHide();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var outlinePosition = function (target) {
|
||||
|
||||
if (target.length > 0 && target.attr('tuning-over') != undefined && target.attr('tuning-over') != '') {
|
||||
|
||||
var localname = target[0].localName;
|
||||
var height = $(target).outerHeight();
|
||||
var width = $(target).outerWidth();
|
||||
var position = $(target).offset();
|
||||
var posY = position.top - $(window).scrollTop();
|
||||
var posX = position.left - $(window).scrollLeft();
|
||||
|
||||
console.info("element select " + localname);
|
||||
|
||||
$("#outline-data").html(target.attr('tuning-over'));
|
||||
$("#outline-data").css('position', 'fixed');
|
||||
$("#outline-data").css('top', posY);
|
||||
$("#outline-data").css('left', posX);
|
||||
$("#outline-data").css('display', 'block');
|
||||
$("#outline-data").css('position', 'fixed');
|
||||
$("#outline-data").css('background-color', 'rgb(164, 198, 253)');
|
||||
$("#outline-data").css('color', '#000000');
|
||||
$("#outline-data").css('padding', '0px 5px 0px 5px');
|
||||
$("#outline-data").css('font-size', '11px');
|
||||
$("#outline-data").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-data").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-data").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-sup").css('display', "block");
|
||||
$("#outline-sup").css('height', "2px");
|
||||
$("#outline-sup").css('width', width + "px");
|
||||
$("#outline-sup").css('position', 'fixed');
|
||||
$("#outline-sup").css('top', posY);
|
||||
$("#outline-sup").css('left', posX);
|
||||
$("#outline-sup").css('background-color', '#a4c6fd');
|
||||
$("#outline-sup").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-sup").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-sup").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-inf").css('display', "block");
|
||||
$("#outline-inf").css('height', "2px");
|
||||
$("#outline-inf").css('width', Number(width + 2) + "px");
|
||||
$("#outline-inf").css('position', 'fixed');
|
||||
$("#outline-inf").css('top', posY + height);
|
||||
$("#outline-inf").css('left', posX);
|
||||
$("#outline-inf").css('background-color', '#a4c6fd');
|
||||
$("#outline-inf").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-inf").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-inf").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-left").css('display', "block");
|
||||
$("#outline-left").css('height', height + "px");
|
||||
$("#outline-left").css('width', "2px");
|
||||
$("#outline-left").css('position', 'fixed');
|
||||
$("#outline-left").css('top', posY);
|
||||
$("#outline-left").css('left', posX);
|
||||
$("#outline-left").css('background-color', '#a4c6fd');
|
||||
$("#outline-left").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-left").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-left").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-right").css('display', "block");
|
||||
$("#outline-right").css('height', height + "px");
|
||||
$("#outline-right").css('width', "2px");
|
||||
$("#outline-right").css('position', 'fixed');
|
||||
$("#outline-right").css('top', posY);
|
||||
$("#outline-right").css('left', posX + width);
|
||||
$("#outline-right").css('background-color', '#a4c6fd');
|
||||
$("#outline-right").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-right").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-right").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
}
|
||||
else {
|
||||
outlineHide();
|
||||
console.info("element not found select");
|
||||
}
|
||||
}
|
||||
|
||||
var outlineHide = function () {
|
||||
|
||||
$("#outline-data").css('display', "none");
|
||||
$("#outline-sup").css('display', "none");
|
||||
$("#outline-inf").css('display', "none");
|
||||
$("#outline-right").css('display', "none");
|
||||
$("#outline-left").css('display', "none");
|
||||
|
||||
}
|
||||
|
||||
var initTuningPanel = function () {
|
||||
|
||||
// Looking for grid row
|
||||
var tuningGridList = []
|
||||
$("div[class^='gridrow_']").each(function (index, value) {
|
||||
tuningGridList.splice(tuningGridList.length + 1, 0, $(value).attr("class"))
|
||||
});
|
||||
|
||||
// Init panel
|
||||
if (parent.setFrameIsLoaded) {
|
||||
parent.setFrameIsLoaded(tuningParameterUrl, tuningGridList);
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
|
||||
// Init ouline layer
|
||||
$("body").append("<div id=\"outline-data\"></div><div id=\"outline-sup\"></div><div id=\"outline-inf\"></div><div id=\"outline-left\"></div><div id=\"outline-right\"></div>");
|
||||
|
||||
// Init tuning panel
|
||||
initTuningPanel();
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* Global function and variable for panel/page com */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
/* Called for every tuning-over rollover */
|
||||
var refrechIntelTuning = function (name) {
|
||||
|
||||
var scope = angular.element($("#tuningPanel")).scope();
|
||||
|
||||
if (scope.schemaFocus != name.toLowerCase()) {
|
||||
|
||||
var notFound = true;
|
||||
angular.forEach(scope.tuningModel.categories, function (category, key) {
|
||||
var isContainer = false;
|
||||
angular.forEach(category.sections, function (section, key) {
|
||||
angular.forEach(section.subSections, function (subSection, key) {
|
||||
if (subSection.name && name.toLowerCase() == subSection.name.toLowerCase()) {
|
||||
isContainer = true;
|
||||
notFound = false
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
if (!category.active) {
|
||||
category.active = isContainer;
|
||||
}
|
||||
});
|
||||
if (notFound) {
|
||||
scope.tuningModel.categories[0].active = true;
|
||||
}
|
||||
scope.$apply();
|
||||
|
||||
if (notFound) {
|
||||
scope.schemaFocus = "body";
|
||||
}
|
||||
else {
|
||||
scope.schemaFocus = name.toLowerCase();
|
||||
}
|
||||
|
||||
scope.$apply();
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when the iframe is first loaded */
|
||||
var setFrameIsLoaded = function (tuningParameterUrl, tuningGridList) {
|
||||
var scope = angular.element($("#tuningPanel")).scope();
|
||||
scope.tuningParameterUrl = tuningParameterUrl;
|
||||
scope.tuningGridList = tuningGridList
|
||||
scope.enableTuning++;
|
||||
scope.$apply();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
/************************************************************************/
|
||||
/* Grid row -ID- */
|
||||
/************************************************************************/
|
||||
|
||||
/***start-lessParam--ID-***/
|
||||
@backgroundRowColor__-ID-:'';
|
||||
@backgroundRowImageOrPattern__-ID-:'';
|
||||
@backgroundRowGradientColor__-ID-:'';
|
||||
@backgroundRowPosition__-ID-:'';
|
||||
@backgroundRowCover__-ID-:'';
|
||||
@backgroundRowRepeat__-ID-:'';
|
||||
@backgroundRowAttachment__-ID-:'';
|
||||
@rowFullSize__-ID-:false;
|
||||
/***end-lessParam--ID-***/
|
||||
|
||||
/***start-gridStyle--ID-***/
|
||||
.Row-cover__-ID- () when (@backgroundRowCover__-ID- = true) {
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.Row-full-size__-ID- () when (@rowFullSize__-ID- = true) {
|
||||
width:100%;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px
|
||||
}
|
||||
|
||||
.-ID- {
|
||||
background-color:@backgroundRowColor__-ID-;
|
||||
background: -moz-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(41%,@backgroundRowColor__-ID-), color-stop(100%,@backgroundRowGradientColor__-ID-));
|
||||
background: -webkit-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: -o-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: -ms-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: linear-gradient(to bottom, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background-image: @backgroundRowImageOrPattern__-ID-;
|
||||
background-position: @backgroundRowPosition__-ID-;
|
||||
background-repeat: @backgroundRowRepeat__-ID-;
|
||||
background-attachment: @backgroundRowAttachment__-ID-;
|
||||
.Row-cover__-ID-;}
|
||||
|
||||
.-ID- .container {
|
||||
.Row-full-size__-ID-;
|
||||
}
|
||||
|
||||
/***end-gridStyle--ID-***/
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Dialogs.ApprovedColorPickerController", function ($scope, $http, umbPropEditorHelper, assetsService) {
|
||||
assetsService.loadJs("lib/cssparser/cssparser.js")
|
||||
.then(function () {
|
||||
|
||||
var cssPath = $scope.dialogData.cssPath;
|
||||
$scope.cssClass = $scope.dialogData.cssClass;
|
||||
|
||||
$scope.classes = [];
|
||||
|
||||
$scope.change = function (newClass) {
|
||||
$scope.model.value = newClass;
|
||||
}
|
||||
|
||||
$http.get(cssPath)
|
||||
.success(function (data) {
|
||||
var parser = new CSSParser();
|
||||
$scope.classes = parser.parse(data, false, false).cssRules;
|
||||
$scope.classes.splice(0, 0, "noclass");
|
||||
})
|
||||
|
||||
assetsService.loadCss("/App_Plugins/Lecoati.uSky.Grid/lib/uSky.Grid.ApprovedColorPicker.css");
|
||||
assetsService.loadCss(cssPath);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<div ng-controller="Umbraco.Dialogs.ApprovedColorController">
|
||||
<div class='CssClassPickerBox {{(class.mSelectorText.substring(1) == cssClass)? "select" : "" }}'
|
||||
ng-click="submit(class.mSelectorText.substring(1))" ng-repeat='class in classes'>
|
||||
<div class='{{class.mSelectorText.substring(1)}}'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,15 +1,116 @@
|
||||
function ContentEditDialogController($scope) {
|
||||
function ContentEditDialogController($scope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, umbModelMapper, $http) {
|
||||
//setup scope vars
|
||||
$scope.model = {};
|
||||
$scope.model.defaultButton = null;
|
||||
$scope.model.subButtons = [];
|
||||
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
if(dialogOptions.entity){
|
||||
$scope.model.entity = dialogOptions.entity;
|
||||
$scope.loaded = true;
|
||||
$scope.model.nodeId = 0;
|
||||
|
||||
var dialogOptions = $scope.$parent.dialogOptions;
|
||||
|
||||
if(angular.isObject(dialogOptions.entity)){
|
||||
$scope.model.entity = $scope.filterTabs(dialogOptions.entity, dialogOptions.tabFilter);
|
||||
$scope.loaded = true;
|
||||
}else{
|
||||
|
||||
if (dialogOptions.create) {
|
||||
//we are creating so get an empty content item
|
||||
contentResource.getScaffold(dialogOptions.id, dialogOptions.contentType)
|
||||
.then(function(data) {
|
||||
$scope.loaded = true;
|
||||
$scope.model.entity = $scope.filterTabs(data, dialogOptions.tabFilter);
|
||||
});
|
||||
}
|
||||
else {
|
||||
//we are editing so get the content item from the server
|
||||
contentResource.getById(dialogOptions.id)
|
||||
.then(function(data) {
|
||||
$scope.loaded = true;
|
||||
$scope.model.entity = $scope.filterTabs(data, dialogOptions.tabFilter);
|
||||
|
||||
|
||||
//in one particular special case, after we've created a new item we redirect back to the edit
|
||||
// route but there might be server validation errors in the collection which we need to display
|
||||
// after the redirect, so we will bind all subscriptions which will show the server validation errors
|
||||
// if there are any and then clear them so the collection no longer persists them.
|
||||
serverValidationManager.executeAndClearAllSubscriptions();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function performSave(args) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
$scope.busy = true;
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: args.statusMessage })) {
|
||||
|
||||
args.saveMethod($scope.model.entity, $routeParams.create, fileManager.getFiles())
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.model.entity, data)
|
||||
});
|
||||
|
||||
$scope.busy = false;
|
||||
deferred.resolve(data);
|
||||
|
||||
}, function (err) {
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
redirectOnFailure: true,
|
||||
err: err,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.model.entity, err.data)
|
||||
});
|
||||
|
||||
$scope.busy = false;
|
||||
deferred.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
$scope.busy = false;
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
$scope.filterTabs = function(entity, blackList){
|
||||
if(blackList){
|
||||
_.each(entity.tabs, function(tab){
|
||||
tab.hide = _.contains(blackList, tab.alias);
|
||||
});
|
||||
}
|
||||
|
||||
return entity;
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function() {
|
||||
$scope.submit($scope.model.entity);
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function() {
|
||||
performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." })
|
||||
.then(function(content){
|
||||
if(dialogOptions.closeOnSave){
|
||||
$scope.submit(content);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.save = function () {
|
||||
performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." })
|
||||
.then(function(content){
|
||||
if(dialogOptions.closeOnSave){
|
||||
$scope.submit(content);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Dialogs.Content.EditController", ContentEditDialogController);
|
||||
@@ -6,12 +6,15 @@
|
||||
|
||||
<div class="umb-panel">
|
||||
<div class="umb-panel-header">
|
||||
<h1>{{model.entity.name}}</h1>
|
||||
<umb-content-name
|
||||
placeholder="@placeholders_entername"
|
||||
ng-model="model.entity.name"/>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body with-footer">
|
||||
<div id="tab{{tab.id}}" ng-repeat="tab in model.entity.tabs">
|
||||
<div class="umb-pane">
|
||||
<div class="umb-pane" ng-if="!tab.hide">
|
||||
<h5>{{tab.label}} - {{tab.alias}}</h5>
|
||||
<umb-property
|
||||
property="property"
|
||||
ng-repeat="property in tab.properties">
|
||||
@@ -26,31 +29,31 @@
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
<localize key="general_close">Close</localize>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="btn-group dropup">
|
||||
<!-- primary button -->
|
||||
<a class="btn btn-success" href="#" ng-click="saveAndPublish()" prevent-default>
|
||||
Publish
|
||||
</a>
|
||||
|
||||
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<!-- sub buttons -->
|
||||
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel">
|
||||
<a href ng-click="save()" prevent-default>
|
||||
Save
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropup" ng-if="defaultButton" >
|
||||
<!-- primary button -->
|
||||
<a class="btn btn-success" href="#" ng-click="performAction(model.defaultButton)" prevent-default>
|
||||
<localize key="{{model.defaultButton.labelKey}}">{{defaultButton.labelKey}}</localize>
|
||||
</a>
|
||||
|
||||
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<!-- sub buttons -->
|
||||
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel"
|
||||
ng-if="model.subButtons.length > 0">
|
||||
<li ng-repeat="btn in model.subButtons">
|
||||
<a href="#" ng-click="performAction(btn)" ng-disabled="true" prevent-default>
|
||||
<localize key="{{btn.labelKey}}">{{btn.labelKey}}</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
angular.module("umbraco").controller('Umbraco.Dialogs.Template.QueryBuilderController',
|
||||
function($scope, $http, dialogService){
|
||||
|
||||
|
||||
$http.get("backoffice/UmbracoApi/TemplateQuery/GetAllowedProperties").then(function(response) {
|
||||
$scope.properties = response.data;
|
||||
});
|
||||
|
||||
$http.get("backoffice/UmbracoApi/TemplateQuery/GetContentTypes").then(function (response) {
|
||||
$scope.contentTypes = response.data;
|
||||
});
|
||||
|
||||
$http.get("backoffice/UmbracoApi/TemplateQuery/GetFilterConditions").then(function (response) {
|
||||
$scope.conditions = response.data;
|
||||
});
|
||||
|
||||
|
||||
$scope.query = {
|
||||
contentType: {
|
||||
name: "Everything"
|
||||
},
|
||||
source:{
|
||||
name: "My website"
|
||||
},
|
||||
filters:[
|
||||
{
|
||||
property:undefined,
|
||||
operator: undefined
|
||||
}
|
||||
],
|
||||
sort:{
|
||||
property:{
|
||||
alias: "",
|
||||
name: "",
|
||||
},
|
||||
direction: "Ascending"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
$scope.chooseSource = function(query){
|
||||
dialogService.contentPicker({
|
||||
callback: function (data) {
|
||||
|
||||
if (data.id > 0) {
|
||||
query.source = { id: data.id, name: data.name };
|
||||
} else {
|
||||
query.source.name = "My website";
|
||||
delete query.source.id;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var throttledFunc = _.throttle(function() {
|
||||
|
||||
$http.post("backoffice/UmbracoApi/TemplateQuery/PostTemplateQuery", $scope.query).then(function (response) {
|
||||
$scope.result = response.data;
|
||||
});
|
||||
|
||||
}, 200);
|
||||
|
||||
$scope.$watch("query", function(value) {
|
||||
throttledFunc();
|
||||
}, true);
|
||||
|
||||
$scope.getPropertyOperators = function (property) {
|
||||
|
||||
var conditions = _.filter($scope.conditions, function(condition) {
|
||||
var index = condition.appliesTo.indexOf(property.type);
|
||||
return index >= 0;
|
||||
});
|
||||
return conditions;
|
||||
};
|
||||
|
||||
|
||||
$scope.addFilter = function(query){
|
||||
query.filters.push({});
|
||||
};
|
||||
|
||||
$scope.trashFilter = function (query) {
|
||||
query.filters.splice(query,1);
|
||||
};
|
||||
|
||||
$scope.changeSortOrder = function(query){
|
||||
if(query.sort.direction === "ascending"){
|
||||
query.sort.direction = "descending";
|
||||
}else{
|
||||
query.sort.direction = "ascending";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setSortProperty = function(query, property){
|
||||
query.sort.property = property;
|
||||
if(property.type === "datetime"){
|
||||
query.sort.direction = "descending";
|
||||
}else{
|
||||
query.sort.direction = "ascending";
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,158 @@
|
||||
<form novalidate name="contentForm"
|
||||
ng-controller="Umbraco.Dialogs.Template.QueryBuilderController"
|
||||
ng-submit="close()"
|
||||
val-form-manager>
|
||||
|
||||
<style>
|
||||
.umb-querybuilder .row {font-size: 12px; line-height: 12px}
|
||||
|
||||
.umb-querybuilder .row a.btn{font-size: 12px; background: lightyellow}
|
||||
|
||||
.umb-querybuilder .row > div{
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="umb-panel">
|
||||
|
||||
<div class="umb-panel-header">
|
||||
<h1 class="headline" style="margin: 10px 0 0 0">Build a query</h1>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body with-footer umb-querybuilder">
|
||||
|
||||
<div class="row">
|
||||
<div>
|
||||
I want
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{query.contentType.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="contentType in contentTypes">
|
||||
<a href ng-click="query.contentType = contentType">
|
||||
{{contentType.name}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<span>from</span>
|
||||
|
||||
<a href class="btn btn-link" ng-click="chooseSource(query)">
|
||||
{{query.source.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="filter in query.filters">
|
||||
|
||||
<span ng-if="$first">Where</span>
|
||||
<span ng-if="!$first">And</span>
|
||||
|
||||
<div class="btn-group">
|
||||
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{filter.property.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="property in properties">
|
||||
<a href ng-click="filter.property = property">
|
||||
{{property.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="btn-group" ng-if="filter.property">
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{filter.term.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="term in getPropertyOperators(filter.property)">
|
||||
<a href ng-click="filter.term = term">
|
||||
{{term.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<input type="text" ng-if="filter.term" style="width:90px;" ng-model="filter.constraintValue" />
|
||||
|
||||
<a href ng-click="addFilter(query)">
|
||||
<i class="icon-add"></i>
|
||||
</a>
|
||||
|
||||
<a href ng-if="query.filters.length > 1" ng-click="trashFilter(query)">
|
||||
<i class="icon-trash"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
Order by
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{query.sort.property.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="property in properties">
|
||||
<a href ng-click="setSortProperty(query, property)">
|
||||
{{property.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<a href class="btn" ng-click="changeSortOrder(query)">
|
||||
{{query.sort.direction}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h4>Returns {{result.resultCount}} items in {{result.executionTime}} miliseconds</h4>
|
||||
|
||||
<ul class="nav unstyled">
|
||||
<li ng-repeat="item in result.sampleResults">
|
||||
<i class="icon icon-document blue"></i> {{item.name}}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<pre>{{result.queryExpression}}</pre>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-footer" >
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_close">Close</localize>
|
||||
</a>
|
||||
|
||||
<a href ng-click="submit(result.queryExpression)" class="btn btn-primary">Insert</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -14,7 +14,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
$scope.nav = navigationService;
|
||||
$scope.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.currentNode = null; //the editors affiliated node
|
||||
|
||||
|
||||
|
||||
//This sets up the action buttons based on what permissions the user has.
|
||||
//The allowedActions parameter contains a list of chars, each represents a button by permission so
|
||||
@@ -37,7 +37,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Now we need to make the drop down button list, this is also slightly tricky because:
|
||||
//We cannot have any buttons if there's no default button above.
|
||||
//We cannot have the unpublish button (Z) when there's no publish permission.
|
||||
@@ -57,7 +57,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
//if we are not creating, then we should add unpublish too,
|
||||
// so long as it's already published and if the user has access to publish
|
||||
if (!$routeParams.create) {
|
||||
if (content.publishDate && _.contains(content.allowedActions,"U")) {
|
||||
if (content.publishDate && _.contains(content.allowedActions, "U")) {
|
||||
$scope.subButtons.push(createButtonDefinition("Z"));
|
||||
}
|
||||
}
|
||||
@@ -65,11 +65,11 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
|
||||
//We fetch all ancestors of the node to generate the footer breadcrump navigation
|
||||
if (!$routeParams.create) {
|
||||
entityResource.getAncestors(content.id, "document")
|
||||
.then(function(anc) {
|
||||
anc.pop();
|
||||
$scope.ancestors = anc;
|
||||
});
|
||||
entityResource.getAncestors(content.id, "document")
|
||||
.then(function (anc) {
|
||||
anc.pop();
|
||||
$scope.ancestors = anc;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,9 +117,9 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Syncs the content item to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(content, path, initialLoad) {
|
||||
function syncTreeNode(content, path, initialLoad) {
|
||||
|
||||
//If this is a child of a list view then we can't actually sync the real tree
|
||||
if (!$scope.content.isChildOfListView) {
|
||||
@@ -132,7 +132,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
// from the server so that we can load in the actions menu.
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(content.treeNodeUrl),
|
||||
'Failed to retrieve data for child node ' + content.id).then(function(node) {
|
||||
'Failed to retrieve data for child node ' + content.id).then(function (node) {
|
||||
$scope.currentNode = node;
|
||||
});
|
||||
}
|
||||
@@ -165,9 +165,9 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
syncTreeNode($scope.content, data.path);
|
||||
|
||||
deferred.resolve(data);
|
||||
|
||||
|
||||
}, function (err) {
|
||||
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
redirectOnFailure: true,
|
||||
err: err,
|
||||
@@ -191,10 +191,10 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
if ($routeParams.create) {
|
||||
//we are creating so get an empty content item
|
||||
contentResource.getScaffold($routeParams.id, $routeParams.doctype)
|
||||
.then(function(data) {
|
||||
.then(function (data) {
|
||||
$scope.loaded = true;
|
||||
$scope.content = data;
|
||||
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
configureButtons($scope.content);
|
||||
@@ -203,14 +203,14 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
else {
|
||||
//we are editing so get the content item from the server
|
||||
contentResource.getById($routeParams.id)
|
||||
.then(function(data) {
|
||||
.then(function (data) {
|
||||
$scope.loaded = true;
|
||||
$scope.content = data;
|
||||
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
|
||||
configureButtons($scope.content);
|
||||
|
||||
|
||||
//in one particular special case, after we've created a new item we redirect back to the edit
|
||||
// route but there might be server validation errors in the collection which we need to display
|
||||
// after the redirect, so we will bind all subscriptions which will show the server validation errors
|
||||
@@ -224,12 +224,12 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
|
||||
|
||||
$scope.unPublish = function () {
|
||||
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Unpublishing...", skipValidation: true })) {
|
||||
|
||||
contentResource.unPublish($scope.content.id)
|
||||
.then(function (data) {
|
||||
|
||||
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
@@ -246,36 +246,42 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
$scope.sendToPublish = function() {
|
||||
$scope.sendToPublish = function () {
|
||||
return performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending..." });
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function() {
|
||||
return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
|
||||
$scope.saveAndPublish = function () {
|
||||
return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
|
||||
};
|
||||
|
||||
$scope.save = function () {
|
||||
return performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." });
|
||||
};
|
||||
|
||||
$scope.preview = function(content){
|
||||
$scope.preview = function (content) {
|
||||
// Chromes popup blocker will kick in if a window is opened
|
||||
// outwith the initial scoped request. This trick will fix that.
|
||||
//
|
||||
var previewWindow = $window.open('preview/?id=' + content.id, 'umbpreview');
|
||||
$scope.save().then(function (data) {
|
||||
$window.open('dialogs/preview.aspx?id=' + data.id, 'umbpreview');
|
||||
// Build the correct path so both /#/ and #/ work.
|
||||
var redirect = Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + '/preview/?id=' + data.id;
|
||||
previewWindow.location.href = redirect;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/** this method is called for all action buttons and then we proxy based on the btn definition */
|
||||
$scope.performAction = function(btn) {
|
||||
$scope.performAction = function (btn) {
|
||||
|
||||
if (!btn || !angular.isFunction(btn.handler)) {
|
||||
throw "btn.handler must be a function reference";
|
||||
}
|
||||
|
||||
if(!$scope.busy){
|
||||
btn.handler.apply(this);
|
||||
|
||||
if (!$scope.busy) {
|
||||
btn.handler.apply(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
|
||||
<div class="umb-tab-buttons" detect-fold ng-class="{'umb-dimmed': busy}">
|
||||
|
||||
<div class="btn-group" ng-show="content.template">
|
||||
<a class="btn" ng-click="preview(content)">
|
||||
<localize key="buttons_showPage">Preview page</localize>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Dashboard.RecycleBinController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Controls the recycle bin dashboards
|
||||
*
|
||||
*/
|
||||
|
||||
function RecycleBinController($scope, $routeParams) {
|
||||
if ($routeParams.section) {
|
||||
|
||||
if ($routeParams.section === "content") {
|
||||
$routeParams.id = "-20";
|
||||
}
|
||||
else if ($routeParams.section === "media") {
|
||||
$routeParams.id = "-21";
|
||||
}
|
||||
|
||||
$scope.model = { config: { entityType: $routeParams.section } };
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('umbraco').controller("Umbraco.Dashboard.RecycleBinController", RecycleBinController);
|
||||
@@ -1,9 +1,14 @@
|
||||
<umb-panel>
|
||||
<div class="umb-panel-header">
|
||||
<div class="row-fluid">
|
||||
<span class="span4 umb-panel-header-meta">
|
||||
<h1>Recycle bin</h1>
|
||||
</span>
|
||||
<umb-panel ng-controller="Umbraco.Dashboard.RecycleBinController">
|
||||
<umb-header>
|
||||
<div class="umb-headline-editor-wrapper span12">
|
||||
<h1><localize key="general_recycleBin">Recycle Bin</localize></h1>
|
||||
</div>
|
||||
</div>
|
||||
</umb-header>
|
||||
<umb-tab-view>
|
||||
<umb-tab id="tabRecycleBin" rel="RecycleBin">
|
||||
<umb-pane>
|
||||
<div ng-include="'views/propertyeditors/listview/listview.html'"></div>
|
||||
</umb-pane>
|
||||
</umb-tab>
|
||||
</umb-tab-view>
|
||||
</umb-panel>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Loading</title>
|
||||
<link href="/umbraco/assets/css/umbraco.css" type="text/css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="content-column-body">
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
<div>
|
||||
<div class='umb-modalcolumn-header'>
|
||||
<h1>{{menuDialogTitle}}</h1>
|
||||
<h1 ng-bind-html="menuDialogTitle"></h1>
|
||||
</div>
|
||||
|
||||
<div class='umb-modalcolumn-body'>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<umb-panel ng-controller="Umbraco.Dashboard.RecycleBinController">
|
||||
<umb-header>
|
||||
<div class="umb-headline-editor-wrapper span12">
|
||||
<h1><localize key="general_recycleBin">Recycle Bin</localize></h1>
|
||||
</div>
|
||||
</umb-header>
|
||||
<umb-tab-view>
|
||||
<umb-tab id="tabRecycleBin" rel="RecycleBin">
|
||||
<umb-pane>
|
||||
<div ng-include="'views/propertyeditors/listview/listview.html'"></div>
|
||||
</umb-pane>
|
||||
</umb-tab>
|
||||
</umb-tab-view>
|
||||
</umb-panel>
|
||||
+106
-94
@@ -4,35 +4,35 @@ angular.module('umbraco')
|
||||
.controller("Umbraco.PropertyEditors.ContentPickerController",
|
||||
|
||||
function($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams){
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
entityType: "Document",
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
entityType: "Document",
|
||||
filterCssClass: "not-allowed not-published",
|
||||
|
||||
startNode: {
|
||||
startNode: {
|
||||
query: "",
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.model.config) {
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
if ($scope.model.config) {
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
|
||||
if ($scope.cfg.startNode.type === "member") {
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
if ($scope.cfg.startNode.type === "member") {
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
|
||||
//if we have a query for the startnode, we will use that.
|
||||
if($scope.cfg.startNode.query){
|
||||
@@ -44,90 +44,102 @@ angular.module('umbraco')
|
||||
$scope.cfg.startNodeId = $scope.cfg.startNode.id;
|
||||
}
|
||||
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.section = $scope.cfg.startNode.type;
|
||||
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.edit = function (node) {
|
||||
dialogService.open(
|
||||
{
|
||||
template: "views/common/dialogs/content/edit.html",
|
||||
id: node.id,
|
||||
closeOnSave:true,
|
||||
tabFilter: ["Generic properties"],
|
||||
callback: function(data){
|
||||
node.name = data.name;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.add = function (item) {
|
||||
if ($scope.ids.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
$scope.add = function (item) {
|
||||
if ($scope.ids.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
$scope.ids = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
$scope.ids = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
|
||||
//Validate!
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
});
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
|
||||
function populate(data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
function populate(data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -15,6 +15,7 @@
|
||||
<i class="{{node.icon}} hover-hide"></i>
|
||||
{{node.name}}
|
||||
</a>
|
||||
<br/><small><a href ng-click="edit(node)">Edit</a></small>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
var uSkyGridConfig = [
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 12,
|
||||
percentage: 100,
|
||||
|
||||
cellModels: [
|
||||
{
|
||||
name: "Single column",
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}, {
|
||||
name: "Article",
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["media","quote"]
|
||||
}, {
|
||||
grid: 8,
|
||||
percentage: 66.6,
|
||||
allowed: ["rte"]
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: "Article, reverse",
|
||||
models: [
|
||||
{
|
||||
grid: 8,
|
||||
percentage: 66.6,
|
||||
allowed: ["rte","macro"]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["media","quote","embed"]
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: "Profile page",
|
||||
models: [
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["media"]
|
||||
},
|
||||
{
|
||||
grid: 8,
|
||||
percentage: 66.6,
|
||||
allowed: ["rte"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Headline",
|
||||
models: [
|
||||
{
|
||||
grid: 12,
|
||||
percentage: 100,
|
||||
max: 1,
|
||||
allowed: ["headline"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Three columns",
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["rte"]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["rte"]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["rte"]
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 9,
|
||||
percentage: 70,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}, {
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, ]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}, {
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 3,
|
||||
percentage: 30,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 3,
|
||||
percentage: 30,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 9,
|
||||
percentage: 70,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}, {
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, ]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}, {
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
body.mce-content-body {
|
||||
background: transparent !important;
|
||||
overflow-x:hidden !important;
|
||||
padding-bottom: 10px !important;
|
||||
/*margin:0px;*/
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
border-radius:4px;
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"name": "Headline",
|
||||
"alias": "headline",
|
||||
"view": "textstring",
|
||||
"icon": "icon-coin",
|
||||
"config": {
|
||||
"style": "font-size: 36px; font-weight: bold",
|
||||
"markup" : "<h1>#value#</h1>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Quote",
|
||||
"alias": "quote",
|
||||
"view": "textstring",
|
||||
"icon": "icon-quote",
|
||||
"config": {
|
||||
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px",
|
||||
"markup": "<blockquote>#value#</blockquote>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Rich text editor",
|
||||
"alias": "rte",
|
||||
"view": "rte",
|
||||
"icon": "icon-article"
|
||||
},
|
||||
{
|
||||
"name": "Media",
|
||||
"alias": "media",
|
||||
"view": "media",
|
||||
"icon": "icon-picture"
|
||||
},
|
||||
{
|
||||
"name": "Macro",
|
||||
"alias": "macro",
|
||||
"view": "macro",
|
||||
"icon": "icon-settings-alt"
|
||||
},
|
||||
{
|
||||
"name": "Embed",
|
||||
"alias": "embed",
|
||||
"view": "embed",
|
||||
"icon": "icon-movie-alt"
|
||||
}
|
||||
]
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
|
||||
body{
|
||||
background: white;
|
||||
}
|
||||
|
||||
.editor{padding: 20px; margin: 20px; border: 3px dashed black; }
|
||||
.editor:hover{border-color: red;}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.EmbedController",
|
||||
function ($scope, $rootScope, $timeout, dialogService) {
|
||||
|
||||
$scope.setEmbed = function(){
|
||||
dialogService.embedDialog({
|
||||
callback: function (data) {
|
||||
$scope.control.value = data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$timeout(function(){
|
||||
if($scope.control.value === null){
|
||||
$scope.setEmbed();
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.Grid.EmbedController">
|
||||
|
||||
<div class="usky-editor-placeholder" ng-click="setEmbed()" ng-if="control.value === null">
|
||||
<i class="icon icon-movie-alt"></i>
|
||||
<div class="help-text">Click to embed</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="control.value" ng-bind-html-unsafe="control.value"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.MacroController",
|
||||
function ($scope, $rootScope, $timeout, dialogService, macroResource, macroService, $routeParams) {
|
||||
|
||||
$scope.title = "Click to insert macro";
|
||||
$scope.setMacro = function(){
|
||||
dialogService.macroPicker({
|
||||
callback: function (data) {
|
||||
|
||||
$scope.control.value = {
|
||||
syntax: data.syntax,
|
||||
macroAlias: data.macroAlias,
|
||||
marcoParamsDictionary: data.macroParamsDictionary
|
||||
};
|
||||
|
||||
$scope.setPreview(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setPreview = function(macro){
|
||||
var contentId = $routeParams.id;
|
||||
|
||||
macroResource.getMacroResultAsHtmlForEditor(macro.macroAlias, contentId, macro.macroParamsDictionary)
|
||||
.then(function (htmlResult) {
|
||||
$scope.title = macro.macroAlias;
|
||||
if(htmlResult.trim().length > 0 && htmlResult.indexOf("Macro:") < 0){
|
||||
$scope.preview = htmlResult;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$timeout(function(){
|
||||
if($scope.control.value === null){
|
||||
$scope.setMacro();
|
||||
}else{
|
||||
var parsed = macroService.parseMacroSyntax($scope.control.value.syntax);
|
||||
$scope.setPreview(parsed);
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.Grid.MacroController">
|
||||
|
||||
<div class="usky-editor-placeholder" ng-click="setMacro()">
|
||||
<div ng-if="!preview">
|
||||
<i class="icon icon-settings-alt"></i>
|
||||
<div class="help-text">{{title}}</div>
|
||||
</div>
|
||||
<div ng-if="preview">
|
||||
<div
|
||||
ng-if="preview" style="text-align: left"
|
||||
ng-bind-html-unsafe="preview">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.MediaController",
|
||||
function ($scope, $rootScope, $timeout, dialogService) {
|
||||
|
||||
$scope.setImage = function(){
|
||||
dialogService.mediaPicker({
|
||||
multiPicker: false,
|
||||
callback: function (data) {
|
||||
$scope.control.value = {
|
||||
id: data.id,
|
||||
image: data.image,
|
||||
thumbnail: data.thumbnail
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$timeout(function(){
|
||||
if($scope.control.value === null){
|
||||
$scope.setImage();
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user