Merge pull request #5209 from umbraco/v8/feature/4940-save-media-reference-instead-of-media-url
Save media reference instead of media url
This commit is contained in:
@@ -6,6 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade
|
||||
{
|
||||
@@ -139,6 +140,7 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
|
||||
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
|
||||
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
|
||||
To<ConvertTinyMceAndGridMediaUrlsToLocalLink>("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}");
|
||||
|
||||
//FINAL
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Migrations.PostMigrations;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
{
|
||||
public class ConvertTinyMceAndGridMediaUrlsToLocalLink : MigrationBase
|
||||
{
|
||||
private readonly IMediaService _mediaService;
|
||||
|
||||
public ConvertTinyMceAndGridMediaUrlsToLocalLink(IMigrationContext context, IMediaService mediaService) : base(context)
|
||||
{
|
||||
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
|
||||
}
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
var mediaLinkPattern = new Regex(
|
||||
@"(<a[^>]*href="")(\/ media[^""\?]*)([^>]*>)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
var sqlPropertyData = Sql()
|
||||
.Select<PropertyDataDto>()
|
||||
.AndSelect<PropertyTypeDto>()
|
||||
.AndSelect<DataTypeDto>()
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
|
||||
.Where<DataTypeDto>(x =>
|
||||
x.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce ||
|
||||
x.EditorAlias == Constants.PropertyEditors.Aliases.Grid);
|
||||
|
||||
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var value = property.TextValue;
|
||||
if (string.IsNullOrWhiteSpace(value)) continue;
|
||||
|
||||
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
|
||||
{
|
||||
var obj = JsonConvert.DeserializeObject<JObject>(value);
|
||||
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
|
||||
|
||||
foreach (var control in allControls.SelectMany(c => c))
|
||||
{
|
||||
var controlValue = control["value"];
|
||||
if (controlValue.Type == JTokenType.String)
|
||||
{
|
||||
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
|
||||
}
|
||||
}
|
||||
|
||||
property.TextValue = JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value);
|
||||
}
|
||||
|
||||
Database.Update(property);
|
||||
}
|
||||
|
||||
Context.AddPostMigration<RebuildPublishedSnapshot>();
|
||||
}
|
||||
|
||||
private string UpdateMediaUrls(Regex mediaLinkPattern, string value)
|
||||
{
|
||||
return mediaLinkPattern.Replace(value, match =>
|
||||
{
|
||||
// match groups:
|
||||
// - 1 = from the beginning of the a tag until href attribute value begins
|
||||
// - 2 = the href attribute value excluding the querystring (if present)
|
||||
// - 3 = anything after group 2 until the a tag is closed
|
||||
var href = match.Groups[2].Value;
|
||||
|
||||
var media = _mediaService.GetMediaByPath(href);
|
||||
return media == null
|
||||
? match.Value
|
||||
: $"{match.Groups[1].Value}/{{localLink:{media.GetUdi()}}}{match.Groups[3].Value}";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,6 +219,7 @@
|
||||
<Compile Include="Mapping\MapDefinitionCollectionBuilder.cs" />
|
||||
<Compile Include="Mapping\IMapDefinition.cs" />
|
||||
<Compile Include="Mapping\UmbracoMapper.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs" />
|
||||
<Compile Include="Models\CultureImpact.cs" />
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
|
||||
|
||||
@@ -61,10 +61,12 @@ namespace Umbraco.Tests.Web
|
||||
|
||||
[TestCase("", "")]
|
||||
[TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/media/1001/my-image.jpg\" world ")]
|
||||
//this one has an invalid char so won't match
|
||||
[TestCase("hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")]
|
||||
public void ParseLocalLinks(string input, string result)
|
||||
{
|
||||
var serviceCtxMock = new TestObjects(null).GetServiceContextMock();
|
||||
@@ -77,7 +79,7 @@ namespace Umbraco.Tests.Web
|
||||
// return Attempt.Succeed(1234);
|
||||
// });
|
||||
|
||||
//setup a mock url provider which we'll use fo rtesting
|
||||
//setup a mock url provider which we'll use for testing
|
||||
var testUrlProvider = new Mock<IUrlProvider>();
|
||||
testUrlProvider
|
||||
.Setup(x => x.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
@@ -96,6 +98,10 @@ namespace Umbraco.Tests.Web
|
||||
Mock.Get(snapshot).Setup(x => x.Content).Returns(contentCache);
|
||||
var snapshotService = Mock.Of<IPublishedSnapshotService>();
|
||||
Mock.Get(snapshotService).Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(snapshot);
|
||||
var media = Mock.Of<IPublishedContent>();
|
||||
Mock.Get(media).Setup(x => x.Url).Returns("/media/1001/my-image.jpg");
|
||||
var mediaCache = Mock.Of<IPublishedMediaCache>();
|
||||
Mock.Get(mediaCache).Setup(x => x.GetById(It.IsAny<Guid>())).Returns(media);
|
||||
|
||||
var umbracoContextFactory = new UmbracoContextFactory(
|
||||
Umbraco.Web.Composing.Current.UmbracoContextAccessor,
|
||||
@@ -110,7 +116,7 @@ namespace Umbraco.Tests.Web
|
||||
|
||||
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
|
||||
{
|
||||
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider);
|
||||
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider, mediaCache);
|
||||
|
||||
Assert.AreEqual(result, output);
|
||||
}
|
||||
|
||||
@@ -431,6 +431,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
} else {
|
||||
//Considering these fixed because UDI will now be used and thus
|
||||
// we have no need for rel http://issues.umbraco.org/issue/U4-6228, http://issues.umbraco.org/issue/U4-6595
|
||||
//TODO: Kill rel attribute
|
||||
data["rel"] = img.id;
|
||||
data["data-id"] = img.id;
|
||||
}
|
||||
@@ -964,12 +965,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
rel: target.rel ? target.rel : null
|
||||
};
|
||||
|
||||
if (hasUdi) {
|
||||
a["data-udi"] = target.udi;
|
||||
} else if (target.id) {
|
||||
a["data-id"] = target.id;
|
||||
}
|
||||
|
||||
if (target.anchor) {
|
||||
a["data-anchor"] = target.anchor;
|
||||
a.href = a.href + target.anchor;
|
||||
@@ -996,8 +991,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
return;
|
||||
}
|
||||
|
||||
//if we have an id, it must be a locallink:id, aslong as the isMedia flag is not set
|
||||
if (id && (angular.isUndefined(target.isMedia) || !target.isMedia)) {
|
||||
//if we have an id, it must be a locallink:id
|
||||
if (id) {
|
||||
|
||||
href = "/{localLink:" + id + "}";
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.udiParser
|
||||
* @description A object used to parse UDIs
|
||||
**/
|
||||
function udiParser() {
|
||||
return {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.udiParser#parse
|
||||
* @methodOf umbraco.services.udiParser
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Converts the string representation of an entity identifier into the equivalent Udi instance.
|
||||
*
|
||||
* @param {string} input The string to parse
|
||||
* @returns {Object} The parsed UDI or null if input isn't a valid UDI
|
||||
*/
|
||||
parse: function(input) {
|
||||
if (!input || typeof input !== "string" || !input.startsWith("umb://"))
|
||||
return null;
|
||||
|
||||
var lastIndexOfSlash = input.substring("umb://".length).lastIndexOf("/");
|
||||
|
||||
var entityType = lastIndexOfSlash === -1 ? input.substring("umb://".length) : input.substr("umb://".length, lastIndexOfSlash);
|
||||
var value = lastIndexOfSlash === -1 ? null : input.substring("umb://".length + lastIndexOfSlash + 1);
|
||||
|
||||
return {
|
||||
entityType,
|
||||
value,
|
||||
|
||||
toString: function() {
|
||||
return "umb://" + entityType + (value === null ? "" : "/" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco.services").factory("udiParser", udiParser);
|
||||
|
||||
})();
|
||||
@@ -1,6 +1,6 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
|
||||
function ($scope, eventsService, entityResource, contentResource, mediaHelper, userService, localizationService, tinyMceService, editorService) {
|
||||
function ($scope, eventsService, entityResource, contentResource, mediaResource, mediaHelper, udiParser, userService, localizationService, tinyMceService, editorService) {
|
||||
|
||||
var vm = this;
|
||||
var dialogOptions = $scope.model;
|
||||
@@ -66,8 +66,22 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
|
||||
//will be either a udi or an int
|
||||
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
|
||||
|
||||
// is it a content link?
|
||||
if (!$scope.model.target.isMedia) {
|
||||
if ($scope.model.target.udi) {
|
||||
// extract the entity type from the udi and set target.isMedia accordingly
|
||||
var udi = udiParser.parse(id);
|
||||
|
||||
if (udi && udi.entityType === "media") {
|
||||
$scope.model.target.isMedia = true;
|
||||
} else {
|
||||
delete $scope.model.target.isMedia;
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.model.target.isMedia) {
|
||||
mediaResource.getById(id).then(function (resp) {
|
||||
$scope.model.target.url = resp.mediaLink;
|
||||
});
|
||||
} else {
|
||||
// get the content path
|
||||
entityResource.getPath(id, "Document").then(function (path) {
|
||||
$scope.model.target.path = path;
|
||||
@@ -96,9 +110,9 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
|
||||
}
|
||||
}
|
||||
|
||||
// need to translate the link target ("_blank" or "") into a boolean value for umb-checkbox
|
||||
// need to translate the link target ("_blank" or "") into a boolean value for umb-checkbox
|
||||
vm.openInNewWindow = $scope.model.target.target === "_blank";
|
||||
}
|
||||
}
|
||||
else if (dialogOptions.anchors) {
|
||||
$scope.anchorValues = dialogOptions.anchors;
|
||||
}
|
||||
|
||||
@@ -64,8 +64,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
var target = link ? {
|
||||
name: link.name,
|
||||
anchor: link.queryString,
|
||||
// the linkPicker breaks if it get an udi for media
|
||||
udi: link.isMedia ? null : link.udi,
|
||||
udi: link.udi,
|
||||
url: link.url,
|
||||
target: link.target
|
||||
} : null;
|
||||
@@ -80,21 +79,13 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
model.target.anchor = (model.target.anchor.indexOf('=') === -1 ? '#' : '?') + model.target.anchor;
|
||||
}
|
||||
if (link) {
|
||||
if (link.isMedia && link.url === model.target.url) {
|
||||
// we can assume the existing media item is changed and no new file has been selected
|
||||
// so we don't need to update the udi and isMedia fields
|
||||
} else {
|
||||
link.udi = model.target.udi;
|
||||
link.isMedia = model.target.isMedia;
|
||||
}
|
||||
|
||||
link.udi = model.target.udi;
|
||||
link.name = model.target.name || model.target.url || model.target.anchor;
|
||||
link.queryString = model.target.anchor;
|
||||
link.target = model.target.target;
|
||||
link.url = model.target.url;
|
||||
} else {
|
||||
link = {
|
||||
isMedia: model.target.isMedia,
|
||||
name: model.target.name || model.target.url || model.target.anchor,
|
||||
queryString: model.target.anchor,
|
||||
target: model.target.target,
|
||||
@@ -105,7 +96,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
}
|
||||
|
||||
if (link.udi) {
|
||||
var entityType = link.isMedia ? "media" : "document";
|
||||
var entityType = model.target.isMedia ? "Media" : "Document";
|
||||
|
||||
entityResource.getById(link.udi, entityType).then(function (data) {
|
||||
link.icon = iconHelper.convertFromLegacyIcon(data.icon);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
describe("udiParser tests", function () {
|
||||
|
||||
var udiParser;
|
||||
|
||||
beforeEach(module('umbraco.services'));
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
udiParser = $injector.get('udiParser');
|
||||
}));
|
||||
|
||||
describe("Parse UDI", function () {
|
||||
it("can parse a valid document UDI", function() {
|
||||
var entityType = "document";
|
||||
var key = "c0a62ced-6402-4025-8d46-a234a34f6a56";
|
||||
var value = "umb://" + entityType + "/" + key;
|
||||
|
||||
var udi = udiParser.parse(value);
|
||||
|
||||
expect(udi.entityType).toBe(entityType);
|
||||
expect(udi.value).toBe(key);
|
||||
});
|
||||
|
||||
it("can parse a valid media UDI", function() {
|
||||
var entityType = "media";
|
||||
var key = "f82f3313-f8e9-42b0-a67f-80a7f452dd21";
|
||||
var value = "umb://" + entityType + "/" + key;
|
||||
|
||||
var udi = udiParser.parse(value);
|
||||
|
||||
expect(udi.entityType).toBe(entityType);
|
||||
expect(udi.value).toBe(key);
|
||||
});
|
||||
|
||||
it("returns the full UDI when calling toString() on the returned value", function() {
|
||||
var value = "umb://document/c0a62ced-6402-4025-8d46-a234a34f6a56";
|
||||
|
||||
var udi = udiParser.parse(value);
|
||||
|
||||
expect(udi.toString()).toBe(value);
|
||||
});
|
||||
|
||||
it("can parse an open UDI", function() {
|
||||
var entityType = "media";
|
||||
var value = "umb://" + entityType;
|
||||
|
||||
var udi = udiParser.parse(value);
|
||||
|
||||
expect(udi.entityType).toBe(entityType);
|
||||
expect(udi.value).toBeNull();
|
||||
expect(udi.toString()).toBe(value);
|
||||
});
|
||||
|
||||
it("returns null if the input is invalid", function() {
|
||||
var value = "not an UDI";
|
||||
|
||||
var udi = udiParser.parse(value);
|
||||
|
||||
expect(udi).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -9,9 +9,6 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "icon")]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[DataMember(Name = "isMedia")]
|
||||
public bool IsMedia { get; set; }
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
GuidUdi udi = null;
|
||||
var icon = "icon-link";
|
||||
var isMedia = false;
|
||||
var published = true;
|
||||
var trashed = false;
|
||||
var url = dto.Url;
|
||||
@@ -88,7 +87,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
else if(entity is IContentEntitySlim contentEntity)
|
||||
{
|
||||
icon = contentEntity.ContentTypeIcon;
|
||||
isMedia = true;
|
||||
published = !contentEntity.Trashed;
|
||||
udi = new GuidUdi(Constants.UdiEntityType.Media, contentEntity.Key);
|
||||
url = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(entity.Key)?.Url ?? "#";
|
||||
@@ -104,7 +102,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
result.Add(new LinkDisplay
|
||||
{
|
||||
Icon = icon,
|
||||
IsMedia = isMedia,
|
||||
Name = dto.Name,
|
||||
Target = dto.Target,
|
||||
Trashed = trashed,
|
||||
|
||||
@@ -4,6 +4,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Templates
|
||||
@@ -32,9 +33,14 @@ namespace Umbraco.Web.Templates
|
||||
/// <param name="text"></param>
|
||||
/// <param name="urlProvider"></param>
|
||||
/// <returns></returns>
|
||||
public static string ParseInternalLinks(string text, UrlProvider urlProvider)
|
||||
public static string ParseInternalLinks(string text, UrlProvider urlProvider) =>
|
||||
ParseInternalLinks(text, urlProvider, Current.UmbracoContext.MediaCache);
|
||||
|
||||
// TODO: Replace mediaCache with media url provider
|
||||
internal static string ParseInternalLinks(string text, UrlProvider urlProvider, IPublishedMediaCache mediaCache)
|
||||
{
|
||||
if (urlProvider == null) throw new ArgumentNullException("urlProvider");
|
||||
if (urlProvider == null) throw new ArgumentNullException(nameof(urlProvider));
|
||||
if (mediaCache == null) throw new ArgumentNullException(nameof(mediaCache));
|
||||
|
||||
// Parse internal links
|
||||
var tags = LocalLinkPattern.Matches(text);
|
||||
@@ -45,18 +51,25 @@ namespace Umbraco.Web.Templates
|
||||
var id = tag.Groups[1].Value; //.Remove(tag.Groups[1].Value.Length - 1, 1);
|
||||
|
||||
//The id could be an int or a UDI
|
||||
Udi udi;
|
||||
if (Udi.TryParse(id, out udi))
|
||||
if (Udi.TryParse(id, out var udi))
|
||||
{
|
||||
var guidUdi = udi as GuidUdi;
|
||||
if (guidUdi != null)
|
||||
{
|
||||
var newLink = urlProvider.GetUrl(guidUdi.Guid);
|
||||
var newLink = "#";
|
||||
if (guidUdi.EntityType == Constants.UdiEntityType.Document)
|
||||
newLink = urlProvider.GetUrl(guidUdi.Guid);
|
||||
else if (guidUdi.EntityType == Constants.UdiEntityType.Media)
|
||||
newLink = mediaCache.GetById(guidUdi.Guid)?.Url;
|
||||
|
||||
if (newLink == null)
|
||||
newLink = "#";
|
||||
|
||||
text = text.Replace(tag.Value, "href=\"" + newLink);
|
||||
}
|
||||
}
|
||||
int intId;
|
||||
if (int.TryParse(id, out intId))
|
||||
|
||||
if (int.TryParse(id, out var intId))
|
||||
{
|
||||
var newLink = urlProvider.GetUrl(intId);
|
||||
text = text.Replace(tag.Value, "href=\"" + newLink);
|
||||
|
||||
Reference in New Issue
Block a user