/// <summary>
        /// Resolves the content of the root node.
        /// </summary>
        protected virtual void ResolveRootContent(DothtmlRootNode root, IAbstractContentNode view, IControlResolverMetadata viewMetadata)
        {
            // WORKAROUND:
            // if there is a control in root of a MarkupControl that has DataContext assigned, it will not find the data context space, because the space of DataContext property does not include the control itself and the space of MarkupControl also does not include the MarkupControl. And because the MarkupControl is a direct parent of the DataContext-bound control there is no space in between.

            if (viewMetadata.Type.IsAssignableTo(new ResolvedTypeDescriptor(typeof(DotvvmMarkupControl))))
            {
                var placeHolder = this.treeBuilder.BuildControl(
                    this.controlResolver.ResolveControl(new ResolvedTypeDescriptor(typeof(PlaceHolder))),
                    view.DothtmlNode,
                    view.DataContextTypeStack
                    );
                this.treeBuilder.AddChildControl(view, placeHolder);
                view         = placeHolder;
                viewMetadata = placeHolder.Metadata;
            }

            foreach (var node in root.Content)
            {
                var child = ProcessNode(view, node, viewMetadata, view.DataContextTypeStack);
                if (child != null)
                {
                    treeBuilder.AddChildControl(view, child);
                }
            }
        }
        private bool ProcessDirectives(int position, DothtmlRootNode rootNode)
        {
            var currentDirective = GetCurrentDirective(position, rootNode);

            if (currentDirective == null)
            {
                return(false);
            }

            //check viewModel and typeBased directive and navigate to definition of the viewModel
            if (currentDirective.Name.Equals(Constants.ViewModelDirectiveName, StringComparison.InvariantCultureIgnoreCase) ||
                currentDirective.Name.Equals(Constants.BaseTypeDirective, StringComparison.InvariantCultureIgnoreCase))
            {
                if (NavigateToViewModel(new ViewModelDirectiveValue(currentDirective)))
                {
                    return(true);
                }
            }

            //check masterPage directive
            if (currentDirective.Name.Equals(Constants.MasterPageDirective, StringComparison.InvariantCultureIgnoreCase))
            {
                if (NavigateToMasterPage(currentDirective))
                {
                    return(true);
                }
            }
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Resolves the control tree.
        /// </summary>
        public virtual IAbstractTreeRoot ResolveTree(DothtmlRootNode root, string fileName)
        {
            var directives       = ProcessDirectives(root);
            var wrapperType      = ResolveWrapperType(directives, fileName);
            var viewModelType    = ResolveViewModelType(directives, root, fileName);
            var namespaceImports = ResolveNamespaceImports(directives, root);

            // We need to call BuildControlMetadata instead of ResolveControl. The control builder for the control doesn't have to be compiled yet so the
            // metadata would be incomplete and ResolveControl caches them internally. BuildControlMetadata just builds the metadata and the control is
            // actually resolved when the control builder is ready and the metadata are complete.
            var viewMetadata = controlResolver.BuildControlMetadata(CreateControlType(wrapperType, fileName));

            var dataContextTypeStack = CreateDataContextTypeStack(viewModelType, null, namespaceImports, new BindingExtensionParameter[] {
                new CurrentMarkupControlExtensionParameter(wrapperType),
                new BindingPageInfoExtensionParameter()
            });

            var view = treeBuilder.BuildTreeRoot(this, viewMetadata, root, dataContextTypeStack, directives);

            view.FileName = fileName;

            ResolveRootContent(root, view, viewMetadata);

            return(view);
        }
Пример #4
0
        public ResolvedTreeRoot ResolveTree(DothtmlRootNode root, string fileName)
        {
            var wrapperType = ResolveWrapperType(root, fileName.EndsWith(".dotcontrol", StringComparison.Ordinal) ? typeof(DotvvmMarkupControl) : typeof(DotvvmView));

            // We need to call BuildControlMetadata instead of ResolveControl. The control builder for the control doesn't have to be compiled yet so the
            // metadata would be incomplete and ResolveControl caches them internally. BuildControlMetadata just builds the metadata and the control is
            // actually resolved when the control builder is ready and the metadata are complete.
            var viewMetadata = controlResolver.BuildControlMetadata(new ControlType(wrapperType, virtualPath: fileName));
            var view         = new ResolvedTreeRoot(viewMetadata, root, null);

            foreach (var directive in root.Directives)
            {
                if (!string.Equals(directive.Name, Constants.BaseTypeDirective, StringComparison.InvariantCultureIgnoreCase))
                {
                    view.Directives.Add(directive.Name, directive.Value);
                }
            }

            ResolveViewModel(fileName, view, wrapperType);

            foreach (var node in root.Content)
            {
                view.Content.Add(ProcessNode(node, viewMetadata, view.DataContextTypeStack));
            }
            return(view);
        }
Пример #5
0
 /// <summary>
 /// Resolves the content of the root node.
 /// </summary>
 private void ResolveRootContent(DothtmlRootNode root, IAbstractTreeRoot view, IControlResolverMetadata viewMetadata)
 {
     foreach (var node in root.Content)
     {
         var child = ProcessNode(view, node, viewMetadata, view.DataContextTypeStack);
         if (child != null)
         {
             treeBuilder.AddChildControl(view, child);
         }
     }
 }
Пример #6
0
        /// <summary>
        /// Resolves the type of the wrapper.
        /// </summary>
        private Type ResolveWrapperType(DothtmlRootNode node, Type defaultType)
        {
            var wrapperType = defaultType;

            var baseControlDirective = node.Directives.SingleOrDefault(d => string.Equals(d.Name, Constants.BaseTypeDirective, StringComparison.InvariantCultureIgnoreCase));

            if (baseControlDirective != null)
            {
                wrapperType = ReflectionUtils.FindType(baseControlDirective.Value);
                if (wrapperType == null)
                {
                    throw new DotvvmCompilationException($"The type '{baseControlDirective.Value}' specified in baseType directive was not found!");
                }
                if (!typeof(DotvvmMarkupControl).IsAssignableFrom(wrapperType))
                {
                    throw new DotvvmCompilationException("Markup controls must derive from DotvvmMarkupControl class!");
                }
            }

            return(wrapperType);
        }
Пример #7
0
 private IEnumerable <NamespaceImport> ResolveNamespaceImportsCore(IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives, DothtmlRootNode root)
 => directives.Values.SelectMany(d => d).OfType <IAbstractImportDirective>()
 .Where(d => !d.HasError)
 .Select(d => new NamespaceImport(d.NameSyntax.ToDisplayString(), d.AliasSyntax.As <IdentifierNameBindingParserNode>()?.Name));
Пример #8
0
        /// <summary>
        /// Resolves the view model for the root node.
        /// </summary>
        protected virtual ITypeDescriptor ResolveViewModelType(IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives, DothtmlRootNode root, string fileName)
        {
            if (!directives.ContainsKey(ParserConstants.ViewModelDirectiveName) || directives[ParserConstants.ViewModelDirectiveName].Count == 0)
            {
                root.AddError($"The @viewModel directive is missing in the page '{fileName}'!");
                return(null);
            }
            var viewmodelDirective = directives[ParserConstants.ViewModelDirectiveName].First();

            var viewModelType = FindType(viewmodelDirective.Value);

            if (viewModelType == null)
            {
                viewmodelDirective.DothtmlNode.AddError($"The type '{viewmodelDirective.Value}' required in the @viewModel directive was not found!");
            }

            return(viewModelType);
        }
Пример #9
0
 protected virtual ImmutableList <NamespaceImport> ResolveNamespaceImports(IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives, DothtmlRootNode root)
 => ResolveNamespaceImportsCore(directives).ToImmutableList();
Пример #10
0
        protected virtual IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > ProcessDirectives(DothtmlRootNode root)
        {
            var directives = new Dictionary <string, IReadOnlyList <IAbstractDirective> >(StringComparer.OrdinalIgnoreCase);

            foreach (var directiveGroup in root.Directives.GroupBy(d => d.Name, StringComparer.OrdinalIgnoreCase))
            {
                if (SingleValueDirectives.Contains(directiveGroup.Key) && directiveGroup.Count() > 1)
                {
                    foreach (var d in directiveGroup)
                    {
                        ProcessDirective(d);
                        d.AddError($"Directive '{d.Name}' can not be present multiple times.");
                    }
                    directives[directiveGroup.Key] = ImmutableList.Create(ProcessDirective(directiveGroup.First()));
                }
                else
                {
                    directives[directiveGroup.Key] = directiveGroup.Select(ProcessDirective).ToImmutableList();
                }
            }

            return(new ReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> >(directives));
        }
Пример #11
0
        /// <summary>
        /// Resolves the view model for the root node.
        /// </summary>
        protected virtual ITypeDescriptor ResolveViewModelType(IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives, DothtmlRootNode root, string fileName)
        {
            if (!directives.ContainsKey(ParserConstants.ViewModelDirectiveName) || directives[ParserConstants.ViewModelDirectiveName].Count == 0)
            {
                root.AddError($"The @viewModel directive is missing in the page '{fileName}'!");
                return(null);
            }
            var viewmodelDirective = (IAbstractViewModelDirective)directives[ParserConstants.ViewModelDirectiveName].First();

            return(viewmodelDirective.ResolvedType);
        }
Пример #12
0
 public void Visit(DothtmlRootNode root)
 {
     ResolveFromParent(root);
 }
Пример #13
0
 public IAbstractTreeRoot BuildTreeRoot(IControlTreeResolver controlTreeResolver, IControlResolverMetadata metadata, DothtmlRootNode node, IDataContextStack dataContext, IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives)
 {
     return(new ResolvedTreeRoot((ControlResolverMetadata)metadata, node, (DataContextStack)dataContext, directives));
 }
Пример #14
0
        /// <summary>
        /// Resolves the type of the wrapper.
        /// </summary>
        private ITypeDescriptor ResolveWrapperType(IReadOnlyDictionary <string, IReadOnlyList <IAbstractDirective> > directives, DothtmlRootNode root, string fileName)
        {
            var wrapperType = GetDefaultWrapperType(fileName);

            var baseControlDirective = !directives.ContainsKey(ParserConstants.BaseTypeDirective)
                ? null
                : directives[ParserConstants.BaseTypeDirective].SingleOrDefault();

            if (baseControlDirective != null)
            {
                var baseType = FindType(baseControlDirective.Value);
                if (baseType == null)
                {
                    baseControlDirective.DothtmlNode.AddError($"The type '{baseControlDirective.Value}' specified in baseType directive was not found!");
                }
                else if (!baseType.IsAssignableTo(new ResolvedTypeDescriptor(typeof(DotvvmMarkupControl))))
                {
                    baseControlDirective.DothtmlNode.AddError("Markup controls must derive from DotvvmMarkupControl class!");
                    wrapperType = baseType;
                }
                else
                {
                    wrapperType = baseType;
                }
            }

            return(wrapperType);
        }
Пример #15
0
 protected override void ResolveRootContent(DothtmlRootNode root, IAbstractContentNode view, IControlResolverMetadata viewMetadata)
 {
     ((ResolvedTreeRoot)view).ResolveContentAction = () => base.ResolveRootContent(root, view, viewMetadata);
 }
 /// <summary>
 /// Checks if directive is selected and returns it.
 /// </summary>
 private static DothtmlDirectiveNode GetCurrentDirective(int position, DothtmlRootNode rootNode)
 {
     return(rootNode.Directives.FirstOrDefault(s => s.StartPosition <= position &&
                                               position <= s.StartPosition + s.Length));
 }
Пример #17
0
 public void Visit(DothtmlRootNode root)
 {
     ResolveFromParent(root);
 }