diff --git a/src/js/core/fluidNewRenderer.js b/src/js/core/fluidNewRenderer.js index ab2b44e..7cc2d5a 100644 --- a/src/js/core/fluidNewRenderer.js +++ b/src/js/core/fluidNewRenderer.js @@ -51,10 +51,13 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt includeTemplateRoot: false, workflows: { global: { + bindMarkup: { + funcName: "fluid.renderer.workflow.bindMarkup", + priority: "after:fetchTemplates", + waitIO: true + }, renderMarkup: { - funcName: "fluid.renderer.renderMarkup", - // TODO: Should really be able to specify that this depends on BOTH resolveResourceModel AND fetchTemplates - // But then what becomes of our "positional" priority scheme! + funcName: "fluid.renderer.workflow.renderMarkup", priority: "after:resolveResourceModel", waitIO: true } @@ -154,6 +157,16 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt target.classList.add.apply(target.classList, source.classList); }; + /** Render the template for the supplied component, given a representation of the parent container. If the parent + * is a renderer DOM range, the new container will be appended to the end of the range. If the parent is a + * DocumentFragment for a fresh DOM section, the template will be appended as the first (and expected only) child. + * If the parent is a conventional (single) DOM node, the template root node will be fused with it. + * @param {fluid.newRendererComponent} that - The renderer component for which the template is to be rendered + * @param {DomRange} outerContainer - A jQuery-like wrapper for the parent DOM range. Either a return from + * a renderer DOM binder or a conventional wrapped node + * @return {Element} The template root node which was cloned from the component's template. In case 3 where the + * template was fused to an existing DOM node, this will not be the upcoming component's container. + */ fluid.renderer.renderTemplate = function (that, outerContainer) { var $b = fluid.renderer.binderSymbol; var templateContainer = that.resources.template.parsed.node.cloneNode(true); @@ -210,10 +223,11 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt } // We do this here otherwise there is nothing we could initialise "container" with - and also in this case // we know there must be a parent rendererComponent and hence we are not in "split mode" - innerContainer = fluid.renderer.renderTemplate(that, outerContainer); + innerContainer = $(fluid.renderer.renderTemplate(that, outerContainer)); } } - return $(innerContainer); + fluid.allocateSimpleId(innerContainer); + return innerContainer; }; // Modifies supplied argument @@ -320,7 +334,11 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt var innerContainer = dom.containerFragment || dom.locate("container"); // TODO: Resolve "elideParent" option to fuse inner and outer containers // TODO: Extract some kind of base class out of "fluid.containerRenderingView" so that we could expose a path via override of renderMarkup and that.options.markup.container - fluid.renderer.renderTemplate(that, innerContainer); + var templateContainer = fluid.renderer.renderTemplate(that, innerContainer); + if (dom.containerFragment) { + // Copy the upcoming id in so that self-based selectors will work + templateContainer.id = dom.locate("container")[0].id; + } } }; @@ -417,11 +435,14 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt } }, events: { + bindMarkup: null, render: null }, - members: { - }, listeners: { + "bindMarkup.bindMarkup": { + funcName: "fluid.renderer.bindMarkup", + args: ["{that}", "{arguments}.0"] + }, "render.render": { funcName: "fluid.renderer.render", args: ["{that}", "{arguments}.0"] @@ -429,9 +450,9 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt } }); - /** Main listener to the fluid.renderer's "render" event */ + /** Main listener to the fluid.renderer's "bindMarkup" event */ - fluid.renderer.render = function (renderer, shadows) { + fluid.renderer.bindMarkup = function (renderer, shadows) { // First phase of render workflow after resource resolution - first listener to renderer.events.render console.log("About to render " + shadows.length + " components to renderer " + fluid.dumpComponentPath(renderer)); @@ -440,17 +461,14 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt // Evaluating the container of each component will force it to evaluate and render into it fluid.getForComponent(that, "container"); fluid.getForComponent(that, "dom"); - that.events.onDomBind.fire(that); }); + }; + fluid.renderer.render = function (renderer, shadows) { + // Final call for model-driven DOM modifications before we are attached shadows.forEach(function (shadow) { - // TODO: Will eventually be "Late materialised model relay" which is possible since transaction is not closed - // until notifyInitModel - // Note that leaf components will probably be abolished - this work will be done during onDomBind through materialisation var that = shadow.that; - if (fluid.componentHasGrade(that, "fluid.leafRendererComponent")) { - fluid.getForComponent(that, "updateTemplateMarkup")(that.container[0], that.model); - } + that.events.onDomBind.fire(that); }); // Final pass to render all accumulate documentFragments into the real dom shadows.forEach(function (shadow) { @@ -461,12 +479,22 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt }); }; + fluid.registerNamespace("fluid.renderer.workflow"); + + fluid.renderer.workflow.bindMarkup = function (shadows) { + fluid.renderer.workflow.toEvent(shadows, "bindMarkup"); + }; + + fluid.renderer.workflow.render = function (shadows) { + fluid.renderer.workflow.toEvent(shadows, "render"); + }; + /** Main workflow function for fluid.newRendererComponent's global workflow. * Assembles map of rendererComponent's to corresponding renderer, and then fires the "render" * event on each renderer */ - fluid.renderer.renderMarkup = function (shadows) { + fluid.renderer.workflow.toEvent = function (shadows, eventKey) { // Map of parent renderer's id to list of nested renderer components var rendererToShadows = {}; shadows.forEach(function (shadow) { @@ -479,11 +507,9 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt fluid.pushArray(rendererToShadows, parentRenderer.id, shadow); } }); - // var renderId = fluid.allocateGuid(); fluid.each(rendererToShadows, function (shadows, key) { var renderer = fluid.globalInstantiator.idToShadow[key].that; - fluid.getForComponent(renderer, "events.render"); - renderer.events.render.fire(shadows); + renderer.events[eventKey].fire(renderer, shadows); }); }; diff --git a/src/js/core/fluidNewRendererComponents.js b/src/js/core/fluidNewRendererComponents.js index 7db432a..e633869 100644 --- a/src/js/core/fluidNewRendererComponents.js +++ b/src/js/core/fluidNewRendererComponents.js @@ -12,76 +12,103 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt (function ($, fluid) { "use strict"; - // Mix this in to any fluid.leafRendererComponent under a fluid.renderer.template in order to keep it live - fluid.defaults("fluid.templateLeafRendererComponent", { - modelListeners: { - updateTemplateMarkup: { - path: "", - func: "{that}.updateTemplateMarkup", - args: ["{that}.container.0", "{change}.value"] + fluid.defaults("fluid.polyMarkupComponent", { + gradeNames: "fluid.newRendererComponent", + listeners: { + "onDomBind.checkMarkup": { + listener: "fluid.polyMarkupComponent.check", + args: "{that}" } } }); - fluid.defaults("fluid.leafRendererComponent", { - gradeNames: "fluid.newRendererComponent", - invokers: { - updateTemplateMarkup: { - // signature: container node, model contents - funcName: "fluid.notImplemented" + fluid.polyMarkupComponent.check = function (that) { + var checks = fluid.getForComponent(that, ["options", "markupChecks"]); + var grade = fluid.find(checks, function (grade, value) { + if (value.selector !== undefined) { + var container = that.dom.container; + var fullSelector = "#" + container.id + " " + value.selector; + var nodes = that.dom.doQuery(fullSelector, "*"); + if (nodes[0].tagName === value.tagName) { + return grade; + } + } else { + return grade; } - }, - parentMarkup: true - }); + }); + if (grade !== undefined) { + var shadow = fluid.shadowForComponent(that); + // Cheapskate strategy - grade content will be wrong since we can't be bothered to hack into computeDynamicGrades and its malignly hidden "rec" structure + shadow.mergeBlocks.push(fluid.generateExpandBlock({ + options: fluid.defaults(grade), + recordType: "polyMarkupBindings", + priority: fluid.mergeRecordTypes.distribution + }, that, {})); + shadow.mergeOptions.updateBlocks(); + } + }; fluid.defaults("fluid.uiValue", { - gradeNames: "fluid.leafRendererComponent", + gradeNames: "fluid.polyMarkupComponent", model: { // value: any }, - invokers: { - updateTemplateMarkup: { - funcName: "fluid.uiValue.updateTemplateMarkup", - // container node, new model - args: ["{arguments}.0", "{that}.options.verbatim", "{arguments}.1"] + markupChecks: { + "fluid.uiInputValue": { + selector: "", + tagName: "input" + }, + "fluid.uiTextValue": {} + } + }); + + fluid.defaults("fluid.uiTextValue", { + modelRelay: { + value: { + target: "dom.container.text", + source: "{that}.model.value" } }, resources: { template: { resourceText: "" } - }, - verbatim: false + } }); - // See old fluidRenderer.js renderComponent - - fluid.registerNamespace("fluid.uiValue.template"); - - fluid.uiValue.updateTemplateMarkup = function (node, verbatim, model) { - if (typeof(model.value) !== "string") { - fluid.fail("uiValue component is missing required model field \"value\": model contents are ", model); - } - var encodedValue = verbatim ? model.value : fluid.XMLEncode(model.value); - var tagName = node.tagName; - if (tagName === "input") { - fluid.setImmediate(node, ["attrs", "value"], encodedValue); - } else { - node.children = [{text: encodedValue}]; + fluid.defaults("fluid.uiInputValue", { + gradeNames: "fluid.polyMarkupComponent", + model: { + // value: any + }, + modelRelay: { + value: { + target: "dom.container.value", + source: "{that}.model.value" + } + }, + resources: { + template: { + resourceText: "" + } } - }; + }); fluid.defaults("fluid.uiLink", { - gradeNames: "fluid.leafRendererComponent", + gradeNames: "fluid.newRendererComponent", + parentMarkup: true, model: { // target: string - // linktext: string (optional) + // linkText: string (optional) }, - invokers: { - updateTemplateMarkup: { - funcName: "fluid.uiLink.updateTemplateMarkup", - // container node, new model - args: ["{arguments}.0", "{that}.options.verbatim", "{arguments}.1"] + modelRelay: { + linkTarget: { + target: "dom.container.attrs.href", + source: "{that}.model.target" + }, + linkText: { + target: "dom.container.text", + source: "{that}.model.linkText" } }, resources: { @@ -91,6 +118,10 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt } }); + /** Could be supported some day via some variety of AFFERENT POLYMORPHISM but the reusability value seems low - + * the user is far more likely to simply specify the relay rule onto the relevant attribute inline as above + */ + /* fluid.uiLink.attributeMap = { // From old fluidRenderer.js a: "href", link: "href", @@ -119,5 +150,6 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt }]; } }; + */ })(jQuery, fluid_3_0_0);