Compare commits

..

36 Commits

Author SHA1 Message Date
Sebastiaan Janssen 88d61a4d37 Merge branch 'dev-v7.6' into master-v76 2017-10-23 14:15:42 +02:00
Sebastiaan Janssen a36184a261 Bump version to 7.6.11 2017-10-23 14:14:59 +02:00
Sebastiaan Janssen 75f4535157 Merge branch 'dev-v7.6' into master-v76 2017-10-23 14:11:26 +02:00
Claus 9c50e1c48d fixing bug in U4-10524 Show warning in UI for the media/content picker that is referencing a trashed or deleted item 2017-10-17 23:52:34 +02:00
Sebastiaan Janssen 78bf75615f Merge branch 'dev-v7.6' into master-v76 2017-10-17 11:04:27 +02:00
Sebastiaan Janssen 9411a22a0d Don't forget to call the ConfigureUmbracoAuthentication method 2017-10-17 11:04:01 +02:00
Sebastiaan Janssen 51649879cd Merge branch 'dev-v7.6' into master-v76 2017-10-17 11:00:28 +02:00
Sebastiaan Janssen 461ce64feb Bump version to 7.6.10 2017-10-17 10:57:18 +02:00
Sebastiaan Janssen ab050eb7ac Merge branch 'dev-v7.6' into master-v76 2017-10-17 10:55:56 +02:00
Sebastiaan Janssen c5a55b17e6 Manually applying U4-10369: Split out ConfigureUmbracoAuthentication method 2017-10-17 10:08:37 +02:00
Sebastiaan Janssen fd577afe2c Html encode nodenames to prevent XSS attacks. Fixes U4-10497 XSS Vulnerability in page name.
(cherry picked from commit fe2b86b681)
2017-10-16 20:32:56 +02:00
Sebastiaan Janssen f46ef0b006 U4-10506 Importing a specially crafted document type file can cause XXE attack
(cherry picked from commit 5dde2efe0d)
2017-10-16 20:32:04 +02:00
Sebastiaan Janssen dc937ec942 Fix the "Add media" box no longer being square 2017-10-16 16:13:47 +02:00
Shannon cefd9e7323 Fixes PostAddFolder
(cherry picked from commit c5d874464a)

# Conflicts:
#	src/Umbraco.Web/Editors/MediaController.cs
2017-10-16 15:53:54 +02:00
Mads Rasmussen 315690e758 fixes breadcrumbs and search when start node is set
(cherry picked from commit 1ec07aa205)
2017-10-16 15:14:24 +02:00
Mads Rasmussen fb8c519f71 fixes: U4-10521 Creating new folders from the media picker no longer works
(cherry picked from commit 1cc3b39601)

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html
2017-10-16 15:13:56 +02:00
Warren Buckley 5df4d3509d Fix in PowerShell build - The 7Zip tool download was giving two paths & thus break the build script
(cherry picked from commit a2e6da2491)
2017-10-16 14:22:09 +02:00
Claus 4bd263e7bc U4-10524 Show warning in UI for the media/content picker that is referencing a trashed or deleted item
U4-10533 Show warning in UI for the link picker that is referencing a trashed or deleted item
cherrypicked from dev-v7.
2017-10-16 13:52:17 +02:00
Shannon 916bc6badb U4-10539 - reverts merge issue that reverted the fix for U4-9262
(cherry picked from commit 2a0cc71d06)
2017-10-16 08:38:17 +02:00
Sebastiaan Janssen 2461924a89 Merge branch 'master-v76' of https://github.com/umbraco/Umbraco-CMS into master-v76 2017-10-02 13:53:41 +02:00
Sebastiaan Janssen 581f15b172 Manually applying change from U4-10478 7.7.1 HtmlStringUtilities Truncate throws an IndexOutOfRange when input word is shorter than "…" and crash the entire site to 7.6.9 too. 2017-10-01 12:05:40 +02:00
Shannon 33d7598d3c Adding key fallback to list view select functions to fix issue when selecting multiple items with an ID of int.MaxValue 2017-09-29 13:16:53 +10:00
Sebastiaan Janssen 476773fce5 Merge pull request #2224 from umbraco/temp-U4-5222
U4-5222 Rollback Feature fails to update the UI to show the rolled ba…
2017-09-28 20:00:13 +02:00
Sebastiaan Janssen 953355cddd Merge pull request #2222 from umbraco/temp-U4-10364-2
U4-10364 SQL error occurs when we attempt to sort media items by "Cre…
2017-09-28 19:39:19 +02:00
Shannon d2d43255aa U4-5222 Rollback Feature fails to update the UI to show the rolled back content - requires refresh 2017-09-28 02:38:53 +10:00
Shannon b39e218d51 U4-10364 SQL error occurs when we attempt to sort media items by "Created by" column 2017-09-27 23:04:53 +10:00
Sebastiaan Janssen 4b581a2182 Merge pull request #2217 from umbraco/temp-U4-10470
U4-10470 Missing transform for the scripts tree when upgrading
2017-09-27 10:06:08 +02:00
Claus 581eac5369 U4-10470 Missing transform for the scripts tree when upgrading 2017-09-27 10:04:07 +02:00
Sebastiaan Janssen 33cf983cae Bump version 2017-09-25 11:19:36 +02:00
Shannon 3ce6eb09aa Ensures HealthCheckController is authorized to user with developer access
(cherry picked from commit 7c4eb71f07)
2017-09-25 10:48:15 +02:00
Stephan 963015cf4a Fix LocalDb detection on 32/64 bits systems
(cherry picked from commit a239e92bc0)
2017-09-25 10:47:38 +02:00
Sebastiaan Janssen cc35af4eab Merge pull request #2209 from umbraco/temp-deploy-401
deploy-401 - fix id reservations
2017-09-25 10:46:05 +02:00
Stephan 349d89e4d7 deploy-401 - fix id reservations 2017-09-22 13:08:05 +02:00
Sebastiaan Janssen 1b3fc9fb21 Oops! Add -docs for all the log file pipes 2017-09-19 18:37:00 +02:00
Sebastiaan Janssen 2e98651d62 Create the out and tmp folders correctly 2017-09-19 18:16:19 +02:00
Sebastiaan Janssen 704e981284 Always do the node/bower/gulp build to get docs, start with node build first 2017-09-19 18:15:31 +02:00
43 changed files with 628 additions and 344 deletions
@@ -7,45 +7,39 @@ function Build-UmbracoDocs
$src = "$($uenv.SolutionRoot)\src"
$out = "$($uenv.SolutionRoot)\build.out"
$tmp = "$($uenv.SolutionRoot)\build.tmp"
$buildTemp = "$PSScriptRoot\temp"
$cache = 2
Prepare-Build -keep $uenv
################ Do the UI docs
# get a temp clean node env (will restore)
Sandbox-Node $uenv
Write-Host "Executing gulp docs"
push-location "$($uenv.SolutionRoot)\src\Umbraco.Web.UI.Client"
write "node version is:" > $tmp\belle-docs.log
&node -v >> $tmp\belle-docs.log 2>&1
write "npm version is:" >> $tmp\belle-docs.log 2>&1
&npm -v >> $tmp\belle-docs.log 2>&1
write "executing npm install" >> $tmp\belle-docs.log 2>&1
&npm install >> $tmp\belle-docs.log 2>&1
write "executing bower install" >> $tmp\belle-docs.log 2>&1
&npm install -g bower >> $tmp\belle-docs.log 2>&1
write "installing gulp" >> $tmp\belle-docs.log 2>&1
&npm install -g gulp >> $tmp\belle-docs.log 2>&1
write "installing gulp-cli" >> $tmp\belle-docs.log 2>&1
&npm install -g gulp-cli --quiet >> $tmp\belle-docs.log 2>&1
write "building docs using gulp" >> $tmp\belle-docs.log 2>&1
&gulp docs >> $tmp\belle-docs.log 2>&1
pop-location
# No need to build belle again if it exists
$belleAppJs = "$src\Umbraco.Web.UI\Umbraco\js\app.js"
if(-not (Test-Path $belleAppJs))
{
# get a temp clean node env (will restore)
Sandbox-Node $uenv
push-location "$($uenv.SolutionRoot)\src\Umbraco.Web.UI.Client"
write "node version is:" > $tmp\belle.log
&node -v >> $tmp\belle.log 2>&1
write "npm version is:" >> $tmp\belle.log 2>&1
&npm -v >> $tmp\belle.log 2>&1
write "cleaning npm cache" >> $tmp\belle.log 2>&1
&npm cache clean >> $tmp\belle.log 2>&1
write "installing bower" >> $tmp\belle.log 2>&1
&npm install -g bower >> $tmp\belle.log 2>&1
write "installing gulp" >> $tmp\belle.log 2>&1
&npm install -g gulp >> $tmp\belle.log 2>&1
write "installing gulp-cli" >> $tmp\belle.log 2>&1
&npm install -g gulp-cli --quiet >> $tmp\belle.log 2>&1
write "executing npm install" >> $tmp\belle.log 2>&1
&npm install >> $tmp\belle.log 2>&1
write "building docs using gulp" >> $tmp\belle.log 2>&1
&gulp docs >> $tmp\belle.log 2>&1
pop-location
# fixme - should we filter the log to find errors?
#get-content .\build.tmp\belle-docs.log | %{ if ($_ -match "build") { write $_}}
} else {
Write-Host "Skipping belle build, $belleAppJs already exists"
}
Write-Host "Completed gulp docs build"
# fixme - should we filter the log to find errors?
#get-content .\build.tmp\belle-docs.log | %{ if ($_ -match "build") { write $_}}
# change baseUrl
$baseUrl = "https://our.umbraco.org/apidocs/ui/"
@@ -40,6 +40,7 @@ function Get-UmbracoBuildEnv
&$nuget install 7-Zip.CommandLine -OutputDirectory $path -Verbosity quiet
$dir = ls "$path\7-Zip.CommandLine.*" | sort -property Name -descending | select -first 1
$file = ls -path "$dir" -name 7za.exe -recurse
$file = ls -path "$dir" -name 7za.exe -recurse | select -first 1 #A select is because there is tools\7za.exe & tools\x64\7za.exe
mv "$dir\$file" $sevenZip
Remove-Directory $dir
}
+11 -5
View File
@@ -51,13 +51,19 @@ function Prepare-Build
if (-not $keep)
{
Remove-Directory "$tmp"
mkdir "$tmp" > $null
Remove-Directory "$out"
mkdir "$out" > $null
Remove-Directory "$tmp"
Remove-Directory "$out"
}
if (-not (Test-Path "$tmp"))
{
mkdir "$tmp" > $null
}
if (-not (Test-Path "$out"))
{
mkdir "$out" > $null
}
# ensure proper web.config
$webUi = "$src\Umbraco.Web.UI"
Store-WebConfig $webUi
+1 -1
View File
@@ -43,7 +43,7 @@
xdt:Locator="Match(application,alias)"
xdt:Transform="InsertIfMissing" />
<add application="settings" alias="scripts" title="Scripts" type="umbraco.loadScripts, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4"
<add application="settings" alias="scripts" title="Scripts" type="Umbraco.Web.Trees.ScriptTreeController, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes()" />
<add application="settings" alias="dictionary" title="Dictionary" type="umbraco.loadDictionary, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="6"
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.6.8")]
[assembly: AssemblyInformationalVersion("7.6.8")]
[assembly: AssemblyFileVersion("7.6.11")]
[assembly: AssemblyInformationalVersion("7.6.11")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.6.8");
private static readonly Version Version = new Version("7.6.11");
/// <summary>
/// Gets the current version of Umbraco.
+22 -9
View File
@@ -24,6 +24,7 @@ namespace Umbraco.Core.Persistence
{
private int _version;
private bool _hasVersion;
private string _exe;
#region Availability & Version
@@ -84,16 +85,31 @@ namespace Umbraco.Core.Persistence
{
_hasVersion = true;
_version = -1;
_exe = null;
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
if (programFiles == null) return;
// MS SQL Server installs in e.g. "C:\Program Files\Microsoft SQL Server", so
// we want to detect it in "%ProgramFiles%\Microsoft SQL Server" - however, if
// Umbraco runs as a 32bits process (e.g. IISExpress configured as 32bits)
// on a 64bits system, %ProgramFiles% will point to "C:\Program Files (x86)"
// and SQL Server cannot be found. But then, %ProgramW6432% will point to
// the original "C:\Program Files". Using it to fix the path.
// see also: MSDN doc for WOW64 implementation
//
var programW6432 = Environment.GetEnvironmentVariable("ProgramW6432");
if (string.IsNullOrWhiteSpace(programW6432) == false && programW6432 != programFiles)
programFiles = programW6432;
if (string.IsNullOrWhiteSpace(programFiles)) return;
// detect 14, 13, 12, 11
for (var i = 14; i > 10; i--)
{
var path = Path.Combine(programFiles, string.Format(@"Microsoft SQL Server\{0}0\Tools\Binn\SqlLocalDB.exe", i));
if (File.Exists(path) == false) continue;
var exe = Path.Combine(programFiles, string.Format(@"Microsoft SQL Server\{0}0\Tools\Binn\SqlLocalDB.exe", i));
if (File.Exists(exe) == false) continue;
_version = i;
_exe = exe;
break;
}
}
@@ -897,16 +913,13 @@ namespace Umbraco.Core.Persistence
/// </remarks>
private int ExecuteSqlLocalDb(string args, out string output, out string error)
{
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
if (programFiles == null)
if (_exe == null) // should never happen - we should not execute if not available
{
output = string.Empty;
error = "SqlLocalDB.exe not found";
return -1;
}
var path = Path.Combine(programFiles, string.Format(@"Microsoft SQL Server\{0}0\Tools\Binn\SqlLocalDB.exe", _version));
var p = new Process
{
StartInfo =
@@ -914,7 +927,7 @@ namespace Umbraco.Core.Persistence
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
FileName = path,
FileName = _exe,
Arguments = args,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
@@ -929,7 +942,7 @@ namespace Umbraco.Core.Persistence
}
/// <summary>
/// Returns a Unicode string with the delimiters added to make the input string a valid SQL Server delimited identifier.
/// Returns a Unicode string with the delimiters added to make the input string a valid SQL Server delimited identifier.
/// </summary>
/// <param name="name">The name to quote.</param>
/// <param name="quote">A quote character.</param>
@@ -705,8 +705,8 @@ ORDER BY contentNodeId, versionId, propertytypeid
case "NAME":
return "umbracoNode.text";
case "PUBLISHED":
case "OWNER":
return "cmsDocument.published";
case "OWNER":
//TODO: This isn't going to work very nicely because it's going to order by ID, not by letter
return "umbracoNode.nodeUser";
// Members only
+6 -6
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Services
{
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
private readonly Dictionary<int, TypedId<Guid>> _id2Key = new Dictionary<int, TypedId<Guid>>();
private readonly Dictionary<Guid, TypedId<int>> _key2Id = new Dictionary<Guid, TypedId<int>>();
@@ -39,8 +39,8 @@ namespace Umbraco.Core.Services
int? val;
using (var uow = _uowProvider.GetUnitOfWork())
{
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id AND nodeObjectType=@nodeObjectType",
new { id = key, nodeObjectType = GetNodeObjectTypeGuid(umbracoObjectType) });
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
new { id = key, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
uow.Commit();
}
@@ -92,8 +92,8 @@ namespace Umbraco.Core.Services
Guid? val;
using (var uow = _uowProvider.GetUnitOfWork())
{
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id AND nodeObjectType=@nodeObjectType",
new { id, nodeObjectType = GetNodeObjectTypeGuid(umbracoObjectType) });
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
new { id, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
uow.Commit();
}
@@ -179,7 +179,7 @@ namespace Umbraco.Core.Services
{
private readonly T _id;
private readonly UmbracoObjectTypes _umbracoObjectType;
public T Id
{
get { return _id; }
@@ -26,15 +26,15 @@ namespace Umbraco.Tests.Services
public override void TearDown()
{
base.TearDown();
}
}
[Test]
public void EntityService_Can_Get_Paged_Content_Children()
{
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
for (int i = 0; i < 10; i++)
{
@@ -45,7 +45,7 @@ namespace Umbraco.Tests.Services
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(6));
Assert.That(total, Is.EqualTo(10));
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray();
@@ -72,7 +72,7 @@ namespace Umbraco.Tests.Services
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
ServiceContext.ContentService.Save(c2);
count++;
}
}
}
var service = ServiceContext.EntityService;
@@ -181,7 +181,7 @@ namespace Umbraco.Tests.Services
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root);
@@ -204,7 +204,7 @@ namespace Umbraco.Tests.Services
Assert.That(entities.Length, Is.EqualTo(50));
Assert.That(total, Is.EqualTo(50));
}
[Test]
public void EntityService_Can_Get_Paged_Media_Children()
{
@@ -227,7 +227,7 @@ namespace Umbraco.Tests.Services
Assert.That(total, Is.EqualTo(10));
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(4));
Assert.That(total, Is.EqualTo(10));
Assert.That(total, Is.EqualTo(10));
}
[Test]
@@ -362,7 +362,7 @@ namespace Umbraco.Tests.Services
var root = MockedMedia.CreateMediaFolder(folderType, -1);
ServiceContext.MediaService.Save(root);
for (int i = 0; i < 10; i++)
{
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
@@ -519,7 +519,7 @@ namespace Umbraco.Tests.Services
Assert.That(
entities.Any(
x =>
x.AdditionalData.Any(y => y.Value is UmbracoEntity.EntityProperty
x.AdditionalData.Any(y => y.Value is UmbracoEntity.EntityProperty
&& ((UmbracoEntity.EntityProperty)y.Value).PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias)), Is.True);
}
@@ -575,6 +575,30 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(result2.Success);
}
[Test]
public void ReserveId()
{
var service = ServiceContext.EntityService;
var guid = Guid.NewGuid();
// can reserve
var reservedId = service.ReserveId(guid);
Assert.IsTrue(reservedId > 0);
// can get it back
var id = service.GetIdForKey(guid, UmbracoObjectTypes.DocumentType);
Assert.IsTrue(id.Success);
Assert.AreEqual(reservedId, id.Result);
// anything goes
id = service.GetIdForKey(guid, UmbracoObjectTypes.Media);
Assert.IsTrue(id.Success);
Assert.AreEqual(reservedId, id.Result);
// a random guid won't work
Assert.IsFalse(service.GetIdForKey(Guid.NewGuid(), UmbracoObjectTypes.DocumentType).Success);
}
private static bool _isSetup = false;
private int folderId;
@@ -589,7 +613,7 @@ namespace Umbraco.Tests.Services
//Create and Save folder-Media -> 1050
var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
ServiceContext.MediaService.Save(folder, 0);
folderId = folder.Id;
@@ -607,9 +631,9 @@ namespace Umbraco.Tests.Services
ServiceContext.MediaService.Save(subfolder, 0);
var subfolder2 = MockedMedia.CreateMediaFolder(folderMediaType, subfolder.Id);
ServiceContext.MediaService.Save(subfolder2, 0);
}
}
}
}
@@ -22,5 +22,38 @@ namespace Umbraco.Tests.Web.Mvc
var expected = "<div><h1>hello world</h1><p>hello world<br />hello world<br />hello world<br />hello world</p></div>";
Assert.AreEqual(expected, output);
}
[Test]
public void TruncateWithElipsis()
{
var output = _htmlStringUtilities.Truncate("hello world", 5, true, false).ToString();
var expected = "hello&hellip;";
Assert.AreEqual(expected, output);
}
[Test]
public void TruncateWithoutElipsis()
{
var output = _htmlStringUtilities.Truncate("hello world", 5, false, false).ToString();
var expected = "hello";
Assert.AreEqual(expected, output);
}
[Test]
public void TruncateShorterWordThanHellip()
{
//http://issues.umbraco.org/issue/U4-10478
var output = _htmlStringUtilities.Truncate("hi", 5, true, false).ToString();
var expected = "hi";
Assert.AreEqual(expected, output);
}
[Test]
public void TruncateAndRemoveSpaceBetweenHellipAndWord()
{
var output = _htmlStringUtilities.Truncate("hello world", 6 /* hello plus space */, true, false).ToString();
var expected = "hello&hellip;";
Assert.AreEqual(expected, output);
}
}
}
@@ -361,11 +361,29 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
rootScope : function(){
return getRootScope();
},
reloadLocation: function() {
var injector = getRootInjector();
var $route = injector.get("$route");
$route.reload();
/**
This will reload the content frame based on it's current route, if pathToMatch is specified it will only reload it if the current
location matches the path
*/
reloadLocation: function(pathToMatch) {
var injector = getRootInjector();
var doChange = true;
if (pathToMatch) {
var $location = injector.get("$location");
var path = $location.path();
if (path != pathToMatch) {
doChange = false;
}
}
if (doChange) {
var $route = injector.get("$route");
$route.reload();
var $rootScope = injector.get("$rootScope");
$rootScope.$apply();
}
},
closeModalWindow: function(rVal) {
@@ -269,7 +269,8 @@
var isSelected = false;
for (var i = 0; selection.length > i; i++) {
var selectedItem = selection[i];
if (item.id === selectedItem.id || item.key === selectedItem.key) {
// if item.id is 2147483647 (int.MaxValue) use item.key
if ((item.id !== 2147483647 && item.id === selectedItem.id) || item.key === selectedItem.key) {
isSelected = true;
}
}
@@ -294,7 +295,8 @@
function deselectItem(item, selection) {
for (var i = 0; selection.length > i; i++) {
var selectedItem = selection[i];
if (item.id === selectedItem.id) {
// if item.id is 2147483647 (int.MaxValue) use item.key
if ((item.id !== 2147483647 && item.id === selectedItem.id) || item.key === selectedItem.key) {
selection.splice(i, 1);
item.selected = false;
}
@@ -366,7 +368,7 @@
var item = items[i];
if (checkbox.checked) {
selection.push({ id: item.id });
selection.push({ id: item.id, key: item.key });
} else {
clearSelection = true;
}
@@ -405,7 +407,8 @@
for (var selectedIndex = 0; selection.length > selectedIndex; selectedIndex++) {
var selectedItem = selection[selectedIndex];
if (item.id === selectedItem.id) {
// if item.id is 2147483647 (int.MaxValue) use item.key
if ((item.id !== 2147483647 && item.id === selectedItem.id) || item.key === selectedItem.key) {
numberOfSelectedItem++;
}
}
@@ -35,3 +35,10 @@
margin-right: 5px;
color: @gray-7;
}
input.umb-breadcrumbs__add-ancestor {
height: 25px;
margin-top: -2px;
margin-left: 3px;
width: 100px;
}
@@ -126,21 +126,21 @@ ul.color-picker li a {
// Media picker
// --------------------------------------------------
.umb-mediapicker .add-link {
display: inline-block;
height: 120px;
width: 120px;
text-align: center;
color: @gray-8;
border: 2px @gray-8 dashed;
line-height: 120px;
text-decoration: none;
display: flex;
justify-content:center;
align-items:center;
width: 120px;
text-align: center;
color: @gray-8;
border: 2px @gray-8 dashed;
text-decoration: none;
transition: all 150ms ease-in-out;
transition: all 150ms ease-in-out;
&:hover {
color: @turquoise-d1;
border-color: @turquoise;
}
&:hover {
color: @turquoise-d1;
border-color: @turquoise;
}
}
.umb-mediapicker .picked-image {
@@ -165,6 +165,10 @@ ul.color-picker li a {
text-decoration: none;
}
.umb-mediapicker .add-link-square {
height: 120px;
}
.umb-thumbnails{
@@ -207,11 +211,10 @@ ul.color-picker li a {
.umb-mediapicker .umb-sortable-thumbnails li {
flex-direction: column;
margin: 0;
margin: 0 5px 0 0;
padding: 5px;
}
.umb-sortable-thumbnails li:hover a {
display: flex;
justify-content: center;
@@ -219,16 +222,20 @@ ul.color-picker li a {
}
.umb-sortable-thumbnails li img {
max-width:100%;
max-height:100%;
margin:auto;
display:block;
background-image: url(../img/checkered-background.png);
max-width:100%;
max-height:100%;
margin:auto;
display:block;
background-image: url(../img/checkered-background.png);
}
.umb-sortable-thumbnails li img.noScale{
max-width: none !important;
max-height: none !important;
.umb-sortable-thumbnails li img.trashed {
opacity:0.3;
}
.umb-sortable-thumbnails li img.noScale {
max-width: none !important;
max-height: none !important;
}
.umb-sortable-thumbnails .umb-icon-holder {
@@ -254,8 +261,8 @@ ul.color-picker li a {
}
.umb-sortable-thumbnails li:hover .umb-sortable-thumbnails__actions {
opacity: 1;
visibility: visible;
opacity: 1;
visibility: visible;
}
.umb-sortable-thumbnails .umb-sortable-thumbnails__action {
@@ -285,27 +292,27 @@ ul.color-picker li a {
// -------------------------------------------------
.umb-cropper{
position: relative;
position: relative;
}
.umb-cropper img, .umb-cropper-gravity img{
position: relative;
max-width: 100%;
height: auto;
top: 0;
left: 0;
position: relative;
max-width: 100%;
height: auto;
top: 0;
left: 0;
}
.umb-cropper img {
max-width: none;
max-width: none;
}
.umb-cropper .overlay, .umb-cropper-gravity .overlay {
top: 0;
left: 0;
cursor: move;
z-index: 6001;
position: absolute;
top: 0;
left: 0;
cursor: move;
z-index: 6001;
position: absolute;
}
.umb-cropper .viewport{
@@ -317,43 +324,43 @@ ul.color-picker li a {
}
.umb-cropper-gravity .viewport{
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
}
.umb-cropper .viewport:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 5999;
-moz-opacity: .75;
opacity: .75;
filter: alpha(opacity=7);
-webkit-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 5999;
-moz-opacity: .75;
opacity: .75;
filter: alpha(opacity=7);
-webkit-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
}
.umb-cropper-gravity .overlay{
width: 14px;
height: 14px;
text-align: center;
border-radius: 20px;
background: @turquoise;
border: 3px solid @white;
opacity: 0.8;
width: 14px;
height: 14px;
text-align: center;
border-radius: 20px;
background: @turquoise;
border: 3px solid @white;
opacity: 0.8;
}
.umb-cropper-gravity .overlay i {
font-size: 26px;
line-height: 26px;
opacity: 0.8 !important;
font-size: 26px;
line-height: 26px;
opacity: 0.8 !important;
}
.umb-cropper .crop-container {
@@ -361,16 +368,16 @@ ul.color-picker li a {
}
.umb-cropper .crop-slider {
padding: 10px;
border-top: 1px solid @gray-10;
margin-top: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
@media (min-width: 769px) {
padding: 10px;
border-top: 1px solid @gray-10;
margin-top: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
@media (min-width: 769px) {
padding: 10px 50px 10px 50px;
}
}
}
.umb-cropper .crop-slider i {
@@ -55,6 +55,46 @@ angular.module("umbraco")
$scope.target = dialogOptions.currentTarget;
}
function onInit() {
if ($scope.startNodeId !== -1) {
entityResource.getById($scope.startNodeId, "media")
.then(function (ent) {
$scope.startNodeId = ent.id;
run();
});
} else {
run();
}
}
function run() {
//default root item
if (!$scope.target) {
if ($scope.lastOpenedNode && $scope.lastOpenedNode !== -1) {
entityResource.getById($scope.lastOpenedNode, "media")
.then(ensureWithinStartNode, gotoStartNode);
} else {
gotoStartNode();
}
} else {
//if a target is specified, go look it up - generally this target will just contain ids not the actual full
//media object so we need to look it up
var id = $scope.target.udi ? $scope.target.udi : $scope.target.id
var altText = $scope.target.altText;
mediaResource.getById(id)
.then(function (node) {
$scope.target = node;
if (ensureWithinStartNode(node)) {
selectImage(node);
$scope.target.url = mediaHelper.resolveFile(node);
$scope.target.altText = altText;
$scope.openDetailsDialog();
}
},
gotoStartNode);
}
}
$scope.upload = function(v) {
angular.element(".umb-file-dropzone-directive .file-select").click();
};
@@ -106,7 +146,7 @@ angular.module("umbraco")
if (folder.id > 0) {
entityResource.getAncestors(folder.id, "media")
.then(function(anc) {
.then(function(anc) {
$scope.path = _.filter(anc,
function(f) {
return f.path.indexOf($scope.startNodeId) !== -1;
@@ -215,32 +255,6 @@ angular.module("umbraco")
$scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
}
//default root item
if (!$scope.target) {
if ($scope.lastOpenedNode && $scope.lastOpenedNode !== -1) {
entityResource.getById($scope.lastOpenedNode, "media")
.then(ensureWithinStartNode, gotoStartNode);
} else {
gotoStartNode();
}
} else {
//if a target is specified, go look it up - generally this target will just contain ids not the actual full
//media object so we need to look it up
var id = $scope.target.udi ? $scope.target.udi : $scope.target.id
var altText = $scope.target.altText;
mediaResource.getById(id)
.then(function(node) {
$scope.target = node;
if (ensureWithinStartNode(node)) {
selectImage(node);
$scope.target.url = mediaHelper.resolveFile(node);
$scope.target.altText = altText;
$scope.openDetailsDialog();
}
},
gotoStartNode);
}
$scope.openDetailsDialog = function() {
$scope.mediaPickerDetailsOverlay = {};
@@ -365,4 +379,7 @@ angular.module("umbraco")
}
}
}
onInit();
});
@@ -55,7 +55,7 @@
<input
type="text"
class="input-foldername input-mini inline"
class="umb-breadcrumbs__add-ancestor"
ng-show="showFolderInput"
ng-model="newFolderName"
ng-keydown="enterSubmitFolder($event)"
@@ -1,7 +1,7 @@
//this controller simply tells the dialogs service to open a mediaPicker window
//with a specified callback, this callback will receive an object with a selection on it
function contentPickerController($scope, entityResource, editorState, iconHelper, $routeParams, angularHelper, navigationService, $location, miniEditorHelper) {
function contentPickerController($scope, entityResource, editorState, iconHelper, $routeParams, angularHelper, navigationService, $location, miniEditorHelper, localizationService) {
var unsubscribe;
@@ -154,7 +154,6 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
}
}
if ($routeParams.section === "settings" && $routeParams.tree === "documentTypes") {
//if the content-picker is being rendered inside the document-type editor, we don't need to process the startnode query
dialogOptions.startNodeId = -1;
@@ -287,8 +286,12 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
entityResource.getUrl(entity.id, entityType).then(function(data){
// update url
angular.forEach($scope.renderModel, function(item){
if(item.id === entity.id) {
item.url = data;
if (item.id === entity.id) {
if (entity.trashed) {
item.url = localizationService.dictionary.general_recycleBin;
} else {
item.url = data;
}
}
});
});
@@ -330,6 +333,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
"icon": item.icon,
"path": item.path,
"url": item.url,
"trashed": item.trashed,
"published": (item.metaData && item.metaData.IsPublished === false && entityType === "Document") ? false : true
// only content supports published/unpublished content so we set everything else to published so the UI looks correct
});
@@ -1,5 +1,8 @@
<div ng-controller="Umbraco.PropertyEditors.ContentPickerController" class="umb-editor umb-contentpicker">
<p ng-if="(renderModel|filter:{trashed:true}).length == 1"><localize key="contentPicker_pickedTrashedItem"></localize></p>
<p ng-if="(renderModel|filter:{trashed:true}).length > 1"><localize key="contentPicker_pickedTrashedItems"></localize></p>
<ng-form name="contentPickerForm">
<div ui-sortable="sortableOptions" ng-model="renderModel">
@@ -1,7 +1,7 @@
//this controller simply tells the dialogs service to open a mediaPicker window
//with a specified callback, this callback will receive an object with a selection on it
angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerController",
function ($rootScope, $scope, dialogService, entityResource, mediaResource, mediaHelper, $timeout, userService, $location) {
function ($rootScope, $scope, dialogService, entityResource, mediaResource, mediaHelper, $timeout, userService, $location, localizationService) {
//check the pre-values for multi-picker
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
@@ -25,17 +25,47 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
// the mediaResource has server side auth configured for which the user must have
// access to the media section, if they don't they'll get auth errors. The entityResource
// acts differently in that it allows access if the user has access to any of the apps that
// might require it's use. Therefore we need to use the metatData property to get at the thumbnail
// might require it's use. Therefore we need to use the metaData property to get at the thumbnail
// value.
entityResource.getByIds(ids, "Media").then(function (medias) {
entityResource.getByIds(ids, "Media").then(function(medias) {
_.each(medias, function (media, i) {
// The service only returns item results for ids that exist (deleted items are silently ignored).
// This results in the picked items value to be set to contain only ids of picked items that could actually be found.
// Since a referenced item could potentially be restored later on, instead of changing the selected values here based
// on whether the items exist during a save event - we should keep "placeholder" items for picked items that currently
// could not be fetched. This will preserve references and ensure that the state of an item does not differ depending
// on whether it is simply resaved or not.
// This is done by remapping the int/guid ids into a new array of items, where we create "Deleted item" placeholders
// when there is no match for a selected id. This will ensure that the values being set on save, are the same as before.
medias = _.map(ids,
function(id) {
var found = _.find(medias,
function(m) {
// We could use coercion (two ='s) here .. but not sure if this works equally well in all browsers and
// it's prone to someone "fixing" it at some point without knowing the effects. Rather use toString()
// compares and be completely sure it works.
return m.udi.toString() === id.toString() || m.id.toString() === id.toString();
});
if (found) {
return found;
} else {
return {
name: localizationService.dictionary.mediaPicker_deletedItem,
id: $scope.model.config.idType !== "udi" ? id : null,
udi: $scope.model.config.idType === "udi" ? id : null,
icon: "icon-picture",
thumbnail: null,
trashed: true
};
}
});
//only show non-trashed items
if (media.parentId >= -1) {
if (!media.thumbnail) {
_.each(medias,
function(media, i) {
// if there is no thumbnail, try getting one if the media is not a placeholder item
if (!media.thumbnail && media.id && media.metaData) {
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
}
@@ -43,12 +73,10 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
if ($scope.model.config.idType === "udi") {
$scope.ids.push(media.udi);
}
else {
} else {
$scope.ids.push(media.id);
}
}
});
});
$scope.sync();
});
@@ -80,8 +108,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
submit: function(model) {
_.each(model.selectedImages, function(media, i) {
if (!media.thumbnail) {
// if there is no thumbnail, try getting one if the media is not a placeholder item
if (!media.thumbnail && media.id && media.metaData) {
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
}
@@ -99,10 +127,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
}
};
};
$scope.sortableOptions = {
@@ -140,5 +166,4 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
//update the display val again if it has changed from the server
setupViewModel();
};
});
@@ -1,47 +1,47 @@
<div class="umb-editor umb-mediapicker" ng-controller="Umbraco.PropertyEditors.MediaPickerController">
<ul ui-sortable="sortableOptions" ng-model="images" class="umb-sortable-thumbnails">
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
<p ng-if="(images|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
<p ng-if="(images|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
<!-- IMAGE -->
<img ng-src="{{image.thumbnail}}" alt="" ng-show="image.thumbnail" title="{{image.name}}" />
<div class="flex error">
<ul ui-sortable="sortableOptions" ng-model="images" class="umb-sortable-thumbnails">
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
<!-- SVG -->
<img ng-if="image.metaData.umbracoExtension.Value === 'svg'" ng-src="{{image.metaData.umbracoFile.Value}}" alt="" title="{{image.name}}" />
<img ng-if="image.extension === 'svg'" ng-src="{{image.file}}" alt="" />
<!-- IMAGE -->
<img ng-class="{'trashed': image.trashed}" ng-src="{{image.thumbnail}}" alt="" ng-show="image.thumbnail" title="{{image.trashed ? 'Trashed: ' + image.name : image.name}}" />
<!-- FILE -->
<span class="umb-icon-holder" ng-hide="image.thumbnail || image.metaData.umbracoExtension.Value === 'svg' || image.extension === 'svg'">
<i class="icon {{image.icon}} large"></i>
<small>{{image.name}}</small>
</span>
<!-- SVG -->
<img ng-class="{'trashed': image.trashed}" ng-if="image.metaData.umbracoExtension.Value === 'svg'" ng-src="{{image.metaData.umbracoFile.Value}}" alt="" title="{{image.trashed ? 'Trashed: ' + image.name : image.name}}" />
<img ng-class="{'trashed': image.trashed}" ng-if="image.extension === 'svg'" ng-src="{{image.file}}" alt="" />
<div class="umb-sortable-thumbnails__actions">
<a class="umb-sortable-thumbnails__action" href="" ng-click="goToItem(image)">
<i class="icon icon-edit"></i>
</a>
<a class="umb-sortable-thumbnails__action -red" href="" ng-click="remove($index)">
<i class="icon icon-delete"></i>
</a>
</div>
<!-- FILE -->
<span class="umb-icon-holder" ng-hide="image.thumbnail || image.metaData.umbracoExtension.Value === 'svg' || image.extension === 'svg'">
<i class="icon {{image.icon}} large"></i>
<small>{{image.name}}</small>
</span>
</li>
</ul>
<div class="umb-sortable-thumbnails__actions">
<a class="umb-sortable-thumbnails__action" href="" ng-click="goToItem(image)">
<i class="icon icon-edit"></i>
</a>
<a class="umb-sortable-thumbnails__action -red" href="" ng-click="remove($index)">
<i class="icon icon-delete"></i>
</a>
</div>
</li>
<ul class="umb-sortable-thumbnails" ng-if="showAdd()">
<li style="border: none">
<a href="#" class="add-link" ng-click="add()" prevent-default>
<i class="icon icon-add large"></i>
</a>
</li>
</ul>
</ul>
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': images.length === 0}" ng-if="showAdd()" prevent-default>
<i class="icon icon-add large"></i>
</a>
</div>
<umb-overlay
ng-if="mediaPickerOverlay.show"
model="mediaPickerOverlay"
position="right"
view="mediaPickerOverlay.view">
</umb-overlay>
<umb-overlay
ng-if="mediaPickerOverlay.show"
model="mediaPickerOverlay"
position="right"
view="mediaPickerOverlay.view">
</umb-overlay>
</div>
+2 -2
View File
@@ -2379,9 +2379,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7680</DevelopmentServerPort>
<DevelopmentServerPort>7611</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7680</IISUrl>
<IISUrl>http://localhost:7611</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -60,21 +60,29 @@
JObject cfg = contentItem.config;
if(cfg != null)
foreach (JProperty property in cfg.Properties()) {
attrs.Add(property.Name + "='" + property.Value.ToString() + "'");
foreach (JProperty property in cfg.Properties())
{
var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
attrs.Add(property.Name + "=\"" + propertyValue + "\"");
}
JObject style = contentItem.styles;
if (style != null) {
var cssVals = new List<string>();
foreach (JProperty property in style.Properties())
cssVals.Add(property.Name + ":" + property.Value.ToString() + ";");
if (style != null) {
var cssVals = new List<string>();
foreach (JProperty property in style.Properties())
{
var propertyValue = property.Value.ToString();
if (string.IsNullOrWhiteSpace(propertyValue) == false)
{
cssVals.Add(property.Name + ":" + propertyValue + ";");
}
}
if (cssVals.Any())
attrs.Add("style='" + string.Join(" ", cssVals) + "'");
if (cssVals.Any())
attrs.Add("style=\"" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "\"");
}
return new MvcHtmlString(string.Join(" ", attrs));
}
}
@@ -60,21 +60,29 @@
JObject cfg = contentItem.config;
if(cfg != null)
foreach (JProperty property in cfg.Properties()) {
attrs.Add(property.Name + "='" + property.Value.ToString() + "'");
foreach (JProperty property in cfg.Properties())
{
var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
attrs.Add(property.Name + "=\"" + propertyValue + "\"");
}
JObject style = contentItem.styles;
if (style != null) {
var cssVals = new List<string>();
foreach (JProperty property in style.Properties())
cssVals.Add(property.Name + ":" + property.Value.ToString() + ";");
if (style != null) {
var cssVals = new List<string>();
foreach (JProperty property in style.Properties())
{
var propertyValue = property.Value.ToString();
if (string.IsNullOrWhiteSpace(propertyValue) == false)
{
cssVals.Add(property.Name + ":" + propertyValue + ";");
}
}
if (cssVals.Any())
attrs.Add("style='" + string.Join(" ", cssVals) + "'");
if (cssVals.Any())
attrs.Add("style=\"" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "\"");
}
return new MvcHtmlString(string.Join(" ", attrs));
}
}
@@ -4,8 +4,8 @@
@if (Model.editor.config.markup != null)
{
string markup = Model.editor.config.markup.ToString();
markup = markup.Replace("#value#", Model.value.ToString());
var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
markup = markup.Replace("#value#", umbracoHelper.ReplaceLineBreaksForHtml(HttpUtility.HtmlEncode(Model.value.ToString())));
markup = markup.Replace("#style#", Model.editor.config.style.ToString());
<text>
@@ -784,6 +784,15 @@ Mange hilsner fra Umbraco robotten
<area alias="colorpicker">
<key alias="noColors">Du har ikke konfigureret nogen godkendte farver</key>
</area>
<area alias="contentPicker">
<key alias="pickedTrashedItem">Du har valgt et dokument som er slettet eller lagt i papirkurven</key>
<key alias="pickedTrashedItems">Du har valgt dokumenter som er slettede eller lagt i papirkurven</key>
</area>
<area alias="mediaPicker">
<key alias="pickedTrashedItem">Du har valgt et medie som er slettet eller lagt i papirkurven</key>
<key alias="pickedTrashedItems">Du har valgt medier som er slettede eller lagt i papirkurven</key>
<key alias="deletedItem">Slettet medie</key>
</area>
<area alias="relatedlinks">
<key alias="enterExternal">indtast eksternt link</key>
<key alias="chooseInternal">vælg en intern side</key>
@@ -952,6 +952,15 @@ To manage your website, simply open the Umbraco back office and start adding con
<area alias="colorpicker">
<key alias="noColors">You have not configured any approved colours</key>
</area>
<area alias="contentPicker">
<key alias="pickedTrashedItem">You have picked a content item currently deleted or in the recycle bin</key>
<key alias="pickedTrashedItems">You have picked content items currently deleted or in the recycle bin</key>
</area>
<area alias="mediaPicker">
<key alias="pickedTrashedItem">You have picked a media item currently deleted or in the recycle bin</key>
<key alias="pickedTrashedItems">You have picked media items currently deleted or in the recycle bin</key>
<key alias="deletedItem">Deleted item</key>
</area>
<area alias="relatedlinks">
<key alias="enterExternal">enter external link</key>
<key alias="chooseInternal">choose internal page</key>
@@ -1011,6 +1011,15 @@ To manage your website, simply open the Umbraco back office and start adding con
<area alias="colorpicker">
<key alias="noColors">You have not configured any approved colors</key>
</area>
<area alias="contentPicker">
<key alias="pickedTrashedItem">You have picked a content item currently deleted or in the recycle bin</key>
<key alias="pickedTrashedItems">You have picked content items currently deleted or in the recycle bin</key>
</area>
<area alias="mediaPicker">
<key alias="pickedTrashedItem">You have picked a media item currently deleted or in the recycle bin</key>
<key alias="pickedTrashedItems">You have picked media items currently deleted or in the recycle bin</key>
<key alias="deletedItem">Deleted item</key>
</area>
<area alias="relatedlinks">
<key alias="enterExternal">enter external link</key>
<key alias="chooseInternal">choose internal page</key>
@@ -30,7 +30,7 @@ namespace Umbraco.Web.UI.Umbraco.Dialogs
}
DocumentId = doc.Id;
PageName = doc.Name;
PageName = Server.HtmlEncode(doc.Name);
DocumentPath = doc.Path;
}
@@ -172,9 +172,9 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
},
reloadLocation: function () {
reloadLocation: function (pathToMatch) {
if (this.mainWindow().UmbClientMgr) {
this.mainWindow().UmbClientMgr.reloadLocation();
this.mainWindow().UmbClientMgr.reloadLocation(pathToMatch);
}
},
+71 -22
View File
@@ -413,7 +413,69 @@ namespace Umbraco.Web.Editors
}
return Request.CreateResponse(HttpStatusCode.OK);
}
}
/// <summary>
/// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT
/// </summary>
/// <param name="parentId"></param>
/// <param name="validatePermissions">
/// If true, this will check if the current user has access to the resolved integer parent id
/// and if that check fails an unauthorized exception will occur
/// </param>
/// <returns></returns>
private int GetParentIdAsInt(string parentId, bool validatePermissions)
{
int intParentId;
GuidUdi parentUdi;
// test for udi
if (GuidUdi.TryParse(parentId, out parentUdi))
{
parentId = parentUdi.Guid.ToString();
}
//if it's not an INT then we'll check for GUID
if (int.TryParse(parentId, out intParentId) == false)
{
// if a guid then try to look up the entity
Guid idGuid;
if (Guid.TryParse(parentId, out idGuid))
{
var entity = Services.EntityService.GetByKey(idGuid);
if (entity != null)
{
intParentId = entity.Id;
}
else
{
throw new EntityNotFoundException(parentId, "The passed id doesn't exist");
}
}
else
{
throw new HttpResponseException(
Request.CreateValidationErrorResponse("The request was not formatted correctly, the parentId is not an integer, Guid or UDI"));
}
}
//ensure the user has access to this folder by parent id!
if (CheckPermissions(
new Dictionary<string, object>(),
Security.CurrentUser,
Services.MediaService,
intParentId) == false)
{
throw new HttpResponseException(Request.CreateResponse(
HttpStatusCode.Forbidden,
new SimpleNotificationModel(new Notification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
Services.TextService.Localize("speechBubbles/invalidUserPermissionsText"),
SpeechBubbleIcon.Warning))));
}
return intParentId;
}
/// <summary>
/// Change the sort order for media
@@ -574,11 +636,13 @@ namespace Umbraco.Web.Editors
}
}
[EnsureUserPermissionForMedia("folder.ParentId")]
public MediaItemDisplay PostAddFolder(EntityBasic folder)
public MediaItemDisplay PostAddFolder(PostedFolder folder)
{
var mediaService = ApplicationContext.Services.MediaService;
var f = mediaService.CreateMedia(folder.Name, folder.ParentId, Constants.Conventions.MediaTypes.Folder);
var intParentId = GetParentIdAsInt(folder.ParentId, validatePermissions: true);
var mediaService = ApplicationContext.Services.MediaService;
var f = mediaService.CreateMedia(folder.Name, intParentId, Constants.Conventions.MediaTypes.Folder);
mediaService.Save(f, Security.CurrentUser.Id);
return Mapper.Map<IMedia, MediaItemDisplay>(f);
@@ -649,21 +713,6 @@ namespace Umbraco.Web.Editors
}
}
//ensure the user has access to this folder by parent id!
if (CheckPermissions(
new Dictionary<string, object>(),
Security.CurrentUser,
Services.MediaService, parentId) == false)
{
return Request.CreateResponse(
HttpStatusCode.Forbidden,
new SimpleNotificationModel(new Notification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
Services.TextService.Localize("speechBubbles/invalidUserPermissionsText"),
SpeechBubbleIcon.Warning)));
}
var tempFiles = new PostedFiles();
var mediaService = ApplicationContext.Services.MediaService;
@@ -793,8 +842,8 @@ namespace Umbraco.Web.Editors
if (origin.Value == "blueimp")
{
return Request.CreateResponse(HttpStatusCode.OK,
tempFiles,
//Don't output the angular xsrf stuff, blue imp doesn't like that
tempFiles,
//Don't output the angular xsrf stuff, blue imp doesn't like that
new JsonMediaTypeFormatter());
}
}
@@ -3,12 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using Umbraco.Web.Editors;
using Umbraco.Web.WebApi.Filters;
namespace Umbraco.Web.HealthCheck
{
/// <summary>
/// The API controller used to display the health check info and execute any actions
/// </summary>
[UmbracoApplicationAuthorize(Core.Constants.Applications.Developer)]
public class HealthCheckController : UmbracoAuthorizedJsonController
{
private readonly IHealthCheckResolver _healthCheckResolver;
+6 -2
View File
@@ -92,6 +92,7 @@ namespace Umbraco.Web
using (var outputms = new MemoryStream())
{
bool lengthReached = false;
using (var outputtw = new StreamWriter(outputms))
{
using (var ms = new MemoryStream())
@@ -106,7 +107,6 @@ namespace Umbraco.Web
using (TextReader tr = new StreamReader(ms))
{
bool isInsideElement = false,
lengthReached = false,
insideTagSpaceEncountered = false,
isTagClose = false;
@@ -254,10 +254,14 @@ namespace Umbraco.Web
//Check to see if there is an empty char between the hellip and the output string
//if there is, remove it
if (string.IsNullOrWhiteSpace(firstTrim) == false)
if (addElipsis && lengthReached && string.IsNullOrWhiteSpace(firstTrim) == false)
{
result = firstTrim[firstTrim.Length - hellip.Length - 1] == ' ' ? firstTrim.Remove(firstTrim.Length - hellip.Length - 1, 1) : firstTrim;
}
else
{
result = firstTrim;
}
return new HtmlString(result);
}
}
@@ -2,10 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Models.Validation;
@@ -0,0 +1,17 @@
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// Used to create a folder with the MediaController
/// </summary>
[DataContract]
public class PostedFolder
{
[DataMember(Name = "parentId")]
public string ParentId { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
}
}
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap<UmbracoEntity, EntityBasic>()
.ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
.ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
.ForMember(dto => dto.Trashed, expression => expression.Ignore())
.ForMember(dto => dto.Trashed, expression => expression.MapFrom(x => x.Trashed))
.ForMember(x => x.Alias, expression => expression.Ignore())
.AfterMap((entity, basic) =>
{
+1
View File
@@ -361,6 +361,7 @@
<Compile Include="Models\ContentEditing\MemberTypeDisplay.cs" />
<Compile Include="Models\ContentEditing\MemberTypeSave.cs" />
<Compile Include="Models\ContentEditing\PostedFiles.cs" />
<Compile Include="Models\ContentEditing\PostedFolder.cs" />
<Compile Include="Models\ContentEditing\PropertyGroupBasic.cs" />
<Compile Include="Models\ContentEditing\PropertyTypeBasic.cs" />
<Compile Include="Models\ContentEditing\SimpleNotificationModel.cs" />
+17 -5
View File
@@ -46,12 +46,10 @@ namespace Umbraco.Web
/// <param name="app"></param>
protected virtual void ConfigureMiddleware(IAppBuilder app)
{
//Ensure owin is configured for Umbraco back office authentication. If you have any front-end OWIN
// cookie configuration, this must be declared after it.
// Configure OWIN for authentication.
ConfigureUmbracoAuthentication(app);
app
.UseUmbracoBackOfficeCookieAuthentication(ApplicationContext, PipelineStage.Authenticate)
.UseUmbracoBackOfficeExternalCookieAuthentication(ApplicationContext, PipelineStage.Authenticate)
.UseUmbracoPreviewAuthentication(ApplicationContext, PipelineStage.Authorize)
.UseSignalR()
.FinalizeMiddlewareConfiguration();
}
@@ -68,6 +66,20 @@ namespace Umbraco.Web
Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider().AsUmbracoMembershipProvider());
}
/// <summary>
/// Configure external/OAuth login providers
/// </summary>
/// <param name="app"></param>
protected virtual void ConfigureUmbracoAuthentication(IAppBuilder app)
{
// Ensure owin is configured for Umbraco back office authentication.
// Front-end OWIN cookie configuration must be declared after this code.
app
.UseUmbracoBackOfficeCookieAuthentication(ApplicationContext, PipelineStage.Authenticate)
.UseUmbracoBackOfficeExternalCookieAuthentication(ApplicationContext, PipelineStage.Authenticate)
.UseUmbracoPreviewAuthentication(ApplicationContext, PipelineStage.Authorize);
}
/// <summary>
/// Raised when the middleware has been configured
/// </summary>
@@ -70,10 +70,11 @@ namespace umbraco.presentation.umbraco.dialogs
private void import_Click(object sender, EventArgs e)
{
var xd = new XmlDocument();
xd.XmlResolver = null;
xd.Load(tempFile.Value);
var userId = base.getUser().Id;
var element = XElement.Parse(xd.InnerXml);
var importContentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element, userId);
var contentType = importContentTypes.FirstOrDefault();
@@ -104,7 +105,8 @@ namespace umbraco.presentation.umbraco.dialogs
documentTypeFile.PostedFile.SaveAs(fileName);
var xd = new XmlDocument();
xd.Load(fileName);
xd.XmlResolver = null;
xd.Load(fileName);
dtName.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Name").FirstChild.Value;
dtAlias.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Alias").FirstChild.Value;
@@ -26,7 +26,7 @@ namespace umbraco.dialogs
protected void Page_Load(object sender, EventArgs e)
{
Button1.Text = ui.Text("update");
pane_form.Text = ui.Text("notifications", "editNotifications", node.Text, base.getUser());
pane_form.Text = ui.Text("notifications", "editNotifications", Server.HtmlEncode(node.Text), base.getUser());
}
#region Web Form Designer generated code
@@ -3,6 +3,7 @@ using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
@@ -117,36 +118,23 @@ namespace umbraco.presentation.dialogs
if (!IsPostBack) {
allVersions.Items.Add(new ListItem(ui.Text("rollback", "selectVersion")+ "...", ""));
foreach (DocumentVersionList dl in currentDoc.GetVersions()) {
foreach (DocumentVersionList dl in currentDoc.GetVersions())
{
//we don't need to show the current version
if (dl.Version == currentDoc.Version)
continue;
allVersions.Items.Add(new ListItem(dl.Text + " (" + ui.Text("content", "createDate") + ": " + dl.Date.ToShortDateString() + " " + dl.Date.ToShortTimeString() + ")", dl.Version.ToString()));
}
Button1.Text = ui.Text("actions", "rollback");
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
#endregion
protected void doRollback_Click(object sender, System.EventArgs e)
{
if (allVersions.SelectedValue.Trim() != "") {
if (allVersions.SelectedValue.Trim() != "")
{
Document d = new Document(int.Parse(helper.Request("nodeId")));
d.RollBack(new Guid(allVersions.SelectedValue), base.getUser());
@@ -159,6 +147,8 @@ namespace umbraco.presentation.dialogs
feedBackMsg.Text = ui.Text("rollback", "documentRolledBack", vars, new global::umbraco.BusinessLogic.User(0)) + "</p><p><a href='#' onclick='" + ClientTools.Scripts.CloseModalWindow() + "'>" + ui.Text("closeThisWindow") + "</a>";
diffPanel.Visible = false;
pl_buttons.Visible = false;
ClientTools.ReloadLocationIfMatched(string.Format("/content/content/edit/{0}", d.Id));
}
}
}
@@ -52,7 +52,8 @@ namespace umbraco.BasePages
public static string ReloadContentFrameUrlIfPathLoaded(string url) {
return string.Format(ClientMgrScript + ".reloadContentFrameUrlIfPathLoaded('{0}');", url);
}
public static string ReloadLocation { get { return string.Format(ClientMgrScript + ".reloadLocation();"); } }
public static string ReloadLocation { get { return ClientMgrScript + ".reloadLocation();"; } }
public static string ReloadLocationIfMatched { get { return ClientMgrScript + ".reloadLocation('{0}');"; } }
public static string ChildNodeCreated = GetMainTree + ".childNodeCreated();";
public static string SyncTree { get { return GetMainTree + ".syncTree('{0}', {1});"; } }
public static string ClearTreeCache { get { return GetMainTree + ".clearTreeCache();"; } }
@@ -277,21 +278,33 @@ namespace umbraco.BasePages
RegisterClientScript(string.Format(Scripts.ReloadActionNode, (!reselect).ToString().ToLower(), (!reloadChildren).ToString().ToLower()));
return this;
}
/// <summary>
/// When the application searches for a node, it searches for nodes in specific tree types.
/// If SyncTree is used, it will sync the tree nodes with the active tree type, therefore if
/// a developer wants to sync a specific tree, they can call this method to set the type to sync.
/// </summary>
/// <remarks>
/// Each branch of a particular tree should theoretically be the same type, however, developers can
/// override the type of each branch in their BaseTree's but this is not standard practice. If there
/// are multiple types of branches in one tree, then only those branches that have the Active tree type
/// will be searched for syncing.
/// </remarks>
/// <param name="treeType"></param>
/// <returns></returns>
public ClientTools SetActiveTreeType(string treeType)
public ClientTools ReloadLocationIfMatched(string routePath)
{
RegisterClientScript(string.Format(Scripts.ReloadLocationIfMatched, routePath));
return this;
}
public ClientTools ReloadLocation()
{
RegisterClientScript(Scripts.ReloadLocation);
return this;
}
/// <summary>
/// When the application searches for a node, it searches for nodes in specific tree types.
/// If SyncTree is used, it will sync the tree nodes with the active tree type, therefore if
/// a developer wants to sync a specific tree, they can call this method to set the type to sync.
/// </summary>
/// <remarks>
/// Each branch of a particular tree should theoretically be the same type, however, developers can
/// override the type of each branch in their BaseTree's but this is not standard practice. If there
/// are multiple types of branches in one tree, then only those branches that have the Active tree type
/// will be searched for syncing.
/// </remarks>
/// <param name="treeType"></param>
/// <returns></returns>
public ClientTools SetActiveTreeType(string treeType)
{
RegisterClientScript(string.Format(Scripts.SetActiveTreeType, treeType));
return this;
+3 -4
View File
@@ -276,13 +276,12 @@ namespace umbraco.cms.businesslogic
{
if (_version == Guid.Empty)
{
string sql = "Select versionId from cmsContentVersion where contentID = " + this.Id +
" order by id desc ";
var sql = string.Format("SELECT versionId FROM cmsDocument where nodeid={0} AND newest = 1 ORDER BY updateDate desc", this.Id);
using (var sqlHelper = Application.SqlHelper)
using (IRecordsReader dr = sqlHelper.ExecuteReader(sql))
{
if (!dr.Read())
if (dr.Read() == false)
_version = Guid.Empty;
else
_version = dr.GetGuid("versionId");