protected override LensFinderViewModel ViewModel(SocketEventContext model, ModelShapeContext context)
        {
            var viewModel = new LensFinderViewModel();

            PopulateLensFinderModel(model, viewModel, context.Prefix, context.Updater);
            return(viewModel);
        }
        public override ModelDriverResult Run(ModelShapeContext context)
        {
            var describe = _formulaService.DescribeModel(context.Model);
            var bits     = describe.Fields.Select(f =>
                                                  ChainShape(f.Model(context), context.Prefix + "." + f.Name, null));

            return(Combined(bits.ToArray()));
        }
 protected override void Update(SocketDisplayContext model, dynamic shapeHelper, IUpdateModel updater, ModelShapeContext context)
 {
 }
Beispiel #4
0
        protected override ModelDriverResult Build(LensViewModel model, LensQueryTextViewModel viewModel, dynamic shapeHelper, ModelShapeContext context)
        {
            var prefix = FullPrefix(context);

            return(ModelShape("Lens_Filters_QueryText",
                              () => shapeHelper.Lens_Filters_QueryText(Model: viewModel, Prefix: prefix)));
        }
        protected override ModelDriverResult Build(SocketEventContext model, LensFinderViewModel viewModel, dynamic shapeHelper, ModelShapeContext context)
        {
            var prefix = FullPrefix(context);

            return(ModelShape("Socket_Finders_LensSearch",
                              () => {
                return shapeHelper.EditorTemplate(TemplateName: "Socket.Finders.LensSearch", Model: viewModel, Prefix: prefix);
            }));
        }
Beispiel #6
0
 protected override ModelDriverResult Editor(SocketEventContext model, dynamic shapeHelper, ModelShapeContext context)
 {
     return(Update(model, shapeHelper, null, context));
 }
        private void BindPlacement(BuildShapeContext context, string displayType, string stereotype, ModelShapeContext modelContext)
        {
            context.FindPlacement = (partShapeType, differentiator, defaultLocation) =>
            {
                var theme      = _themeService.Value.GetRequestTheme(_requestContext);
                var shapeTable = _shapeTableManager.GetShapeTable(theme.Id);
                var request    = _requestContext.HttpContext.Request;

                ShapeDescriptor descriptor;
                if (shapeTable.Descriptors.TryGetValue(partShapeType, out descriptor))
                {
                    var placementContext = new ModelShapePlacementContext
                    {
                        ModelContext   = modelContext,
                        ContentType    = context.ContentItem.ContentType,
                        Stereotype     = stereotype,
                        DisplayType    = displayType,
                        Differentiator = differentiator,
                        Path           = VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(request.Path)) // get the current app-relative path, i.e. ~/my-blog/foo
                    };

                    var placement = descriptor.Placement(placementContext);
                    if (placement != null)
                    {
                        placement.Source = placementContext.Source;
                        return(placement);
                    }
                }

                // Default
                return(new PlacementInfo
                {
                    Location = defaultLocation,
                    Source = String.Empty
                });
            };
        }
 protected override ModelDriverResult Build(IContent model, dynamic shapeHelper, ModelShapeContext context)
 {
     if (context.Mode == "Editor")
     {
         if (context.Updater != null)
         {
             var updater = context.Updater;
             // If there's a parent prefix we can inject it now
             if (!String.IsNullOrWhiteSpace(context.Prefix))
             {
                 updater = new PrefixedUpdateModel(context.Prefix, context.Updater);
             }
             var workContext = _workContextAccessor.GetContext(_requestContext.HttpContext);
             var theme       = workContext.CurrentTheme;
             var shapeTable  = _shapeTableLocator.Value.Lookup(theme.Id);
             var context2    = new UpdateContentEditorContext(context.Shape, model, context.DisplayType, updater, context.GroupId, shapeHelper, shapeTable, context);
             BindPlacement(context2, context.DisplayType, context.Stereotype, context);
             _handlers.Value.Invoke(handler => handler.UpdateEditor(context2), Logger);
         }
         else
         {
             var context2 = new BuildContentEditorContext(context.Shape, model, context.DisplayType, context.GroupId, shapeHelper, context);
             BindPlacement(context2, context.DisplayType, context.Stereotype, context);
             _handlers.Value.Invoke(handler => handler.BuildEditor(context2), Logger);
         }
     }
     else
     {
         var context2 = new BuildContentDisplayContext(context.Shape, model, context.DisplayType, context.GroupId, shapeHelper, context);
         BindPlacement(context2, context.DisplayType, context.Stereotype, context);
         _handlers.Value.Invoke(handler => handler.BuildDisplay(context2), Logger);
     }
     return(null);
 }
        private dynamic BuildDisplayDelegate(SocketDisplayContext socketContext, ModelShapeContext context)
        {
            var prefix = FullPrefix(context, socketContext.Connector.Definition.Name);

            // Set up display text
            socketContext.SocketMetadata.SocketTitle =
                String.IsNullOrWhiteSpace(socketContext.Connector.Settings.SocketDisplayName)
                ? (socketContext.Connector.Definition.DisplayName + (socketContext.Connector.Settings.AllowMany ? "s" : ""))
                : socketContext.Connector.Settings.SocketDisplayName;
            socketContext.SocketMetadata.DisplayHint = socketContext.Connector.Settings.SocketDisplayHint;
            socketContext.SocketMetadata.EditorHint  = socketContext.Connector.Settings.SocketEditorHint;

            // Content querying and filtration process
            // TODO: Fully review and profile all this (and places where the lazies are accessed)
            socketContext.Query = socketContext.Left.ContentPart.Sockets.Socket(socketContext.Name);

            // Build a socket shape
            dynamic socket;

            if (context.Mode == "Editor")
            {
                _socketHandlers.Value.Invoke(s => s.Editing(socketContext), Logger);
                if (!socketContext.RenderSocket)
                {
                    return(null);
                }
                socket = context.New.Socket_Edit(Prefix: prefix, ConnectorType: socketContext.Connector.Definition.Name, ContentItem: socketContext.Left.ContentItem);
            }
            else
            {
                _socketHandlers.Value.Invoke(s => s.Displaying(socketContext), Logger);
                if (!socketContext.RenderSocket)
                {
                    return(null);
                }
                socket = context.New.Socket()
                         .ConnectorType(socketContext.Connector.Name)
                         .ContentItem(socketContext.Left.ContentItem);
            };

            string displayType = socketContext.Left.DisplayType;

            if (!String.IsNullOrWhiteSpace(socketContext.Connector.DisplayType))
            {
                displayType = socketContext.Connector.DisplayType;
            }

            socket.Metadata.DisplayType = displayType;

            if (context.Mode == "Editor")
            {
                // Edit/update handlers
                if (context.Updater == null)
                {
                    _socketHandlers.Value.Invoke(s => s.Editor(socketContext), Logger);
                }
                else
                {
                    _socketHandlers.Value.Invoke(s => s.Updating(socketContext), Logger);
                }
                if (!socketContext.RenderSocket)
                {
                    return(null);
                }

                // Build the editor shape
                var builder1 = _origami.Value.BuildEditorShape(socketContext, context.Updater, prefix, displayType, "Socket", socketContext.Left.ContentType, context)
                               .WithParadigms(socketContext.Paradigms);
                _origami.Value.Build(builder1, socket);

                if (context.Updater != null)
                {
                    _socketHandlers.Value.Invoke(s => s.Updated(socketContext), Logger);
                }
            }
            else
            {
                // Build the display shape
                var builder = _origami.Value.BuildDisplayShape(socketContext, prefix, displayType, "Socket", socketContext.Left.ContentType, context)
                              .WithParadigms(socketContext.Paradigms);
                _origami.Value.Build(builder, socket);
            }
            return(socket);
        }
Beispiel #10
0
        protected override ModelDriverResult Update(ConnectorEventContext model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
        {
            var prefix = FullPrefix(context);
            var part   = model.ConnectorContent.As <SequencePart>();

            if (part != null)
            {
                if (updater != null && updater.TryUpdateModel(part, prefix, null, null))
                {
                    // TODO: Adjust sequence of other items?
                }
                return(ModelShape("Connector_Editors_Sequence", () => shapeHelper.EditorTemplate(TemplateName: "Connector.Editors.Sequence", Model: part, Prefix: prefix)));
            }
            return(null);
        }
Beispiel #11
0
 protected override ModelDriverResult Update(SocketEventContext model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
 {
     return(Combined(
                ModelShape("Socket_Finders_SingleChoiceList",
                           () => {
         var prefix = FullPrefix(context, "Single");
         var viewModel = BuildSingleChoiceModel(model, prefix, updater);
         if (updater != null)
         {
             updater.TryUpdateModel(viewModel, prefix, null, null);
             UpdatedSingleChoiceModel(model, viewModel, prefix, updater);
             // Rebuild model
             viewModel = BuildSingleChoiceModel(model, prefix, updater);
         }
         return shapeHelper.EditorTemplate(TemplateName: "Socket.Finders.SingleChoiceList", Model: viewModel, Prefix: prefix);
     }),
                ModelShape("Socket_Finders_MultipleChoiceList",
                           () => {
         var prefix = FullPrefix(context, "Multiple");
         var viewModel = BuildMultipleChoiceModel(model, prefix, updater);
         if (updater != null)
         {
             updater.TryUpdateModel(viewModel, prefix, null, null);
             UpdatedMultipleChoiceModel(model, viewModel, prefix, updater);
             // Rebuild model
             viewModel = BuildMultipleChoiceModel(model, prefix, updater);
         }
         return shapeHelper.EditorTemplate(TemplateName: "Socket.Finders.MultipleChoiceList", Model: viewModel, Prefix: prefix);
     }
                           )));
 }
Beispiel #12
0
 protected override void Update(LensResultsViewModel model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
 {
     // This model runs after the first LensViewModel, so we've collected filters etc.
 }
Beispiel #13
0
 protected override ModelDriverResult Build(LensResultsViewModel model, dynamic shapeHelper, ModelShapeContext context)
 {
     return(null);
 }
Beispiel #14
0
 protected override ModelDriverResult Build(SocketEventContext model, dynamic shapeHelper, ModelShapeContext context)
 {
     return(ModelShape("Socket_Creators_AddNewLinks", () => {
         var data = model.Connector.Settings.ListAllowedContentRight().Select(c => _contentDefinitionManager.GetTypeDefinition(c)).Select(d => new {
             RouteValues = new {
                 area = "Contents",
                 controller = "Admin",
                 action = "Create",
                 socket_populate_name = d.Name,
                 socket_populate_id = model.Left.ContentItem.Id
             },
             Name = d.DisplayName
         });
         return shapeHelper.Socket_Creators_AddNewLinks(Links: data);
     }));
 }
        private IEnumerable <dynamic> MapContentList(SocketDisplayContext model, ModelShapeContext context,
                                                     Func <ConnectorDisplayContext, string, dynamic> rootShapeFactory,
                                                     Action <ConnectorDisplayContext, dynamic, string> buildDisplay)
        {
            // HACK: Invoke filter delegate
            model.Filtering();

            // Build filters etc. starting with a delegate we'll compose
            // TODO: Need access to some filter functionality outside for Alchemy (part of Alchemy, Lens, or some other system?)
            Func <IContentQuery, IContentQuery> baseDelegate = q => q;

            baseDelegate = model.SocketFilters.Aggregate(baseDelegate, (d, f) => (q => f.Apply(d(q))));
            baseDelegate = model.SocketSorters.Aggregate(baseDelegate, (d, f) => (q => f.Apply(d(q))));
            IEnumerable <IConnector> list;

            list = (model.SocketPager == null?
                    model.Query.Connectors.List(baseDelegate)
                : model.Query.Connectors.List(baseDelegate, model.SocketPager));

            var items = new List <dynamic>();

            foreach (var c in list)
            {
                if (c.RightContent == null)
                {
                    continue;
                }

                var connectorContext = new ConnectorDisplayContext(c, String.IsNullOrWhiteSpace(model.Connector.DisplayType)?context.DisplayType:model.Connector.DisplayType, model);
                if (context.Mode == "Editor")
                {
                    _connectorHandlers.Value.Invoke(ch => ch.Editing(connectorContext, context), Logger);
                }
                else
                {
                    _connectorHandlers.Value.Invoke(ch => ch.Displaying(connectorContext, context), Logger);
                }
                if (!connectorContext.RenderConnector)
                {
                    continue;
                }

                // TODO: This prefix won't work if you add multiple connectors to the same item...
                var prefix = FullPrefix(context, c.Id == 0 ? ("New" + c.RightContentItemId.ToString()) : c.Id.ToString());
                var shape  = rootShapeFactory.Invoke(connectorContext, prefix);
                shape.Metadata.DisplayType = connectorContext.Right.DisplayType;

                shape.Metadata.Prefix = prefix;

                if (context.Mode == "Editor")
                {
                    _connectorHandlers.Value.Invoke(ch => ch.Edit(connectorContext, shape, context), Logger);
                }
                else
                {
                    _connectorHandlers.Value.Invoke(ch => ch.Display(connectorContext, shape, context), Logger);
                }

                buildDisplay.Invoke(connectorContext, shape, prefix);

                items.Add(shape);
            }
            ;
            return(items);
        }
Beispiel #16
0
 protected override ModelDriverResult Build(SocketEventContext model, dynamic shapeHelper, ModelShapeContext context)
 {
     return(Combined(
                ModelShape("Sockets_SocketTitle", () => shapeHelper.Sockets_SocketTitle(SocketTitle: model.SocketMetadata.SocketTitle ?? "", SocketHint: model.SocketMetadata.DisplayHint)),
                ModelShape("Sockets_SocketTitle_Edit", () => shapeHelper.Sockets_SocketTitle_Edit(SocketTitle: model.SocketMetadata.SocketTitle ?? "", SocketHint: model.SocketMetadata.EditorHint))
                ));
 }
Beispiel #17
0
 protected override void Update(SocketEventContext model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
 {
 }
Beispiel #18
0
 protected override void Update(SocketsModel model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
 {
     // Handled in Build
 }
 protected override void Update(IContent model, dynamic dynamic, IUpdateModel iUpdateModel, ModelShapeContext context)
 {
 }
Beispiel #20
0
        protected override ModelDriverResult Build(SocketsModel model, dynamic shapeHelper, ModelShapeContext context)
        {
            // HACK: Check for pre-populated sockets
            // We need a better way to get day into here, we might want to populate other stuff, will need a custom controller
            string prepopulateSocket = null;
            int?   prepopulateId     = null;

            if (Services.WorkContext.HttpContext != null)
            {
                if (Services.WorkContext.HttpContext.Request.QueryString["socket_populate_name"] != null)
                {
                    prepopulateSocket = Services.WorkContext.HttpContext.Request.QueryString["socket_populate_name"];
                    prepopulateId     = Services.WorkContext.HttpContext.Request.QueryString["socket_populate_id"].ParseInt();
                }
            }

            // Get all types of Connector
            var result = new List <ModelDriverResult>();

            foreach (var t in model.LeftContent.As <SocketsPart>().Sockets.Allowed)
            {
                // TODO: Even this constructor performs some non-trivial work; since it could run a lot of times for a detailed request
                // we should simplify it a lot
                var socketContext = new SocketDisplayContext(model.LeftContent, t, context.DisplayType, model)
                {
                    ModelContext = context
                };
                if (!String.IsNullOrWhiteSpace(socketContext.Connector.Settings.DefaultParadigms))
                {
                    socketContext.Paradigms.Add(socketContext.Connector.Settings.DefaultParadigms.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries));
                }
                else
                {
                    socketContext.Paradigms.Add(context.Paradigms.All());
                }
                socketContext.Paradigms.Add("Socket");

                _socketHandlers.Value.Invoke(s => s.Preparing(socketContext), Logger);
                if (!socketContext.RenderSocket)
                {
                    continue;
                }

                // HACK: The way this delegate works is pretty awful and needs revision. It can also get called multiple times (e.g. rendering two different types of socket contents)
                // which is why I'm clearing the filters. Really it needs to work completely differently so we can sort and filter directly on the SocketQuery.
                socketContext.Filtering = () => {
                    socketContext.SocketFilters.Clear();
                    socketContext.SocketSorters.Clear();
                    _socketHandlers.Value.Invoke(s => s.Filtering(socketContext), Logger);
                };

                // From this point on, all the handling needs to happen in a factory so it'll only get executed if placement says so
                // Otherwise, we start running into exponential performance problems as we get more and more connections happening.

                // Place in layout?
                // TODO: LayoutPlacement is completely redundant now we have ZoneProxy and Alchemy methods. Paperclip could still be used for the placement-per-item scenario.
                // TODO: Cache therefore needs fixing to work on normal sockets.
                if (!String.IsNullOrWhiteSpace(socketContext.LayoutPlacement))
                {
                    dynamic display;
                    if (socketContext.CacheSocket)
                    {
                        var key         = new SocketCacheKey(model.LeftContent.Id, t.Name, context.DisplayType, Services.WorkContext.HttpContext.Request.Path);
                        var cacheResult = _cacheManager.Get <SocketCacheKey, SocketCacheResult>(key, ctx => {
                            // Set up cache terms
                            ctx.Monitor(_signals.When(new ContentItemSignal(key.Id)));
                            ctx.Monitor(_signals.When("Mechanics_Cache_AllContent"));

                            // Build shape
                            var socket = BuildDisplayDelegate(socketContext, context);

                            // Sockets can still not render at this point and we want to avoid an error in core shapes
                            return(new SocketCacheResult()
                            {
                                Display = socket
                            });
                        });
                        display = shapeHelper.SocketCache(Cache: cacheResult);
                    }
                    else
                    {
                        display = BuildDisplayDelegate(socketContext, context);
                    }
                    // Figure out exact placement
                    var placementBits = socketContext.LayoutPlacement.Split(':');
                    if (placementBits.Length > 1)
                    {
                        // Zone with position
                        Services.WorkContext.Layout.Zones[placementBits[0]].Add(display, placementBits[1]);
                    }
                    else
                    {
                        // Zone without position
                        Services.WorkContext.Layout.Zones[placementBits[0]].Add(display);
                    }
                }
                else
                {
                    var socketResult = new SocketsDriverResult("Socket", "" /*FullPrefix(context)*/, socketContext, BuildDisplayDelegate).Differentiator(t.Name);
                    // TODO: Hack for Site Settings to show sockets on group pages. We can do more with groups than this; support group-by-placement and have tabbed group zones
                    if (model.LeftContent.ContentItem.ContentType == "Site")
                    {
                        // TODO: Allow this (and other settings) to be mutated during the handler pipeline
                        var groupId = socketContext.Connector.Settings.SocketGroupName;
                        socketResult.OnGroup(groupId);
                    }
                    result.Add(socketResult);
                }
            }

            return(Combined(result.ToArray()));
        }
Beispiel #21
0
 protected override ModelDriverResult Display(SocketEventContext model, dynamic shapeHelper, ModelShapeContext context)
 {
     return(null);
 }
Beispiel #22
0
 public UpdateContentEditorContext(IShape model, IContent content, string displayType, IUpdateModel updater, string groupId, IShapeFactory shapeFactory, ShapeTable shapeTable, ModelShapeContext parentContext = null)
     : base(model, content, updater, groupId, shapeFactory, shapeTable)
 {
     DisplayType   = displayType;
     ParentContext = parentContext;
 }
Beispiel #23
0
        protected override ModelDriverResult Update(SocketEventContext model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
        {
            var prefix    = FullPrefix(context);
            var viewModel = new ConnectorBatchOperationViewModel()
            {
                BatchCommandList = new[] {
                    new SelectListItem()
                    {
                        Selected = true, Text = "(nothing)", Value = ""
                    },
                    new SelectListItem()
                    {
                        Selected = false, Text = "Remove", Value = "Delete"
                    },
                }
            };

            if (updater != null)
            {
                if (updater.TryUpdateModel(viewModel, prefix, null, null))
                {
                    if (!String.IsNullOrWhiteSpace(viewModel.BatchCommand))
                    {
                        context.OnUpdated(updated => {
                            switch (viewModel.BatchCommand)
                            {
                            case "Delete":
                                // Delete all selected
                                foreach (var selector in model.Query.Connectors.State <ConnectorSelector>())
                                {
                                    model.Query.Connectors.Remove(selector.Item1);
                                }
                                break;
                            }
                        });
                    }
                }
            }
            return(ModelShape("Socket_Creators_BatchOperation", () => shapeHelper.EditorTemplate(TemplateName: "Socket.Creators.BatchOperation", Prefix: prefix, Model: viewModel)));
        }
 protected override ModelDriverResult Display(ConnectorEventContext model, dynamic shapeHelper, ModelShapeContext context)
 {
     // TODO: For display purposes we might want to group roles and display "Moderators: username, username; Admins: username, username"
     // Actually that could be done more easily with different connectors for each role rather than crazy grouping scenarios...
     return(new ModelDriverResult());
 }
        protected override void Update(SocketEventContext model, LensFinderViewModel viewModel, dynamic shapeHelper, IUpdateModel updater, ModelShapeContext context)
        {
            var prefix = FullPrefix(context);

            if (updater != null)
            {
                updater.TryUpdateModel(viewModel, prefix, null, null);
                UpdatedLensViewModel(model, viewModel, prefix, updater);
            }
        }
        protected override ModelDriverResult Editor(ConnectorEventContext model, dynamic shapeHelper, ModelShapeContext context)
        {
            var part = model.ConnectorContent.As <EffectiveRolesPart>();

            if (part == null)
            {
                return(new ModelDriverResult());
            }
            var viewModel = BuildViewModel(part);

            return(ModelShape("Connector_Editors_EffectiveRoles",
                              () => shapeHelper.EditorTemplate(TemplateName: "Connector.Editors.EffectiveRoles", Model: viewModel, Prefix: FullPrefix(context))));
        }
Beispiel #27
0
 protected override LensQueryTextViewModel ViewModel(LensViewModel model, ModelShapeContext context)
 {
     return(new LensQueryTextViewModel());
 }
        protected override ModelDriverResult Update(ConnectorEventContext model, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
        {
            var part = model.ConnectorContent.As <EffectiveRolesPart>();

            if (part == null)
            {
                return(new ModelDriverResult());
            }
            var viewModel = BuildViewModel(part);
            var prefix    = FullPrefix(context);

            if (updater.TryUpdateModel(viewModel, prefix, null, null))
            {
                // TODO: Check role exists and user is allowed permission
                part.EffectiveRoles = String.Join(" ", viewModel.SelectRoles.ToArray());
            }
            else
            {
                _notifier.Error(T("Error updating Effective Roles."));
            }
            return(ModelShape("Connector_Editors_EffectiveRoles",
                              () => shapeHelper.EditorTemplate(TemplateName: "Connector.Editors.EffectiveRoles", Model: viewModel, Prefix: prefix)));
        }
Beispiel #29
0
 protected override void Update(LensViewModel model, LensQueryTextViewModel viewModel, dynamic shapeHelper, Orchard.ContentManagement.IUpdateModel updater, ModelShapeContext context)
 {
     updater.TryUpdateModel(model, FullPrefix(context), null, null);
 }
        protected override ModelDriverResult Build(SocketDisplayContext model, dynamic shapeHelper, ModelShapeContext context)
        {
            var results = new List <ModelDriverResult>();

            // TODO: Pagers
            return(Combined(
                       ModelShape(
                           "Sockets_Contents_Connectors", () => {
                var items = MapContentList(model, context,
                                           (c, prefix) => {
                    return shapeHelper.Connector(ConnectorType: c.Descriptor.Name, ContentItem: c.ConnectorContent.ContentItem);
                },
                                           (c, shape, prefix) => {
                    var builder = _origami.Value.BuildDisplayShape(c, prefix, c.Right.DisplayType, context.Stereotype, model.Connector.Name, context).WithParadigms(model.Paradigms);
                    _origami.Value.Build(builder, shape);
                });
                var root = shapeHelper.Sockets_Contents(Contents: items);
                return root;
            }),
                       ModelShape(
                           "Sockets_Contents_Right", () => {
                var items = MapContentList(model, context,
                                           (c, prefix) => {
                    // Build content shape
                    // TODO: Might want to use different display types / paradigms for content shape and connector?
                    return _origami.Value.ContentShape(c.Right.Content, c.Right.DisplayType, prefix: prefix);
                },
                                           (c, shape, prefix) => {
                    var builder = _origami.Value.BuildDisplayShape(c.Right.Content, prefix, c.Right.DisplayType,
                                                                   context.Stereotype, c.Right.ContentType, context)
                                  // TODO: Need mode and updater in here to work properly for editors
                                  .WithParadigms(model.Paradigms).WithParadigms(new[] { "Nested" });
                    _origami.Value.Build(builder, shape);
                });

                var root = shapeHelper.Sockets_Contents(Contents: items);
                return root;
            }),
                       ModelShape(
                           "Sockets_Contents_Flat", () => {
                var items = MapContentList(model, context,
                                           (c, prefix) => {
                    // Build content shape
                    var shape = _origami.Value.ContentShape(c.ConnectorContent.ContentItem, c.Right.DisplayType, prefix: prefix);
                    shape.ContentConnector = c.ConnectorContent.ContentItem;
                    shape.ContentRight = c.Right.Content.ContentItem;
                    shape.ContentLeft = c.SocketContext.Left.ContentItem;
                    return shape;
                },
                                           (c, shape, prefix) => {
                    // TODO: Need mode and updater in here to work properly for editors
                    var builder = _origami.Value.BuildDisplayShape(c.ConnectorContent,
                                                                   prefix, c.Right.DisplayType,
                                                                   context.Stereotype, model.Connector.Name, context)
                                  .WithParadigms(model.Paradigms)
                                  .WithParadigms(new[] { "Nested" });
                    _origami.Value.Build(builder, shape);
                    var builder2 = _origami.Value.BuildDisplayShape(c.Right.Content, prefix, c.Right.DisplayType,
                                                                    context.Stereotype, c.Right.ContentType, context)
                                   .WithParadigms(model.Paradigms)
                                   .WithParadigms(new[] { "Nested" });
                    _origami.Value.Build(builder2, shape);
                });

                var root = shapeHelper.Sockets_Contents(Contents: items);
                return root;
            }),
                       ModelShape(
                           "Sockets_Contents_Edit", () => {
                var items = MapContentList(model, context,
                                           (c, prefix) => {
                    return shapeHelper.Connector_Edit(ContentItem: c.SocketContext.Left.ContentItem, RightContentItem: c.Right.Content, ConnectorType: c.Descriptor.Name, RightContentType: c.Right.ContentType, LeftContentType: c.SocketContext.Left.ContentType);
                },
                                           (c, shape, prefix) => {
                    var builder = _origami.Value.BuildEditorShape(c, context.Updater, prefix, c.Right.DisplayType, context.Stereotype, model.Connector.Name, context).WithMode("Editor").WithParadigms(model.Paradigms);
                    _origami.Value.Build(builder, shape);
                });

                var root = shapeHelper.Sockets_Contents(Contents: items);
                return root;
            }),
                       ModelShape(
                           "Sockets_Contents_Links", () => {
                var items = MapContentList(model, context,
                                           (c, prefix) => {
                    return shapeHelper.Link();
                },
                                           (c, shape, prefix) => {
                    // TODO: I *think* it's best to only populate the shape's properties here; so they can definitely be adjusted in content events first, and
                    // it prevents processing if the connector isn't displayed. On the other hand, maybe it'd be better to let connector events alter the
                    // shape directly instead ..
                    var metadata = c.Right.Metadata;
                    if (metadata.DisplayRouteValues != null)
                    {
                        shape.Text = metadata.DisplayText;
                        shape.Values = metadata.DisplayRouteValues;
                    }
                    ;
                });
                var root = shapeHelper.SeparatorList(Items: items);
                return root;
            })
                       ));
        }