示例#1
0
        // Used on reading from source. Get full list of rules for this control.
        public Dictionary <string, string> GetDefaultRules()
        {
            // Add themes first.
            var defaults        = new Dictionary <string, string>();
            var variantDefaults = new Dictionary <string, string>();

            if (_template != null)
            {
                // Default values from the variants take precedence over the base template
                var hasVariantDefaults = _variantName != null && _template.VariantDefaultValues.TryGetValue(_variantName, out variantDefaults);
                if (hasVariantDefaults)
                {
                    defaults.AddRange(variantDefaults);
                }

                defaults.AddRange(_template.InputDefaults.Where(kvp => !ControlTemplateParser.IsLocalizationKey(kvp.Value) && !(hasVariantDefaults && variantDefaults.ContainsKey(kvp.Key))));
            }

            defaults.AddRange(_theme.GetStyle(_styleName).Where(kvp => !ControlTemplateParser.IsLocalizationKey(kvp.Value)));

            if (_inResponsiveContext)
            {
                defaults.AddRange(DynamicProperties.GetDefaultValues(_templateName, this));
            }

            return(defaults);
        }
        private static void LoadTemplateFiles(ErrorContainer errors, CanvasDocument app, string packagesPath, out Dictionary <string, ControlTemplate> loadedTemplates)
        {
            loadedTemplates = new Dictionary <string, ControlTemplate>();
            var templateList = new List <TemplatesJson.TemplateJson>();

            foreach (var file in new DirectoryReader(packagesPath).EnumerateFiles(string.Empty, "*.xml", searchSubdirectories: false))
            {
                var xmlContents = file.GetContents();
                if (!ControlTemplateParser.TryParseTemplate(new TemplateStore(), xmlContents, app._properties.DocumentAppType, loadedTemplates, out var parsedTemplate, out var templateName))
                {
                    errors.GenericError($"Unable to parse template file {file._relativeName}");
                    throw new DocumentException();
                }
                // Some control templates specify a name with an initial capital letter (e.g. rating control)
                // However, the server doesn't always use that. If the template name doesn't match the one we wrote
                // as the file name, adjust the template name to lowercase
                if (!file._relativeName.StartsWith(templateName))
                {
                    templateName = templateName.ToLower();
                }

                templateList.Add(new TemplatesJson.TemplateJson()
                {
                    Name = templateName, Template = xmlContents, Version = parsedTemplate.Version
                });
            }

            // Also add Screen and App templates (not xml, constructed in code on the server)
            GlobalTemplates.AddCodeOnlyTemplates(new TemplateStore(), loadedTemplates, app._properties.DocumentAppType);

            app._templates = new TemplatesJson()
            {
                UsedTemplates = templateList.ToArray()
            };
        }
        public void TestGalleryNestedTemplateParse()
        {
            var galleryTemplatePath = Path.Combine(Environment.CurrentDirectory, "Templates", "gallery_2.10.0.xml");

            Assert.IsTrue(File.Exists(galleryTemplatePath));

            using var galleryTemplateStream = File.OpenRead(galleryTemplatePath);
            using var galleryTemplateReader = new StreamReader(galleryTemplateStream);

            var galleryTemplateContents = galleryTemplateReader.ReadToEnd();

            var parsedTemplates = new Dictionary <string, ControlTemplate>();
            var templateStore   = new TemplateStore();

            Assert.IsTrue(ControlTemplateParser.TryParseTemplate(templateStore, galleryTemplateContents, AppType.DesktopOrTablet, parsedTemplates, out var topTemplate, out var name));

            Assert.AreEqual(2, parsedTemplates.Count);
            Assert.AreEqual("gallery", name);
            Assert.AreEqual("http://microsoft.com/appmagic/gallery", topTemplate.Id);

            Assert.IsTrue(templateStore.TryGetTemplate("gallery", out _));

            Assert.IsTrue(parsedTemplates.TryGetValue("galleryTemplate", out var innerTemplate));
            Assert.AreEqual("http://microsoft.com/appmagic/galleryTemplate", innerTemplate.Id);
            Assert.AreEqual("RGBA(0, 0, 0, 0)", innerTemplate.InputDefaults["TemplateFill"]);

            Assert.IsTrue(templateStore.TryGetTemplate("galleryTemplate", out _));
        }
示例#4
0
        internal void ApplyAfterMsAppLoadTransforms(ErrorContainer errors)
        {
            // Update volatile documentproperties
            _entropy.SetProperties(_properties);

            // Shard templates, parse for default values
            var templateDefaults = new Dictionary <string, ControlTemplate>();

            foreach (var template in _templates.UsedTemplates)
            {
                if (!ControlTemplateParser.TryParseTemplate(_templateStore, template.Template, _properties.DocumentAppType, templateDefaults, out _, out _))
                {
                    errors.GenericError($"Unable to parse template file {template.Name}");
                    throw new DocumentException();
                }
            }

            // Also add Screen and App templates (not xml, constructed in code on the server)
            GlobalTemplates.AddCodeOnlyTemplates(_templateStore, templateDefaults, _properties.DocumentAppType);

            // PCF templates
            if (_pcfControls.Count == 0)
            {
                foreach (var kvp in _templateStore.Contents)
                {
                    if (kvp.Value.IsPcfControl && kvp.Value.DynamicControlDefinitionJson != null)
                    {
                        _pcfControls.Add(kvp.Key, PcfControl.GetPowerAppsControlFromJson(kvp.Value));
                        kvp.Value.DynamicControlDefinitionJson = null;
                    }
                }
            }

            var componentInstanceTransform = new ComponentInstanceTransform(errors);
            var componentDefTransform      = new ComponentDefinitionTransform(errors, _templateStore, componentInstanceTransform);

            // Transform component definitions and populate template set of component instances that need updates
            foreach (var ctrl in _components)
            {
                AddComponentDefaults(ctrl.Value, templateDefaults);
                componentDefTransform.AfterRead(ctrl.Value);
            }

            var transformer = new SourceTransformer(this, errors, templateDefaults, new Theme(_themes), componentInstanceTransform, _editorStateStore, _templateStore, _entropy);

            foreach (var ctrl in _screens.Concat(_components))
            {
                transformer.ApplyAfterRead(ctrl.Value);
            }

            StabilizeAssetFilePaths(errors);

            // Persist the original order of resource entries in Resources.json in the entropy.
            this.PersistOrderingOfResourcesJsonEntries();
        }
示例#5
0
        internal void ApplyBeforeMsAppWriteTransforms(ErrorContainer errors)
        {
            // Update volatile documentproperties
            _entropy.GetProperties(_properties);

            // Shard templates, parse for default values
            var templateDefaults = new Dictionary <string, ControlTemplate>();

            foreach (var template in _templates.UsedTemplates)
            {
                if (!ControlTemplateParser.TryParseTemplate(_templateStore, template.Template, _properties.DocumentAppType, templateDefaults, out _, out _))
                {
                    errors.GenericError($"Unable to parse template file {template.Name}");
                    throw new DocumentException();
                }
            }

            // Also add Screen and App templates (not xml, constructed in code on the server)
            GlobalTemplates.AddCodeOnlyTemplates(_templateStore, templateDefaults, _properties.DocumentAppType);

            // Generate DynamicControlDefinitionJson for power apps controls
            foreach (var kvp in _pcfControls)
            {
                if (_templateStore.TryGetTemplate(kvp.Key, out var template))
                {
                    template.DynamicControlDefinitionJson = PcfControl.GenerateDynamicControlDefinition(kvp.Value);
                }
                else
                {
                    // Validation for accidental deletion of ocf control templates.
                    errors.ValidationError($"Could not find Pcf Control Template with name: {kvp.Key} in pkgs/PcfControlTemplates directory. " +
                                           $"If it was intentionally deleted, please delete the entry from ControlTemplates.json along with its references from source files.");
                }
            }

            var componentInstanceTransform = new ComponentInstanceTransform(errors);
            var componentDefTransform      = new ComponentDefinitionTransform(errors, _templateStore, componentInstanceTransform);

            // Transform component definitions and populate template set of component instances that need updates
            foreach (var ctrl in _components)
            {
                componentDefTransform.BeforeWrite(ctrl.Value);
                AddComponentDefaults(ctrl.Value, templateDefaults);
            }

            var transformer = new SourceTransformer(this, errors, templateDefaults, new Theme(_themes), componentInstanceTransform, _editorStateStore, _templateStore, _entropy);

            foreach (var ctrl in _screens.Concat(_components))
            {
                transformer.ApplyBeforeWrite(ctrl.Value);
            }

            RestoreAssetFilePaths();
        }
示例#6
0
        // To Load the fluidGrid template defaults
        private Dictionary <string, ControlTemplate> getTemplateStore()
        {
            var parsedTemplates       = new Dictionary <string, ControlTemplate>();
            var fluidGridTemplatePath = Path.Combine(Environment.CurrentDirectory, "Templates", "fluidGrid_2.2.0.xml");

            Assert.IsTrue(File.Exists(fluidGridTemplatePath));

            using var fluidGridTemplateStream = File.OpenRead(fluidGridTemplatePath);
            using var fluidGridTemplateReader = new StreamReader(fluidGridTemplateStream);
            var templateStore             = new TemplateStore();
            var fluidGridTemplateContents = fluidGridTemplateReader.ReadToEnd();

            ControlTemplateParser.TryParseTemplate(templateStore, fluidGridTemplateContents, AppType.DesktopOrTablet, parsedTemplates, out var topTemplate, out var name);

            return(parsedTemplates);
        }
示例#7
0
        public Theme(ThemesJson themeJson)
        {
            Contract.Assert(themeJson != null);

            foreach (var theme in themeJson.CustomThemes)
            {
                Dictionary <string, string> palleteRules = new Dictionary <string, string>();
                foreach (var item in theme.palette)
                {
                    palleteRules[item.name] = item.value;
                }

                foreach (var style in theme.styles)
                {
                    var styleName = style.name;
                    foreach (var prop in style.propertyValuesMap)
                    {
                        var propName  = prop.property;
                        var ruleValue = prop.value;

                        // TODO - share with logic in D:\dev\pa2\PowerApps-Client\src\Cloud\DocumentServer.Core\Document\Document\Theme\ControlStyle.cs
                        // Resolve %%, from palette.
                        {
                            var match = Regex.Match(ruleValue, "%Palette.([^%]+)%");
                            if (match.Success)
                            {
                                var group = match.Groups[1];



                                string resourceValue;
                                // Template may refer to a missing rule.
                                if (palleteRules.TryGetValue(group.ToString(), out resourceValue))
                                {
                                    ruleValue = ruleValue.Replace(match.Value, resourceValue);
                                }
                            }
                        }

                        ruleValue = ControlTemplateParser.UnescapeReservedName(ruleValue);

                        _styles.GetOrCreate(styleName).Add(propName, ruleValue);
                    }
                }
            }
        }
        internal void ApplyBeforeMsAppWriteTransforms(ErrorContainer errors)
        {
            // Update volatile documentproperties
            _entropy.GetProperties(_properties);

            // Shard templates, parse for default values
            var templateDefaults = new Dictionary <string, ControlTemplate>();

            foreach (var template in _templates.UsedTemplates)
            {
                if (!ControlTemplateParser.TryParseTemplate(_templateStore, template.Template, _properties.DocumentAppType, templateDefaults, out _, out _))
                {
                    errors.GenericError($"Unable to parse template file {template.Name}");
                    throw new DocumentException();
                }
            }

            // Also add Screen and App templates (not xml, constructed in code on the server)
            GlobalTemplates.AddCodeOnlyTemplates(_templateStore, templateDefaults, _properties.DocumentAppType);

            var componentInstanceTransform = new ComponentInstanceTransform(errors);
            var componentDefTransform      = new ComponentDefinitionTransform(errors, _templateStore, componentInstanceTransform);

            // Transform component definitions and populate template set of component instances that need updates
            foreach (var ctrl in _components)
            {
                componentDefTransform.BeforeWrite(ctrl.Value);
                AddComponentDefaults(ctrl.Value, templateDefaults);
            }

            var transformer = new SourceTransformer(errors, templateDefaults, new Theme(_themes), componentInstanceTransform, _editorStateStore, _templateStore, _entropy);

            foreach (var ctrl in _screens.Concat(_components))
            {
                transformer.ApplyBeforeWrite(ctrl.Value);
            }

            RestoreAssetFilePaths();
        }
示例#9
0
        // Used on writing to source to omit default rules.
        public bool TryGetDefaultRule(string propertyName, out string defaultScript)
        {
            // Themes (styles) are higher precedence  then Template XML.
            var template = _template;

            if (_theme.TryLookup(_styleName, propertyName, out defaultScript))
            {
                if (ControlTemplateParser.IsLocalizationKey(defaultScript))
                {
                    return(false);
                }
                return(true);
            }

            // Check template variant first, then template base
            if (template != null &&
                ((_variantName != null &&
                  template.VariantDefaultValues.TryGetValue(_variantName, out var defaults) &&
                  defaults.TryGetValue(propertyName, out defaultScript)) ||
                 template.InputDefaults.TryGetValue(propertyName, out defaultScript)))
            {
                if (ControlTemplateParser.IsLocalizationKey(defaultScript))
                {
                    return(false);
                }

                // Found in template.
                return(true);
            }

            if (_inResponsiveContext && DynamicProperties.TryGetDefaultValue(propertyName, _templateName, this, out defaultScript))
            {
                return(true);
            }

            defaultScript = null;
            return(false);
        }
        // Write out to a directory (this shards it)
        public static void SaveAsSource(CanvasDocument app, string directory2, ErrorContainer errors)
        {
            var dir = new DirectoryWriter(directory2);

            dir.DeleteAllSubdirs();

            // Shard templates, parse for default values
            var templateDefaults = new Dictionary <string, ControlTemplate>();

            foreach (var template in app._templates.UsedTemplates)
            {
                var filename = $"{template.Name}_{template.Version}.xml";
                dir.WriteAllXML(PackagesDir, filename, template.Template);
                if (!ControlTemplateParser.TryParseTemplate(app._templateStore, template.Template, app._properties.DocumentAppType, templateDefaults, out _, out _))
                {
                    throw new NotSupportedException($"Unable to parse template file {template.Name}");
                }
            }

            // Also add Screen and App templates (not xml, constructed in code on the server)
            GlobalTemplates.AddCodeOnlyTemplates(app._templateStore, templateDefaults, app._properties.DocumentAppType);

            var importedComponents = app.GetImportedComponents();

            foreach (var control in app._screens)
            {
                string controlName = control.Key;
                var    isTest      = controlName == AppTestControlName;
                var    subDir      = isTest ? TestDir : CodeDir;

                WriteTopParent(dir, app, control.Key, control.Value, subDir);
            }

            foreach (var control in app._components)
            {
                string controlName = control.Key;
                app._templateStore.TryGetTemplate(controlName, out var templateState);

                bool isImported = importedComponents.Contains(templateState.TemplateOriginalName);
                var  subDir     = (isImported) ? ComponentPackageDir : ComponentCodeDir;
                WriteTopParent(dir, app, control.Key, control.Value, subDir);
            }

            // Write out control templates at top level, skipping component templates which are written alongside components
            var nonComponentControlTemplates = app._templateStore.Contents.Where(kvp => !(kvp.Value.IsComponentTemplate ?? false)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            dir.WriteAllJson("", "ControlTemplates.json", nonComponentControlTemplates);

            if (app._checksum != null)
            {
                app._checksum.ClientBuildDetails = _buildVerJson;
                dir.WriteAllJson(EntropyDir, FileKind.Checksum, app._checksum);
            }

            if (app._appCheckerResultJson != null)
            {
                dir.WriteAllJson(EntropyDir, FileKind.AppCheckerResult, app._appCheckerResultJson);
            }

            foreach (var file in app._assetFiles.Values)
            {
                dir.WriteAllBytes(AssetsDir, file.Name, file.RawBytes);
            }

            if (app._logoFile != null)
            {
                dir.WriteAllBytes(AssetsDir, app._logoFile.Name, app._logoFile.RawBytes);
            }

            if (app._themes != null)
            {
                dir.WriteAllJson(CodeDir, "Themes.json", app._themes);
            }

            if (app._resourcesJson != null)
            {
                dir.WriteAllJson(AssetsDir, "Resources.json", app._resourcesJson);
            }

            WriteDataSources(dir, app, errors);

            // Loose files.
            foreach (FileEntry file in app._unknownFiles.Values)
            {
                // Standardize the .json files so they're determinsitc and comparable
                if (file.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
                {
                    ReadOnlyMemory <byte> span = file.RawBytes;
                    var je      = JsonDocument.Parse(span).RootElement;
                    var jsonStr = JsonNormalizer.Normalize(je);
                    dir.WriteAllText(OtherDir, file.Name, jsonStr);
                }
                else
                {
                    dir.WriteAllBytes(OtherDir, file.Name, file.RawBytes);
                }
            }

            var manifest = new CanvasManifestJson
            {
                FormatVersion = CurrentSourceVersion,
                Properties    = app._properties,
                Header        = app._header,
                PublishInfo   = app._publishInfo,
                ScreenOrder   = app._screenOrder
            };

            dir.WriteAllJson("", FileKind.CanvasManifest, manifest);

            if (app._connections != null)
            {
                dir.WriteAllJson(ConnectionDir, FileKind.Connections, app._connections);
            }

            if (app._libraryReferences != null)
            {
                dir.WriteAllJson("", FileKind.ComponentReferences, app._libraryReferences);
            }

            dir.WriteAllJson(EntropyDir, FileKind.Entropy, app._entropy);
        }