Compare commits

..

82 Commits

Author SHA1 Message Date
Sebastiaan Janssen add2f57397 Bump version 2015-08-21 13:30:29 +02:00
Shannon cd3c17d73f Obsoletes AllowAll on MemberAuthorizeAttribute 2015-08-21 12:15:45 +02:00
Shannon fe6d783222 auths member controllers 2015-08-21 12:11:22 +02:00
Shannon fc8b0f1822 Fixes: U4-6934 v7.3.0-beta3 ListView sorting by updateDate throws exception 2015-08-21 12:02:51 +02:00
Shannon 6102c970c8 ensures single tab displays show tab 2015-08-20 19:10:03 +02:00
Shannon 29903058a9 Fixes: U4-6937 Update all web.configs in all subfolders to use MVC4 / Razor 3, U4-6938 While upgrading, delete dlls that shouldn't be there after upgrade 2015-08-20 18:41:39 +02:00
Shannon b3940dea1b Fixes: U4-6982 TAG Group not working as it's expected, when there's more than 2 sets of tag group 2015-08-20 16:52:07 +02:00
Shannon 3dac630d05 Fixes: U4-6998 User language drop down is incorrect when default language is used 2015-08-20 16:07:46 +02:00
Shannon 10108d75b8 Fixes: U4-6953 DatePicker (with time?) seems to be misbehaving since 7.2.8 in Firefox 2015-08-20 15:22:10 +02:00
Shannon 24cb64579b make sure the time is not there for a non time picker when the pre-value is empty. 2015-08-20 12:48:33 +02:00
Shannon 86239cc777 fixes date time picker if the format is cleared from pre-values, it will revert to default. 2015-08-20 12:45:42 +02:00
Shannon 685aea1728 Fixes: U4-6879 Validation issues when creating new content and cancelling save event. 2015-08-20 11:50:32 +02:00
Shannon eb4e041682 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-08-20 10:25:53 +02:00
Shannon 477aa754b3 uses non deprected methods 2015-08-20 10:14:07 +02:00
Shannon Deminick 48bff0aa6c Merge pull request #770 from bjarnef/dev-v7-missing-danish-translations
Add missing Danish translations
2015-08-20 10:12:26 +02:00
Bjarne Fyrstenborg 4ea9fec9e2 Add missing Danish translations
Added missing keys in da.xml and removed some duplicate keys.
2015-08-20 09:56:16 +02:00
Sebastiaan Janssen f3a965841b U4-6043 Error parsing package.manifest value Path line 0 position 0
Added a unit test and updated the logic as it was doing the wrong thing
#U4-6043 Fixed
2015-08-19 19:11:20 +02:00
Sebastiaan Janssen 08ddb5f4c4 Update NuGet dependency for Examine 2015-08-19 18:47:27 +02:00
Sebastiaan Janssen 4ec63ffd0d U4-6939 'html code' button is missing in the Rich Text Editor]
#U4-6939 Fixed
2015-08-19 18:40:04 +02:00
Sebastiaan Janssen 4cb3e82972 U4-6926 HTML tag in nodeName renders as HTML in tree
#U4-6926 Fixed
2015-08-19 18:33:11 +02:00
Shannon 0a20741f39 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-08-19 18:22:26 +02:00
Shannon 4575748f16 adds TODO and formatting 2015-08-19 18:22:06 +02:00
Sebastiaan Janssen 028ee831b8 U4-6043 Error parsing package.manifest value Path line 0 position 0
#U4-6043 Fixed
2015-08-19 18:11:18 +02:00
Sebastiaan Janssen 54981cd57c Merge pull request #764 from Aaen/U4-6977
U4-6977: Updated the Our screenshot to show off the new design
2015-08-19 16:02:10 +02:00
Shannon Deminick 0aab8cacaa Merge pull request #767 from leekelleher/U4-6986
U4-6986 PublishedContentExtensions.FirstChild() throws exception
2015-08-19 15:41:15 +02:00
leekelleher 15b4d33e00 U4-6986 PublishedContentExtensions.FirstChild() throws exception
Changes the return value to use `.FirstOrDefault()` instead of `.First()`.
Includes unit-test.
2015-08-19 13:57:58 +01:00
Shannon Deminick 367ba5cddf Merge pull request #766 from bjarnef/dev-v7-minor-translations
Localize text in help dialog
2015-08-19 10:40:37 +02:00
Dennis Aaen ff64efbcdf Fix: Corrected the height of the image of the new ourumbraco 2015-08-19 10:00:39 +02:00
bjarnef 5bc0c499d8 Localize text in help dialog
Add localization for text in help dialog, create and delete dialogs and
some minor parts of the member area.
2015-08-19 02:03:54 +02:00
Dennis Aaen f667318b58 U4-6977: Updated the Our screenshot to show off the new design 2015-08-18 15:14:51 +02:00
Shannon 87c9d15ad5 removes autocomplete="off" from login 2015-08-18 10:44:45 +02:00
Shannon 127736d188 updates to latest examine 2015-08-13 15:30:28 +02:00
Shannon 139ab8d4df Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-08-13 15:19:26 +02:00
Shannon 4abb8035b8 Changes the shutdown time for the logger to be 1 second 2015-08-13 15:19:16 +02:00
Shannon 0ca1807d64 Adds DelegateExtensions + Tests which is used for retrying and is used with the Examine Index Sync 2015-08-13 15:19:04 +02:00
Shannon Deminick 5ae90d201c Merge pull request #762 from Jeavon/RefreshByJson
Publicise methods and subclasses in MediaCacheRefresher
2015-08-13 14:59:23 +02:00
Jeavon Leopold 6c416009d7 Make DeserializeFromJsonPayload in MediaCacheRefresher and associated sub classes public so that it's possible to easily retrieve the data in custom code 2015-08-13 13:52:21 +01:00
Sebastiaan Janssen 50da9bcb50 Should help with U4-4049 Some images fail when uploading multiple media files 2015-08-13 12:26:00 +02:00
Shannon 9e6a2d8a7c Fixing: U4-6942 During upgrade MUST make sure that the new Property Type GUIDs are consistent ... just needs some testing now; 2015-08-11 15:56:48 +02:00
Shannon cfb84cae44 removes license txt that doesn't make any sense. 2015-08-11 12:23:15 +02:00
Shannon 4239833713 updates NotificationService 2015-08-11 12:12:34 +02:00
Shannon 4fa1a3948e updates how versions are sorted before being sent. 2015-08-11 11:52:06 +02:00
Shannon Deminick 1b78e854f0 Merge pull request #759 from umbraco/U4-5180
Fix: U4-5180 Notifications email highlighting is incorrect. Ensured t…
2015-08-11 11:50:57 +02:00
Shannon Deminick c62a2362d2 Merge pull request #761 from umbraco/U4-6808
U4-6808 Bug in umbRequestHelper service causing exceptions to end up …
2015-08-11 11:48:01 +02:00
Shannon Deminick eb1855fcb7 Merge pull request #760 from umbraco/U4-6798
U4-6798 Rollback Dialog Displays Incorrect Author.
2015-08-11 11:44:10 +02:00
Shannon d4863239cd adds null check to query builder 2015-08-11 10:40:18 +02:00
Shannon 4b7ddb9c15 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-08-10 18:06:50 +02:00
Shannon e5bb35b335 Updates to latest Examine 2015-08-10 18:06:23 +02:00
Claus 7eabd09b3a Ignoring test causing CI to fail occasionally. 2015-08-10 15:11:08 +02:00
Shannon 087f0c0ede updates internals visible for courier. 2015-08-10 13:09:48 +02:00
Shannon db9d6d9109 Makes the getter for InternalSearcher lazy, fixes up the LocalTempStorageDirectory so that it properly deals with both directories the same, including lock files. Fixes up the LocalTempStorageIndexer with a ton more error checks and retry attempts to acquire locks if it cannot do so during initialization. This has proven to work seamlessly with my load tests now including the functionality for Sync. Need to test LocalOnly with the tests now too. Also, this should work if an index gets corrupted in temp storage for some odd reason (shouldn't do now btw). More testing required but this so far is showing to be much more stable especially with the new changes in Examine core. 2015-08-07 00:06:56 +02:00
Shannon 700e180522 Updates ensuring db connection so that it's not waiting arbitrarily to exit. 2015-08-07 00:02:35 +02:00
Claus 8584997f5f U4-6808 Bug in umbRequestHelper service causing exceptions to end up in backoffice. 2015-08-06 16:03:12 +02:00
Claus 4710b3b641 U4-6798 Rollback Dialog Displays Incorrect Author. 2015-08-06 14:53:56 +02:00
Claus 227e2489c1 Fix: U4-5180 Notifications email highlighting is incorrect. Ensured the versions of content used in comparison is sorted correctly so the highlighting is based on previous version and not the base version of the content. 2015-08-06 10:32:41 +02:00
Shannon 91a5b19378 Fixes: U4-6891 Can't get to the "Rebuild" button when Lucene index folder is empty as well as how the polling works. 2015-08-05 18:32:59 +02:00
Shannon 4c20441c4e Fixes: U4-6915 Txt Starter Kit install fails on 7.3.0 beta3 2015-08-05 17:17:49 +02:00
Shannon edfe1e6d54 Fixes: U4-2793 There doesn't seem to be a way to un-assign a template from a content item with the new API. Fixes issue with content type cache clearing when templates are deleted. Fixes the legacy packager to use the new template service to delete templates which does it in a much more graceful way, otherwise we need to do a try catch. 2015-08-05 16:30:21 +02:00
Shannon 7869f77704 Fixes up deleting templates, fixes up legacy template code to ensure things are saved when they are updated 2015-08-05 15:00:28 +02:00
Shannon 34fd405bca Downgrades AutoMapper to the version before the assembly was signed (breaking!), we're stuck on < 3.1 because Automapper decided to sign an assembly in a minor version, nothing we can do till v8 2015-08-05 13:35:42 +02:00
Shannon f03ee9f908 Fixes routing tests and reverts to simplified routing logic based on the Language ISO code returned from the IDomain object. 2015-08-05 12:10:13 +02:00
Shannon b053638204 Fixes: U4-6866 getDescendants of template, N+1 issues for template repo (U4-5618 Repository level performance enhancements - remaining N+1 queries) 2015-08-05 11:50:20 +02:00
Shannon d790194682 Fixes: U4-6918 App_Plugins folder needs to be created properly on app start 2015-08-04 17:36:03 +02:00
Shannon 3fec2b9756 uses the LanguageIsoCode returned from the domain object during routing so it doesn't need to be re-looked up. 2015-08-04 15:53:08 +02:00
Shannon bc7a31d791 Updates IDomain to include language ISO code so we can save a lookup 2015-08-04 15:42:44 +02:00
Shannon 05d84c6673 updates the operation status to return the event messages used when raising events 2015-08-04 14:52:34 +02:00
Shannon f6645e3928 Fixes: U4-6917 ContentTypeService.GetContentType( GUID) throws exception 2015-08-04 14:05:57 +02:00
Shannon 50b00b12b0 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-08-04 13:23:57 +02:00
Shannon 569371ffff Fixes resize panel U4-5308 Umbraco 7 Content Tree Width not resizable or scrollable 2015-08-04 13:22:22 +02:00
Per Ploug Krogslund f7b72b225a Grid: auto-insert layout, row and editors if only 1 is available
When the grid loads and only one layout is available, it will be
inserted automatically.

When a row is inserted and a cell only has a single editor allowed, it
will be inserted.

These are chained so when an empty grid editor is loaded it will
preload layout + controllers if only one option is possible.

Also fixed the cog icon being visible, even without settings available

Adjusted a bit of styling for TinyMCE editors as they are invisible if
no focus + content entered.
2015-08-04 12:25:33 +02:00
Shannon d1bed54cf1 Fixes tabdrop memory leak U4-6907 Bootstrap tab drop has memory leaks, fixes tab/header to use the correct bootstrap tab api, simplifies the header code dramatically and speeds up processing. Fixes mem leak with delayedMouseLeave.directive 2015-08-04 11:59:57 +02:00
Shannon ba868887d4 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-08-03 12:50:18 +02:00
Shannon 3a7853dcbe makes sure the bottom bar buttons are moved when resizing the left pane and that their position stays relative during tab changing. 2015-08-02 11:32:43 +02:00
Shannon 60af7deacd ensures more unbinding is happening 2015-08-02 11:32:14 +02:00
Shannon 49bc3151b0 Fixes the detectfold processing and tab changing events, creates new umbTabs directive to manage the bootstrap tab changing events so other directives can easily subscribe to the changes. updats all editors to use them. 2015-08-02 11:13:26 +02:00
Shannon d6b7bae38a reverts tabs back to use only bootstrap tabs (we can change that at a later date now that we have the code), have fixed up a lot of the detect-fold logic so that it doesn't run an insane amount of calculations, however now we need to properly fix the bootstrap tab event bindings. 2015-08-01 17:33:55 +02:00
Sebastiaan Janssen 715cc22722 Revert "Correct trees.config"
This reverts commit 88b23e09b6.
2015-08-01 15:11:47 +02:00
Sebastiaan Janssen 88b23e09b6 Correct trees.config 2015-08-01 15:05:01 +02:00
Shannon 612484c0b6 ensures more jquery event listeners are unbound 2015-07-31 12:52:29 +02:00
Shannon 0e4974babe Creates windowResizeListener directive... so there's only a single listener for this and things can register/unregister as required from it and the callbacks will always execute in a $digest. Updates the detect-fold and navResize to use this, it is much snappier now with less overhead. 2015-07-31 12:34:02 +02:00
Shannon 5775984730 have new tab implementation working with backwards compat with bootstrap tabs. For our own editors, we will use the new tabs, this gives us more control and should be a bit quicker, perhaps in v8 we can remove bootstrap tabs entirely. 2015-07-31 10:50:33 +02:00
Shannon cfa2a30006 Changes how tabs work ... to no longer have to rely on bootstrap tabs and the hacky timing work-arounds, tabs are actually quite easy and now give us much more control.
Have made this change as backwards compatable (some things are deprecated though). Will update the other editors now.
2015-07-30 18:44:15 +02:00
155 changed files with 2768 additions and 1179 deletions
+2 -2
View File
@@ -30,9 +30,9 @@
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.8.4, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
<dependency id="Examine" version="[0.1.66, 1.0.0)" />
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
@@ -51,6 +51,8 @@
<system.web xdt:Transform="InsertIfMissing" />
<system.web>
<siteMap xdt:Transform="Remove" />
<httpRuntime xdt:Transform="InsertIfMissing" />
<httpRuntime targetFramework="4.5" xdt:Transform="SetAttributes(targetFramework)" />
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
+1 -1
View File
@@ -1,3 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.3.0
beta3
RC
+1 -1
View File
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyInformationalVersion("7.3.0-beta3")]
[assembly: AssemblyInformationalVersion("7.3.0-RC")]
@@ -24,7 +24,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 "beta3"; } }
public static string CurrentComment { get { return "RC"; } }
// 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
+7 -3
View File
@@ -380,14 +380,19 @@ namespace Umbraco.Core
if (ApplicationContext.IsConfigured == false) return;
if (ApplicationContext.DatabaseContext.IsDatabaseConfigured == false) return;
//try now
if (ApplicationContext.DatabaseContext.CanConnect)
return;
var currentTry = 0;
while (currentTry < 5)
{
//first wait, then retry
Thread.Sleep(1000);
if (ApplicationContext.DatabaseContext.CanConnect)
break;
//wait and retry
Thread.Sleep(1000);
currentTry++;
}
@@ -395,7 +400,6 @@ namespace Umbraco.Core
{
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database.");
}
}
/// <summary>
+44
View File
@@ -0,0 +1,44 @@
using System;
using System.Diagnostics;
using System.Threading;
namespace Umbraco.Core
{
public static class DelegateExtensions
{
public static Attempt<T> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T>> task, TimeSpan timeout, TimeSpan pause)
{
if (pause.TotalMilliseconds < 0)
{
throw new ArgumentException("pause must be >= 0 milliseconds");
}
var stopwatch = Stopwatch.StartNew();
do
{
var result = task();
if (result) { return result; }
Thread.Sleep((int)pause.TotalMilliseconds);
}
while (stopwatch.Elapsed < timeout);
return Attempt<T>.Fail();
}
public static Attempt<T> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T>> task, int totalAttempts, TimeSpan pause)
{
if (pause.TotalMilliseconds < 0)
{
throw new ArgumentException("pause must be >= 0 milliseconds");
}
int attempts = 0;
do
{
attempts++;
var result = task(attempts);
if (result) { return result; }
Thread.Sleep((int)pause.TotalMilliseconds);
}
while (attempts < totalAttempts);
return Attempt<T>.Fail();
}
}
}
+1 -52
View File
@@ -8,34 +8,6 @@ namespace Umbraco.Core.Events
/// </summary>
public static class EventExtensions
{
/// <summary>
/// Raises the event and checks if a cancelation has occurred, if so it checks if any messages have been
/// added to the event messages collection and if not it adds a default cancelation message
/// </summary>
/// <typeparam name="TSender"></typeparam>
/// <typeparam name="TArgs"></typeparam>
/// <param name="eventHandler"></param>
/// <param name="evtMsgs"></param>
/// <param name="args"></param>
/// <param name="sender"></param>
/// <returns></returns>
public static bool IsRaisedEventCancelled<TSender, TArgs>(
this TypedEventHandler<TSender, TArgs> eventHandler,
EventMessages evtMsgs,
Func<EventMessages, TArgs> args,
TSender sender)
where TArgs : CancellableEventArgs
{
var evtArgs = args(evtMsgs);
if (eventHandler != null)
{
eventHandler(sender, evtArgs);
}
return evtArgs.Cancel;
}
/// <summary>
/// Raises the event and returns a boolean value indicating if the event was cancelled
/// </summary>
@@ -56,30 +28,7 @@ namespace Umbraco.Core.Events
return args.Cancel;
}
/// <summary>
/// Raises the event with EventMessages
/// </summary>
/// <typeparam name="TSender"></typeparam>
/// <typeparam name="TArgs"></typeparam>
/// <param name="eventHandler"></param>
/// <param name="evtMsgs"></param>
/// <param name="args"></param>
/// <param name="sender"></param>
public static void RaiseEvent<TSender, TArgs>(
this TypedEventHandler<TSender, TArgs> eventHandler,
EventMessages evtMsgs,
Func<EventMessages, TArgs> args,
TSender sender)
where TArgs : EventArgs
{
if (eventHandler != null)
{
var evtArgs = args(evtMsgs);
eventHandler(sender, evtArgs);
}
}
/// <summary>
/// Raises the event
/// </summary>
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Logging
private CancellationTokenSource _loggingCancelationTokenSource;
private CancellationToken _loggingCancelationToken;
private Task _loggingTask;
private Double _shutdownFlushTimeout = 5;
private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(5);
private Double _shutdownFlushTimeout = 1;
private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(1);
private static readonly Type ThisType = typeof(ParallelForwardingAppender);
private volatile bool _shutDownRequested;
private int? _bufferSize = DefaultBufferSize;
+16 -4
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -140,11 +141,22 @@ namespace Umbraco.Core.Manifest
{
var result = new List<PackageManifest>();
foreach (var m in manifestFileContents)
{
if (m.IsNullOrWhiteSpace()) continue;
{
var manifestContent = m;
if (manifestContent.IsNullOrWhiteSpace()) continue;
// Strip byte object marker, JSON.NET does not like it
var preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
// Strangely StartsWith(preamble) would always return true
if (manifestContent.Substring(0, 1) == preamble)
manifestContent = manifestContent.Remove(0, preamble.Length);
if (manifestContent.IsNullOrWhiteSpace()) continue;
//remove any comments first
var replaced = CommentsSurround.Replace(m, match => " ");
var replaced = CommentsSurround.Replace(manifestContent, match => " ");
replaced = CommentsLine.Replace(replaced, match => "");
JObject deserialized;
@@ -154,7 +166,7 @@ namespace Umbraco.Core.Manifest
}
catch (Exception ex)
{
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + m, ex);
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + manifestContent, ex);
continue;
}
+1 -7
View File
@@ -95,13 +95,7 @@ namespace Umbraco.Core.Models
[DataMember]
public virtual ITemplate Template
{
get
{
if (_template == null)
return _contentType.DefaultTemplate;
return _template;
}
get { return _template; }
set
{
SetPropertyValueAndDetectChanges(o =>
+5
View File
@@ -8,5 +8,10 @@ namespace Umbraco.Core.Models
string DomainName { get; set; }
int? RootContentId { get; set; }
bool IsWildcard { get; }
/// <summary>
/// Readonly value of the language ISO code for the domain
/// </summary>
string LanguageIsoCode { get; }
}
}
@@ -23,5 +23,11 @@ namespace Umbraco.Core.Models.Rdbms
[Column("domainName")]
public string DomainName { get; set; }
/// <summary>
/// Used for a result on the query to get the associated language for a domain if there is one
/// </summary>
[ResultColumn("languageISOCode")]
public string IsoCode { get; set; }
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Models
public class Stylesheet : File
{
public Stylesheet(string path)
: base(path)
: base(path.EnsureEndsWith(".css"))
{
InitializeProperties();
}
+10 -4
View File
@@ -14,6 +14,12 @@ namespace Umbraco.Core.Models
_domainName = domainName;
}
public UmbracoDomain(string domainName, string languageIsoCode)
: this(domainName)
{
LanguageIsoCode = languageIsoCode;
}
private int? _contentId;
private int? _languageId;
private string _domainName;
@@ -70,9 +76,9 @@ namespace Umbraco.Core.Models
get { return string.IsNullOrWhiteSpace(DomainName) || DomainName.StartsWith("*"); }
}
public string IsoCode
{
get { throw new NotImplementedException(); }
}
/// <summary>
/// Readonly value of the language ISO code for the domain
/// </summary>
public string LanguageIsoCode { get; internal set; }
}
}
@@ -43,12 +43,8 @@ namespace Umbraco.Core.Persistence.Factories
Path = dto.NodeDto.Path
};
if (childDefinitions.Any(x => x.ParentId == dto.NodeId))
{
template.IsMasterTemplate = true;
}
template.IsMasterTemplate = childDefinitions.Any(x => x.ParentId == dto.NodeId);
//TODO: Change this to ParentId: http://issues.umbraco.org/issue/U4-5846
if(dto.NodeDto.ParentId > 0)
template.MasterTemplateId = new Lazy<int>(() => dto.NodeDto.ParentId);
@@ -30,9 +30,26 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
.NonClustered()
.WithOptions()
.Unique();
//now we need to fill in the data so that it is consistent, we can't have it generating random GUIDs for
// the already existing data, see: http://issues.umbraco.org/issue/U4-6942
foreach (var data in Context.Database.Query<dynamic>(@"
SELECT cmsPropertyType.id ptId, cmsPropertyType.Alias ptAlias, cmsContentType.alias ctAlias
FROM cmsPropertyType
INNER JOIN cmsContentType
ON cmsPropertyType.contentTypeId = cmsContentType.nodeId"))
{
//create a guid from the concatenation of the property type alias + the doc type alias
string concatAlias = data.ptAlias + data.ctAlias;
var ptGuid = concatAlias.ToGuid();
//set the Unique Id to the one we've generated
Update.Table("cmsPropertyType").Set(new {uniqueID = ptGuid}).Where(new {id = data.ptId });
}
}
}
public override void Down()
@@ -340,6 +340,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
((Content)entity).AddingEntity();
//ensure the default template is assigned
if (entity.Template == null)
{
entity.Template = entity.ContentType.DefaultTemplate;
}
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
@@ -648,8 +654,8 @@ namespace Umbraco.Core.Persistence.Repositories
var translator = new SqlTranslator<IContent>(sqlClause, query);
var sql = translator.Translate()
.Where<DocumentDto>(x => x.Published)
.OrderBy<NodeDto>(x => x.Level)
.OrderBy<NodeDto>(x => x.SortOrder);
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
//NOTE: This doesn't allow properties to be part of the query
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql);
@@ -855,7 +861,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
/// </summary>
/// <param name="d"></param>
/// <param name="dto"></param>
/// <param name="contentType"></param>
/// <param name="template"></param>
/// <param name="propCollection"></param>
@@ -873,6 +879,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
content.Template = template ?? _templateRepository.Get(dto.TemplateId.Value);
}
else
{
//ensure there isn't one set.
content.Template = null;
}
content.Properties = propCollection;
@@ -885,7 +896,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
/// </summary>
/// <param name="d"></param>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
@@ -713,7 +713,7 @@ AND umbracoNode.id <> @id",
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
ParentTypes.parentContentTypeId as chtParentId,
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
umbracoNode.uniqueID as nUniqueId
@@ -727,7 +727,12 @@ AND umbracoNode.id <> @id",
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
) AllowedTypes
ON AllowedTypes.Id = cmsContentType.nodeId
LEFT JOIN cmsContentType2ContentType as ParentTypes
LEFT JOIN (
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
FROM cmsContentType2ContentType
INNER JOIN umbracoNode
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
@@ -842,7 +847,7 @@ AND umbracoNode.id <> @id",
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
ParentTypes.parentContentTypeId as chtParentId,
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
umbracoNode.uniqueID as nUniqueId,
@@ -865,7 +870,12 @@ AND umbracoNode.id <> @id",
ON cmsTemplate.nodeId = umbracoNode.id
) as Template
ON Template.nodeId = cmsDocumentType.templateNodeId
LEFT JOIN cmsContentType2ContentType as ParentTypes
LEFT JOIN (
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
FROM cmsContentType2ContentType
INNER JOIN umbracoNode
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
@@ -1043,7 +1053,14 @@ AND umbracoNode.id <> @id",
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Select(x => (TId?)x.chtParentId)
.Select(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? (TId?)x.chtParentId
: (TId?)x.chtParentKey;
})
.Where(x => x.HasValue)
.Distinct()
.Select(x => x.Value).ToList());
@@ -14,6 +14,8 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
//TODO: We need to get a readonly ISO code for the domain assigned
internal class DomainRepository : PetaPocoRepositoryBase<int, IDomain>, IDomainRepository
{
private readonly RepositoryCacheOptions _cacheOptions;
@@ -62,7 +64,18 @@ namespace Umbraco.Core.Persistence.Repositories
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*").From<DomainDto>(SqlSyntax);
if (isCount)
{
sql.Select("COUNT(*)").From<DomainDto>(SqlSyntax);
}
else
{
sql.Select("umbracoDomains.*, umbracoLanguage.languageISOCode")
.From<DomainDto>(SqlSyntax)
.LeftJoin<LanguageDto>(SqlSyntax)
.On<DomainDto, LanguageDto>(SqlSyntax, dto => dto.DefaultLanguage, dto => dto.Id);
}
return sql;
}
@@ -110,6 +123,12 @@ namespace Umbraco.Core.Persistence.Repositories
var id = Convert.ToInt32(Database.Insert(dto));
entity.Id = id;
//if the language changed, we need to resolve the ISO code!
if (entity.LanguageId.HasValue)
{
((UmbracoDomain)entity).LanguageIsoCode = Database.ExecuteScalar<string>("SELECT languageISOCode FROM umbracoLanguage WHERE id=@langId", new { langId = entity.LanguageId });
}
entity.ResetDirtyProperties();
}
@@ -139,6 +158,12 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Update(dto);
//if the language changed, we need to resolve the ISO code!
if (entity.WasPropertyDirty("LanguageId"))
{
((UmbracoDomain)entity).LanguageIsoCode = Database.ExecuteScalar<string>("SELECT languageISOCode FROM umbracoLanguage WHERE id=@langId", new {langId = entity.LanguageId});
}
entity.ResetDirtyProperties();
}
@@ -176,7 +201,12 @@ namespace Umbraco.Core.Persistence.Repositories
public IDomain BuildEntity(DomainDto dto)
{
var domain = new UmbracoDomain(dto.DomainName) { Id = dto.Id, LanguageId = dto.DefaultLanguage, RootContentId = dto.RootStructureId };
var domain = new UmbracoDomain(dto.DomainName, dto.IsoCode)
{
Id = dto.Id,
LanguageId = dto.DefaultLanguage,
RootContentId = dto.RootStructureId
};
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
domain.ResetDirtyProperties(false);
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
@@ -10,12 +11,17 @@ namespace Umbraco.Core.Persistence.Repositories
IEnumerable<ITemplate> GetAll(params string[] aliases);
IEnumerable<ITemplate> GetChildren(int masterTemplateId);
IEnumerable<ITemplate> GetChildren(string alias);
IEnumerable<ITemplate> GetDescendants(int masterTemplateId);
IEnumerable<ITemplate> GetDescendants(string alias);
/// <summary>
/// Returns a template as a template node which can be traversed (parent, children)
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
[Obsolete("Use GetDescendants instead")]
TemplateNode GetTemplateNode(string alias);
/// <summary>
@@ -24,6 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="anyNode"></param>
/// <param name="alias"></param>
/// <returns></returns>
[Obsolete("Use GetDescendants instead")]
TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias);
/// <summary>
@@ -25,6 +25,8 @@ namespace Umbraco.Core.Persistence.Repositories
public override Stylesheet Get(string id)
{
id = id.EnsureEndsWith(".css");
if (FileSystem.FileExists(id) == false)
{
return null;
@@ -63,7 +65,10 @@ namespace Umbraco.Core.Persistence.Repositories
public override IEnumerable<Stylesheet> GetAll(params string[] ids)
{
//ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
ids = ids.Distinct().ToArray();
ids = ids
.Select(x => x.EnsureEndsWith(".css"))
.Distinct()
.ToArray();
if (ids.Any())
{
@@ -477,7 +477,7 @@ namespace Umbraco.Core.Persistence.Repositories
tagSetSql,
" inner join cmsTags as NewTags on (TagSet.Tag = NewTags.Tag and TagSet.",
SqlSyntax.GetQuotedColumnName("group"),
" = TagSet.",
" = NewTags.",
SqlSyntax.GetQuotedColumnName("group"),
") ",
") as NewTagsSet ",
@@ -67,7 +67,15 @@ namespace Umbraco.Core.Persistence.Repositories
protected override ITemplate PerformGet(int id)
{
return GetAll(new[] { id }).FirstOrDefault();
var sql = GetBaseQuery(false).Where<TemplateDto>(x => x.NodeId == id);
var result = Database.Fetch<TemplateDto, NodeDto>(sql).FirstOrDefault();
if (result == null) return null;
//look up the simple template definitions that have a master template assigned, this is used
// later to populate the template item's properties
var childIds = GetAxisDefinitions(result).ToArray();
return MapFromDto(result, childIds);
}
protected override IEnumerable<ITemplate> PerformGetAll(params int[] ids)
@@ -89,20 +97,15 @@ namespace Umbraco.Core.Persistence.Repositories
//look up the simple template definitions that have a master template assigned, this is used
// later to populate the template item's properties
var childIdsSql = new Sql()
.Select("nodeId,alias,parentID")
.From<TemplateDto>()
.InnerJoin<NodeDto>()
.On<TemplateDto, NodeDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(t => t.ParentId > 0);
var childIds = Database.Fetch<dynamic>(childIdsSql)
.Select(x => new UmbracoEntity
var childIds = (ids.Any()
? GetAxisDefinitions(dtos.ToArray())
: dtos.Select(x => new UmbracoEntity
{
Id = x.nodeId,
ParentId = x.parentID,
Name = x.alias
});
Id = x.NodeId,
ParentId = x.NodeDto.ParentId,
Name = x.Alias
})).ToArray();
return dtos.Select(d => MapFromDto(d, childIds));
}
@@ -118,19 +121,7 @@ namespace Umbraco.Core.Persistence.Repositories
//look up the simple template definitions that have a master template assigned, this is used
// later to populate the template item's properties
var childIdsSql = new Sql()
.Select("nodeId,alias,parentID")
.From<TemplateDto>()
.InnerJoin<NodeDto>()
.On<TemplateDto, NodeDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(t => t.ParentId > 0);
var childIds = Database.Fetch<dynamic>(childIdsSql)
.Select(x => new UmbracoEntity
{
Id = x.nodeId,
ParentId = x.parentID,
Name = x.alias
});
var childIds = GetAxisDefinitions(dtos.ToArray()).ToArray();
return dtos.Select(d => MapFromDto(d, childIds));
}
@@ -143,9 +134,9 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*")
.From<TemplateDto>()
.InnerJoin<NodeDto>()
.On<TemplateDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.From<TemplateDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<TemplateDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
}
@@ -273,7 +264,11 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Update(dto.NodeDto);
Database.Update(dto);
//re-update if this is a master template, since it could have changed!
var axisDefs = GetAxisDefinitions(dto);
template.IsMasterTemplate = axisDefs.Any(x => x.ParentId == dto.NodeId);
//now do the file work
if (DetermineTemplateRenderingEngine(entity) == RenderingEngine.Mvc)
@@ -304,34 +299,27 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistDeletedItem(ITemplate entity)
{
var deletes = GetDeleteClauses().ToArray();
//TODO: This isn't the most ideal way to delete a template tree, because below it will actually end up
// recursing back to this method for each descendant and re-looking up the template list causing an extrac
// SQL call - not ideal but there shouldn't ever be a heaping list of descendant templates.
//The easiest way to overcome this is to expose the underlying cache upwards so that the repository has access
// to it, then in the PersistDeletedTemplate we wouldn't recurse the underlying function, we'd just call
// PersistDeletedItem with a Template object and clear it's cache.
var descendants = GetDescendants(entity.Id).ToList();
var sql = GetBaseQuery(false).Where<NodeDto>(dto => dto.ParentId > 0 || dto.NodeId == entity.Id);
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql);
var self = dtos.Single(x => x.NodeId == entity.Id);
var allChildren = dtos.Except(new[] { self });
var hierarchy = GenerateTemplateHierarchy(self, allChildren);
//remove ourselves
hierarchy.Remove(self);
//change the order so it goes bottom up!
hierarchy.Reverse();
//change the order so it goes bottom up! (deepest level first)
descendants.Reverse();
//delete the hierarchy
foreach (var descendant in hierarchy)
foreach (var descendant in descendants)
{
PersistDeletedTemplate(descendant);
foreach (var delete in deletes)
{
Database.Execute(delete, new { Id = GetEntityId(descendant) });
}
}
//now we can delete this one
base.PersistDeletedItem(entity);
foreach (var delete in deletes)
{
Database.Execute(delete, new { Id = GetEntityId(entity) });
}
if (DetermineTemplateRenderingEngine(entity) == RenderingEngine.Mvc)
{
@@ -342,28 +330,57 @@ namespace Umbraco.Core.Persistence.Repositories
{
var masterpageName = string.Concat(entity.Alias, ".master");
_masterpagesFileSystem.DeleteFile(masterpageName);
}
}
}
#endregion
private ITemplate MapFromDto(TemplateDto dto, IEnumerable<IUmbracoEntity> childDefinitions)
private IEnumerable<IUmbracoEntity> GetAxisDefinitions(params TemplateDto[] templates)
{
//look up the simple template definitions that have a master template assigned, this is used
// later to populate the template item's properties
var childIdsSql = new Sql()
.Select("nodeId,alias,parentID")
.From<TemplateDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<TemplateDto, NodeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.NodeId)
//lookup axis's
.Where("umbracoNode." + SqlSyntax.GetQuotedColumnName("id") + " IN (@parentIds) OR umbracoNode.parentID IN (@childIds)",
new {parentIds = templates.Select(x => x.NodeDto.ParentId), childIds = templates.Select(x => x.NodeId)});
var childIds = Database.Fetch<dynamic>(childIdsSql)
.Select(x => new UmbracoEntity
{
Id = x.nodeId,
ParentId = x.parentID,
Name = x.alias
});
return childIds;
}
/// <summary>
/// Maps from a dto to an ITemplate
/// </summary>
/// <param name="dto"></param>
/// <param name="axisDefinitions">
/// This is a collection of template definitions ... either all templates, or the collection of child templates and it's parent template
/// </param>
/// <returns></returns>
private ITemplate MapFromDto(TemplateDto dto, IUmbracoEntity[] axisDefinitions)
{
string csViewName = string.Concat(dto.Alias, ".cshtml");
string vbViewName = string.Concat(dto.Alias, ".vbhtml");
string masterpageName = string.Concat(dto.Alias, ".master");
var factory = new TemplateFactory();
var template = factory.BuildEntity(dto, childDefinitions);
var template = factory.BuildEntity(dto, axisDefinitions);
if (dto.NodeDto.ParentId > 0)
{
//TODO: Fix this n+1 query!
var masterTemplate = Get(dto.NodeDto.ParentId);
var masterTemplate = axisDefinitions.FirstOrDefault(x => x.Id == dto.NodeDto.ParentId);
if (masterTemplate != null)
{
template.MasterTemplateAlias = masterTemplate.Alias;
template.MasterTemplateAlias = masterTemplate.Name;
template.MasterTemplateId = new Lazy<int>(() => dto.NodeDto.ParentId);
}
}
@@ -390,36 +407,7 @@ namespace Umbraco.Core.Persistence.Repositories
return template;
}
private void PersistDeletedTemplate(TemplateDto dto)
{
//we need to get the real template for this item unfortunately to remove it
var template = Get(dto.NodeId);
if (template != null)
{
//NOTE: We must cast here so that it goes to the outter method to
// ensure the cache is updated.
PersistDeletedItem((IEntity)template);
}
}
/// <summary>
/// Returns a list of templates in order of descendants from the parent
/// </summary>
/// <param name="template"></param>
/// <param name="allChildTemplates"></param>
/// <returns></returns>
private static List<TemplateDto> GenerateTemplateHierarchy(TemplateDto template, IEnumerable<TemplateDto> allChildTemplates)
{
var hierarchy = new List<TemplateDto> { template };
foreach (var t in allChildTemplates.Where(x => x.NodeDto.ParentId == template.NodeId))
{
hierarchy.AddRange(GenerateTemplateHierarchy(t, allChildTemplates));
}
return hierarchy;
}
private void PopulateViewTemplate(ITemplate template, string fileName)
{
string content;
@@ -460,49 +448,119 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
return Get(dto.NodeId);
return MapFromDto(dto, GetAxisDefinitions(dto).ToArray());
}
public IEnumerable<ITemplate> GetAll(params string[] aliases)
{
var sql = GetBaseQuery(false);
if (aliases.Any())
{
foreach (var id in aliases)
{
yield return Get(id);
}
}
else
{
var nodeDtos = Database.Fetch<NodeDto>("WHERE nodeObjectType = @NodeObjectType", new { NodeObjectType = NodeObjectTypeId });
foreach (var nodeDto in nodeDtos)
{
yield return Get(nodeDto.NodeId);
}
sql.Where("cmsTemplate.alias IN (@aliases)", new {aliases = aliases});
}
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
}
public IEnumerable<ITemplate> GetChildren(int masterTemplateId)
{
//TODO: Fix this N+1!
List<TemplateDto> found;
if (masterTemplateId == -1)
var sql = GetBaseQuery(false);
if (masterTemplateId <= 0)
{
var sql = GetBaseQuery(false).Where<NodeDto>(x => x.ParentId <= 0);
found = Database.Fetch<TemplateDto, NodeDto>(sql);
sql.Where<NodeDto>(x => x.ParentId <= 0);
}
else
{
var sql = GetBaseQuery(false).Where<NodeDto>(x => x.ParentId == masterTemplateId);
found = Database.Fetch<TemplateDto, NodeDto>(sql);
sql.Where<NodeDto>(x => x.ParentId == masterTemplateId);
}
foreach (var templateDto in found)
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
}
public IEnumerable<ITemplate> GetChildren(string alias)
{
var sql = GetBaseQuery(false);
if (alias.IsNullOrWhiteSpace())
{
yield return Get(templateDto.NodeId);
sql.Where<NodeDto>(x => x.ParentId <= 0);
}
else
{
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
// in a single query, now we have to lookup the path to acheive the same thing
var parent = Database.ExecuteScalar<int?>(new Sql().Select("nodeId").From<TemplateDto>(SqlSyntax).Where<TemplateDto>(dto => dto.Alias == alias));
if (parent.HasValue == false) return Enumerable.Empty<ITemplate>();
sql.Where<NodeDto>(x => x.ParentId == parent.Value);
}
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
}
public IEnumerable<ITemplate> GetDescendants(int masterTemplateId)
{
var sql = GetBaseQuery(false);
if (masterTemplateId > 0)
{
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
// in a single query, now we have to lookup the path to acheive the same thing
var path = Database.ExecuteScalar<string>(
new Sql().Select(SqlSyntax.GetQuotedColumnName("path"))
.From<TemplateDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<TemplateDto, NodeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(dto => dto.NodeId == masterTemplateId));
if (path.IsNullOrWhiteSpace()) return Enumerable.Empty<ITemplate>();
sql.Where(@"(umbracoNode." + SqlSyntax.GetQuotedColumnName("path") + @" LIKE @query)", new { query = path + ",%" });
}
sql.OrderBy("umbracoNode." + SqlSyntax.GetQuotedColumnName("level"));
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
}
public IEnumerable<ITemplate> GetDescendants(string alias)
{
var sql = GetBaseQuery(false);
if (alias.IsNullOrWhiteSpace() == false)
{
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
// in a single query, now we have to lookup the path to acheive the same thing
var path = Database.ExecuteScalar<string>(
"SELECT umbracoNode.path FROM cmsTemplate INNER JOIN umbracoNode ON cmsTemplate.nodeId = umbracoNode.id WHERE cmsTemplate.alias = @alias", new { alias = alias });
if (path.IsNullOrWhiteSpace()) return Enumerable.Empty<ITemplate>();
sql.Where(@"(umbracoNode." + SqlSyntax.GetQuotedColumnName("path") + @" LIKE @query)", new {query = path + ",%" });
}
sql.OrderBy("umbracoNode." + SqlSyntax.GetQuotedColumnName("level"));
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
}
/// <summary>
@@ -510,13 +568,9 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
[Obsolete("Use GetDescendants instead")]
public TemplateNode GetTemplateNode(string alias)
{
//in order to do this we need to get all of the templates and then organize,
// TODO: unfortunately our db structure does not use the path correctly for templates so we cannot just look
// up a template tree easily.
//TODO: We do use the 'path' now, so this might be able to be fixed up
{
//first get all template objects
var allTemplates = GetAll().ToArray();
@@ -525,23 +579,17 @@ namespace Umbraco.Core.Persistence.Repositories
{
return null;
}
//then we need to get all template Dto's because those contain the master property
var sql = GetBaseQuery(false);
var allDtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
var selfDto = allDtos.Single(x => x.NodeId == selfTemplate.Id);
//need to get the top-most node of the current tree
var top = selfDto;
while (top.NodeDto.ParentId > 0)
var top = selfTemplate;
while (top.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
{
top = allDtos.Single(x => x.NodeId == top.NodeDto.ParentId);
top = allTemplates.Single(x => x.Alias == top.MasterTemplateAlias);
}
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.NodeId));
var childIds = allDtos.Where(x => x.NodeDto.ParentId == top.NodeId).Select(x => x.NodeId);
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.Id));
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias == top.Alias);
//This now creates the hierarchy recursively
topNode.Children = CreateChildren(topNode, childIds, allTemplates, allDtos);
topNode.Children = CreateChildren(topNode, childTemplates, allTemplates);
//now we'll return the TemplateNode requested
return FindTemplateInTree(topNode, alias);
@@ -568,6 +616,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="anyNode"></param>
/// <param name="alias"></param>
/// <returns></returns>
[Obsolete("Use GetDescendants instead")]
public TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias)
{
//first get the root
@@ -658,12 +707,12 @@ namespace Umbraco.Core.Persistence.Repositories
return validFile && validExtension;
}
private static IEnumerable<TemplateNode> CreateChildren(TemplateNode parent, IEnumerable<int> childIds, ITemplate[] allTemplates, TemplateDto[] allDtos)
private static IEnumerable<TemplateNode> CreateChildren(TemplateNode parent, IEnumerable<ITemplate> childTemplates, ITemplate[] allTemplates)
{
var children = new List<TemplateNode>();
foreach (var i in childIds)
foreach (var childTemplate in childTemplates)
{
var template = allTemplates.Single(x => x.Id == i);
var template = allTemplates.Single(x => x.Id == childTemplate.Id);
var child = new TemplateNode(template)
{
Parent = parent
@@ -673,10 +722,11 @@ namespace Umbraco.Core.Persistence.Repositories
children.Add(child);
//get this node's children
var kids = allDtos.Where(x => x.NodeDto.ParentId == i).Select(x => x.NodeId).ToArray();
var local = childTemplate;
var kids = allTemplates.Where(x => x.MasterTemplateAlias == local.Alias);
//recurse
child.Children = CreateChildren(child, kids, allTemplates, allDtos);
child.Children = CreateChildren(child, kids, allTemplates);
}
return children;
}
@@ -41,14 +41,14 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = new Sql();
sql.Select("*")
.From<ContentVersionDto>()
.InnerJoin<ContentDto>()
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.From<ContentVersionDto>(SqlSyntax)
.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.NodeId == id)
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql);
foreach (var dto in dtos)
@@ -513,6 +513,8 @@ WHERE EXISTS(
// of ContentItemBasic instances) to the database field names.
switch (orderBy.ToUpperInvariant())
{
case "UPDATEDATE":
return "cmsContentVersion.VersionDate";
case "NAME":
return "umbracoNode.text";
case "OWNER":
+1 -1
View File
@@ -38,9 +38,9 @@ using System.Security.Permissions;
[assembly: InternalsVisibleTo("UmbracoExamine")]
[assembly: InternalsVisibleTo("Concorde.Sync")]
[assembly: InternalsVisibleTo("Umbraco.Belle")]
[assembly: InternalsVisibleTo("Umbraco.VisualStudio")]
[assembly: InternalsVisibleTo("Umbraco.Courier.Core")]
[assembly: InternalsVisibleTo("Umbraco.Courier.Persistence")]
[assembly: InternalsVisibleTo("umbraco.providers")]
//allow this to be mocked in our unit tests
+5 -4
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
@@ -9,16 +10,16 @@ namespace Umbraco.Core.Publishing
/// </summary>
public class PublishStatus : OperationStatus<IContent, PublishStatusType>
{
public PublishStatus(IContent content, PublishStatusType statusType)
: base(content, statusType)
public PublishStatus(IContent content, PublishStatusType statusType, EventMessages eventMessages)
: base(content, statusType, eventMessages)
{
}
/// <summary>
/// Creates a successful publish status
/// </summary>
public PublishStatus(IContent content)
: this(content, PublishStatusType.Success)
public PublishStatus(IContent content, EventMessages eventMessages)
: this(content, PublishStatusType.Success, eventMessages)
{
}
@@ -33,14 +33,14 @@ namespace Umbraco.Core.Publishing
/// <param name="userId">Id of the User issueing the publish operation</param>
internal Attempt<PublishStatus> PublishInternal(IContent content, int userId)
{
var evtMsgs = _eventMessagesFactory.Get();
if (Publishing.IsRaisedEventCancelled(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(content), this))
new PublishEventArgs<IContent>(content, evtMsgs), this))
{
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", content.Name, content.Id));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
}
//Check if the Content is Expired to verify that it can in fact be published
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Publishing
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
content.Name, content.Id));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired, evtMsgs));
}
//Check if the Content is Awaiting Release to verify that it can in fact be published
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Publishing
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
content.Name, content.Id));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease, evtMsgs));
}
//Check if the Content is Trashed to verify that it can in fact be published
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Publishing
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
content.Name, content.Id));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed));
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed, evtMsgs));
}
content.ChangePublishedState(PublishedState.Published);
@@ -76,7 +76,7 @@ namespace Umbraco.Core.Publishing
string.Format("Content '{0}' with Id '{1}' has been published.",
content.Name, content.Id));
return Attempt.Succeed(new PublishStatus(content));
return Attempt.Succeed(new PublishStatus(content, evtMsgs));
}
/// <summary>
@@ -136,10 +136,12 @@ namespace Umbraco.Core.Publishing
// Because we're grouping I think this will execute all the queries anyways so need to fetch it all first.
var fetchedContent = content.ToArray();
var evtMsgs = _eventMessagesFactory.Get();
//We're going to populate the statuses with all content that is already published because below we are only going to iterate over
// content that is not published. We'll set the status to "AlreadyPublished"
statuses.AddRange(fetchedContent.Where(x => x.Published)
.Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished))));
.Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished, evtMsgs))));
int? firstLevel = null;
@@ -179,13 +181,12 @@ namespace Umbraco.Core.Publishing
//Fire Publishing event
if (Publishing.IsRaisedEventCancelled(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(item, messages), this))
new PublishEventArgs<IContent>(item, evtMsgs), this))
{
//the publishing has been cancelled.
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent)));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent, evtMsgs)));
//Does this document apply to our rule to cancel it's children being published?
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
@@ -194,12 +195,12 @@ namespace Umbraco.Core.Publishing
}
//Check if the content is valid if the flag is set to check
if (!item.IsValid())
if (item.IsValid() == false)
{
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.",
item.Name, item.Id));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid)));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid, evtMsgs)));
//Does this document apply to our rule to cancel it's children being published?
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
@@ -213,7 +214,7 @@ namespace Umbraco.Core.Publishing
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
item.Name, item.Id));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired)));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired, evtMsgs)));
//Does this document apply to our rule to cancel it's children being published?
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
@@ -227,7 +228,7 @@ namespace Umbraco.Core.Publishing
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
item.Name, item.Id));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease)));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease, evtMsgs)));
//Does this document apply to our rule to cancel it's children being published?
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
@@ -241,7 +242,7 @@ namespace Umbraco.Core.Publishing
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
item.Name, item.Id));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed)));
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed, evtMsgs)));
//Does this document apply to our rule to cancel it's children being published?
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
@@ -255,7 +256,7 @@ namespace Umbraco.Core.Publishing
string.Format("Content '{0}' with Id '{1}' has been published.",
item.Name, item.Id));
statuses.Add(Attempt.Succeed(new PublishStatus(item)));
statuses.Add(Attempt.Succeed(new PublishStatus(item, evtMsgs)));
}
}
@@ -341,14 +342,15 @@ namespace Umbraco.Core.Publishing
// if published != newest, then the published flags need to be reseted by whoever is calling that method
// at the moment it's done by the content service
var evtMsgs = _eventMessagesFactory.Get();
//Fire UnPublishing event
if (UnPublishing.IsRaisedEventCancelled(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(content, messages), this))
if (UnPublishing.IsRaisedEventCancelled(
new PublishEventArgs<IContent>(content, evtMsgs), this))
{
_logger.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' will not be unpublished, the event was cancelled.", content.Name, content.Id));
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
}
//If Content has a release date set to before now, it should be removed so it doesn't interrupt an unpublish
@@ -370,7 +372,7 @@ namespace Umbraco.Core.Publishing
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
content.Name, content.Id));
return Attempt.Succeed(new PublishStatus(content));
return Attempt.Succeed(new PublishStatus(content, evtMsgs));
}
/// <summary>
@@ -402,9 +404,9 @@ namespace Umbraco.Core.Publishing
/// <param name="content"><see cref="IContent"/> thats being published</param>
public override void PublishingFinalized(IContent content)
{
Published.RaiseEvent(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(content, false, false, messages), this);
var evtMsgs = _eventMessagesFactory.Get();
Published.RaiseEvent(
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
}
/// <summary>
@@ -414,9 +416,9 @@ namespace Umbraco.Core.Publishing
/// <param name="isAllRepublished">Boolean indicating whether its all content that is republished</param>
public override void PublishingFinalized(IEnumerable<IContent> content, bool isAllRepublished)
{
var evtMsgs = _eventMessagesFactory.Get();
Published.RaiseEvent(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(content, false, isAllRepublished, messages), this);
new PublishEventArgs<IContent>(content, false, isAllRepublished, evtMsgs), this);
}
@@ -426,9 +428,9 @@ namespace Umbraco.Core.Publishing
/// <param name="content"><see cref="IContent"/> thats being unpublished</param>
public override void UnPublishingFinalized(IContent content)
{
var evtMsgs = _eventMessagesFactory.Get();
UnPublished.RaiseEvent(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(content, false, false, messages), this);
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
}
/// <summary>
@@ -437,9 +439,9 @@ namespace Umbraco.Core.Publishing
/// <param name="content">An enumerable list of <see cref="IContent"/> thats being unpublished</param>
public override void UnPublishingFinalized(IEnumerable<IContent> content)
{
var evtMsgs = _eventMessagesFactory.Get();
UnPublished.RaiseEvent(
_eventMessagesFactory.Get(),
messages => new PublishEventArgs<IContent>(content, false, false, messages), this);
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
}
/// <summary>
@@ -1,3 +1,4 @@
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
@@ -8,16 +9,16 @@ namespace Umbraco.Core.Publishing
/// </summary>
public class UnPublishStatus : OperationStatus<IContent, UnPublishedStatusType>
{
public UnPublishStatus(IContent content, UnPublishedStatusType statusType)
: base(content, statusType)
public UnPublishStatus(IContent content, UnPublishedStatusType statusType, EventMessages eventMessages)
: base(content, statusType, eventMessages)
{
}
/// <summary>
/// Creates a successful unpublish status
/// </summary>
public UnPublishStatus(IContent content)
: this(content, UnPublishedStatusType.Success)
public UnPublishStatus(IContent content, EventMessages eventMessages)
: this(content, UnPublishedStatusType.Success, eventMessages)
{
}
+44 -35
View File
@@ -889,16 +889,17 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the User deleting the Content</param>
Attempt<OperationStatus> IContentServiceOperations.MoveToRecycleBin(IContent content, int userId)
{
var evtMsgs = EventMessagesFactory.Get();
using (new WriteLock(Locker))
{
var originalPath = content.Path;
if (Trashing.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new MoveEventArgs<IContent>(messages, new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)),
if (Trashing.IsRaisedEventCancelled(
new MoveEventArgs<IContent>(evtMsgs, new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)),
this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
var moveInfo = new List<MoveEventInfo<IContent>>
@@ -941,11 +942,11 @@ namespace Umbraco.Core.Services
uow.Commit();
}
Trashed.RaiseEvent(EventMessagesFactory.Get(), messages => new MoveEventArgs<IContent>(false, messages, moveInfo.ToArray()), this);
Trashed.RaiseEvent(new MoveEventArgs<IContent>(false, evtMsgs, moveInfo.ToArray()), this);
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
}
@@ -1060,14 +1061,15 @@ namespace Umbraco.Core.Services
{
var asArray = contents.ToArray();
var evtMsgs = EventMessagesFactory.Get();
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new SaveEventArgs<IContent>(asArray, messages),
new SaveEventArgs<IContent>(asArray, evtMsgs),
this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
}
using (new WriteLock(Locker))
@@ -1107,11 +1109,11 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IContent>(asArray, false, messages), this);
Saved.RaiseEvent(new SaveEventArgs<IContent>(asArray, false, evtMsgs), this);
Audit(AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
}
@@ -1126,14 +1128,15 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the User deleting the Content</param>
Attempt<OperationStatus> IContentServiceOperations.Delete(IContent content, int userId)
{
var evtMsgs = EventMessagesFactory.Get();
using (new WriteLock(Locker))
{
if (Deleting.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new DeleteEventArgs<IContent>(content, messages),
if (Deleting.IsRaisedEventCancelled(
new DeleteEventArgs<IContent>(content, evtMsgs),
this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
//Make sure that published content is unpublished before being deleted
@@ -1154,10 +1157,9 @@ namespace Umbraco.Core.Services
{
repository.Delete(content);
uow.Commit();
var evtMsgs = EventMessagesFactory.Get();
var args = new DeleteEventArgs<IContent>(content, false, evtMsgs);
Deleted.RaiseEvent(evtMsgs, messages => args, this);
Deleted.RaiseEvent(args, this);
//remove any flagged media files
repository.DeleteMediaFiles(args.MediaFilesToDelete);
@@ -1165,7 +1167,7 @@ namespace Umbraco.Core.Services
Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
}
@@ -1772,6 +1774,8 @@ namespace Umbraco.Core.Services
{
if (content == null) throw new ArgumentNullException("content");
var evtMsgs = EventMessagesFactory.Get();
using (new WriteLock(Locker))
{
var result = new List<Attempt<PublishStatus>>();
@@ -1783,7 +1787,7 @@ namespace Umbraco.Core.Services
string.Format(
"Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.",
content.Name, content.Id));
result.Add(Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedPathNotPublished)));
result.Add(Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedPathNotPublished, evtMsgs)));
return result;
}
@@ -1795,7 +1799,7 @@ namespace Umbraco.Core.Services
content.Name, content.Id));
result.Add(
Attempt.Fail(
new PublishStatus(content, PublishStatusType.FailedContentInvalid)
new PublishStatus(content, PublishStatusType.FailedContentInvalid, evtMsgs)
{
InvalidProperties = ((ContentBase)content).LastInvalidProperties
}));
@@ -1857,14 +1861,17 @@ namespace Umbraco.Core.Services
var newest = GetById(content.Id); // ensure we have the newest version
if (content.Version != newest.Version) // but use the original object if it's already the newest version
content = newest;
var evtMsgs = EventMessagesFactory.Get();
var published = content.Published ? content : GetPublishedVersion(content.Id); // get the published version
if (published == null)
{
return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.SuccessAlreadyUnPublished)); // already unpublished
return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.SuccessAlreadyUnPublished, evtMsgs)); // already unpublished
}
var unpublished = _publishingStrategy.UnPublish(content, userId);
if (unpublished == false) return Attempt.Fail(new UnPublishStatus(content, UnPublishedStatusType.FailedCancelledByEvent));
if (unpublished == false) return Attempt.Fail(new UnPublishStatus(content, UnPublishedStatusType.FailedCancelledByEvent, evtMsgs));
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
@@ -1884,7 +1891,7 @@ namespace Umbraco.Core.Services
Audit(AuditType.UnPublish, "UnPublish performed by user", userId, content.Id);
return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.Success));
return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.Success, evtMsgs));
}
/// <summary>
@@ -1896,13 +1903,14 @@ namespace Umbraco.Core.Services
/// <returns>True if publishing succeeded, otherwise False</returns>
private Attempt<PublishStatus> SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true)
{
var evtMsgs = EventMessagesFactory.Get();
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new SaveEventArgs<IContent>(content, messages), this))
new SaveEventArgs<IContent>(content, evtMsgs), this))
{
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
}
}
@@ -1910,7 +1918,7 @@ namespace Umbraco.Core.Services
{
//Has this content item previously been published? If so, we don't need to refresh the children
var previouslyPublished = content.HasIdentity && HasPublishedVersion(content.Id); //content might not have an id
var publishStatus = new PublishStatus(content, PublishStatusType.Success); //initially set to success
var publishStatus = new PublishStatus(content, PublishStatusType.Success, evtMsgs); //initially set to success
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
publishStatus.StatusType = CheckAndLogIsPublishable(content);
@@ -1960,7 +1968,7 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IContent>(content, false, messages), this);
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false, evtMsgs), this);
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
if (published)
@@ -1991,14 +1999,15 @@ namespace Umbraco.Core.Services
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
private Attempt<OperationStatus> Save(IContent content, bool changeState, int userId = 0, bool raiseEvents = true)
{
var evtMsgs = EventMessagesFactory.Get();
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new SaveEventArgs<IContent>(content, messages),
if (Saving.IsRaisedEventCancelled(
new SaveEventArgs<IContent>(content, evtMsgs),
this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
}
@@ -2026,11 +2035,11 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IContent>(content, false, messages), this);
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false, evtMsgs), this);
Audit(AuditType.Save, "Save Content performed by user", userId, content.Id);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
}
+47
View File
@@ -319,6 +319,53 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<ITemplate> GetTemplateDescendants(string alias)
{
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
{
return repository.GetDescendants(alias);
}
}
/// <summary>
/// Gets the template descendants
/// </summary>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
public IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId)
{
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
{
return repository.GetDescendants(masterTemplateId);
}
}
/// <summary>
/// Gets the template children
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
public IEnumerable<ITemplate> GetTemplateChildren(string alias)
{
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
{
return repository.GetChildren(alias);
}
}
/// <summary>
/// Gets the template children
/// </summary>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
public IEnumerable<ITemplate> GetTemplateChildren(int masterTemplateId)
{
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
{
return repository.GetChildren(masterTemplateId);
}
}
/// <summary>
/// Returns a template as a template node which can be traversed (parent, children)
/// </summary>
+29 -1
View File
@@ -130,10 +130,38 @@ namespace Umbraco.Core.Services
ITemplate GetTemplate(int id);
/// <summary>
/// Returns a template as a template node which can be traversed (parent, children)
/// Gets the template descendants
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
IEnumerable<ITemplate> GetTemplateDescendants(string alias);
/// <summary>
/// Gets the template descendants
/// </summary>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId);
/// <summary>
/// Gets the template children
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
IEnumerable<ITemplate> GetTemplateChildren(string alias);
/// <summary>
/// Gets the template children
/// </summary>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
IEnumerable<ITemplate> GetTemplateChildren(int masterTemplateId);
/// <summary>
/// Returns a template as a template node which can be traversed (parent, children)
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
TemplateNode GetTemplateNode(string alias);
/// <summary>
@@ -47,5 +47,13 @@ namespace Umbraco.Core.Services
/// to resolve the full culture if possible.
/// </remarks>
CultureInfo ConvertToSupportedCultureWithRegionCode(CultureInfo currentCulture);
/// <summary>
/// HAAAAAAAAAAACK! Used for backwards compat to convert a user's real culture code to a region code - normally this would be two letters
/// TODO: REmove in v8
/// </summary>
/// <param name="currentCulture"></param>
/// <returns></returns>
string ConvertToRegionCodeFromSupportedCulture(CultureInfo currentCulture);
}
}
@@ -191,6 +191,23 @@ namespace Umbraco.Core.Services
return attempt ? attempt.Result : currentCulture;
}
/// <summary>
/// HAAAAAAAAAAACK! Used for backwards compat to convert a user's real culture code to a region code - normally this would be two letters
/// </summary>
/// <param name="currentCulture"></param>
/// <returns></returns>
public string ConvertToRegionCodeFromSupportedCulture(CultureInfo currentCulture)
{
if (currentCulture == null) throw new ArgumentNullException("currentCulture");
if (_fileSources == null) return currentCulture.Name;
var attempt = _fileSources.Value.TryConvert4LetterCultureTo2Letter(currentCulture);
return attempt
? attempt.Result
: currentCulture.Name;
}
private string GetFromDictionarySource(CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
{
if (_dictionarySource.ContainsKey(culture) == false)
@@ -158,7 +158,7 @@ namespace Umbraco.Core.Services
//TODO: See other notes in this class, this is purely a hack because we store 2 letter culture file names that contain 4 letter cultures :(
public Attempt<CultureInfo> TryConvert2LetterCultureTo4Letter(string twoLetterCulture)
{
if (twoLetterCulture.Length != 2) Attempt<CultureInfo>.Fail();
if (twoLetterCulture.Length != 2) return Attempt<CultureInfo>.Fail();
//This needs to be resolved before continuing so that the _twoLetterCultureConverter cache is initialized
var resolved = _xmlSources.Value;
@@ -168,6 +168,19 @@ namespace Umbraco.Core.Services
: Attempt<CultureInfo>.Fail();
}
//TODO: See other notes in this class, this is purely a hack because we store 2 letter culture file names that contain 4 letter cultures :(
public Attempt<string> TryConvert4LetterCultureTo2Letter(CultureInfo culture)
{
if (culture == null) throw new ArgumentNullException("culture");
//This needs to be resolved before continuing so that the _twoLetterCultureConverter cache is initialized
var resolved = _xmlSources.Value;
return _twoLetterCultureConverter.Values.Contains(culture)
? Attempt.Succeed(culture.Name.Substring(0, 2))
: Attempt<string>.Fail();
}
private void MergeSupplementaryFiles(CultureInfo culture, XDocument xMasterDoc)
{
if (xMasterDoc.Root == null) return;
+24 -24
View File
@@ -741,12 +741,12 @@ namespace Umbraco.Core.Services
Attempt<OperationStatus> IMediaServiceOperations.Delete(IMedia media, int userId)
{
//TODO: IT would be much nicer to mass delete all in one trans in the repo level!
var evtMsgs = EventMessagesFactory.Get();
if (Deleting.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new DeleteEventArgs<IMedia>(media, messages), this))
if (Deleting.IsRaisedEventCancelled(
new DeleteEventArgs<IMedia>(media, evtMsgs), this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
//Delete children before deleting the 'possible parent'
@@ -762,9 +762,8 @@ namespace Umbraco.Core.Services
repository.Delete(media);
uow.Commit();
var msgs = EventMessagesFactory.Get();
var args = new DeleteEventArgs<IMedia>(media, false, msgs);
Deleted.RaiseEvent(msgs, messages => args, this);
var args = new DeleteEventArgs<IMedia>(media, false, evtMsgs);
Deleted.RaiseEvent(args, this);
//remove any flagged media files
repository.DeleteMediaFiles(args.MediaFilesToDelete);
@@ -772,7 +771,7 @@ namespace Umbraco.Core.Services
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
/// <summary>
@@ -783,14 +782,15 @@ namespace Umbraco.Core.Services
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
Attempt<OperationStatus> IMediaServiceOperations.Save(IMedia media, int userId, bool raiseEvents)
{
var evtMsgs = EventMessagesFactory.Get();
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new SaveEventArgs<IMedia>(media, messages),
new SaveEventArgs<IMedia>(media, evtMsgs),
this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
}
@@ -811,11 +811,11 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IMedia>(media, false, messages), this);
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false, evtMsgs), this);
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
/// <summary>
@@ -827,15 +827,15 @@ namespace Umbraco.Core.Services
Attempt<OperationStatus> IMediaServiceOperations.Save(IEnumerable<IMedia> medias, int userId, bool raiseEvents)
{
var asArray = medias.ToArray();
var evtMsgs = EventMessagesFactory.Get();
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new SaveEventArgs<IMedia>(asArray, messages),
new SaveEventArgs<IMedia>(asArray, evtMsgs),
this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
}
@@ -859,11 +859,11 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IMedia>(asArray, false, messages), this);
Saved.RaiseEvent(new SaveEventArgs<IMedia>(asArray, false, evtMsgs), this);
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
/// <summary>
@@ -960,11 +960,12 @@ namespace Umbraco.Core.Services
var originalPath = media.Path;
var evtMsgs = EventMessagesFactory.Get();
if (Trashing.IsRaisedEventCancelled(
EventMessagesFactory.Get(),
messages => new MoveEventArgs<IMedia>(messages, new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
{
return Attempt.Fail(OperationStatus.Cancelled);
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
}
var moveInfo = new List<MoveEventInfo<IMedia>>
@@ -1002,12 +1003,11 @@ namespace Umbraco.Core.Services
}
Trashed.RaiseEvent(
EventMessagesFactory.Get(),
messages => new MoveEventArgs<IMedia>(false, messages, moveInfo.ToArray()), this);
new MoveEventArgs<IMedia>(false, evtMsgs, moveInfo.ToArray()), this);
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
return Attempt.Succeed(OperationStatus.Success);
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
}
/// <summary>
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Services
}
var content = (IContent) entity;
//we'll lazily get these if we need to send notifications
IContent[] allVersions = null;
IEnumerable<IContent> allVersions = null;
int totalUsers;
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
@@ -75,12 +75,17 @@ namespace Umbraco.Core.Services
//lazy load versions if notifications are required
if (allVersions == null)
{
allVersions = _contentService.GetVersions(entity.Id).ToArray();
allVersions = _contentService.GetVersions(entity.Id);
}
try
{
SendNotification(operatingUser, u, content, allVersions, actionName, http, createSubject, createBody);
SendNotification(
operatingUser, u, content,
allVersions,
actionName, http, createSubject, createBody);
_logger.Debug<NotificationService>(string.Format("Notification type: {0} sent to {1} ({2})", action, u.Name, u.Email));
}
catch (Exception ex)
@@ -192,7 +197,7 @@ namespace Umbraco.Core.Services
/// <param name="http"></param>
/// <param name="createSubject">Callback to create the mail subject</param>
/// <param name="createBody">Callback to create the mail body</param>
private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IContent[] allVersions, string actionName, HttpContextBase http,
private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IEnumerable<IContent> allVersions, string actionName, HttpContextBase http,
Func<IUser, string[], string> createSubject,
Func<IUser, string[], string> createBody)
{
@@ -204,8 +209,11 @@ namespace Umbraco.Core.Services
if (createSubject == null) throw new ArgumentNullException("createSubject");
if (createBody == null) throw new ArgumentNullException("createBody");
int versionCount = (allVersions.Length > 1) ? (allVersions.Length - 2) : (allVersions.Length - 1);
var oldDoc = _contentService.GetByVersion(allVersions[versionCount].Version);
//Ensure they are sorted: http://issues.umbraco.org/issue/U4-5180
var allVersionsAsArray = allVersions.OrderBy(x => x.UpdateDate).ToArray();
int versionCount = (allVersionsAsArray.Length > 1) ? (allVersionsAsArray.Length - 2) : (allVersionsAsArray.Length - 1);
var oldDoc = _contentService.GetByVersion(allVersionsAsArray[versionCount].Version);
// build summary
var summary = new StringBuilder();
+15 -8
View File
@@ -1,3 +1,5 @@
using System;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
namespace Umbraco.Core.Services
@@ -8,7 +10,7 @@ namespace Umbraco.Core.Services
public class OperationStatus<TEntity, TStatus> : OperationStatus<TStatus>
where TStatus : struct
{
public OperationStatus(TEntity entity, TStatus statusType) : base(statusType)
public OperationStatus(TEntity entity, TStatus statusType, EventMessages eventMessages) : base(statusType, eventMessages)
{
Entity = entity;
}
@@ -20,12 +22,15 @@ namespace Umbraco.Core.Services
public class OperationStatus<TStatus>
where TStatus : struct
{
public OperationStatus(TStatus statusType)
public OperationStatus(TStatus statusType, EventMessages eventMessages)
{
if (eventMessages == null) throw new ArgumentNullException("eventMessages");
StatusType = statusType;
EventMessages = eventMessages;
}
public TStatus StatusType { get; internal set; }
public EventMessages EventMessages { get; private set; }
}
/// <summary>
@@ -33,21 +38,23 @@ namespace Umbraco.Core.Services
/// </summary>
public class OperationStatus : OperationStatus<OperationStatusType>
{
public OperationStatus(OperationStatusType statusType) : base(statusType)
public OperationStatus(OperationStatusType statusType, EventMessages eventMessages) : base(statusType, eventMessages)
{
}
#region Static Helper methods
internal static OperationStatus Cancelled
internal static OperationStatus Cancelled(EventMessages eventMessages)
{
get { return new OperationStatus(OperationStatusType.FailedCancelledByEvent); }
return new OperationStatus(OperationStatusType.FailedCancelledByEvent, eventMessages);
}
internal static OperationStatus Success
internal static OperationStatus Success(EventMessages eventMessages)
{
get { return new OperationStatus(OperationStatusType.Success); }
}
return new OperationStatus(OperationStatusType.Success, eventMessages);
}
#endregion
}
+13
View File
@@ -1409,5 +1409,18 @@ namespace Umbraco.Core
{
return string.IsNullOrEmpty(text) ? text : InvalidXmlChars.Replace(text, "");
}
/// <summary>
/// Converts a string to a Guid - WARNING, depending on the string, this may not be unique
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
internal static Guid ToGuid(this string text)
{
var md5 = MD5.Create();
byte[] myStringBytes = Encoding.ASCII.GetBytes(text);
byte[] hash = md5.ComputeHash(myStringBytes);
return new Guid(hash);
}
}
}
+7 -7
View File
@@ -37,13 +37,13 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -302,6 +302,7 @@
<Compile Include="DatabaseContext.cs" />
<Compile Include="DataTableExtensions.cs" />
<Compile Include="DateTimeExtensions.cs" />
<Compile Include="DelegateExtensions.cs" />
<Compile Include="DictionaryExtensions.cs" />
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
@@ -1386,7 +1387,6 @@
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
@@ -0,0 +1,46 @@
using System;
using Lucene.Net.Index;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests
{
[TestFixture]
public class DelegateExtensionsTests
{
[Test]
public void Only_Executes_Specific_Count()
{
var maxTries = 5;
var totalTries = 0;
DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) =>
{
totalTries = currentTry;
return Attempt<IndexWriter>.Fail();
}, 5, TimeSpan.FromMilliseconds(10));
Assert.AreEqual(maxTries, totalTries);
}
[Test]
public void Quits_On_Success_Count()
{
var maxTries = 5;
var totalTries = 0;
DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) =>
{
totalTries = currentTry;
if (totalTries == 2)
{
return Attempt<string>.Succeed();
}
return Attempt<string>.Fail();
}, 5, TimeSpan.FromMilliseconds(10));
Assert.AreEqual(2, totalTries);
}
}
}
@@ -119,6 +119,7 @@ namespace Umbraco.Tests.Logging
}
[Test]
[Ignore]
public void CanLogAtleast1000MessagesASecond()
{
// Arrange
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -460,13 +461,15 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
var content2 = "{javascript: []}";
var content3 = "{javascript: ['~/test.js', '~/test2.js']}";
var content4 = "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js']}";
var content5 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()) + "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js']}";
var result = ManifestParser.CreateManifests(null, content1, content2, content3, content4);
var result = ManifestParser.CreateManifests(null, content1, content2, content3, content4, content5);
Assert.AreEqual(4, result.Count());
Assert.AreEqual(5, result.Count());
Assert.AreEqual(0, result.ElementAt(1).JavaScriptInitialize.Count);
Assert.AreEqual(2, result.ElementAt(2).JavaScriptInitialize.Count);
Assert.AreEqual(2, result.ElementAt(3).JavaScriptInitialize.Count);
Assert.AreEqual(2, result.ElementAt(4).JavaScriptInitialize.Count);
}
[Test]
@@ -44,7 +44,13 @@ namespace Umbraco.Tests.Persistence.Repositories
private ContentRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository)
{
var templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
TemplateRepository tr;
return CreateRepository(unitOfWork, out contentTypeRepository, out tr);
}
private ContentRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository)
{
templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
var tagRepository = new TagRepository(unitOfWork, CacheHelper, Logger, SqlSyntax);
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, templateRepository);
var repository = new ContentRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>());
@@ -217,6 +223,37 @@ namespace Umbraco.Tests.Persistence.Repositories
// Assert
Assert.That(contentType.HasIdentity, Is.True);
Assert.That(textpage.HasIdentity, Is.True);
}
}
[Test]
public void Can_Perform_Add_With_Default_Template()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
TemplateRepository templateRepository;
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository, out templateRepository))
{
var template = new Template("hello", "hello");
templateRepository.AddOrUpdate(template);
unitOfWork.Commit();
ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage");
contentType.SetDefaultTemplate(template);
Content textpage = MockedContent.CreateSimpleContent(contentType);
// Act
contentTypeRepository.AddOrUpdate(contentType);
repository.AddOrUpdate(textpage);
unitOfWork.Commit();
// Assert
Assert.That(textpage.Template, Is.Not.Null);
Assert.That(textpage.Template, Is.EqualTo(contentType.DefaultTemplate));
}
}
@@ -327,6 +364,28 @@ namespace Umbraco.Tests.Persistence.Repositories
}
[Test]
public void Can_Update_With_Null_Template()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
// Act
var content = repository.Get(NodeDto.NodeIdSeed + 2);
content.Template = null;
repository.AddOrUpdate(content);
unitOfWork.Commit();
var updatedContent = repository.Get(NodeDto.NodeIdSeed + 2);
// Assert
Assert.That(updatedContent.Template, Is.Null);
}
}
[Test]
public void Can_Perform_Delete_On_ContentRepository()
{
@@ -235,13 +235,16 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var repository = CreateRepository(unitOfWork))
{
var contentType = repository.Get(NodeDto.NodeIdSeed + 1);
var childContentType = MockedContentTypes.CreateSimpleContentType("blah", "Blah", contentType, randomizeAliases:true);
repository.AddOrUpdate(childContentType);
unitOfWork.Commit();
// Act
contentType = repository.Get(contentType.Key);
var result = repository.Get(childContentType.Key);
// Assert
Assert.That(contentType, Is.Not.Null);
Assert.That(contentType.Id, Is.EqualTo(NodeDto.NodeIdSeed + 1));
Assert.That(result, Is.Not.Null);
Assert.That(result.Id, Is.EqualTo(childContentType.Id));
}
}
@@ -85,9 +85,41 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual("test.com", domain.DomainName);
Assert.AreEqual(content.Id, domain.RootContentId);
Assert.AreEqual(lang.Id, domain.LanguageId);
Assert.AreEqual(lang.IsoCode, domain.LanguageIsoCode);
}
}
[Test]
public void Can_Create_And_Get_By_Id_Empty_lang()
{
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentType ct;
var contentId = CreateTestData("en-AU", out ct);
ContentRepository contentRepo;
LanguageRepository langRepo;
ContentTypeRepository contentTypeRepo;
using (var repo = CreateRepository(unitOfWork, out contentTypeRepo, out contentRepo, out langRepo))
{
var content = contentRepo.Get(contentId);
var domain = (IDomain)new UmbracoDomain("test.com") { RootContentId = content.Id };
repo.AddOrUpdate(domain);
unitOfWork.Commit();
//re-get
domain = repo.Get(domain.Id);
Assert.NotNull(domain);
Assert.IsTrue(domain.HasIdentity);
Assert.Greater(domain.Id, 0);
Assert.AreEqual("test.com", domain.DomainName);
Assert.AreEqual(content.Id, domain.RootContentId);
Assert.IsFalse(domain.LanguageId.HasValue);
}
}
[Test]
@@ -203,11 +235,13 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual("blah.com", domain.DomainName);
Assert.AreEqual(content2.Id, domain.RootContentId);
Assert.AreEqual(lang2.Id, domain.LanguageId);
Assert.AreEqual(lang2.IsoCode, domain.LanguageIsoCode);
}
}
[Test]
public void Exists()
{
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -489,77 +490,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var unitOfWork = provider.GetUnitOfWork();
using (var repository = CreateRepository(unitOfWork))
{
var parent = new Template("parent", "parent")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var child1 = new Template("child1", "child1")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler1 = new Template("toddler1", "toddler1")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler2 = new Template("toddler2", "toddler2")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var baby1 = new Template("baby1", "baby1")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var child2 = new Template("child2", "child2")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler3 = new Template("toddler3", "toddler3")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler4 = new Template("toddler4", "toddler4")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var baby2 = new Template("baby2", "baby2")
{
Content = @"<%@ Master Language=""C#"" %>"
};
child1.MasterTemplateAlias = parent.Alias;
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
child2.MasterTemplateAlias = parent.Alias;
child2.MasterTemplateId = new Lazy<int>(() => parent.Id);
toddler1.MasterTemplateAlias = child1.Alias;
toddler1.MasterTemplateId = new Lazy<int>(() => child1.Id);
toddler2.MasterTemplateAlias = child1.Alias;
toddler2.MasterTemplateId = new Lazy<int>(() => child1.Id);
toddler3.MasterTemplateAlias = child2.Alias;
toddler3.MasterTemplateId = new Lazy<int>(() => child2.Id);
toddler4.MasterTemplateAlias = child2.Alias;
toddler4.MasterTemplateId = new Lazy<int>(() => child2.Id);
baby1.MasterTemplateAlias = toddler2.Alias;
baby1.MasterTemplateId = new Lazy<int>(() => toddler2.Id);
baby2.MasterTemplateAlias = toddler4.Alias;
baby2.MasterTemplateId = new Lazy<int>(() => toddler4.Id);
repository.AddOrUpdate(parent);
repository.AddOrUpdate(child1);
repository.AddOrUpdate(child2);
repository.AddOrUpdate(toddler1);
repository.AddOrUpdate(toddler2);
repository.AddOrUpdate(toddler3);
repository.AddOrUpdate(toddler4);
repository.AddOrUpdate(baby1);
repository.AddOrUpdate(baby2);
unitOfWork.Commit();
CreateHierarchy(repository, unitOfWork);
// Act
var rootNode = repository.GetTemplateNode("parent");
@@ -575,8 +506,102 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby1"));
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby2"));
}
}
[Test]
public void Can_Get_All()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
using (var repository = CreateRepository(unitOfWork))
{
var created = CreateHierarchy(repository, unitOfWork).ToArray();
// Act
var all = repository.GetAll();
var allByAlias = repository.GetAll("parent", "child2", "baby2", "notFound");
var allById = repository.GetAll(created[0].Id, created[2].Id, created[4].Id, created[5].Id, 999999);
// Assert
Assert.AreEqual(9, all.Count());
Assert.AreEqual(9, all.DistinctBy(x => x.Id).Count());
Assert.AreEqual(3, allByAlias.Count());
Assert.AreEqual(3, allByAlias.DistinctBy(x => x.Id).Count());
Assert.AreEqual(4, allById.Count());
Assert.AreEqual(4, allById.DistinctBy(x => x.Id).Count());
}
}
[Test]
public void Can_Get_Children()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
using (var repository = CreateRepository(unitOfWork))
{
var created = CreateHierarchy(repository, unitOfWork).ToArray();
// Act
var childrenById = repository.GetChildren(created[1].Id);
var childrenByAlias = repository.GetChildren(created[1].Alias);
// Assert
Assert.AreEqual(2, childrenById.Count());
Assert.AreEqual(2, childrenById.DistinctBy(x => x.Id).Count());
Assert.AreEqual(2, childrenByAlias.Count());
Assert.AreEqual(2, childrenByAlias.DistinctBy(x => x.Id).Count());
}
}
[Test]
public void Can_Get_Children_At_Root()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
using (var repository = CreateRepository(unitOfWork))
{
CreateHierarchy(repository, unitOfWork).ToArray();
// Act
var children = repository.GetChildren(-1);
// Assert
Assert.AreEqual(1, children.Count());
Assert.AreEqual(1, children.DistinctBy(x => x.Id).Count());
}
}
[Test]
public void Can_Get_Descendants()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
using (var repository = CreateRepository(unitOfWork))
{
var created = CreateHierarchy(repository, unitOfWork).ToArray();
// Act
var descendantsById = repository.GetDescendants(created[1].Id);
var descendantsByAlias = repository.GetDescendants(created[1].Alias);
// Assert
Assert.AreEqual(3, descendantsById.Count());
Assert.AreEqual(3, descendantsById.DistinctBy(x => x.Id).Count());
Assert.AreEqual(3, descendantsByAlias.Count());
Assert.AreEqual(3, descendantsByAlias.DistinctBy(x => x.Id).Count());
}
}
[Test]
@@ -717,5 +742,82 @@ namespace Umbraco.Tests.Persistence.Repositories
return stream;
}
private IEnumerable<ITemplate> CreateHierarchy(ITemplateRepository repository, IDatabaseUnitOfWork unitOfWork)
{
var parent = new Template("parent", "parent")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var child1 = new Template("child1", "child1")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler1 = new Template("toddler1", "toddler1")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler2 = new Template("toddler2", "toddler2")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var baby1 = new Template("baby1", "baby1")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var child2 = new Template("child2", "child2")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler3 = new Template("toddler3", "toddler3")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var toddler4 = new Template("toddler4", "toddler4")
{
Content = @"<%@ Master Language=""C#"" %>"
};
var baby2 = new Template("baby2", "baby2")
{
Content = @"<%@ Master Language=""C#"" %>"
};
child1.MasterTemplateAlias = parent.Alias;
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
child2.MasterTemplateAlias = parent.Alias;
child2.MasterTemplateId = new Lazy<int>(() => parent.Id);
toddler1.MasterTemplateAlias = child1.Alias;
toddler1.MasterTemplateId = new Lazy<int>(() => child1.Id);
toddler2.MasterTemplateAlias = child1.Alias;
toddler2.MasterTemplateId = new Lazy<int>(() => child1.Id);
toddler3.MasterTemplateAlias = child2.Alias;
toddler3.MasterTemplateId = new Lazy<int>(() => child2.Id);
toddler4.MasterTemplateAlias = child2.Alias;
toddler4.MasterTemplateId = new Lazy<int>(() => child2.Id);
baby1.MasterTemplateAlias = toddler2.Alias;
baby1.MasterTemplateId = new Lazy<int>(() => toddler2.Id);
baby2.MasterTemplateAlias = toddler4.Alias;
baby2.MasterTemplateId = new Lazy<int>(() => toddler4.Id);
repository.AddOrUpdate(parent);
repository.AddOrUpdate(child1);
repository.AddOrUpdate(child2);
repository.AddOrUpdate(toddler1);
repository.AddOrUpdate(toddler2);
repository.AddOrUpdate(toddler3);
repository.AddOrUpdate(toddler4);
repository.AddOrUpdate(baby1);
repository.AddOrUpdate(baby2);
unitOfWork.Commit();
return new[] {parent, child1, child2, toddler1, toddler2, toddler3, toddler4, baby1, baby2};
}
}
}
@@ -454,6 +454,20 @@ namespace Umbraco.Tests.PublishedContent
}
[Test]
public void FirstChild()
{
var doc = GetNode(1173); // has child nodes
Assert.IsNotNull(doc.FirstChild());
Assert.IsNotNull(doc.FirstChild(x => true));
Assert.IsNotNull(doc.FirstChild<IPublishedContent>());
doc = GetNode(1175); // does not have child nodes
Assert.IsNull(doc.FirstChild());
Assert.IsNull(doc.FirstChild(x => true));
Assert.IsNull(doc.FirstChild<IPublishedContent>());
}
[Test]
public void HasProperty()
{
@@ -13,7 +13,7 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001}
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"}
});
}
@@ -22,12 +22,12 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001},
new UmbracoDomain("domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
new UmbracoDomain("domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032}
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
@@ -30,19 +30,22 @@ namespace Umbraco.Tests.Routing
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("domain1.com/en")
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 10011
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.com/fr")
{
Id = 1,
LanguageId = LangFrId,
RootContentId = 10012
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
}
});
}
@@ -55,55 +58,64 @@ namespace Umbraco.Tests.Routing
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("domain1.com/en")
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 10011
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.com/fr")
{
Id = 1,
LanguageId = LangFrId,
RootContentId = 10012
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
},
new UmbracoDomain("*1001")
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("*10011")
{
Id = 1,
LanguageId = LangCzId,
RootContentId = 10011
RootContentId = 10011,
LanguageIsoCode = "cs-CZ"
},
new UmbracoDomain("*100112")
{
Id = 1,
LanguageId = LangNlId,
RootContentId = 100112
RootContentId = 100112,
LanguageIsoCode = "nl-NL"
},
new UmbracoDomain("*1001122")
{
Id = 1,
LanguageId = LangDkId,
RootContentId = 1001122
RootContentId = 1001122,
LanguageIsoCode = "da-DK"
},
new UmbracoDomain("*10012")
{
Id = 1,
LanguageId = LangNlId,
RootContentId = 10012
RootContentId = 10012,
LanguageIsoCode = "nl-NL"
},
new UmbracoDomain("*10031")
{
Id = 1,
LanguageId = LangNlId,
RootContentId =10031
RootContentId =10031,
LanguageIsoCode = "nl-NL"
}
});
}
@@ -343,19 +355,22 @@ namespace Umbraco.Tests.Routing
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 1001
RootContentId = 1001,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.fr/")
{
Id = 1,
LanguageId = LangFrId,
RootContentId = 1001
RootContentId = 1001,
LanguageIsoCode = "fr-FR"
},
new UmbracoDomain("*100112")
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 100112
RootContentId = 100112,
LanguageIsoCode = "de-DE"
}
});
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.Routing
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001}
new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
});
}
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001}
new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
});
}
@@ -44,7 +44,7 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011}
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011, LanguageIsoCode = "fr-FR"}
});
}
@@ -52,12 +52,12 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001},
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032}
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
@@ -65,14 +65,14 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
new UmbracoDomain("http://domain1a.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
new UmbracoDomain("http://domain1b.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
new UmbracoDomain("http://domain1a.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
new UmbracoDomain("http://domain1b.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032}
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1a.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1b.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain1a.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain1b.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
@@ -42,19 +42,10 @@ namespace Umbraco.Tests.Routing
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = 333, RootContentId = 1001},
new UmbracoDomain("domain1.com/en"){Id = 1, LanguageId = 334, RootContentId = 10011},
new UmbracoDomain("domain1.com/fr"){Id = 1, LanguageId = 335, RootContentId = 10012}
});
var langService = Mock.Get(svcCtx.LocalizationService);
//setup mock domain service
langService.Setup(service => service.GetLanguageById(LangDeId)).Returns(new Language("de-DE") {Id = LangDeId });
langService.Setup(service => service.GetLanguageById(LangEngId)).Returns(new Language("en-US") { Id = LangEngId });
langService.Setup(service => service.GetLanguageById(LangFrId)).Returns(new Language("fr-FR") { Id = LangFrId });
langService.Setup(service => service.GetLanguageById(LangCzId)).Returns(new Language("cs-CZ") { Id = LangCzId });
langService.Setup(service => service.GetLanguageById(LangNlId)).Returns(new Language("nl-NL") { Id = LangNlId });
langService.Setup(service => service.GetLanguageById(LangDkId)).Returns(new Language("da-DK") { Id = LangDkId });
new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"},
new UmbracoDomain("domain1.com/en"){Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/fr"){Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}
});
return svcCtx;
}
@@ -80,8 +80,8 @@ namespace Umbraco.Tests.Routing
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001},
new UmbracoDomain("http://domain2.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 10011}
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain2.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}
});
}
@@ -24,6 +24,18 @@ namespace Umbraco.Tests.Strings
ShortStringHelperResolver.Reset();
}
[TestCase("hello", "world", false)]
[TestCase("hello", "hello", true)]
[TestCase("hellohellohellohellohellohellohello", "hellohellohellohellohellohellohelloo", false)]
[TestCase("hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohelloo", false)]
[TestCase("hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", true)]
public void String_To_Guid(string first, string second, bool result)
{
Console.WriteLine("First: " + first.ToGuid());
Console.WriteLine("Second: " + second.ToGuid());
Assert.AreEqual(result, first.ToGuid() == second.ToGuid());
}
[TestCase("alert('hello');", false)]
[TestCase("~/Test.js", true)]
[TestCase("../Test.js", true)]
+9 -9
View File
@@ -51,16 +51,16 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Examine, Version=0.1.66.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.66.0\lib\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.68.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.68.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
@@ -176,6 +176,7 @@
<Compile Include="Cache\CacheRefresherTests.cs" />
<Compile Include="Cache\DeepCloneRuntimeCacheProviderTests.cs" />
<Compile Include="Controllers\BackOfficeControllerUnitTests.cs" />
<Compile Include="DelegateExtensionsTests.cs" />
<Compile Include="Logging\AsyncRollingFileAppenderTest.cs" />
<Compile Include="Logging\DebugAppender.cs" />
<Compile Include="Logging\ParallelForwarderTest.cs" />
@@ -730,7 +731,6 @@
xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" /Y /F /E /D</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="Examine" version="0.1.66.0" targetFramework="net45" />
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="Examine" version="0.1.68.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
-1
View File
@@ -25,7 +25,6 @@
"jquery-ui": "1.10.3",
"angular-dynamic-locale": "~0.1.27",
"tinymce": "~4.1.10",
"bootstrap-tabdrop": "~1.0.0",
"codemirror": "~5.3.0"
}
}
+3 -6
View File
@@ -418,7 +418,8 @@ module.exports = function (grunt) {
ignorePackages: ['blueimp-canvas-to-blob', 'blueimp-tmpl', 'bootstrap'],
packageSpecific: {
'typeahead.js': {
keepExpandedHierarchy: false
keepExpandedHierarchy: false,
files: ['dist/typeahead.bundle.min.js']
},
'underscore': {
files: ['underscore-min.js', 'underscore-min.map']
@@ -455,11 +456,7 @@ module.exports = function (grunt) {
},
'angular-dynamic-locale': {
files: ['tmhDynamicLocale.min.js', 'tmhDynamicLocale.min.js.map']
},
'bootstrap-tabdrop': {
keepExpandedHierarchy: false,
files: ['build/js/bootstrap-tabdrop.min.js']
},
},
'codemirror': {
files: [
'lib/codemirror.js',
@@ -0,0 +1,62 @@
bootstrap-tabdrop
=================
*****************************************************************
NOTE: THIS IS A CUSTOM FIXED VERSION!!!!!!!!!!!!!!!!!!!!!!
- THE ORIGINAL HAS A MEMORY LEAK, SO WE'VE HAD TO EMBED THIS
INTO THE CORE WITH THE FIX
--- UMBRACO CORE TEAM
*****************************************************************
A dropdown tab tool for @twitter bootstrap forked from Stefan Petre's (of eyecon.ro),
The dropdown tab appears when your tabs do not all fit in the same row.
Original site and examples: http://www.eyecon.ro/bootstrap-tabdrop/
Added functionality: Displays the text of an active tab selected from the dropdown list instead of the text option on the dropdown tab.
## Requirements
* [Bootstrap](http://twitter.github.com/bootstrap/) 2.0.4+
* [jQuery](http://jquery.com/) 1.7.1+
## Example
No additional HTML needed - the script adds it when the dropdown tab is needed.
Using bootstrap-tabdrop.js
Call the tab drop via javascript on .nav-tabs and .nav-pills:
```js
$('.nav-pills, .nav-tabs').tabdrop()
```
### Options
#### text
Type: string
Default: icon
```html
<i class="icon-align-justify"></i>
```
To change the default value, call
```javascript
.tabdrop({text: "your text here"});
```
when initalizing the tabdrop. The displayed value will change when a tab is selected from the dropdown list.
### Methods
```js
.tabdrop(options)
```
Initializes an tab drop.
```js
.tabdrop('layout')
```
Checks if the tabs fit in one single row.
@@ -0,0 +1,132 @@
/* =========================================================
* bootstrap-tabdrop.js
* http://www.eyecon.ro/bootstrap-tabdrop
* =========================================================
* Copyright 2012 Stefan Petre
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
/*****************************************************************
* NOTE: THIS IS A CUSTOM FIXED VERSION!!!!!!!!!!!!!!!!!!!!!!
* - THE ORIGINAL HAS A MEMORY LEAK, SO WE'VE HAD TO EMBED THIS
* INTO THE CORE WITH THE FIX
*
* --- UMBRACO CORE TEAM
*****************************************************************/
!function( $ ) {
var WinReszier = (function(){
var registered = [];
var inited = false;
var timer;
var resize = function(ev) {
clearTimeout(timer);
timer = setTimeout(notify, 100);
};
var notify = function() {
for(var i=0, cnt=registered.length; i<cnt; i++) {
registered[i].apply();
}
};
return {
register: function(fn) {
registered.push(fn);
if (inited === false) {
$(window).bind('resize', resize);
inited = true;
}
},
unregister: function(fn) {
var index = registered.indexOf(fn);
if (index > -1) {
registered.splice(index, 1);
}
}
};
}());
var TabDrop = function(element, options) {
this.element = $(element);
this.dropdown = $('<li class="dropdown hide pull-right tabdrop">' +
'<a class="dropdown-toggle" data-toggle="dropdown" href="#">' +
options.text + ' <b class="caret"></b></a>' +
'<ul class="dropdown-menu"></ul></li>').prependTo(this.element);
if (this.element.parent().is('.tabs-below')) {
this.dropdown.addClass('dropup');
}
this.resizeCallback = $.proxy(this.layout, this);
WinReszier.register(this.resizeCallback);
this.layout();
};
TabDrop.prototype = {
constructor: TabDrop,
layout: function() {
var collection = [];
this.dropdown.removeClass('hide');
this.element
.append(this.dropdown.find('li'))
.find('>li')
.not('.tabdrop')
.each(function(){
if(this.offsetTop > 0) {
collection.push(this);
}
});
if (collection.length > 0) {
collection = $(collection);
this.dropdown
.find('ul')
.empty()
.append(collection);
if (this.dropdown.find('.active').length == 1) {
this.dropdown.addClass('active');
} else {
this.dropdown.removeClass('active');
}
} else {
this.dropdown.addClass('hide');
}
},
destroy: function() {
this.dropdown.html();
WinReszier.unregister(this.resizeCallback);
}
};
$.fn.tabdrop = function ( option ) {
return this.each(function () {
var $this = $(this),
data = $this.data('tabdrop'),
options = typeof option === 'object' && option;
if (!data) {
$this.data('tabdrop', (data = new TabDrop(this, $.extend({},
$.fn.tabdrop.defaults,options))));
}
if (typeof option == 'string') {
data[option]();
}
});
};
$.fn.tabdrop.defaults = {
text: '<i class="icon-align-justify"></i>'
};
$.fn.tabdrop.Constructor = TabDrop;
}(window.jQuery);
@@ -1,32 +1,41 @@
angular.module("umbraco.directives")
.directive('umbAutoResize', function($timeout) {
return {
require: "^?umbTabs",
link: function(scope, element, attr, tabsCtrl) {
var domEl = element[0];
var update = function(force) {
if (force === true) {
element.height(0);
}
return function(scope, element, attr){
var domEl = element[0];
var update = function(force) {
if (domEl.scrollHeight !== domEl.clientHeight) {
element.height(domEl.scrollHeight);
}
};
var blur = function() {
update(true);
};
if(force === true){
element.height(0);
element.bind('keyup keydown keypress change', update);
element.bind('blur', blur);
$timeout(function() {
update(true);
}, 200);
//listen for tab changes
if (tabsCtrl != null) {
tabsCtrl.onTabShown(function(args) {
update();
});
}
if(domEl.scrollHeight !== domEl.clientHeight){
element.height(domEl.scrollHeight);
}
};
element.bind('keyup keydown keypress change', update);
element.bind('blur', function(){ update(true); });
$timeout(function() {
update(true);
}, 200);
//I hate bootstrap tabs
$('a[data-toggle="tab"]').on('shown', update);
scope.$on('$destroy', function() {
$('a[data-toggle="tab"]').unbind("shown", update);
});
};
});
scope.$on('$destroy', function () {
element.unbind('keyup keydown keypress change', update);
element.unbind('blur', blur);
});
}
};
});
@@ -1,5 +1,13 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbHeader
* @restrict E
* @function
* @description
* The header on an editor that contains tabs using bootstrap tabs - THIS IS OBSOLETE, use umbTabHeader instead
**/
angular.module("umbraco.directives")
.directive('umbHeader', function($parse, $timeout){
.directive('umbHeader', function ($parse, $timeout) {
return {
restrict: 'E',
replace: true,
@@ -11,50 +19,13 @@ angular.module("umbraco.directives")
tabs: "="
},
link: function (scope, iElement, iAttrs) {
var maxTabs = 4;
function collectFromDom(activeTab){
var $panes = $('div.tab-content');
angular.forEach($panes.find('.tab-pane'), function (pane, index) {
var $this = angular.element(pane);
var id = $this.attr("rel");
var label = $this.attr("label");
var tab = {id: id, label: label, active: false};
if(!activeTab){
tab.active = true;
activeTab = tab;
}
if ($this.attr("rel") === String(activeTab.id)) {
$this.addClass('active');
}
else {
$this.removeClass('active');
}
if(label){
scope.visibleTabs.push(tab);
}
});
$('.nav-pills, .nav-tabs').tabdrop();
}
scope.showTabs = iAttrs.tabs ? true : false;
scope.visibleTabs = [];
scope.overflownTabs = [];
$timeout(function () {
collectFromDom(undefined);
}, 500);
//when the tabs change, we need to hack the planet a bit and force the first tab content to be active,
//unfortunately twitter bootstrap tabs is not playing perfectly with angular.
scope.$watch("tabs", function (newValue, oldValue) {
//since tabs are loaded async, we need to put a watch on them to determine
// when they are loaded, then we can close the watch
var tabWatch = scope.$watch("tabs", function (newValue, oldValue) {
angular.forEach(newValue, function(val, index){
var tab = {id: val.id, label: val.label};
@@ -64,16 +35,25 @@ angular.module("umbraco.directives")
//don't process if we cannot or have already done so
if (!newValue) {return;}
if (!newValue.length || newValue.length === 0){return;}
var activeTab = _.find(newValue, function (item) {
return item.active;
});
//we need to do a timeout here so that the current sync operation can complete
// and update the UI, then this will fire and the UI elements will be available.
$timeout(function () {
collectFromDom(activeTab);
}, 500);
//use bootstrap tabs API to show the first one
iElement.find(".nav-tabs a:first").tab('show');
//enable the tab drop
iElement.find('.nav-pills, .nav-tabs').tabdrop();
//ensure to destroy tabdrop (unbinds window resize listeners)
scope.$on('$destroy', function () {
iElement.find('.nav-pills, .nav-tabs').tabdrop("destroy");
});
//stop watching now
tabWatch();
}, 200);
});
}
@@ -4,11 +4,11 @@
* @restrict E
**/
angular.module("umbraco.directives")
.directive('umbTab', function(){
return {
.directive('umbTab', function ($parse, $timeout) {
return {
restrict: 'E',
replace: true,
transclude: 'true',
templateUrl: 'views/directives/umb-tab.html'
};
replace: true,
transclude: 'true',
templateUrl: 'views/directives/umb-tab.html'
};
});
@@ -0,0 +1,45 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbTabs
* @restrict A
* @description Used to bind to bootstrap tab events so that sub directives can use this API to listen to tab changes
**/
angular.module("umbraco.directives")
.directive('umbTabs', function () {
return {
restrict: 'A',
controller: function ($scope, $element, $attrs) {
var callbacks = [];
this.onTabShown = function(cb) {
callbacks.push(cb);
};
function tabShown(event) {
var curr = $(event.target); // active tab
var prev = $(event.relatedTarget); // previous tab
for (var c in callbacks) {
callbacks[c].apply(this, [{current: curr, previous: prev}]);
}
}
//NOTE: it MUST be done this way - binding to an ancestor element that exists
// in the DOM to bind to the dynamic elements that will be created.
// It would be nicer to create this event handler as a directive for which child
// directives can attach to.
$element.on('shown', '.nav-tabs a', tabShown);
//ensure to unregister
$scope.$on('$destroy', function () {
$element.off('shown', '.nav-tabs a', tabShown);
for (var c in callbacks) {
delete callbacks[c];
}
callbacks = null;
});
}
};
});
@@ -7,7 +7,7 @@
* Handles how the navigation responds to window resizing and controls how the draggable resize panel works
**/
angular.module("umbraco.directives")
.directive('navResize', function (appState, eventsService) {
.directive('navResize', function (appState, eventsService, windowResizeListener) {
return {
restrict: 'A',
link: function (scope, element, attrs, ctrl) {
@@ -22,22 +22,28 @@ angular.module("umbraco.directives")
function enableResize() {
//only enable when the size is correct and it's not already enabled
if (!resizeEnabled && appState.getGlobalState("isTablet") === false) {
element.find(".navigation-inner-container").resizable(
element.resizable(
{
containment: $("#mainwrapper"),
autoHide: true,
handles: 'e',
handles: "e",
alsoResize: ".navigation-inner-container",
resize: function(e, ui) {
var wrapper = $("#mainwrapper");
var contentPanel = $("#leftcolumn").next();
var contentPanel = $("#contentwrapper");
var apps = $("#applications");
var navOffeset = ui.element.next();
var bottomBar = contentPanel.find(".umb-bottom-bar");
var navOffeset = $("#navOffset");
var leftPanelWidth = ui.element.width() + apps.width();
contentPanel.css({ left: leftPanelWidth });
bottomBar.css({ left: leftPanelWidth });
navOffeset.css({ "margin-left": ui.element.outerWidth() });
},
stop: function(e, ui) {
stop: function (e, ui) {
}
});
@@ -47,14 +53,14 @@ angular.module("umbraco.directives")
function resetResize() {
if (resizeEnabled) {
var navInnerContainer = element.find(".navigation-inner-container");
//kill the resize
navInnerContainer.resizable("destroy");
element.resizable("destroy");
element.css("width", "");
var navInnerContainer = element.find(".navigation-inner-container");
navInnerContainer.css("width", "");
$("#leftcolumn").next().css("left", "");
navInnerContainer.next().css("margin-left", "");
$("#contentwrapper").css("left", "");
$("#navOffset").css("margin-left", "");
resizeEnabled = false;
}
@@ -74,16 +80,17 @@ angular.module("umbraco.directives")
}
}));
$(window).bind("resize", function () {
var resizeCallback = function(size) {
//set the global app state
appState.setGlobalState("isTablet", ($(window).width() <= minScreenSize));
appState.setGlobalState("isTablet", (size.width <= minScreenSize));
setTreeMode();
});
};
windowResizeListener.register(resizeCallback);
//ensure to unregister from all events and kill jquery plugins
scope.$on('$destroy', function () {
windowResizeListener.unregister(resizeCallback);
for (var e in evts) {
eventsService.unsubscribe(evts[e]);
}
@@ -91,7 +98,6 @@ angular.module("umbraco.directives")
navInnerContainer.resizable("destroy");
});
//init
//set the global app state
appState.setGlobalState("isTablet", ($(window).width() <= minScreenSize));
@@ -86,7 +86,7 @@ angular.module("umbraco.directives")
icon.addClass(node.cssClass);
icon.attr("title", node.routePath);
element.find("a:first").html(node.name);
element.find("a:first").text(node.name);
if (!node.menuUrl) {
element.find("a.umb-options").remove();
@@ -5,21 +5,31 @@ angular.module("umbraco.directives")
link: function (scope, element, attrs, ctrl) {
var active = false;
var fn = $parse(attrs.delayedMouseleave);
element.on("mouseleave", function(event) {
var callback = function() {
fn(scope, {$event:event});
function mouseLeave(event) {
var callback = function () {
fn(scope, { $event: event });
};
active = false;
$timeout(function(){
if(active === false){
$timeout(function () {
if (active === false) {
scope.$apply(callback);
}
}, 650);
});
}
element.on("mouseenter", function(event, args){
function mouseEnter(event, args){
active = true;
}
element.on("mouseleave", mouseLeave);
element.on("mouseenter", mouseEnter);
//unbind!!
scope.$on('$destroy', function () {
element.off("mouseleave", mouseLeave);
element.off("mouseenter", mouseEnter);
});
}
};
@@ -1,49 +1,80 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbPanel
* @restrict E
* @description This is used for the editor buttons to ensure they are displayed correctly if the horizontal overflow of the editor
* exceeds the height of the window
**/
angular.module("umbraco.directives.html")
.directive('detectFold', function($timeout, $log){
return {
.directive('detectFold', function ($timeout, $log, windowResizeListener) {
return {
require: "^?umbTabs",
restrict: 'A',
link: function (scope, el, attrs) {
var state = false,
parent = $(".umb-panel-body"),
winHeight = $(window).height(),
calculate = _.throttle(function(){
if(el && el.is(":visible") && !el.hasClass("umb-bottom-bar")){
//var parent = el.parent();
var hasOverflow = parent.innerHeight() < parent[0].scrollHeight;
//var belowFold = (el.offset().top + el.height()) > winHeight;
if(hasOverflow){
el.addClass("umb-bottom-bar");
}
}
return state;
}, 1000);
link: function (scope, el, attrs, tabsCtrl) {
scope.$watch(calculate, function(newVal, oldVal) {
if(newVal !== oldVal){
if(newVal){
el.addClass("umb-bottom-bar");
}else{
el.removeClass("umb-bottom-bar");
}
}
});
var firstRun = false;
var parent = $(".umb-panel-body");
var winHeight = $(window).height();
var calculate = function () {
if (el && el.is(":visible") && !el.hasClass("umb-bottom-bar")) {
$(window).bind("resize", function () {
winHeight = $(window).height();
el.removeClass("umb-bottom-bar");
state = false;
calculate();
});
//now that the element is visible, set the flag in a couple of seconds,
// this will ensure that loading time of a current tab get's completed and that
// we eventually stop watching to save on CPU time
$timeout(function() {
firstRun = true;
}, 4000);
$('a[data-toggle="tab"]').on('shown', function (e) {
calculate();
});
//var parent = el.parent();
var hasOverflow = parent.innerHeight() < parent[0].scrollHeight;
//var belowFold = (el.offset().top + el.height()) > winHeight;
if (hasOverflow) {
el.addClass("umb-bottom-bar");
//I wish we didn't have to put this logic here but unfortunately we
// do. This needs to calculate the left offest to place the bottom bar
// depending on if the left column splitter has been moved by the user
// (based on the nav-resize directive)
var wrapper = $("#mainwrapper");
var contentPanel = $("#leftcolumn").next();
var contentPanelLeftPx = contentPanel.css("left");
el.css({ left: contentPanelLeftPx });
}
}
return firstRun;
};
var resizeCallback = function(size) {
winHeight = size.height;
el.removeClass("umb-bottom-bar");
calculate();
};
windowResizeListener.register(resizeCallback);
//Only execute the watcher if this tab is the active (first) tab on load, otherwise there's no reason to execute
// the watcher since it will be recalculated when the tab changes!
if (el.closest(".umb-tab-pane").index() === 0) {
//run a watcher to ensure that the calculation occurs until it's firstRun but ensure
// the calculations are throttled to save a bit of CPU
var listener = scope.$watch(_.throttle(calculate, 1000), function (newVal, oldVal) {
if (newVal !== oldVal) {
listener();
}
});
}
//listen for tab changes
if (tabsCtrl != null) {
tabsCtrl.onTabShown(function (args) {
calculate();
});
}
//ensure to unregister
scope.$on('$destroy', function() {
windowResizeListener.unregister(resizeCallback);
});
}
};
});
@@ -242,18 +242,19 @@ angular.module('umbraco.services')
_.each(assets, function (asset) {
LazyLoad.js(appendRnd(asset.path), function () {
asset.state = "loaded";
if (!scope) {
asset.state = "loaded";
asset.deferred.resolve(true);
} else {
asset.state = "loaded";
}
else {
angularHelper.safeApply(scope, function () {
asset.deferred.resolve(true);
});
}
});
});
} else {
}
else {
//return and resolve
var deferred = $q.defer();
promise = deferred.promise;
@@ -55,6 +55,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
err: err,
rebindCallback: self.reBindChangedProperties(args.content, err.data)
});
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
args.scope.busy = false;
deferred.reject(err);
});
@@ -466,13 +472,13 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
* @description
* Changes the location to be editing the newly created content after create was successful.
* We need to decide if we need to redirect to edito mode or if we will remain in create mode.
* We will only need to maintain create mode if we have not fulfilled the basic requirements for creating an entity which is at least having a name.
* We will only need to maintain create mode if we have not fulfilled the basic requirements for creating an entity which is at least having a name and ID
*/
redirectToCreatedContent: function (id, modelState) {
//only continue if we are currently in create mode and if there is no 'Name' modelstate errors
// since we need at least a name to create content.
if ($routeParams.create && (!modelState || !modelState["Name"])) {
if ($routeParams.create && (id > 0 && (!modelState || !modelState["Name"]))) {
//need to change the location to not be in 'create' mode. Currently the route will be something like:
// /belle/#/content/edit/1234?doctype=newsArticle&create=true
@@ -248,7 +248,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
//This is a bit of a hack to check if the error is due to a file being uploaded that is too large,
// we have to just check for the existence of a string value but currently that is the best way to
// do this since it's very hacky/difficult to catch this on the server
if (data.indexOf("Maximum request length exceeded") >= 0) {
if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) {
notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed");
}
else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
@@ -0,0 +1,67 @@
/**
* @ngdoc service
* @name umbraco.services.windowResizeListener
* @function
*
* @description
* A single window resize listener... we don't want to have more than one in theory to ensure that
* there aren't too many events raised. This will debounce the event with 100 ms intervals and force
* a $rootScope.$apply when changed and notify all listeners
*
*/
function windowResizeListener($rootScope) {
var WinReszier = (function () {
var registered = [];
var inited = false;
var resize = _.debounce(function(ev) {
notify();
}, 100);
var notify = function () {
var h = $(window).height();
var w = $(window).width();
//execute all registrations inside of a digest
$rootScope.$apply(function() {
for (var i = 0, cnt = registered.length; i < cnt; i++) {
registered[i].apply($(window), [{ width: w, height: h }]);
}
});
};
return {
register: function (fn) {
registered.push(fn);
if (inited === false) {
$(window).bind('resize', resize);
inited = true;
}
},
unregister: function (fn) {
var index = registered.indexOf(fn);
if (index > -1) {
registered.splice(index, 1);
}
}
};
}());
return {
/**
* Register a callback for resizing
* @param {Function} cb
*/
register: function (cb) {
WinReszier.register(cb);
},
/**
* Removes a registered callback
* @param {Function} cb
*/
unregister: function(cb) {
WinReszier.unregister(cb);
}
};
}
angular.module('umbraco.services').factory('windowResizeListener', windowResizeListener);
@@ -1,12 +1,3 @@
/*!
* Belle v1.0.0
*
* Copyright 2013 Umbraco
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
// Core variables and mixins
@import "fonts.less"; // Loading fonts
@import "variables.less"; // Modify this for custom colors, font-sizes, etc
@@ -5,7 +5,7 @@
overflow-y:hidden!important;
}
IFRAME {overflow:hidden;}
.usky-grid IFRAME {overflow:hidden;}
// Sortabel
@@ -279,12 +279,12 @@ IFRAME {overflow:hidden;}
.usky-grid .usky-control-inner.selectedControl , .usky-grid .usky-row-inner.selectedRow{
border: 1px dashed @grayLight;
> ins.item-label {
display: block;
z-index:100000;
}
}
}
@@ -322,12 +322,12 @@ IFRAME {overflow:hidden;}
padding-bottom: 30px;
position: relative;
background-color: white;
border: 4px dashed @grayLight;
border: 4px dashed @grayLighter;
text-align: center;
text-align: -moz-center;
}
.usky-grid .usky-editor-placeholder i{
color: @grayLight;
color: @grayLighter;
font-size: 85px;
line-height: 85px;
display: block;
@@ -380,7 +380,7 @@ IFRAME {overflow:hidden;}
border-radius: 200px;
background: rgba(255,255,255, 1);
border:1px solid rgb(182, 182, 182);
margin: 2px;
margin: 2px;
}
.usky-grid .iconBox span.prompt {
@@ -464,7 +464,7 @@ IFRAME {overflow:hidden;}
// TINYMCE EDITOR
// -------------------------
.usky-grid .mce-panel {
border:none !important;
border: none !important;
clear:both;
}
@@ -499,6 +499,9 @@ IFRAME {overflow:hidden;}
background-color: #F7F7F7 !important;
}
.usky-cell-rte{
border: 1px solid @grayLighter;
}
// MEDIA EDITOR
// -------------------------
@@ -1,13 +1,13 @@
<div class="umb-panel" ng-controller="Umbraco.Dialogs.HelpController">
<div class="umb-panel-header">
<h1 class="headline">Help</h1>
<h1 class="headline"><localize key="sections_help">Help</localize></h1>
<small class="umb-version">Umbraco version {{version}}</small>
</div>
<div class="umb-panel-body umb-scrollable">
<div class="tab-content umb-control-group">
<div class="umb-pane">
<h5>Help topics for: {{section}}</h5>
<h5><localize key="help_helpTopicsFor">Help topics for</localize>: {{section}}</h5>
<ul class="unstyled list-icons" ng-show="topics">
<li ng-repeat="topic in topics">
<i class="icon icon-help-alt"></i>
@@ -23,7 +23,7 @@
<li>
<i class="icon icon-favorite"></i>
<a target="_blank" href="http://our.umbraco.org?utm_source=core&utm_medium=help&utm_content=link&utm_campaign=our">
go to our.umbraco.org
<localize key="help_goTo">go to</localize> our.umbraco.org
</a>
<small class="umb-detail">The friendliest community</small>
</li>
@@ -31,7 +31,7 @@
</div>
<div class="umb-pane">
<h5>Video chapters for: {{section}}</h5>
<h5><localize key="help_videoChaptersFor">Video chapters for</localize>: {{section}}</h5>
<ul class="thumbnails" ng-show="videos">
<li class="span2" ng-repeat="video in videos">
@@ -47,9 +47,9 @@
<li>
<i class="icon icon-tv-old"></i>
<a target="_blank" href="http://umbraco.tv?utm_source=core&utm_medium=help&utm_content=link&utm_campaign=tv">
go to umbraco.tv
<localize key="help_goTo">go to</localize> umbraco.tv
</a>
<small class="umb-detail">The best umbraco video tutorials</small>
<small class="umb-detail"><localize key="help_theBestUmbracoVideoTutorials">The best Umbraco video tutorials</localize></small>
</li>
</ul>
</div>
@@ -36,7 +36,7 @@
<form method="POST" name="loginForm" ng-submit="loginSubmit(login, password)">
<div class="control-group" ng-class="{error: loginForm.username.$invalid}">
<input type="text" autofocus ng-model="login" name="username" class="input-xlarge" localize="placeholder" placeholder="@placeholders_username" autocomplete="off" />
<input type="text" autofocus ng-model="login" name="username" class="input-xlarge" localize="placeholder" placeholder="@placeholders_username" />
</div>
<div class="control-group" ng-class="{error: loginForm.password.$invalid}">
@@ -39,7 +39,7 @@
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<button class="btn" ng-click="nav.hideDialog(true)">
<localize key="buttons_somethingElse">Do something else</localize>
</button>
<button class="btn" ng-click="nav.hideDialog(true)">
<localize key="buttons_somethingElse">Do something else</localize>
</button>
</div>
@@ -2,7 +2,7 @@
<div class="umb-dialog-body" auto-scale="90">
<p class="umb-abstract">
Are you sure you want to delete <strong>{{currentNode.name}}</strong> ?
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
</p>
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
@@ -4,7 +4,7 @@
ng-submit="save()"
val-form-manager>
<umb-panel ng-class="{'editor-breadcrumb': ancestors && ancestors.length > 0}">
<umb-panel umb-tabs ng-class="{'editor-breadcrumb': ancestors && ancestors.length > 0}">
<umb-header tabs="content.tabs">
<div class="span7">
@@ -20,7 +20,7 @@
<umb-options-menu ng-show="currentNode"
current-node="currentNode"
current-section="{{currentSection}}">
current-section="{{currentSection}}">
</umb-options-menu>
</div>
@@ -5,7 +5,7 @@
</div>
</umb-header>
<umb-tab-view>
<umb-tab id="tabRecycleBin" rel="RecycleBin">
<umb-tab id="tabRecycleBin" rel="RecycleBin" style="display: block;">
<umb-pane>
<div ng-include="listViewPath"></div>
</umb-pane>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 22 KiB

@@ -10,7 +10,7 @@ function examineMgmtController($scope, umbRequestHelper, $log, $http, $q, $timeo
'Failed to check index processing')
.then(function(data) {
if (data) {
if (data !== null && data !== "null") {
//copy all resulting properties
for (var k in data) {
@@ -67,7 +67,9 @@ function examineMgmtController($scope, umbRequestHelper, $log, $http, $q, $timeo
"Depending on how much content there is in your site this could take a while. " +
"It is not recommended to rebuild an index during times of high website traffic " +
"or when editors are editing content.")) {
indexer.isProcessing = true;
indexer.processingAttempts = 0;
umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "PostRebuildIndex", { indexerName: indexer.name })),
@@ -2,7 +2,7 @@
<div class="umb-dialog-body">
<p class="umb-abstract">
Are you sure you want to delete <strong>{{currentNode.name}}</strong> ?
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
</p>
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
@@ -5,7 +5,7 @@
<ul ng-show="showTabs" class="nav nav-tabs umb-nav-tabs span12">
<li ng-class="{active: $first, 'tab-error': tabHasError}" ng-repeat="tab in visibleTabs" val-tab>
<li ng-class="{'tab-error': tabHasError}" ng-repeat="tab in visibleTabs" val-tab>
<a href="#tab{{tab.id}}" data-toggle="tab">{{ tab.label }}</a>
</li>
@@ -72,7 +72,7 @@
</div>
</div>
<div class="offset6" style="z-index: 10">
<div class="offset6" id="navOffset" style="z-index: 10">
<!-- The context menu -->
<div id='contextMenu' class="umb-modalcolumn fill shadow" ng-swipe-left="nav.hideMenu()" ng-show="showContextMenu" ng-animate="'slide'">
@@ -97,4 +97,5 @@
</div>
</div>
</div>
</div>
@@ -1,5 +1,5 @@
<div class="umb-panel-body umb-scrollable row-fluid">
<div class="tab-content form-horizontal" ng-transclude>
<div class="tab-content form-horizontal" ng-transclude>
</div>
</div>
@@ -2,7 +2,7 @@
<div class="umb-dialog-body" auto-scale="90">
<p class="umb-abstract">
Are you sure you want to delete <strong>{{currentNode.name}}</strong> ?
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
</p>
<umb-confirm on-confirm="performDelete" on-cancel="cancel"></umb-confirm>
@@ -3,7 +3,7 @@
ng-show="loaded"
ng-submit="save()"
val-form-manager>
<umb-panel ng-class="{'editor-breadcrumb': ancestors && ancestors.length > 0}">
<umb-panel umb-tabs ng-class="{'editor-breadcrumb': ancestors && ancestors.length > 0}">
<umb-header tabs="content.tabs">
<div class="span7">
@@ -108,6 +108,13 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, enti
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
});
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
editorState.set($scope.content);
$scope.busy = false;
});
@@ -5,7 +5,7 @@
</div>
</umb-header>
<umb-tab-view>
<umb-tab id="tabRecycleBin" rel="RecycleBin">
<umb-tab id="tabRecycleBin" rel="RecycleBin" style="display: block;">
<umb-pane>
<div ng-include="listViewPath"></div>
</umb-pane>
@@ -1,7 +1,7 @@
<div class="umb-dialog-body with-footer" ng-controller="Umbraco.Editors.Member.CreateController">
<div class="umb-pane">
<h5>Create a new member</h5>
<h5><localize key="member_createNewMember">Create a new member</localize></h5>
<ul class="umb-actions umb-actions-child">
<li ng-repeat="docType in allowedTypes">
@@ -20,6 +20,8 @@
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" >
<button type="button" class="btn" ng-click="nav.hideDialog()">Do something else</button>
<button type="button" class="btn" ng-click="nav.hideDialog()">
<localize key="buttons_somethingElse">Do something else</localize>
</button>
</div>
@@ -2,7 +2,7 @@
<div class="umb-dialog-body" auto-scale="90">
<p class="umb-abstract">
Are you sure you want to delete <strong>{{currentNode.name}}</strong> ?
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
</p>
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
@@ -3,7 +3,7 @@
ng-show="loaded"
ng-submit="save()"
val-form-manager>
<umb-panel>
<umb-panel umb-tabs>
<umb-header tabs="content.tabs">
<div class="span7" ng-if="content.membershipScenario == 0">
@@ -9,7 +9,7 @@
assetsService.load([
//"lib/spectrum/tinycolor.js",
"lib/spectrum/spectrum.js"
]).then(function () {
], $scope).then(function () {
var elem = $element.find("input");
elem.spectrum({
color: null,
@@ -17,6 +17,10 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
//map the user config
$scope.model.config = angular.extend(config, $scope.model.config);
//ensure the format doesn't get overwritten with an empty string
if ($scope.model.config.format === "" || $scope.model.config.format === undefined || $scope.model.config.format === null) {
$scope.model.config.format = $scope.model.config.pickTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD";
}
$scope.hasDatetimePickerValue = $scope.model.value ? true : false;
$scope.datetimePickerValue = null;
@@ -39,12 +43,7 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
if (e.date && e.date.isValid()) {
$scope.datePickerForm.datepicker.$setValidity("pickerError", true);
$scope.hasDatetimePickerValue = true;
if (!$scope.model.config.format) {
$scope.datetimePickerValue = e.date;
}
else {
$scope.datetimePickerValue = e.date.format($scope.model.config.format);
}
$scope.datetimePickerValue = e.date.format($scope.model.config.format);
}
else {
$scope.hasDatetimePickerValue = false;
@@ -78,8 +77,8 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
$scope.model.config.language = user.locale;
assetsService.load(filesToLoad).then(
function () {
assetsService.load(filesToLoad, $scope).then(
function () {
//The Datepicker js and css files are available and all components are ready to use.
// Get the id of the datepicker button that was clicked
@@ -98,15 +97,10 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
if ($scope.hasDatetimePickerValue) {
//assign value to plugin/picker
element.datetimepicker("setValue", $scope.model.value ? new Date($scope.model.value) : moment());
if (!$scope.model.config.format) {
$scope.datetimePickerValue = moment($scope.model.value);
}
else {
$scope.datetimePickerValue = moment($scope.model.value).format($scope.model.config.format);
}
//assign value to plugin/picker
var dateVal = $scope.model.value ? moment($scope.model.value, $scope.model.config.format) : moment();
element.datetimepicker("setValue", dateVal);
$scope.datetimePickerValue = moment($scope.model.value).format($scope.model.config.format);
}
element.find("input").bind("blur", function() {
@@ -1,6 +1,6 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.GoogleMapsController",
function ($rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) {
function ($element, $rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) {
assetsService.loadJs('http://www.google.com/jsapi')
.then(function () {
@@ -58,8 +58,21 @@ angular.module("umbraco")
});
});
$('a[data-toggle="tab"]').on('shown', function (e) {
var tabShown = function(e) {
google.maps.event.trigger(map, 'resize');
};
//listen for tab changes
if (tabsCtrl != null) {
tabsCtrl.onTabShown(function (args) {
tabShown();
});
}
$element.closest('.umb-panel.tabbable').on('shown', '.nav-tabs a', tabShown);
$scope.$on('$destroy', function () {
$element.closest('.umb-panel.tabbable').off('shown', '.nav-tabs a', tabShown);
});
}
@@ -44,7 +44,7 @@ angular.module("umbraco")
$timeout(function(){
if($scope.control.$initializing){
$scope.setImage();
}else{
}else if($scope.control.value){
$scope.setUrl();
}
}, 200);
@@ -19,8 +19,8 @@ angular.module("umbraco")
$scope.sortableOptions = {
distance: 10,
cursor: "move",
placeholder: 'ui-sortable-placeholder',
handle: '.cell-tools-move',
placeholder: "ui-sortable-placeholder",
handle: ".cell-tools-move",
forcePlaceholderSize: true,
tolerance: "pointer",
zIndex: 999999999999999999,
@@ -33,30 +33,30 @@ angular.module("umbraco")
sort: function (event, ui) {
/* prevent vertical scroll out of the screen */
var max = $(".usky-grid").width() - 150;
if (parseInt(ui.helper.css('left')) > max) {
ui.helper.css({ 'left': max + "px" })
if (parseInt(ui.helper.css("left")) > max) {
ui.helper.css({ "left": max + "px" });
}
if (parseInt(ui.helper.css('left')) < 20) {
ui.helper.css({ 'left': 20 })
if (parseInt(ui.helper.css("left")) < 20) {
ui.helper.css({ "left": 20 });
}
},
start: function (e, ui) {
draggedRteSettings = {};
ui.item.find('.mceNoEditor').each(function () {
ui.item.find(".mceNoEditor").each(function () {
// remove all RTEs in the dragged row and save their settings
var id = $(this).attr('id');
var id = $(this).attr("id");
draggedRteSettings[id] = _.findWhere(tinyMCE.editors, { id: id }).settings;
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.execCommand("mceRemoveEditor", false, id);
});
},
stop: function (e, ui) {
// reset all RTEs affected by the dragging
ui.item.parents(".usky-column").find('.mceNoEditor').each(function () {
var id = $(this).attr('id');
ui.item.parents(".usky-column").find(".mceNoEditor").each(function () {
var id = $(this).attr("id");
draggedRteSettings[id] = draggedRteSettings[id] || _.findWhere(tinyMCE.editors, { id: id }).settings;
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.execCommand("mceRemoveEditor", false, id);
tinyMCE.init(draggedRteSettings[id]);
});
}
@@ -69,7 +69,7 @@ angular.module("umbraco")
distance: 10,
cursor: "move",
placeholder: "ui-sortable-placeholder",
handle: '.cell-tools-move',
handle: ".cell-tools-move",
connectWith: ".usky-cell",
forcePlaceholderSize: true,
tolerance: "pointer",
@@ -82,18 +82,18 @@ angular.module("umbraco")
sort: function (event, ui) {
/* prevent vertical scroll out of the screen */
var position = parseInt(ui.item.parent().offset().left) + parseInt(ui.helper.css('left')) - parseInt($(".usky-grid").offset().left);
var position = parseInt(ui.item.parent().offset().left) + parseInt(ui.helper.css("left")) - parseInt($(".usky-grid").offset().left);
var max = $(".usky-grid").width() - 220;
if (position > max) {
ui.helper.css({ 'left': max - parseInt(ui.item.parent().offset().left) + parseInt($(".usky-grid").offset().left) + "px" })
ui.helper.css({ "left": max - parseInt(ui.item.parent().offset().left) + parseInt($(".usky-grid").offset().left) + "px" });
}
if (position < 0) {
ui.helper.css({ 'left': 0 - parseInt(ui.item.parent().offset().left) + parseInt($(".usky-grid").offset().left) + "px" })
ui.helper.css({ "left": 0 - parseInt(ui.item.parent().offset().left) + parseInt($(".usky-grid").offset().left) + "px" });
}
},
over: function (event, ui) {
allowedEditors = $(event.target).scope().area.allowed;
var allowedEditors = $(event.target).scope().area.allowed;
if ($.inArray(ui.item.scope().control.editor.alias, allowedEditors) < 0 && allowedEditors) {
ui.placeholder.hide();
@@ -112,16 +112,16 @@ angular.module("umbraco")
if (cancelMove) {
ui.item.sortable.cancel();
}
ui.item.parents(".usky-cell").find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr('id'));
ui.item.parents(".usky-cell").find(".mceNoEditor").each(function () {
if ($.inArray($(this).attr("id"), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr("id"));
}
});
}
else {
$(event.target).find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr('id'));
$(event.target).find(".mceNoEditor").each(function () {
if ($.inArray($(this).attr("id"), notIncludedRte) < 0) {
notIncludedRte.splice(0, 0, $(this).attr("id"));
}
});
}
@@ -132,22 +132,22 @@ angular.module("umbraco")
// reset dragged RTE settings in case a RTE isn't dragged
draggedRteSettings = undefined;
ui.item.find('.mceNoEditor').each(function () {
ui.item.find(".mceNoEditor").each(function () {
notIncludedRte = [];
// save the dragged RTE settings
draggedRteSettings = _.findWhere(tinyMCE.editors, { id: $(this).attr('id') }).settings;
draggedRteSettings = _.findWhere(tinyMCE.editors, { id: $(this).attr("id") }).settings;
// remove the dragged RTE
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
tinyMCE.execCommand("mceRemoveEditor", false, $(this).attr("id"));
});
},
stop: function (e, ui) {
ui.item.parents(".usky-cell").find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
ui.item.parents(".usky-cell").find(".mceNoEditor").each(function () {
if ($.inArray($(this).attr("id"), notIncludedRte) < 0) {
// add all dragged's neighbouring RTEs in the new cell
notIncludedRte.splice(0, 0, $(this).attr('id'));
notIncludedRte.splice(0, 0, $(this).attr("id"));
}
});
$timeout(function () {
@@ -158,9 +158,9 @@ angular.module("umbraco")
_.forEach(notIncludedRte, function (id) {
// reset all the other RTEs
if (draggedRteSettings === undefined || id != draggedRteSettings.id) {
if (draggedRteSettings === undefined || id !== draggedRteSettings.id) {
var rteSettings = _.findWhere(tinyMCE.editors, { id: id }).settings;
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.execCommand("mceRemoveEditor", false, id);
tinyMCE.init(rteSettings);
}
});
@@ -188,7 +188,6 @@ angular.module("umbraco")
//todo calculate position...
var offset = $(event.target).offset();
var height = $(window).height();
var width = $(window).width();
if ((height - offset.top) < 250) {
$scope.overlayMenu.style.bottom = 0;
@@ -260,11 +259,11 @@ angular.module("umbraco")
});
}
else {
return layouts;
}
};
}
$scope.addRow = function (section, layout) {
@@ -285,7 +284,8 @@ angular.module("umbraco")
section.rows.splice($index, 1);
$scope.currentRow = null;
$scope.openRTEToolbarId = null;
$scope.initContent();
//$scope.initContent();
}
};
@@ -372,9 +372,6 @@ angular.module("umbraco")
$scope.currentInfohighlightControl = null;
};
$scope.setUniqueId = function (cell, index) {
return guid();
};
var guid = (function () {
function s4() {
@@ -383,18 +380,23 @@ angular.module("umbraco")
.substring(1);
}
return function () {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
return s4() + s4() + "-" + s4() + "-" + s4() + "-" +
s4() + "-" + s4() + s4() + s4();
};
})();
$scope.addControl = function (editor, cell, index) {
$scope.setUniqueId = function (cell, index) {
return guid();
};
$scope.addControl = function (editor, cell, index, initialize) {
$scope.closeItemOverlay();
initialize = (initialize !== false);
var newControl = {
value: null,
editor: editor,
$initializing: true
$initializing: initialize
};
if (index === undefined) {
@@ -430,11 +432,11 @@ angular.module("umbraco")
scopedObject.deletePrompt = false;
e.preventDefault();
e.stopPropagation();
}
};
$scope.showPrompt = function (scopedObject) {
scopedObject.deletePrompt = true;
}
};
// *********************************************
@@ -453,11 +455,12 @@ angular.module("umbraco")
var clear = true;
//settings indicator shortcut
if ($scope.model.config.items.config || $scope.model.config.items.styles) {
if ( ($scope.model.config.items.config && $scope.model.config.items.config.length > 0) || ($scope.model.config.items.styles && $scope.model.config.items.styles.length > 0)) {
$scope.hasSettings = true;
}
//ensure the grid has a column value set, if nothing is found, set it to 12
//ensure the grid has a column value set,
//if nothing is found, set it to 12
if ($scope.model.config.items.columns && angular.isString($scope.model.config.items.columns)) {
$scope.model.config.items.columns = parseInt($scope.model.config.items.columns);
} else {
@@ -469,7 +472,7 @@ angular.module("umbraco")
if ($scope.model.value.name && angular.isArray($scope.model.config.items.templates)) {
//This will occur if it is an existing value, in which case
// we need to determine which layout was applied by looking up
// we need to determine which layout was applied by looking up
// the name
// TODO: We need to change this to an immutable ID!!
@@ -479,14 +482,14 @@ angular.module("umbraco")
if (found && angular.isArray(found.sections) && found.sections.length === $scope.model.value.sections.length) {
//Cool, we've found the template associated with our current value with matching sections counts, now we need to
//Cool, we've found the template associated with our current value with matching sections counts, now we need to
// merge this template data on to our current value (as if it was new) so that we can preserve what is and isn't
// allowed for this template based on the current config.
_.each(found.sections, function (templateSection, index) {
angular.extend($scope.model.value.sections[index], angular.copy(templateSection));
});
}
}
@@ -505,6 +508,7 @@ angular.module("umbraco")
});
} else if ($scope.model.config.items.templates && $scope.model.config.items.templates.length === 1) {
$scope.addTemplate($scope.model.config.items.templates[0]);
clear = false;
}
if (clear) {
@@ -517,8 +521,11 @@ angular.module("umbraco")
section.$allowedLayouts = getAllowedLayouts(section);
if (!section.rows) {
if (!section.rows || section.rows.length === 0) {
section.rows = [];
if(section.$allowedLayouts.length === 1){
$scope.addRow(section, section.$allowedLayouts[0]);
}
} else {
_.forEach(section.rows, function (row, index) {
if (!row.$initialized) {
@@ -565,22 +572,6 @@ angular.module("umbraco")
area.styles = currentArea.styles;
}
//copy over existing controls into the new areas
if (row.areas.length > areaIndex && row.areas[areaIndex].controls) {
area.controls = currentArea.controls;
_.forEach(area.controls, function (control, controlIndex) {
$scope.initControl(control, controlIndex);
});
} else {
area.controls = [];
}
//set width
area.$percentage = $scope.percentage(area.grid);
area.$uniqueId = $scope.setUniqueId();
//set editor permissions
if (!area.allowed || area.allowAll === true) {
area.$allowedEditors = $scope.availableEditors;
@@ -594,6 +585,29 @@ angular.module("umbraco")
area.$allowsRTE = true;
}
}
//copy over existing controls into the new areas
if (row.areas.length > areaIndex && row.areas[areaIndex].controls) {
area.controls = currentArea.controls;
_.forEach(area.controls, function (control, controlIndex) {
$scope.initControl(control, controlIndex);
});
} else {
//if empty
area.controls = [];
//if only one allowed editor
if(area.$allowedEditors.length === 1){
$scope.addControl(area.$allowedEditors[0], area, 0, false);
}
}
//set width
area.$percentage = $scope.percentage(area.grid);
area.$uniqueId = $scope.setUniqueId();
} else {
original.areas.splice(areaIndex, 1);
}
@@ -623,7 +637,7 @@ angular.module("umbraco")
control.$uniqueId = $scope.setUniqueId();
//error handling in case of missing editor..
//should only happen if stripped earlier
//should only happen if stripped earlier
if (!control.editor) {
control.$editorPath = "views/propertyeditors/grid/editors/error.html";
}
@@ -664,13 +678,13 @@ angular.module("umbraco")
});
//Clean the grid value before submitting to the server, we don't need
//Clean the grid value before submitting to the server, we don't need
// all of that grid configuration in the value to be stored!! All of that
// needs to be merged in at runtime to ensure that the real config values are used
// if they are ever updated.
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function () {
if ($scope.model.value && $scope.model.value.sections) {
_.each($scope.model.value.sections, function(section) {
if (section.rows) {
@@ -692,7 +706,7 @@ angular.module("umbraco")
var alias = control.editor.alias;
control.editor = {
alias: alias
}
};
}
});
}
@@ -705,7 +719,7 @@ angular.module("umbraco")
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
$scope.$on("$destroy", function () {
unsubscribe();
});
+8 -9
View File
@@ -107,13 +107,13 @@
<Project>{07fbc26b-2927-4a22-8d96-d644c667fecc}</Project>
<Name>UmbracoExamine</Name>
</ProjectReference>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.8.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.8.4\lib\net45\ClientDependency.Core.dll</HintPath>
@@ -127,8 +127,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.66.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.66.0\lib\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.68.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.68.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
@@ -2456,5 +2456,4 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
</Project>

Some files were not shown because too many files have changed in this diff Show More