2025-01-31 10:31:06 +01:00
using System.Collections.Frozen ;
2023-03-28 10:18:41 +02:00
using System.Diagnostics ;
2021-02-18 11:06:02 +01:00
using System.Globalization ;
2020-08-23 23:36:48 +02:00
using Microsoft.Extensions.Options ;
2021-02-18 11:06:02 +01:00
using Umbraco.Cms.Core.Configuration.Models ;
using Umbraco.Extensions ;
2018-06-29 19:52:40 +02:00
2021-02-18 11:06:02 +01:00
namespace Umbraco.Cms.Core.Strings
2018-06-29 19:52:40 +02:00
{
/// <summary>
2020-10-05 20:48:38 +02:00
/// New default implementation of string functions for short strings such as aliases or URL segments.
2018-06-29 19:52:40 +02:00
/// </summary>
/// <remarks>
/// <para>Not optimized to work on large bodies of text.</para>
/// <para>Meant to replace <c>LegacyShortStringHelper</c> where/when backward compatibility is not an issue.</para>
/// <para>NOTE: pre-filters run _before_ the string is re-encoded.</para>
/// </remarks>
public class DefaultShortStringHelper : IShortStringHelper
{
#region Ctor , consts and vars
2025-12-13 01:55:26 +00:00
public DefaultShortStringHelper ( IOptions < RequestHandlerSettings > settings , IUtf8ToAsciiConverter asciiConverter )
2018-06-29 19:52:40 +02:00
{
2020-08-23 23:36:48 +02:00
_config = new DefaultShortStringHelperConfig ( ) . WithDefault ( settings . Value ) ;
2025-12-13 01:55:26 +00:00
_asciiConverter = asciiConverter ;
2018-06-29 19:52:40 +02:00
}
// clones the config so it cannot be changed at runtime
2025-12-13 01:55:26 +00:00
public DefaultShortStringHelper ( DefaultShortStringHelperConfig config , IUtf8ToAsciiConverter asciiConverter )
2018-06-29 19:52:40 +02:00
{
_config = config . Clone ( ) ;
2025-12-13 01:55:26 +00:00
_asciiConverter = asciiConverter ;
2018-06-29 19:52:40 +02:00
}
// see notes for CleanAsciiString
//// beware! the order is quite important here!
//const string ValidStringCharactersSource = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//readonly static char[] ValidStringCharacters;
private readonly DefaultShortStringHelperConfig _config ;
2025-12-13 01:55:26 +00:00
private readonly IUtf8ToAsciiConverter _asciiConverter ;
2018-06-29 19:52:40 +02:00
// see notes for CleanAsciiString
//static DefaultShortStringHelper()
//{
// ValidStringCharacters = ValidStringCharactersSource.ToCharArray();
//}
#endregion
#region Filters
2019-01-22 18:03:39 -05:00
// ok to be static here because it's not configurable in any way
2025-01-31 10:31:06 +01:00
private static readonly FrozenSet < char > InvalidFileNameChars =
2018-06-29 19:52:40 +02:00
Path . GetInvalidFileNameChars ( )
. Union ( "!*'();:@&=+$,/?%#[]-~{}\"<>\\^`| " . ToCharArray ( ) )
. Distinct ( )
2025-01-31 10:31:06 +01:00
. ToFrozenSet ( ) ;
2018-06-29 19:52:40 +02:00
public static bool IsValidFileNameChar ( char c )
{
return InvalidFileNameChars . Contains ( c ) = = false ;
}
#endregion
#region IShortStringHelper CleanFor . . .
/// <summary>
/// Cleans a string to produce a string that can safely be used in an alias.
/// </summary>
/// <param name="text">The text to filter.</param>
/// <returns>The safe alias.</returns>
/// <remarks>
/// <para>The string will be cleaned in the context of the default culture.</para>
/// <para>Safe aliases are Ascii only.</para>
/// </remarks>
public virtual string CleanStringForSafeAlias ( string text )
{
return CleanStringForSafeAlias ( text , _config . DefaultCulture ) ;
}
/// <summary>
/// Cleans a string, in the context of a specified culture, to produce a string that can safely be used in an alias.
/// </summary>
/// <param name="text">The text to filter.</param>
/// <param name="culture">The culture.</param>
/// <returns>The safe alias.</returns>
/// <remarks>
/// <para>Safe aliases are Ascii only.</para>
/// </remarks>
public virtual string CleanStringForSafeAlias ( string text , string culture )
{
return CleanString ( text , CleanStringType . Alias , culture ) ;
}
/// <summary>
2020-10-05 20:48:38 +02:00
/// Cleans a string to produce a string that can safely be used in an URL segment.
2018-06-29 19:52:40 +02:00
/// </summary>
/// <param name="text">The text to filter.</param>
2020-10-05 20:48:38 +02:00
/// <returns>The safe URL segment.</returns>
2018-06-29 19:52:40 +02:00
/// <remarks>
/// <para>The string will be cleaned in the context of the default culture.</para>
/// <para>Url segments are Ascii only (no accents...).</para>
/// </remarks>
public virtual string CleanStringForUrlSegment ( string text )
{
return CleanStringForUrlSegment ( text , _config . DefaultCulture ) ;
}
/// <summary>
2020-10-05 20:48:38 +02:00
/// Cleans a string, in the context of a specified culture, to produce a string that can safely be used in an URL segment.
2018-06-29 19:52:40 +02:00
/// </summary>
/// <param name="text">The text to filter.</param>
/// <param name="culture">The culture.</param>
2020-10-05 20:48:38 +02:00
/// <returns>The safe URL segment.</returns>
2018-06-29 19:52:40 +02:00
/// <remarks>
/// <para>Url segments are Ascii only (no accents...).</para>
/// </remarks>
2022-01-21 11:43:58 +01:00
public virtual string CleanStringForUrlSegment ( string text , string? culture )
2018-06-29 19:52:40 +02:00
{
return CleanString ( text , CleanStringType . UrlSegment , culture ) ;
}
/// <summary>
/// Cleans a string, in the context of the default culture, to produce a string that can safely be used as a filename,
2020-10-05 20:48:38 +02:00
/// both internally (on disk) and externally (as a URL).
2018-06-29 19:52:40 +02:00
/// </summary>
/// <param name="text">The text to filter.</param>
/// <returns>The safe filename.</returns>
/// <remarks>Legacy says this was used to "overcome an issue when Umbraco is used in IE in an intranet environment" but that issue is not documented.</remarks>
public virtual string CleanStringForSafeFileName ( string text )
{
return CleanStringForSafeFileName ( text , _config . DefaultCulture ) ;
}
/// <summary>
/// Cleans a string to produce a string that can safely be used as a filename,
2020-10-05 20:48:38 +02:00
/// both internally (on disk) and externally (as a URL).
2018-06-29 19:52:40 +02:00
/// </summary>
/// <param name="text">The text to filter.</param>
/// <param name="culture">The culture.</param>
/// <returns>The safe filename.</returns>
public virtual string CleanStringForSafeFileName ( string text , string culture )
{
if ( string . IsNullOrWhiteSpace ( text ) )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
return string . Empty ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
2022-06-07 15:28:38 +02:00
culture = culture ? ? string . Empty ;
2018-06-29 19:52:40 +02:00
text = text . ReplaceMany ( Path . GetInvalidFileNameChars ( ) , '-' ) ;
var name = Path . GetFileNameWithoutExtension ( text ) ;
var ext = Path . GetExtension ( text ) ; // includes the dot, empty if no extension
Debug . Assert ( name ! = null , "name != null" ) ;
if ( name . Length > 0 )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
name = CleanString ( name , CleanStringType . FileName , culture ) ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
Debug . Assert ( ext ! = null , "ext != null" ) ;
if ( ext . Length > 0 )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
ext = CleanString ( ext . Substring ( 1 ) , CleanStringType . FileName , culture ) ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
2022-06-07 15:28:38 +02:00
return ext . Length > 0 ? name + "." + ext : name ;
2018-06-29 19:52:40 +02:00
}
#endregion
#region CleanString
// MS rules & guidelines:
// - Do capitalize both characters of two-character acronyms, except the first word of a camel-cased identifier.
// eg "DBRate" (pascal) or "ioHelper" (camel) - "SpecialDBRate" (pascal) or "specialIOHelper" (camel)
// - Do capitalize only the first character of acronyms with three or more characters, except the first word of a camel-cased identifier.
// eg "XmlWriter (pascal) or "htmlReader" (camel) - "SpecialXmlWriter" (pascal) or "specialHtmlReader" (camel)
// - Do not capitalize any of the characters of any acronyms, whatever their length, at the beginning of a camel-cased identifier.
// eg "xmlWriter" or "dbWriter" (camel)
//
// Our additional stuff:
// - Leading digits are removed.
// - Many consecutive separators are folded into one unique separator.
private const byte StateBreak = 1 ;
private const byte StateUp = 2 ;
private const byte StateWord = 3 ;
private const byte StateAcronym = 4 ;
/// <summary>
/// Cleans a string.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <returns>The clean string.</returns>
/// <remarks>The string is cleaned in the context of the default culture.</remarks>
2022-06-07 15:28:38 +02:00
public string CleanString ( string text , CleanStringType stringType ) = > CleanString ( text , stringType , _config . DefaultCulture , null ) ;
2018-06-29 19:52:40 +02:00
/// <summary>
/// Cleans a string, using a specified separator.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <param name="separator">The separator.</param>
/// <returns>The clean string.</returns>
/// <remarks>The string is cleaned in the context of the default culture.</remarks>
2022-06-07 15:28:38 +02:00
public string CleanString ( string text , CleanStringType stringType , char separator ) = > CleanString ( text , stringType , _config . DefaultCulture , separator ) ;
2018-06-29 19:52:40 +02:00
/// <summary>
/// Cleans a string in the context of a specified culture.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <param name="culture">The culture.</param>
/// <returns>The clean string.</returns>
2022-01-21 11:43:58 +01:00
public string CleanString ( string text , CleanStringType stringType , string? culture )
2018-06-29 19:52:40 +02:00
{
return CleanString ( text , stringType , culture , null ) ;
}
/// <summary>
/// Cleans a string in the context of a specified culture, using a specified separator.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <param name="separator">The separator.</param>
/// <param name="culture">The culture.</param>
/// <returns>The clean string.</returns>
public string CleanString ( string text , CleanStringType stringType , char separator , string culture )
{
return CleanString ( text , stringType , culture , separator ) ;
}
2022-01-21 11:43:58 +01:00
protected virtual string CleanString ( string text , CleanStringType stringType , string? culture , char? separator )
2018-06-29 19:52:40 +02:00
{
// be safe
2022-06-07 15:28:38 +02:00
if ( text = = null )
{
throw new ArgumentNullException ( nameof ( text ) ) ;
}
culture = culture ? ? string . Empty ;
2018-06-29 19:52:40 +02:00
// get config
2022-06-07 15:28:38 +02:00
DefaultShortStringHelperConfig . Config config = _config . For ( stringType , culture ) ;
2018-06-29 19:52:40 +02:00
stringType = config . StringTypeExtend ( stringType ) ;
// apply defaults
if ( ( stringType & CleanStringType . CaseMask ) = = CleanStringType . None )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
stringType | = CleanStringType . CamelCase ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
if ( ( stringType & CleanStringType . CodeMask ) = = CleanStringType . None )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
stringType | = CleanStringType . Ascii ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
// use configured unless specified
separator = separator ? ? config . Separator ;
// apply pre-filter
if ( config . PreFilter ! = null )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
text = config . PreFilter ( text ) ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
// apply replacements
//if (config.Replacements != null)
// text = ReplaceMany(text, config.Replacements);
// recode
2022-06-07 15:28:38 +02:00
CleanStringType codeType = stringType & CleanStringType . CodeMask ;
2018-06-29 19:52:40 +02:00
switch ( codeType )
{
case CleanStringType . Ascii :
2025-12-13 01:55:26 +00:00
text = _asciiConverter . Convert ( text ) ;
2018-06-29 19:52:40 +02:00
break ;
case CleanStringType . TryAscii :
const char ESC = ( char ) 27 ;
2025-12-13 01:55:26 +00:00
var ctext = _asciiConverter . Convert ( text , ESC ) ;
2022-06-07 15:28:38 +02:00
if ( ctext . Contains ( ESC ) = = false )
{
text = ctext ;
}
2018-06-29 19:52:40 +02:00
break ;
default :
text = RemoveSurrogatePairs ( text ) ;
break ;
}
// clean
text = CleanCodeString ( text , stringType , separator . Value , culture , config ) ;
// apply post-filter
if ( config . PostFilter ! = null )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
text = config . PostFilter ( text ) ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
return text ;
}
Merge branch 'v15/dev' into v16/dev (#18971)
* Only prevent the unpublish or delete of a related item when configured to do so if it is related as a child, not as a parent (#18886)
* Only prevent the unpubkish or delete of a related item when configured to do so if it is related as a child, not as a parent.
* Fixed incorect parameter names.
* Fixed failing integration tests.
* Use using variable instead to reduce nesting
* Applied suggestions from code review.
* Used simple using statement throughout RelationService for consistency.
* Applied XML header comments consistently.
---------
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
* Feature: highlight invariant doc with variant blocks is unsupported (#18806)
* mark variant blocks in invariant docs as invalid
* implement RTE Blocks
* Fix pagination for users restricted by start nodes (#18907)
* Fix pagination for users restricted by start nodes
* Default implementation to avoid breakage
* Review comments
* Fix failing test
* Add media start node tests
* Fix issue preventing blueprint derived values from being scaffolded (#18917)
* Fix issue preventing blueprint derived values from being scaffolded.
* fix manipulating frooen array
* compare with variantId as well
---------
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* Remove admin permission on user configuration, allowing users with user section access only to manaage users and groups. (#18848)
* Tiptap RTE: Style Menu extension kind (#18918)
* Adds 'styleMenu' Tiptap toolbar extension kind
* Adds icons for `<h4>` and `<p>` tags
* Adds commands to HTML Global Attributes extension
for setting the `class` and `id` attributes.
* Renamed "default-tiptap-toolbar-element.api.ts" file
The "element" part was confusing.
* Toolbar Menu: uses correct `item` value
* Cascading Menu: adds localization for the label
* Adds `label` attribute to UUI components
for accessibility.
* Toolbar Menu: uses correct `appearance` value
* Removed unrequired `api` from Style Select
* Destructs the `item.data` object
* Ensure has children reflects only items with folder children when folders only are queried. (#18790)
* Ensure has children reflects only items with folder children when folders only are queried.
* Added supression for change to integration test public code.
---------
Co-authored-by: Migaroez <geusens@gmail.com>
* Only apply validation on content update to variant cultures where the editor has permission for the culture (#18778)
* Only apply validation on content update to variant cultures where the editor has permission for the culture.
* Remove inadvertent comment updates.
* Fixed failing integration test.
* Adds ancestor ID details on document tree and collection responses (#18909)
* Populate ancestor keys on document tree response items.
* Populate ancestor keys on document collection response items.
* Update OpenApi.json
* Use array of objects rather than Ids for the ancestor collection.
* Update OpenApi.json.
* Move publish with descendants to a background task with polling (#18497)
* Use background queue for database cache rebuild and track rebuilding status.
* Updated OpenApi.json and client-side types.
* Updated client to poll for completion of database rebuild.
* Move IBackgroundTaskQueue to core and prepare publish branch to run as background task.
* Endpoints for retrieval of status and result from branch publish operations.
* Poll and retrieve result for publish with descendants.
* Handled issues from testing.
* Rework to single controller for status and result.
* Updated client side sdk.
* OpenApi post dev merge gen
---------
Co-authored-by: Migaroez <geusens@gmail.com>
* Clear roots before rebuilding navigation dictionary (#18766)
* Clear roots before rebuilding navigation dictionary.
* Added tests to verify fix.
* Correct test implementation.
* Convert integration tests with method overloads into test cases.
* Integration test compatibility supressions.
* Fixes save of empty, invariant block list on variant content. (#18932)
* remove unnecessary code (#18927)
* V15/bugfix/fix route issue from 18859 (#18931)
* unique check
* unique for workspace empty path
* more unique routes
* Bump vite from 6.2.3 to 6.2.4 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.3 to 6.2.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.4/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.4/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 6.2.4
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
* removes autogenerated workflows
* make getHasUnpersistedChanges public (#18929)
* Added management API endpoint, service and repository for retrieval of references from the recycle bin (#18882)
* Added management API endpoint, service and repository for retrieval of references from the recycle bin.
* Update src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ReferencedByDocumentRecycleBinController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Removed unused code.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Updated management API endpoint and model for data type references to align with that used for documents, media etc. (#18905)
* Updated management API endpoint and model for data type references to align with that used for documents, media etc.
* Refactoring.
* Update src/Umbraco.Core/Constants-ReferenceTypes.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fixed typos.
* Added id to tracked reference content type response.
* Updated OpenApi.json.
* Added missing updates.
* Renamed model and constants from code review feedback.
* Fix typo
* Fix multiple enumeration
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
* Skip lock tests
* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined (#18763)
* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined.
* Added tests to verify functionality.
* Added reference to previous PR.
* Referenced second PR.
* Assemble URLs for all cultures, not just the default.
* Revert previous update.
* Display an original URL if we have one.
* Bump vite from 6.2.4 to 6.2.5 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.4 to 6.2.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.5/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.5/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 6.2.5
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
* Add raw value validation to multiple text strings property editor (#18936)
* Add raw value validation to multiple text strings property editor
* Added additional assert on unit test and comment on validation logic.
* Don't remove items to obtain a valid value
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Integration tests for content publishing with ancestor unpublished (#18941)
* Resolved warnings in test class.
* Refactor regions into partial classes.
* Aligned test names.
* Variable name refactoring.
* Added tests for unpublished paths.
* Adjust tests to verify current behaviour.
* Cleaned up project file.
* fix circular icon import (#18952)
* remove segment toggle for elements (#18949)
* Fix modal route registration circular import (#18953)
* fix modal route registration circular import
* Update modal-route-registration.controller.ts
* V15/fix/18595 (#18925)
* fix for #18595
* updates the en.ts
* Avoid unneeded Dictionary operations (#18890)
* Avoid some heap allocations
* Remove unneeded double seek
* Avoid allocating new empty arrays, reuse existing empty array
* Avoid allocating strings for parsing comma separated int values (#18199)
* Data type References UI: Workspace + Delete (#18914)
* Updated management API endpoint and model for data type references to align with that used for documents, media etc.
* Refactoring.
* Update src/Umbraco.Core/Constants-ReferenceTypes.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fixed typos.
* generate server models
* add extension slot
* register data type reference info app
* add reference data mappers
* Added id to tracked reference content type response.
* Updated OpenApi.json.
* Added missing updates.
* generate new models
* update models
* register ref item
* remove debugger
* render types
* register member type property type ref
* register media type property type ref
* Renamed model and constants from code review feedback.
* register reference workspace info app kind
* use kind for document references
* use kind for media references
* use kind for member references
* use deleteWithRelation kind when deleting data types
* fix manifest types
* fix types
* Update types.gen.ts
* update code to fit new server models
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Feature: discard changes for block workspace (#18930)
* make getHasUnpersistedChanges public
* Discard changes impl for Block Workspace
* fix 18367 (#18956)
* Merge commit from fork
* Prevent path traveral vulnerability with upload of temporary files.
* Used BadRequest instead of NotFound for invalid file name response.
* V15 QA Fixing the failing media acceptance tests (#18881)
* Fixed the function name due to test helper changes
* Updated assertion steps due to UI changes
* Added more waits
* Bumped version
* Increase timeout
* Reverted
---------
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
* V15 QA added clipboard test for not being able to copy to root when block is not allowed at root (#18937)
* Added clipboard test
* Bumped version
* Updated to use the name
* Run all tests on the pipeline
* Reverted command
* build: adjusts circular ref number to 4
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Migaroez <geusens@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com>
Co-authored-by: Henrik <hg@impact.dk>
Co-authored-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2025-04-09 09:58:01 +02:00
private static string RemoveSurrogatePairs ( string text )
2018-06-29 19:52:40 +02:00
{
2023-03-28 10:18:41 +02:00
var input = text . AsSpan ( ) ;
Span < char > output = input . Length < = 1024 ? stackalloc char [ input . Length ] : new char [ text . Length ] ;
2018-06-29 19:52:40 +02:00
var opos = 0 ;
for ( var ipos = 0 ; ipos < input . Length ; ipos + + )
{
var c = input [ ipos ] ;
if ( char . IsSurrogate ( c ) ) // ignore high surrogate
{
ipos + + ; // and skip low surrogate
output [ opos + + ] = '?' ;
}
else
{
output [ opos + + ] = c ;
}
}
2023-03-28 10:18:41 +02:00
return new string ( output ) ;
2018-06-29 19:52:40 +02:00
}
// here was a subtle, ascii-optimized version of the cleaning code, and I was
// very proud of it until benchmarking showed it was an order of magnitude slower
// that the utf8 version. Micro-optimizing sometimes isn't such a good idea.
// note: does NOT support surrogate pairs in text
internal string CleanCodeString ( string text , CleanStringType caseType , char separator , string culture , DefaultShortStringHelperConfig . Config config )
{
int opos = 0 , ipos = 0 ;
var state = StateBreak ;
2022-06-07 15:28:38 +02:00
culture = culture ? ? string . Empty ;
2018-06-29 19:52:40 +02:00
caseType & = CleanStringType . CaseMask ;
// if we apply global ToUpper or ToLower to text here
// then we cannot break words on uppercase chars
var input = text ;
// it's faster to use an array than a StringBuilder
var ilen = input . Length ;
2023-03-28 10:18:41 +02:00
var totalSize = ilen * 2 ;
Span < char > output = totalSize < = 1024 ? stackalloc char [ totalSize ] : new char [ totalSize ] ; // twice the length should be OK in all cases
2018-06-29 19:52:40 +02:00
for ( var i = 0 ; i < ilen ; i + + )
{
var c = input [ i ] ;
// leading as long as StateBreak and ipos still zero
var leading = state = = StateBreak & & ipos = = 0 ;
var isTerm = config . IsTerm ( c , leading ) ;
//var isDigit = char.IsDigit(c);
var isUpper = char . IsUpper ( c ) ; // false for digits, symbols...
//var isLower = char.IsLower(c); // false for digits, symbols...
2022-04-29 13:46:19 +02:00
// what should I do with surrogates? - E.g emojis like 🎈
// no idea, really, so they are not supported at the moment and we just continue
2018-06-29 19:52:40 +02:00
var isPair = char . IsSurrogate ( c ) ;
if ( isPair )
2022-04-29 13:46:19 +02:00
{
continue ;
}
2018-06-29 19:52:40 +02:00
switch ( state )
{
// within a break
case StateBreak :
// begin a new term if char is a term char,
// and ( pos > 0 or it's also a valid leading char )
if ( isTerm )
{
ipos = i ;
if ( opos > 0 & & separator ! = char . MinValue )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
output [ opos + + ] = separator ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
state = isUpper ? StateUp : StateWord ;
}
2022-06-07 15:28:38 +02:00
2018-06-29 19:52:40 +02:00
break ;
// within a term / word
case StateWord :
// end a term if char is not a term char,
// or ( it's uppercase and we break terms on uppercase)
if ( isTerm = = false | | ( config . BreakTermsOnUpper & & isUpper ) )
{
CopyTerm ( input , ipos , output , ref opos , i - ipos , caseType , culture , false ) ;
ipos = i ;
state = isTerm ? StateUp : StateBreak ;
if ( state ! = StateBreak & & separator ! = char . MinValue )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
output [ opos + + ] = separator ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
}
2022-06-07 15:28:38 +02:00
2018-06-29 19:52:40 +02:00
break ;
// within a term / acronym
case StateAcronym :
// end an acronym if char is not a term char,
// or if it's not uppercase / config
if ( isTerm = = false | | ( config . CutAcronymOnNonUpper & & isUpper = = false ) )
{
// whether it's part of the acronym depends on whether we're greedy
if ( isTerm & & config . GreedyAcronyms = = false )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
i - = 1 ; // handle that char again, in another state - not part of the acronym
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
if ( i - ipos > 1 ) // single-char can't be an acronym
{
CopyTerm ( input , ipos , output , ref opos , i - ipos , caseType , culture , true ) ;
ipos = i ;
state = isTerm ? StateWord : StateBreak ;
if ( state ! = StateBreak & & separator ! = char . MinValue )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
output [ opos + + ] = separator ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
}
else if ( isTerm )
{
state = StateWord ;
}
}
else if ( isUpper = = false ) // isTerm == true
{
// it's a term char and we don't cut...
// keep moving forward as a word
state = StateWord ;
}
2022-06-07 15:28:38 +02:00
2018-06-29 19:52:40 +02:00
break ;
// within a term / uppercase = could be a word or an acronym
case StateUp :
if ( isTerm )
{
// add that char to the term and pick word or acronym
state = isUpper ? StateAcronym : StateWord ;
}
else
{
// single char, copy then break
CopyTerm ( input , ipos , output , ref opos , 1 , caseType , culture , false ) ;
state = StateBreak ;
}
break ;
default :
throw new Exception ( "Invalid state." ) ;
}
}
switch ( state )
{
case StateBreak :
break ;
case StateWord :
CopyTerm ( input , ipos , output , ref opos , input . Length - ipos , caseType , culture , false ) ;
break ;
case StateAcronym :
case StateUp :
CopyTerm ( input , ipos , output , ref opos , input . Length - ipos , caseType , culture , true ) ;
break ;
default :
throw new Exception ( "Invalid state." ) ;
}
2023-03-28 10:18:41 +02:00
return new string ( output . Slice ( 0 , opos ) ) ;
2018-06-29 19:52:40 +02:00
}
// note: supports surrogate pairs in input string
2023-03-28 10:18:41 +02:00
internal void CopyTerm ( string input , int ipos , Span < char > output , ref int opos , int len , CleanStringType caseType , string culture , bool isAcronym )
2018-06-29 19:52:40 +02:00
{
var term = input . Substring ( ipos , len ) ;
2022-06-07 15:28:38 +02:00
CultureInfo cultureInfo = string . IsNullOrEmpty ( culture ) ? CultureInfo . InvariantCulture : CultureInfo . GetCultureInfo ( culture ) ;
2018-06-29 19:52:40 +02:00
if ( isAcronym )
{
if ( ( caseType = = CleanStringType . CamelCase & & len < = 2 & & opos > 0 ) | |
( caseType = = CleanStringType . PascalCase & & len < = 2 ) | |
2022-06-07 15:28:38 +02:00
caseType = = CleanStringType . UmbracoCase )
{
2018-06-29 19:52:40 +02:00
caseType = CleanStringType . Unchanged ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
}
// note: MSDN seems to imply that ToUpper or ToLower preserve the length
// of the string, but that this behavior is not guaranteed and could change.
char c ;
int i ;
string s ;
switch ( caseType )
{
//case CleanStringType.LowerCase:
//case CleanStringType.UpperCase:
case CleanStringType . Unchanged :
2023-03-28 10:18:41 +02:00
term . CopyTo ( output . Slice ( opos , len ) ) ;
2018-06-29 19:52:40 +02:00
opos + = len ;
break ;
case CleanStringType . LowerCase :
term = term . ToLower ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
term . CopyTo ( output . Slice ( opos , term . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = term . Length ;
break ;
case CleanStringType . UpperCase :
term = term . ToUpper ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
term . CopyTo ( output . Slice ( opos , term . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = term . Length ;
break ;
case CleanStringType . CamelCase :
c = term [ 0 ] ;
i = 1 ;
if ( char . IsSurrogate ( c ) )
{
s = term . Substring ( ipos , 2 ) ;
s = opos = = 0 ? s . ToLower ( cultureInfo ) : s . ToUpper ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
s . CopyTo ( output . Slice ( opos , s . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = s . Length ;
i + + ; // surrogate pair len is 2
}
else
{
output [ opos ] = opos + + = = 0 ? char . ToLower ( c , cultureInfo ) : char . ToUpper ( c , cultureInfo ) ;
}
if ( len > i )
{
term = term . Substring ( i ) . ToLower ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
term . CopyTo ( output . Slice ( opos , term . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = term . Length ;
}
break ;
case CleanStringType . PascalCase :
c = term [ 0 ] ;
i = 1 ;
if ( char . IsSurrogate ( c ) )
{
s = term . Substring ( ipos , 2 ) ;
s = s . ToUpper ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
s . CopyTo ( output . Slice ( opos , s . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = s . Length ;
i + + ; // surrogate pair len is 2
}
else
{
output [ opos + + ] = char . ToUpper ( c , cultureInfo ) ;
}
if ( len > i )
{
term = term . Substring ( i ) . ToLower ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
term . CopyTo ( output . Slice ( opos , term . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = term . Length ;
}
break ;
case CleanStringType . UmbracoCase :
c = term [ 0 ] ;
i = 1 ;
if ( char . IsSurrogate ( c ) )
{
s = term . Substring ( ipos , 2 ) ;
s = opos = = 0 ? s : s . ToUpper ( cultureInfo ) ;
2023-03-28 10:18:41 +02:00
s . CopyTo ( output . Slice ( opos , s . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = s . Length ;
i + + ; // surrogate pair len is 2
}
else
{
output [ opos ] = opos + + = = 0 ? c : char . ToUpper ( c , cultureInfo ) ;
}
if ( len > i )
{
term = term . Substring ( i ) ;
2023-03-28 10:18:41 +02:00
term . CopyTo ( output . Slice ( opos , term . Length ) ) ;
2018-06-29 19:52:40 +02:00
opos + = term . Length ;
}
break ;
default :
throw new ArgumentOutOfRangeException ( nameof ( caseType ) ) ;
}
}
#endregion
#region SplitPascalCasing
/// <summary>
/// Splits a Pascal-cased string into a phrase separated by a separator.
/// </summary>
/// <param name="text">The text to split.</param>
/// <param name="separator">The separator, which defaults to a whitespace.</param>
2019-01-22 18:03:39 -05:00
/// <returns>The split text.</returns>
2018-06-29 19:52:40 +02:00
/// <remarks>Supports Utf8 and Ascii strings, not Unicode strings.</remarks>
// NOTE does not support surrogates pairs at the moment
public virtual string SplitPascalCasing ( string text , char separator )
{
// be safe
if ( text = = null )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
throw new ArgumentNullException ( nameof ( text ) ) ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
var input = text . ToCharArray ( ) ;
Merge branch 'v15/dev' into v16/dev (#18971)
* Only prevent the unpublish or delete of a related item when configured to do so if it is related as a child, not as a parent (#18886)
* Only prevent the unpubkish or delete of a related item when configured to do so if it is related as a child, not as a parent.
* Fixed incorect parameter names.
* Fixed failing integration tests.
* Use using variable instead to reduce nesting
* Applied suggestions from code review.
* Used simple using statement throughout RelationService for consistency.
* Applied XML header comments consistently.
---------
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
* Feature: highlight invariant doc with variant blocks is unsupported (#18806)
* mark variant blocks in invariant docs as invalid
* implement RTE Blocks
* Fix pagination for users restricted by start nodes (#18907)
* Fix pagination for users restricted by start nodes
* Default implementation to avoid breakage
* Review comments
* Fix failing test
* Add media start node tests
* Fix issue preventing blueprint derived values from being scaffolded (#18917)
* Fix issue preventing blueprint derived values from being scaffolded.
* fix manipulating frooen array
* compare with variantId as well
---------
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* Remove admin permission on user configuration, allowing users with user section access only to manaage users and groups. (#18848)
* Tiptap RTE: Style Menu extension kind (#18918)
* Adds 'styleMenu' Tiptap toolbar extension kind
* Adds icons for `<h4>` and `<p>` tags
* Adds commands to HTML Global Attributes extension
for setting the `class` and `id` attributes.
* Renamed "default-tiptap-toolbar-element.api.ts" file
The "element" part was confusing.
* Toolbar Menu: uses correct `item` value
* Cascading Menu: adds localization for the label
* Adds `label` attribute to UUI components
for accessibility.
* Toolbar Menu: uses correct `appearance` value
* Removed unrequired `api` from Style Select
* Destructs the `item.data` object
* Ensure has children reflects only items with folder children when folders only are queried. (#18790)
* Ensure has children reflects only items with folder children when folders only are queried.
* Added supression for change to integration test public code.
---------
Co-authored-by: Migaroez <geusens@gmail.com>
* Only apply validation on content update to variant cultures where the editor has permission for the culture (#18778)
* Only apply validation on content update to variant cultures where the editor has permission for the culture.
* Remove inadvertent comment updates.
* Fixed failing integration test.
* Adds ancestor ID details on document tree and collection responses (#18909)
* Populate ancestor keys on document tree response items.
* Populate ancestor keys on document collection response items.
* Update OpenApi.json
* Use array of objects rather than Ids for the ancestor collection.
* Update OpenApi.json.
* Move publish with descendants to a background task with polling (#18497)
* Use background queue for database cache rebuild and track rebuilding status.
* Updated OpenApi.json and client-side types.
* Updated client to poll for completion of database rebuild.
* Move IBackgroundTaskQueue to core and prepare publish branch to run as background task.
* Endpoints for retrieval of status and result from branch publish operations.
* Poll and retrieve result for publish with descendants.
* Handled issues from testing.
* Rework to single controller for status and result.
* Updated client side sdk.
* OpenApi post dev merge gen
---------
Co-authored-by: Migaroez <geusens@gmail.com>
* Clear roots before rebuilding navigation dictionary (#18766)
* Clear roots before rebuilding navigation dictionary.
* Added tests to verify fix.
* Correct test implementation.
* Convert integration tests with method overloads into test cases.
* Integration test compatibility supressions.
* Fixes save of empty, invariant block list on variant content. (#18932)
* remove unnecessary code (#18927)
* V15/bugfix/fix route issue from 18859 (#18931)
* unique check
* unique for workspace empty path
* more unique routes
* Bump vite from 6.2.3 to 6.2.4 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.3 to 6.2.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.4/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.4/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 6.2.4
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
* removes autogenerated workflows
* make getHasUnpersistedChanges public (#18929)
* Added management API endpoint, service and repository for retrieval of references from the recycle bin (#18882)
* Added management API endpoint, service and repository for retrieval of references from the recycle bin.
* Update src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ReferencedByDocumentRecycleBinController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Removed unused code.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Updated management API endpoint and model for data type references to align with that used for documents, media etc. (#18905)
* Updated management API endpoint and model for data type references to align with that used for documents, media etc.
* Refactoring.
* Update src/Umbraco.Core/Constants-ReferenceTypes.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fixed typos.
* Added id to tracked reference content type response.
* Updated OpenApi.json.
* Added missing updates.
* Renamed model and constants from code review feedback.
* Fix typo
* Fix multiple enumeration
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
* Skip lock tests
* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined (#18763)
* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined.
* Added tests to verify functionality.
* Added reference to previous PR.
* Referenced second PR.
* Assemble URLs for all cultures, not just the default.
* Revert previous update.
* Display an original URL if we have one.
* Bump vite from 6.2.4 to 6.2.5 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.4 to 6.2.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.5/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.5/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 6.2.5
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
* Add raw value validation to multiple text strings property editor (#18936)
* Add raw value validation to multiple text strings property editor
* Added additional assert on unit test and comment on validation logic.
* Don't remove items to obtain a valid value
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Integration tests for content publishing with ancestor unpublished (#18941)
* Resolved warnings in test class.
* Refactor regions into partial classes.
* Aligned test names.
* Variable name refactoring.
* Added tests for unpublished paths.
* Adjust tests to verify current behaviour.
* Cleaned up project file.
* fix circular icon import (#18952)
* remove segment toggle for elements (#18949)
* Fix modal route registration circular import (#18953)
* fix modal route registration circular import
* Update modal-route-registration.controller.ts
* V15/fix/18595 (#18925)
* fix for #18595
* updates the en.ts
* Avoid unneeded Dictionary operations (#18890)
* Avoid some heap allocations
* Remove unneeded double seek
* Avoid allocating new empty arrays, reuse existing empty array
* Avoid allocating strings for parsing comma separated int values (#18199)
* Data type References UI: Workspace + Delete (#18914)
* Updated management API endpoint and model for data type references to align with that used for documents, media etc.
* Refactoring.
* Update src/Umbraco.Core/Constants-ReferenceTypes.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fixed typos.
* generate server models
* add extension slot
* register data type reference info app
* add reference data mappers
* Added id to tracked reference content type response.
* Updated OpenApi.json.
* Added missing updates.
* generate new models
* update models
* register ref item
* remove debugger
* render types
* register member type property type ref
* register media type property type ref
* Renamed model and constants from code review feedback.
* register reference workspace info app kind
* use kind for document references
* use kind for media references
* use kind for member references
* use deleteWithRelation kind when deleting data types
* fix manifest types
* fix types
* Update types.gen.ts
* update code to fit new server models
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Feature: discard changes for block workspace (#18930)
* make getHasUnpersistedChanges public
* Discard changes impl for Block Workspace
* fix 18367 (#18956)
* Merge commit from fork
* Prevent path traveral vulnerability with upload of temporary files.
* Used BadRequest instead of NotFound for invalid file name response.
* V15 QA Fixing the failing media acceptance tests (#18881)
* Fixed the function name due to test helper changes
* Updated assertion steps due to UI changes
* Added more waits
* Bumped version
* Increase timeout
* Reverted
---------
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
* V15 QA added clipboard test for not being able to copy to root when block is not allowed at root (#18937)
* Added clipboard test
* Bumped version
* Updated to use the name
* Run all tests on the pipeline
* Reverted command
* build: adjusts circular ref number to 4
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Migaroez <geusens@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com>
Co-authored-by: Henrik <hg@impact.dk>
Co-authored-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2025-04-09 09:58:01 +02:00
int outputLength = input . Length * 2 ;
Span < char > output = outputLength < = 1024 ? stackalloc char [ outputLength ] : new char [ outputLength ] ;
2018-06-29 19:52:40 +02:00
var opos = 0 ;
var a = input . Length > 0 ? input [ 0 ] : char . MinValue ;
var upos = char . IsUpper ( a ) ? 1 : 0 ;
for ( var i = 1 ; i < input . Length ; i + + )
{
var c = input [ i ] ;
if ( char . IsUpper ( c ) )
{
output [ opos + + ] = a ;
if ( upos = = 0 )
{
if ( opos > 0 )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
output [ opos + + ] = separator ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
upos = i + 1 ;
}
}
else
{
if ( upos > 0 )
{
if ( upos < i & & opos > 0 )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
output [ opos + + ] = separator ;
2022-06-07 15:28:38 +02:00
}
2018-06-29 19:52:40 +02:00
upos = 0 ;
}
2022-06-07 15:28:38 +02:00
2018-06-29 19:52:40 +02:00
output [ opos + + ] = a ;
}
2022-06-07 15:28:38 +02:00
2018-06-29 19:52:40 +02:00
a = c ;
}
2022-06-07 15:28:38 +02:00
2018-06-29 19:52:40 +02:00
if ( a ! = char . MinValue )
2022-06-07 15:28:38 +02:00
{
2018-06-29 19:52:40 +02:00
output [ opos + + ] = a ;
2022-06-07 15:28:38 +02:00
}
Merge branch 'v15/dev' into v16/dev (#18971)
* Only prevent the unpublish or delete of a related item when configured to do so if it is related as a child, not as a parent (#18886)
* Only prevent the unpubkish or delete of a related item when configured to do so if it is related as a child, not as a parent.
* Fixed incorect parameter names.
* Fixed failing integration tests.
* Use using variable instead to reduce nesting
* Applied suggestions from code review.
* Used simple using statement throughout RelationService for consistency.
* Applied XML header comments consistently.
---------
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
* Feature: highlight invariant doc with variant blocks is unsupported (#18806)
* mark variant blocks in invariant docs as invalid
* implement RTE Blocks
* Fix pagination for users restricted by start nodes (#18907)
* Fix pagination for users restricted by start nodes
* Default implementation to avoid breakage
* Review comments
* Fix failing test
* Add media start node tests
* Fix issue preventing blueprint derived values from being scaffolded (#18917)
* Fix issue preventing blueprint derived values from being scaffolded.
* fix manipulating frooen array
* compare with variantId as well
---------
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com
* Remove admin permission on user configuration, allowing users with user section access only to manaage users and groups. (#18848)
* Tiptap RTE: Style Menu extension kind (#18918)
* Adds 'styleMenu' Tiptap toolbar extension kind
* Adds icons for `<h4>` and `<p>` tags
* Adds commands to HTML Global Attributes extension
for setting the `class` and `id` attributes.
* Renamed "default-tiptap-toolbar-element.api.ts" file
The "element" part was confusing.
* Toolbar Menu: uses correct `item` value
* Cascading Menu: adds localization for the label
* Adds `label` attribute to UUI components
for accessibility.
* Toolbar Menu: uses correct `appearance` value
* Removed unrequired `api` from Style Select
* Destructs the `item.data` object
* Ensure has children reflects only items with folder children when folders only are queried. (#18790)
* Ensure has children reflects only items with folder children when folders only are queried.
* Added supression for change to integration test public code.
---------
Co-authored-by: Migaroez <geusens@gmail.com>
* Only apply validation on content update to variant cultures where the editor has permission for the culture (#18778)
* Only apply validation on content update to variant cultures where the editor has permission for the culture.
* Remove inadvertent comment updates.
* Fixed failing integration test.
* Adds ancestor ID details on document tree and collection responses (#18909)
* Populate ancestor keys on document tree response items.
* Populate ancestor keys on document collection response items.
* Update OpenApi.json
* Use array of objects rather than Ids for the ancestor collection.
* Update OpenApi.json.
* Move publish with descendants to a background task with polling (#18497)
* Use background queue for database cache rebuild and track rebuilding status.
* Updated OpenApi.json and client-side types.
* Updated client to poll for completion of database rebuild.
* Move IBackgroundTaskQueue to core and prepare publish branch to run as background task.
* Endpoints for retrieval of status and result from branch publish operations.
* Poll and retrieve result for publish with descendants.
* Handled issues from testing.
* Rework to single controller for status and result.
* Updated client side sdk.
* OpenApi post dev merge gen
---------
Co-authored-by: Migaroez <geusens@gmail.com>
* Clear roots before rebuilding navigation dictionary (#18766)
* Clear roots before rebuilding navigation dictionary.
* Added tests to verify fix.
* Correct test implementation.
* Convert integration tests with method overloads into test cases.
* Integration test compatibility supressions.
* Fixes save of empty, invariant block list on variant content. (#18932)
* remove unnecessary code (#18927)
* V15/bugfix/fix route issue from 18859 (#18931)
* unique check
* unique for workspace empty path
* more unique routes
* Bump vite from 6.2.3 to 6.2.4 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.3 to 6.2.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.4/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.4/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 6.2.4
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
* removes autogenerated workflows
* make getHasUnpersistedChanges public (#18929)
* Added management API endpoint, service and repository for retrieval of references from the recycle bin (#18882)
* Added management API endpoint, service and repository for retrieval of references from the recycle bin.
* Update src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ReferencedByDocumentRecycleBinController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Removed unused code.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Updated management API endpoint and model for data type references to align with that used for documents, media etc. (#18905)
* Updated management API endpoint and model for data type references to align with that used for documents, media etc.
* Refactoring.
* Update src/Umbraco.Core/Constants-ReferenceTypes.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fixed typos.
* Added id to tracked reference content type response.
* Updated OpenApi.json.
* Added missing updates.
* Renamed model and constants from code review feedback.
* Fix typo
* Fix multiple enumeration
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
* Skip lock tests
* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined (#18763)
* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined.
* Added tests to verify functionality.
* Added reference to previous PR.
* Referenced second PR.
* Assemble URLs for all cultures, not just the default.
* Revert previous update.
* Display an original URL if we have one.
* Bump vite from 6.2.4 to 6.2.5 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.4 to 6.2.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.5/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.5/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 6.2.5
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
* Add raw value validation to multiple text strings property editor (#18936)
* Add raw value validation to multiple text strings property editor
* Added additional assert on unit test and comment on validation logic.
* Don't remove items to obtain a valid value
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Integration tests for content publishing with ancestor unpublished (#18941)
* Resolved warnings in test class.
* Refactor regions into partial classes.
* Aligned test names.
* Variable name refactoring.
* Added tests for unpublished paths.
* Adjust tests to verify current behaviour.
* Cleaned up project file.
* fix circular icon import (#18952)
* remove segment toggle for elements (#18949)
* Fix modal route registration circular import (#18953)
* fix modal route registration circular import
* Update modal-route-registration.controller.ts
* V15/fix/18595 (#18925)
* fix for #18595
* updates the en.ts
* Avoid unneeded Dictionary operations (#18890)
* Avoid some heap allocations
* Remove unneeded double seek
* Avoid allocating new empty arrays, reuse existing empty array
* Avoid allocating strings for parsing comma separated int values (#18199)
* Data type References UI: Workspace + Delete (#18914)
* Updated management API endpoint and model for data type references to align with that used for documents, media etc.
* Refactoring.
* Update src/Umbraco.Core/Constants-ReferenceTypes.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fixed typos.
* generate server models
* add extension slot
* register data type reference info app
* add reference data mappers
* Added id to tracked reference content type response.
* Updated OpenApi.json.
* Added missing updates.
* generate new models
* update models
* register ref item
* remove debugger
* render types
* register member type property type ref
* register media type property type ref
* Renamed model and constants from code review feedback.
* register reference workspace info app kind
* use kind for document references
* use kind for media references
* use kind for member references
* use deleteWithRelation kind when deleting data types
* fix manifest types
* fix types
* Update types.gen.ts
* update code to fit new server models
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Feature: discard changes for block workspace (#18930)
* make getHasUnpersistedChanges public
* Discard changes impl for Block Workspace
* fix 18367 (#18956)
* Merge commit from fork
* Prevent path traveral vulnerability with upload of temporary files.
* Used BadRequest instead of NotFound for invalid file name response.
* V15 QA Fixing the failing media acceptance tests (#18881)
* Fixed the function name due to test helper changes
* Updated assertion steps due to UI changes
* Added more waits
* Bumped version
* Increase timeout
* Reverted
---------
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
* V15 QA added clipboard test for not being able to copy to root when block is not allowed at root (#18937)
* Added clipboard test
* Bumped version
* Updated to use the name
* Run all tests on the pipeline
* Reverted command
* build: adjusts circular ref number to 4
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Migaroez <geusens@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com>
Co-authored-by: Henrik <hg@impact.dk>
Co-authored-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2025-04-09 09:58:01 +02:00
return new string ( output [ . . opos ] ) ;
2018-06-29 19:52:40 +02:00
}
2020-03-12 12:46:08 +01:00
#endregion
2018-06-29 19:52:40 +02:00
}
}