protected override void Preparing(SocketDisplayContext context) { if (context.ModelContext.Mode == "Display" && context.Paradigms.Has("Navigation") && context.ModelContext.DisplayType == "Navigation") { context.Connector.DisplayType = "Navigation"; } }
protected override void Displaying(SocketDisplayContext context) { // Set a paradigm for empty sockets if (context.Query.TotalCount == 0) { context.Paradigms.Add("Empty"); if (!context.Paradigms.Has("ShowEmpty")) { context.RenderSocket = false; } // TODO: A pure-placement method didn't work because Displaying happens after Placement. But we don't want to execute the count for every single connector type // because a lot will already be decided against in advance. Either a) cache the current count on SocketsPartRecord or b) find another way, e.g. a delegate that // will only run if placement hasn't already been denied. // context.Paradigms.Add("Empty"); } // Do some default display type mapping // TODO: Could be done in placement now? if (String.IsNullOrWhiteSpace(context.Connector.DisplayType)) { switch (context.Left.DisplayType) { case "Detail": context.Connector.DisplayType = "Summary"; break; case "Summary": context.Connector.DisplayType = "SummaryTiny"; context.Paradigms.Add("ConnectorsFlatten"); break; case "SummaryAdmin": context.Connector.DisplayType = "Link"; context.Paradigms.Add("ConnectorsFlatten"); break; case "SummaryTiny": // Prevent further recursion by default context.RenderSocket = false; break; case "Link": // Prevent further recursion by default context.RenderSocket = false; break; default: // Any other situtations we don't understand, just use links. context.Connector.DisplayType = "Link"; break; } } }
protected override void Displaying(SocketDisplayContext context) { // TODO: Optionally expose a unified feed comprised of all applicable connector types. // TODO: We could feasibly want to register the feed on other display types if (context.Left.DisplayType == "Detail") { var settings = context.Connector.PartDefinition.Settings.GetModel <AggregationTypePartSettings>(); if (settings != null && settings.ExposeFeed) { _feedManager.Register(context.Left.ContentItem.GetTitle() + " - " + context.SocketMetadata.SocketTitle, "rss", new RouteValueDictionary { { "id", context.Left.ContentItem.Id }, { "connector", context.Connector.Name } }); } } }
protected override void Preparing(SocketDisplayContext context) { context.ModelContext.With <DrillFilterData>(df => { if (context.Connector.Name == df.DrillType) { context.Paradigms.Add("DrillSummary"); if (df.Id.HasValue) { context.ModelContext.Paradigms.Add("DrillDetail"); } } else { context.Paradigms.Add("DrillExclude"); } }); }
protected override void Preparing(SocketDisplayContext context) { if (context.Left.DisplayType == "Detail") { var clipPart = context.Connector.Definition.Parts.FirstOrDefault(p => p.PartDefinition.Name == "PaperclipPart"); if (clipPart != null) { // Get actual part model from item var settings = clipPart.Settings.GetModel <PaperclipTypePartSettings>(); if (!String.IsNullOrWhiteSpace(settings.DefaultPlacement)) { context.LayoutPlacement = settings.DefaultPlacement; } if (!String.IsNullOrWhiteSpace(settings.DefaultDisplayType)) { context.Connector.DisplayType = settings.DefaultDisplayType; } } } }
protected override void Editing(SocketDisplayContext context) { context.Left.DisplayType = "Editor"; context.Connector.DisplayType = "EditorConnector"; if (context.Query.TotalCount == 0) { context.Paradigms.Add("Empty"); } // Check box list or drop down list? context.Paradigms.Add(context.Connector.Settings.AllowMany ? "Many" : "One"); context.Paradigms.Add(context.Connector.Settings.AllowDuplicates ? "DuplicatesPossible" : "Unique"); // Outright hide editor. Typically used when we have an inverse connector and we only // actually want to work with one end of the connector in UI. if (context.Paradigms.Has("Hidden")) { context.RenderSocket = false; } }
protected override void Displaying(SocketDisplayContext context) { if (context.RootModel.DisplayType == "Detail") { switch (context.Connector.Name) { case "CountryToTown": context.Left.DisplayType = context.Connector.DisplayType = "Directory"; // TODO: In migration add to settings context.Paradigms.Add("Count"); break; case "TownToAddress": context.Left.DisplayType = context.Connector.DisplayType = "Listing"; // TODO: In migration add to settings context.Paradigms.Add("Collapse"); break; } } // From DirectoryController, we get a bunch of Address items in Summary mode if (context.RootModel.DisplayType == "Summary") { switch (context.Connector.Name) { case "AddressToUser": context.Left.DisplayType = context.Connector.DisplayType = "Listing"; break; case "AddressToTown": context.Left.DisplayType = context.Connector.DisplayType = "Listing"; break; } } if (context.RootModel.DisplayType == "Listing") { // ... } }
public SocketsDriverResult(string shapeType, string prefix, Framework.SocketDisplayContext socketContext, Func <SocketDisplayContext, ModelShapeContext, dynamic> factory) : base(shapeType, prefix, (c) => factory(socketContext, c)) { SocketContext = socketContext; }
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())); }
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); }
protected override void Displaying(SocketDisplayContext context) { }