diff --git a/.build/ReleaseCleanup.ps1 b/.build/ReleaseCleanup.ps1 new file mode 100644 index 0000000000..81ffb55d0a --- /dev/null +++ b/.build/ReleaseCleanup.ps1 @@ -0,0 +1,56 @@ +param ( + [string]$cleanupTargetName, + [string]$cleanupDirectory +) + +Write-Host "ReleaseCleanup script started..." +# This script deletes/rename files according to rules in ReleaseCleanupConfiguration.xml - it is used by automated builds + +if(-not($cleanupTargetName)) { Throw "You must supply a value for -cleanupTargetName - matching a target name in ReleaseCleanupConfiguration.xml" } +if(-not($cleanupDirectory)) { Throw "You must supply a value for -cleanupDirectory - this is the path where cleaning will be taking place" } + +$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition +[xml]$xml = Get-Content (Join-Path $scriptPath "ReleaseCleanupConfiguration.xml") + +$targetItems = $xml.SelectNodes("/Configuration/Target[@name='" + $cleanupTargetName + "']/*/*[@path]") + +Foreach ($fileNode in $targetItems) { + $relPath = $fileNode.Attributes["path"].Value + $fullPath = Join-Path $cleanupDirectory $relPath + + if (($fileNode.Attributes["rename-find"]) -and ($fileNode.Attributes["rename-replace"]) ) { + # if rename + Write-Host "Handling $fullPath for renaming" + + $findString = $fileNode.Attributes["rename-find"].Value.Replace("\","/") + $replaceString = $fileNode.Attributes["rename-replace"].Value + + $matches = Get-ChildItem -Path $fullPath -Recurse + + if ($matches.length -eq 0) { Write-Warning "Pattern matched 0 files - probably you should remove it from ReleaseCleanupConfiguration.xml in repo" } + + Foreach ($match in $matches) { + $name = $match.FullName.Replace("\","/") + $newName = $name.Replace($findString.Replace("\","/"), $replaceString) + + #ensure dir + $newDirPath = Split-Path -Path $newName + if (-not (Test-Path($newDirPath))) { New-Item -ItemType Directory -Force -Path $newDirPath } + Move-Item $match -Destination $newName -Force + } + } + else { + # assume delete otherwise + Write-Host "Handling $fullPath for deletion" + + if (($fileNode.Name -eq "Directory") -and (Test-Path $fullPath)) { + Remove-Item -LiteralPath $fullPath -Force -Recurse + } else { + $matches = Get-ChildItem -Path $fullPath -Recurse + + if ($matches.length -eq 0) { Write-Warning "Pattern matched 0 files - probably you should remove it from ReleaseCleanupConfiguration.xml in repo" } + + $matches | Where-Object { Test-Path($_) } | Remove-Item -Force -Recurse + } + } +} diff --git a/.build/ReleaseCleanupConfiguration.xml b/.build/ReleaseCleanupConfiguration.xml new file mode 100644 index 0000000000..7857487446 --- /dev/null +++ b/.build/ReleaseCleanupConfiguration.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Composite/C1Console/Forms/CoreUiControls/TreeSelectorUiControl.cs b/Composite/C1Console/Forms/CoreUiControls/TreeSelectorUiControl.cs new file mode 100644 index 0000000000..3741db400e --- /dev/null +++ b/Composite/C1Console/Forms/CoreUiControls/TreeSelectorUiControl.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using Composite.C1Console.Forms.Foundation; + +namespace Composite.C1Console.Forms.CoreUiControls +{ + [ControlValueProperty("SelectedKeys")] + internal abstract class TreeSelectorUiControl : UiControl + { + [BindableProperty] + [FormsProperty] + public string SelectedKey { get; set; } + + [FormsProperty] + public string ElementProvider { get; set; } + + [FormsProperty] + public string SelectableElementPropertyName { get; set; } + + [FormsProperty] + public string SelectableElementPropertyValue { get; set; } + + [FormsProperty] + public string SelectableElementReturnValue { get; set; } + + [FormsProperty] + public string SerializedSearchToken { get; set; } + + [FormsProperty] + public bool Required { get; set; } + } +} diff --git a/Composite/Composite.csproj b/Composite/Composite.csproj index 58956dd4f5..936fe0a436 100644 --- a/Composite/Composite.csproj +++ b/Composite/Composite.csproj @@ -233,6 +233,7 @@ + @@ -260,6 +261,10 @@ + + ASPXCodeBehind + + diff --git a/Composite/Core/Localization/LocalizationFacade.cs b/Composite/Core/Localization/LocalizationFacade.cs index f06c60ee2b..97225512fd 100644 --- a/Composite/Core/Localization/LocalizationFacade.cs +++ b/Composite/Core/Localization/LocalizationFacade.cs @@ -178,6 +178,19 @@ internal static void AddLocale(CultureInfo cultureInfo, string urlMappingName, b UserSettings.SetForeignLocaleCultureInfo(username, cultureInfo); } } + + List usergroupids = + (from u in DataFacade.GetData() + select u.Id).ToList(); + + foreach (Guid usergroupid in usergroupids) + { + var groupLang = DataFacade.BuildNew(); + groupLang.Id = Guid.NewGuid(); + groupLang.CultureName = cultureInfo.ToString(); + groupLang.UserGroupId = usergroupid; + DataFacade.AddNew(groupLang); + } } if (DataLocalizationFacade.DefaultLocalizationCulture == null) diff --git a/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs b/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs index afa2739080..211a723ff3 100644 --- a/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs +++ b/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs @@ -191,15 +191,18 @@ private XElement AddData(DataType dataType, CultureInfo cultureInfo) } - var dataKey = CopyFieldValues(dataType, data, addElement); + var dataKey = PopulateAndReturnKeyPropertyValues(dataType, data, addElement); if (dataType.AllowOverwrite || dataType.OnlyUpdate) { - IData existingData = DataFacade.TryGetDataByUniqueKey(interfaceType, dataKey); + List existingDataList = DataFacade.TryGetDataByLookupKeys(interfaceType, dataKey).ToList(); + if (existingDataList.Count > 1) throw new InvalidOperationException("Got more than 1 existing data element when querying on key properties for " + addElement.ToString()); + + IData existingData = existingDataList.FirstOrDefault(); if (existingData != null) { - CopyFieldValues(dataType, existingData, addElement); + PopulateAndReturnKeyPropertyValues(dataType, existingData, addElement); DataFacade.Update(existingData, false, true, false); continue; @@ -280,13 +283,16 @@ private void UpdateVersionId(IVersioned data) } } - - private static DataKeyPropertyCollection CopyFieldValues(DataType dataType, IData data, XElement addElement) + + private static DataPropertyValueCollection PopulateAndReturnKeyPropertyValues(DataType dataType, IData dataToPopulate, XElement addElement) { - var dataKeyPropertyCollection = new DataKeyPropertyCollection(); + var dataKeyPropertyCollection = new DataPropertyValueCollection(); var properties = GetDataTypeProperties(dataType.InterfaceType); + var keyPropertyNames = dataType.InterfaceType.GetKeyPropertyNames(); + var versionKeyPropertyNames = dataType.InterfaceType.GetVersionKeyPropertyNames(); + foreach (XAttribute attribute in addElement.Attributes()) { string fieldName = attribute.Name.LocalName; @@ -298,11 +304,11 @@ private static DataKeyPropertyCollection CopyFieldValues(DataType dataType, IDat PropertyInfo propertyInfo = properties[fieldName]; object fieldValue = ValueTypeConverter.Convert(attribute.Value, propertyInfo.PropertyType); - propertyInfo.SetValue(data, fieldValue, null); + propertyInfo.SetValue(dataToPopulate, fieldValue, null); - if (dataType.InterfaceType.GetKeyPropertyNames().Contains(fieldName)) + if (keyPropertyNames.Contains(fieldName) || versionKeyPropertyNames.Contains(fieldName)) { - dataKeyPropertyCollection.AddKeyProperty(fieldName, fieldValue); + dataKeyPropertyCollection.AddKeyProperty(propertyInfo, fieldValue); } } diff --git a/Composite/Data/DataFacade.cs b/Composite/Data/DataFacade.cs index 9b42e89ab7..c44e9b5a8a 100644 --- a/Composite/Data/DataFacade.cs +++ b/Composite/Data/DataFacade.cs @@ -371,7 +371,7 @@ public static IQueryable GetDataFromOtherScope(T data, DataScopeIdentifier using (new DataScope(dataScopeIdentifier)) { - return DataExpressionBuilder.GetQueryableByData(data, true); + return DataExpressionBuilder.GetQueryableByData(data); } } @@ -384,7 +384,7 @@ public static IQueryable GetDataFromOtherLocale(T data, CultureInfo cultur using (new DataScope(cultureInfo)) { - return DataExpressionBuilder.GetQueryableByData(data, true); + return DataExpressionBuilder.GetQueryableByData(data); } } @@ -397,13 +397,6 @@ public static IEnumerable GetDataFromOtherScope(IData data, DataScopeIden /// public static IEnumerable GetDataFromOtherScope( IData data, DataScopeIdentifier dataScopeIdentifier, bool useCaching) - { - return GetDataFromOtherScope(data, dataScopeIdentifier, useCaching, true); - } - - /// - public static IEnumerable GetDataFromOtherScope( - IData data, DataScopeIdentifier dataScopeIdentifier, bool useCaching, bool ignoreVersioning) { Verify.ArgumentNotNull(data, "data"); Verify.ArgumentNotNull(dataScopeIdentifier, nameof(dataScopeIdentifier)); @@ -432,7 +425,7 @@ public static IEnumerable GetDataFromOtherScope( { IQueryable table = GetData(data.DataSourceId.InterfaceType, false); - IQueryable queryable = DataExpressionBuilder.GetQueryableByData(data, table, ignoreVersioning); + IQueryable queryable = DataExpressionBuilder.GetQueryableByData(data, table); foreach (object obj in queryable) { @@ -509,7 +502,7 @@ public static LambdaExpression GetPredicateExpressionByUniqueKey(Type interfaceT // Private helper private static Expression GetPredicateExpressionByUniqueKeyFilterExpression(IReadOnlyList keyProperties, DataKeyPropertyCollection dataKeyPropertyCollection, ParameterExpression parameterExpression) { - if (keyProperties.Count != dataKeyPropertyCollection.Count) throw new ArgumentException("Missing og to many key properties"); + if (keyProperties.Count != dataKeyPropertyCollection.Count) throw new ArgumentException("Missing or too many key properties"); var propertiesWithValues = new List>(); foreach (var kvp in dataKeyPropertyCollection.KeyProperties) @@ -606,6 +599,28 @@ public static IData TryGetDataByUniqueKey(Type interfaceType, DataKeyPropertyCol return data; } + /// + /// Returns all data items of the given type, which matches the provided dataPropertyCollection (property/value pairs) + /// + /// The data type to query - type is expected to implement a subinterface of IData + /// The properties and values to use for filtering + /// Data matching the provided property values + public static IEnumerable TryGetDataByLookupKeys(Type interfaceType, DataPropertyValueCollection dataPropertyCollection) + { + Verify.ArgumentNotNull(interfaceType, nameof(interfaceType)); + Verify.ArgumentNotNull(dataPropertyCollection, nameof(dataPropertyCollection)); + + LambdaExpression lambdaExpression = GetPredicateExpression(interfaceType, dataPropertyCollection); + + MethodInfo methodInfo = GetGetDataWithPredicatMethodInfo(interfaceType); + + var queryable = (IQueryable)methodInfo.Invoke(null, new object[] { lambdaExpression }); + + return ((IEnumerable)queryable).Cast(); + } + + + /// public static IEnumerable TryGetDataVersionsByUniqueKey(Type interfaceType, DataKeyPropertyCollection dataKeyPropertyCollection) diff --git a/Composite/Data/Foundation/DataExpressionBuilder.cs b/Composite/Data/Foundation/DataExpressionBuilder.cs index 0a861aa5c2..c712392d2b 100644 --- a/Composite/Data/Foundation/DataExpressionBuilder.cs +++ b/Composite/Data/Foundation/DataExpressionBuilder.cs @@ -29,21 +29,14 @@ static DataExpressionBuilder() /// public static IQueryable GetQueryableByData(IData data) { - return GetQueryableByData(data, true); + return GetQueryableByData(data, null); } - public static IQueryable GetQueryableByData(IData data, bool ignoreVersioning) + public static IQueryable GetQueryableByData(IData data, IQueryable sourceQueryable) { - return GetQueryableByData(data, null, ignoreVersioning); - } - - - - public static IQueryable GetQueryableByData(IData data, IQueryable sourceQueryable, bool ignoreVersioning) - { - LambdaExpression whereLambdaExpression = GetWhereLambdaExpression(data, ignoreVersioning); + LambdaExpression whereLambdaExpression = GetWhereLambdaExpression(data); if (sourceQueryable == null) { @@ -59,10 +52,10 @@ public static IQueryable GetQueryableByData(IData data, IQueryable sourceQueryab - public static IQueryable GetQueryableByData(T data, bool ignoreVersioning) + public static IQueryable GetQueryableByData(T data) where T : class, IData { - LambdaExpression whereLambdaExpression = GetWhereLambdaExpression(data, ignoreVersioning); + LambdaExpression whereLambdaExpression = GetWhereLambdaExpression(data); IQueryable queryable = DataFacade.GetData(data.DataSourceId.InterfaceType); @@ -75,9 +68,9 @@ public static IQueryable GetQueryableByData(T data, bool ignoreVersioning) - public static Delegate GetWherePredicateDelegate(IData data, bool ignoreVersioning) + public static Delegate GetWherePredicateDelegate(IData data) { - LambdaExpression whereLambdaExpression = GetWhereLambdaExpression(data, ignoreVersioning); + LambdaExpression whereLambdaExpression = GetWhereLambdaExpression(data); Delegate resultDelegate = whereLambdaExpression.Compile(); @@ -86,7 +79,7 @@ public static Delegate GetWherePredicateDelegate(IData data, bool ignoreVersioni - private static LambdaExpression GetWhereLambdaExpression(IData data, bool ignoreVersioning) + private static LambdaExpression GetWhereLambdaExpression(IData data) { var propertyInfoes = data.DataSourceId.InterfaceType.GetPhysicalKeyProperties(); diff --git a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs index ff2d64def2..329cda425f 100644 --- a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs +++ b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs @@ -370,7 +370,7 @@ public List GetActions(IData data, Type elementProviderType) var clientActions = visualTrans.Select(newState => _visualTransitionsActions[newState]()).ToList(); - IData publicData = DataFacade.GetDataFromOtherScope(data, DataScopeIdentifier.Public, true, false).FirstOrDefault(); + IData publicData = DataFacade.GetDataFromOtherScope(data, DataScopeIdentifier.Public, true).FirstOrDefault(); if (publicData != null) { var unpublishAction = new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Unpublish) { DoIgnoreEntityTokenLocking = true })) diff --git a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedTreelSelectorUiControlFactory.cs b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedTreelSelectorUiControlFactory.cs new file mode 100644 index 0000000000..4fb965d3a7 --- /dev/null +++ b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedTreelSelectorUiControlFactory.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Configuration; +using System.Web.UI; +using Composite.C1Console.Forms; +using Composite.C1Console.Forms.CoreUiControls; +using Composite.C1Console.Forms.Plugins.UiControlFactory; +using Composite.C1Console.Forms.WebChannel; +using Composite.Plugins.Forms.WebChannel.Foundation; +using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; +using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder; +using Microsoft.Practices.ObjectBuilder; + + +namespace Composite.Plugins.Forms.WebChannel.UiControlFactories +{ + /// + /// + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public abstract class TreeSelectorTemplateUserControlBase : UserControl, IPostBackDataHandler + { + /// + protected abstract void BindStateToProperties(); + + /// + protected abstract void InitializeViewState(); + + /// + public abstract string GetDataFieldClientName(); + + internal void BindStateToControlProperties() + { + this.BindStateToProperties(); + } + + internal void InitializeWebViewState() + { + this.InitializeViewState(); + } + + /// + public string SelectedKey { get; set; } + + /// + public string ElementProvider { get; set; } + + /// + public string SelectableElementPropertyName { get; set; } + + /// + public string SelectableElementPropertyValue { get; set; } + + /// + public string SelectableElementReturnValue { get; set; } + + /// + public string SerializedSearchToken { get; set; } + + /// + public bool Required { get; set; } + + /// + /// When implemented by a class, processes postback data for an ASP.NET server control. + /// + /// + /// + /// + public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) + { + return false; + } + + /// + /// When implemented by a class, signals the server control to notify the ASP.NET application that the state of the control has changed. + /// + public virtual void RaisePostDataChangedEvent() + { + } + } + + + + internal sealed class TemplatedTreeSelectorUiControl : TreeSelectorUiControl, IWebUiControl + { + private readonly Type _userControlType; + private TreeSelectorTemplateUserControlBase _userControl; + + internal TemplatedTreeSelectorUiControl(Type userControlType) + { + _userControlType = userControlType; + } + + public override void BindStateToControlProperties() + { + _userControl.BindStateToControlProperties(); + + this.SelectedKey = _userControl.SelectedKey; + } + + public void InitializeViewState() + { + _userControl.InitializeWebViewState(); + } + + + public Control BuildWebControl() + { + _userControl = _userControlType.ActivateAsUserControl(this.UiControlID); + + _userControl.SelectedKey = this.SelectedKey; + _userControl.ElementProvider = this.ElementProvider; + _userControl.SelectableElementPropertyName = this.SelectableElementPropertyName; + _userControl.SelectableElementPropertyValue = this.SelectableElementPropertyValue; + _userControl.SelectableElementReturnValue = this.SelectableElementReturnValue; + _userControl.SerializedSearchToken = this.SerializedSearchToken; + _userControl.Required = this.Required; + + return _userControl; + } + + public bool IsFullWidthControl => false; + + public string ClientName => _userControl.GetDataFieldClientName(); + } + + + + [ConfigurationElementType(typeof(TemplatedTreeSelectorUiControlFactoryData))] + internal sealed class TemplatedTreeSelectorUiControlFactory : Base.BaseTemplatedUiControlFactory + { + public TemplatedTreeSelectorUiControlFactory(TemplatedTreeSelectorUiControlFactoryData data) + : base(data) + { } + + public override IUiControl CreateControl() + { + var control = new TemplatedTreeSelectorUiControl(this.UserControlType); + + return control; + } + } + + + + [Assembler(typeof(TemplatedTreeSelectorUiControlFactoryAssembler))] + internal sealed class TemplatedTreeSelectorUiControlFactoryData : UiControlFactoryData, Base.ITemplatedUiControlFactoryData + { + private const string _userControlVirtualPathPropertyName = "userControlVirtualPath"; + private const string _cacheCompiledUserControlTypePropertyName = "cacheCompiledUserControlType"; + + [ConfigurationProperty(_userControlVirtualPathPropertyName, IsRequired = true)] + public string UserControlVirtualPath + { + get { return (string)base[_userControlVirtualPathPropertyName]; } + set { base[_userControlVirtualPathPropertyName] = value; } + } + + [ConfigurationProperty(_cacheCompiledUserControlTypePropertyName, IsRequired = false, DefaultValue = true)] + public bool CacheCompiledUserControlType + { + get { return (bool)base[_cacheCompiledUserControlTypePropertyName]; } + set { base[_cacheCompiledUserControlTypePropertyName] = value; } + } + } + + + + internal sealed class TemplatedTreeSelectorUiControlFactoryAssembler : IAssembler + { + public IUiControlFactory Assemble(IBuilderContext context, UiControlFactoryData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache) + { + return new TemplatedTreeSelectorUiControlFactory( + objectConfiguration as TemplatedTreeSelectorUiControlFactoryData); + } + } +} diff --git a/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/StandardWidgetFunctionProvider.cs b/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/StandardWidgetFunctionProvider.cs index dbb52c6ffc..7e8848ef22 100644 --- a/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/StandardWidgetFunctionProvider.cs +++ b/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/StandardWidgetFunctionProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Composite.Data; @@ -90,6 +90,7 @@ private void InitializeStaticTypeFunctions() _widgetStaticTypeFunctions.Add(new TextAreaWidgetFuntion(_entityTokenFactory)); _widgetStaticTypeFunctions.Add(new String.SelectorWidgetFunction(_entityTokenFactory)); _widgetStaticTypeFunctions.Add(new String.HierarchicalSelectorWidgetFunction(_entityTokenFactory)); + _widgetStaticTypeFunctions.Add(new TreeSelectorWidgetFunction(_entityTokenFactory)); _widgetStaticTypeFunctions.Add(new DataIdMultiSelectorWidgetFunction(_entityTokenFactory)); _widgetStaticTypeFunctions.Add(new String.VisualXhtmlEditorFuntion(_entityTokenFactory)); _widgetStaticTypeFunctions.Add(new String.UrlComboBoxWidgetFunction(_entityTokenFactory)); diff --git a/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/String/TreeSelectorWidgetFunction.cs b/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/String/TreeSelectorWidgetFunction.cs new file mode 100644 index 0000000000..217dbe51a5 --- /dev/null +++ b/Composite/Plugins/Functions/WidgetFunctionProviders/StandardWidgetFunctionProvider/String/TreeSelectorWidgetFunction.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +using Composite.Functions; +using Composite.Plugins.Functions.WidgetFunctionProviders.StandardWidgetFunctionProvider.Foundation; +using Composite.C1Console.Forms.CoreUiControls; +using Composite.Core.Xml; + +namespace Composite.Plugins.Functions.WidgetFunctionProviders.StandardWidgetFunctionProvider.String +{ + internal sealed class TreeSelectorWidgetFunction : CompositeWidgetFunctionBase + { + private const string _functionName = "TreeSelector"; + public const string CompositeName = CompositeWidgetFunctionBase.CommonNamespace + ".String." + _functionName; + + public TreeSelectorWidgetFunction(EntityTokenFactory entityTokenFactory) + : base(CompositeName, typeof(string), entityTokenFactory) + { + SetParameterProfiles(); + } + + + private void SetParameterProfiles() + { + base.AddParameterProfile( + new ParameterProfile("ElementProvider", + typeof(string), + true, + new ConstantValueProvider(string.Empty), + StandardWidgetFunctions.TextBoxWidget, + null, + "Element Provider", new HelpDefinition("The name of a tree element provider (as defined in Composite.config)"))); + + base.AddParameterProfile( + new ParameterProfile("SelectableElementPropertyName", + typeof(string), + true, + new ConstantValueProvider(string.Empty), + StandardWidgetFunctions.TextBoxWidget, + null, + "Selectable Element Property Name", new HelpDefinition("The name of a property used to identify a selectable tree element by"))); + + base.AddParameterProfile( + new ParameterProfile("SelectableElementPropertyValue", + typeof(string), + false, + new ConstantValueProvider(string.Empty), + StandardWidgetFunctions.TextBoxWidget, + null, + "Selectable Element Property Value", new HelpDefinition("The value of the property optionally used (if provided) to further identify a selectable tree element by"))); + + base.AddParameterProfile( + new ParameterProfile("SelectableElementReturnValue", + typeof(string), + false, + new ConstantValueProvider(string.Empty), + StandardWidgetFunctions.TextBoxWidget, + null, + "Selectable Element Return Value", new HelpDefinition("The value to return for the selected tree element"))); + base.AddParameterProfile( + new ParameterProfile("SerializedSearchToken", + typeof(string), + false, + new ConstantValueProvider(string.Empty), + StandardWidgetFunctions.TextBoxWidget, + null, + "Selectable Element Return Value", new HelpDefinition("A search token to filter tree elements by"))); + base.AddParameterProfile( + new ParameterProfile("Required", + typeof(bool), + false, + new ConstantValueProvider(true), + StandardWidgetFunctions.GetBoolSelectorWidget("Yes, selection is required", "No, a 'none' selection is allowed."), + null, + "Required", new HelpDefinition("An option that indicates whether the user is required to make a selection"))); + + } + + + public override XElement GetWidgetMarkup(ParameterList parameters, string label, HelpDefinition helpDefinition, string bindingSourceName) + { + XElement formElement = base.BuildBasicWidgetMarkup("TreeSelector", "SelectedKey", label, helpDefinition, bindingSourceName); + foreach (var propertyName in new [] + { + "ElementProvider", "SelectableElementPropertyName", "SelectableElementPropertyValue", "SelectableElementReturnValue", "SerializedSearchToken", "Required" + }) + { + string propertyValue = parameters.GetParameter(propertyName); + formElement.Add(new XAttribute(propertyName, propertyValue)); + } + return formElement; + } + } +} diff --git a/Composite/Properties/SharedAssemblyInfo.cs b/Composite/Properties/SharedAssemblyInfo.cs index c83dfe9766..dc4329dde4 100644 --- a/Composite/Properties/SharedAssemblyInfo.cs +++ b/Composite/Properties/SharedAssemblyInfo.cs @@ -2,9 +2,9 @@ // General Information about the assemblies Composite and Composite.Workflows #if !InternalBuild -[assembly: AssemblyTitle("C1 CMS 6.7")] +[assembly: AssemblyTitle("C1 CMS 6.8")] #else -[assembly: AssemblyTitle("C1 CMS 6.7 (Internal Build)")] +[assembly: AssemblyTitle("C1 CMS 6.8 (Internal Build)")] #endif [assembly: AssemblyCompany("Orckestra Inc")] @@ -13,4 +13,4 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("6.7.*")] +[assembly: AssemblyVersion("6.8.*")] diff --git a/Package.nuspec b/Package.nuspec index 6054b350dd..5925153686 100644 --- a/Package.nuspec +++ b/Package.nuspec @@ -28,9 +28,8 @@ - - - - + + + diff --git a/Website/App_Data/Composite/DebugBuild.Composite.config b/Website/App_Data/Composite/DebugBuild.Composite.config index b444bb16eb..c1c5c02345 100644 --- a/Website/App_Data/Composite/DebugBuild.Composite.config +++ b/Website/App_Data/Composite/DebugBuild.Composite.config @@ -194,7 +194,8 @@ - + + diff --git a/Website/App_Data/Composite/ReleaseBuild.Composite.config b/Website/App_Data/Composite/ReleaseBuild.Composite.config index 112f99a63d..b257af27c6 100644 --- a/Website/App_Data/Composite/ReleaseBuild.Composite.config +++ b/Website/App_Data/Composite/ReleaseBuild.Composite.config @@ -189,7 +189,8 @@ - + + diff --git a/Website/App_Data/Composite/ReleaseBuild.Composite.config.changeHistory.txt b/Website/App_Data/Composite/ReleaseBuild.Composite.config.changeHistory.txt index 9b5c5997ea..6e456a7377 100644 --- a/Website/App_Data/Composite/ReleaseBuild.Composite.config.changeHistory.txt +++ b/Website/App_Data/Composite/ReleaseBuild.Composite.config.changeHistory.txt @@ -173,4 +173,4 @@ Changes in 6.0 or later -Added to loggingConfiguration/specialSources/allEvents/listeners Changes in 6.7 or later: - - n/a \ No newline at end of file + -Added to configuration/Composite.C1Console.Forms.Plugins.UiControlFactoryConfiguration/Channels/Channel/Namespaces/Namespace/Factories \ No newline at end of file diff --git a/Website/Composite/CompileScripts.xml b/Website/Composite/CompileScripts.xml index 6cca8a60ce..6973950b2d 100644 --- a/Website/Composite/CompileScripts.xml +++ b/Website/Composite/CompileScripts.xml @@ -1,4 +1,4 @@ - + @@ -196,6 +196,7 @@ + /> diff --git a/Website/Composite/scripts/source/top/core/ViewDefinitions.js b/Website/Composite/scripts/source/top/core/ViewDefinitions.js index 1cf01c2c8b..a24999d56a 100644 --- a/Website/Composite/scripts/source/top/core/ViewDefinitions.js +++ b/Website/Composite/scripts/source/top/core/ViewDefinitions.js @@ -436,6 +436,26 @@ var ViewDefinitions = { } }), + /* + * Stub for tree selector. + */ + "Composite.Management.TreeSelectorDialog": new DialogViewDefinition({ + handle: "Composite.Management.TreeSelectorDialog", + isMutable : true, + position: Dialog.MODAL, + url: Dialog.URL_TREESELECTOR, + argument: { + label: "", + image: "${icon:link}", + selectionProperty: "ElementType", + selectionValue: null, + selectionResult: null, + nodes: [ + { key: null } + ] + } + }), + /* * Function selector (ALL TYPES). */ diff --git a/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/DataInputDialogBinding.js b/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/DataInputDialogBinding.js index d3eae4d87f..3ebf05284a 100644 --- a/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/DataInputDialogBinding.js +++ b/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/DataInputDialogBinding.js @@ -68,12 +68,8 @@ DataInputDialogBinding.prototype.buildButton = function () { self._isButtonClicked = false; }, 1000); - var handle = self.getProperty("handle"); - var definition = ViewDefinition.clone( - handle, - "Generated.ViewDefinition.Handle." + KeyMaster.getUniqueKey() - ); + var definition = self.getDefinition(); if (definition instanceof DialogViewDefinition) { @@ -108,6 +104,22 @@ DataInputDialogBinding.prototype.buildButton = function () { this._dialogButtonBinding = button; }; +/** + * Get definition to invoke. + */ +DataInputDialogBinding.prototype.getDefinition = function () { + + var handle = this.getProperty("handle"); + + var definition = ViewDefinition.clone( + handle, + "Generated.ViewDefinition.Handle." + KeyMaster.getUniqueKey() + ); + + return definition; +}; + + /** * Invoke dialog programatically. */ diff --git a/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/TreeSelectorDialogBinding.js b/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/TreeSelectorDialogBinding.js new file mode 100644 index 0000000000..5ae041dcfa --- /dev/null +++ b/Website/Composite/scripts/source/top/ui/bindings/data/dialogs/TreeSelectorDialogBinding.js @@ -0,0 +1,53 @@ +TreeSelectorDialogBinding.prototype = new DataInputDialogBinding; +TreeSelectorDialogBinding.prototype.constructor = TreeSelectorDialogBinding; +TreeSelectorDialogBinding.superclass = DataInputDialogBinding.prototype; + +/** +* @class +* @implements {IData} +*/ +function TreeSelectorDialogBinding() { + + /** + * @type {SystemLogger} + */ + this.logger = SystemLogger.getLogger("TreeSelectorDialogBinding"); + + /** + * @type {LabelBinding} + */ + this.labelBinding = null; + + +} + +/** +* Identifies binding. +*/ +TreeSelectorDialogBinding.prototype.toString = function () { + + return "[TreeSelectorDialogBinding]"; +} + +/** + * Get definition to invoke. + * @overloads {DataInputDialogBinding#getDefinition} + */ +TreeSelectorDialogBinding.prototype.getDefinition = function () { + + var definition = ViewDefinition.clone( + "Composite.Management.TreeSelectorDialog", + "Generated.ViewDefinition.Handle." + KeyMaster.getUniqueKey() + ); + definition.argument.selectionProperty = this.getProperty("selection-property"); + definition.argument.selectionValue = this.getProperty("selection-value"); + definition.argument.selectionResult = this.getProperty("selection-result"); + definition.argument.nodes = [ + { + key: this.getProperty("element-provider"), + search: this.getProperty('serialized-search-token') + } + ]; + + return definition; +}; \ No newline at end of file diff --git a/Website/Frontend/Config/VisualEditor/Default.common.xml b/Website/Frontend/Config/VisualEditor/ReleaseBuild.common.xml similarity index 99% rename from Website/Frontend/Config/VisualEditor/Default.common.xml rename to Website/Frontend/Config/VisualEditor/ReleaseBuild.common.xml index f30438f247..9cfefcfa90 100644 --- a/Website/Frontend/Config/VisualEditor/Default.common.xml +++ b/Website/Frontend/Config/VisualEditor/ReleaseBuild.common.xml @@ -130,4 +130,4 @@ - \ No newline at end of file + diff --git a/Website/ReleaseCleanupConfiguration.xml b/Website/ReleaseCleanupConfiguration.xml index 20ff15d3fc..92ece5a5fc 100644 --- a/Website/ReleaseCleanupConfiguration.xml +++ b/Website/ReleaseCleanupConfiguration.xml @@ -1,4 +1,4 @@ - + diff --git a/Website/WebSite.csproj b/Website/WebSite.csproj index 820e32b677..c0eb6cac51 100644 --- a/Website/WebSite.csproj +++ b/Website/WebSite.csproj @@ -324,6 +324,7 @@ + @@ -664,6 +665,7 @@ + @@ -2799,19 +2801,18 @@ ) if not exist "$(ProjectDir)Frontend\Config\VisualEditor\common.xml" ( - copy "$(ProjectDir)Frontend\Config\VisualEditor\Default.common.xml" "$(ProjectDir)Frontend\Config\VisualEditor\common.xml" + copy "$(ProjectDir)Frontend\Config\VisualEditor\ReleaseBuild.common.xml" "$(ProjectDir)Frontend\Config\VisualEditor\common.xml" ) if not exist "$(TargetDir)\System.Threading.Tasks.Dataflow.dll" ( copy "$(ProjectDir)\..\Packages\System.Threading.Tasks.Dataflow.4.6.0\lib\netstandard1.1\System.Threading.Tasks.Dataflow.dll" "$(TargetDir)\System.Threading.Tasks.Dataflow.dll" ) - cd "$(ProjectDir)" - .\node_modules\.bin\jspm install --quick + robocopy "..\Packages\PhantomJS.2.1.1\tools\phantomjs" "App_Data\Composite\PhantomJs" "phantomjs.exe" + .\node_modules\.bin\jspm install --quick - robocopy "$(ProjectDir)\..\Packages\PhantomJS.2.1.1\tools\phantomjs" "$(ProjectDir)\App_Data\Composite\PhantomJs" "phantomjs.exe" set rce=%25errorlevel%25 if not %25rce%25==1 exit %25rce%25 else exit 0 @@ -2819,4 +2820,4 @@ - \ No newline at end of file + diff --git a/Website/package.json b/Website/package.json index 95bb8dc981..53d939be87 100644 --- a/Website/package.json +++ b/Website/package.json @@ -14,10 +14,10 @@ "devDependencies": { "JSONPath": "^0.10.0", "autoprefixer-core": "^5.2.1", - "chromedriver": "^2.34.0", "chokidar-socket-emitter": "0.5.4", + "chromedriver": "^2.34.0", "csswring": "^3.0.5", - "eslint": "3.1.1", + "eslint": "^4.18.2", "eslint-plugin-mocha": "4.0.0", "eslint-plugin-react": "5.2.2", "grunt": "~0.4.5",