Combining complex panels in the preferences framework

Justin Obara obara.justin at gmail.com
Wed Aug 28 20:35:09 UTC 2013


I was talking to Alexander about ways to modularize a panel that contained multiple adjusters/preferences. We don't have a lot of examples currently of this case with the exception of linksControls which combines links and inputsLarger preferences. Today I tried to tackle this and see how we could break it apart, for modularity, and bring them back together to be used in a single panel.

    /*
        original
     */

    fluid.defaults("fluid.uiOptions.panels.linksControls", {
        gradeNames: ["fluid.uiOptions.panels", "autoInit"],
        preferenceMap: {
            "fluid.uiOptions.emphasizeLinks": {
                "model.links": "default"
            },
            "fluid.uiOptions.inputsLarger": {
                "model.inputsLarger": "default"
            }
        },
        selectors: {
            links: ".flc-uiOptions-links",
            inputsLarger: ".flc-uiOptions-inputs-larger",
            label: ".flc-uiOptions-links-label",
            linksChoiceLabel: ".flc-uiOptions-links-choice-label",
            inputsChoiceLabel: ".flc-uiOptions-links-inputs-choice-label"
        },
        protoTree: {
            label: {messagekey: "linksLabel"},
            linksChoiceLabel: {messagekey: "linksChoiceLabel"},
            inputsChoiceLabel: {messagekey: "inputsChoiceLabel"},
            links: "${links}",
            inputsLarger: "${inputsLarger}"
        }
    });


The two options I could think of would be to 1) have each preference as a separate panel and use grade merging to combine them and 2) use a set of subcomponents. I'll give examples of these below. Any thoughts on which of these options seems more appropriate and if there is a better alternative?

     /*
        Grade merging
     */


    fluid.defaults("fluid.uiOptions.panels.links", {
        gradeNames: ["fluid.uiOptions.panels", "autoInit"],
        preferenceMap: {
            "fluid.uiOptions.emphasizeLinks": {
                "model.value": "default"
            }
        },
        selectors: {
            links: ".flc-uiOptions-links",
            linksChoiceLabel: ".flc-uiOptions-links-choice-label"
        },
        protoTree: {
            linksChoiceLabel: {messagekey: "linksChoiceLabel"},
            links: "${links}"
        }
    });

    fluid.defaults("fluid.uiOptions.panels.inputsLarger", {
        gradeNames: ["fluid.uiOptions.panels", "autoInit"],
        preferenceMap: {
            "fluid.uiOptions.inputsLarger": {
                "model.value": "default"
            }
        },
        selectors: {
            inputsLarger: ".flc-uiOptions-inputs-larger",
            inputsChoiceLabel: ".flc-uiOptions-links-inputs-choice-label"
        },
        protoTree: {
            inputsChoiceLabel: {messagekey: "inputsChoiceLabel"},
            inputsLarger: "${inputsLarger}"
        }
    });

    fluid.defaults("fluid.uiOptions.panels.linksControls", {
        gradeNames: ["fluid.uiOptions.panels", "fluid.uiOptions.panels.links", "fluid.uiOptions.panels.inputsLarger", "autoInit"],
        selectors: {
            label: ".flc-uiOptions-links-label"
        },
        protoTree: {
            label: {messagekey: "linksLabel"},
            linksChoiceLabel: {messagekey: "linksChoiceLabel"},
            inputsChoiceLabel: {messagekey: "inputsChoiceLabel"},
            links: "${links}",
            inputsLarger: "${inputsLarger}"
        }
    });


With the grade merging we run into issues around the model values. Each individual grade would have to have a unique model or else all of the preferences will share the same one. Which, in most cases, would be undesirable. There are two places where this would be an issue:  preferenceMap and protoTree. We seem to always have to override the protoTree when merging grades, so this is less of an issue in terms of the model. However, the preferenceMaps do merge. We could override them in the new grade, "fluid.uiOptions.panels.linksControls" in this case. Another issue, as mentioned, the protoTree seems to always need to be set in the new grade, which is a bit of a hassle to have to manually combine them all.

     /*
        Subcomponents option
      */

    fluid.defaults("fluid.checkbox", {
        gradeNames: ["fluid.rendererComponent", "autoInit"],
        strings: {},
        selectors: {
            input: ".flc-checkbox-input",
            label: ".flc-checkbox-label"
        },
        protoTree: {
            input: "${value}",
            label: {messagekey: "label"}
        }
    });

    fluid.defaults("fluid.uiOptions.panels.linksControls", {
        gradeNames: ["fluid.uiOptions.panels", "autoInit"],
        preferenceMap: {
            "fluid.uiOptions.emphasizeLinks": {
                "model.links": "default"
            },
            "fluid.uiOptions.inputsLarger": {
                "model.inputsLarger": "default"
            }
        },
        selectors: {
            links: ".flc-uiOptions-links",
            inputsLarger: ".flc-uiOptions-inputs-larger",
            label: ".flc-uiOptions-links-label",
            linksChoiceLabel: ".flc-uiOptions-links-choice-label",
            inputsChoiceLabel: ".flc-uiOptions-links-inputs-choice-label"
        },
        selectorsToIgnore: ["links", "inputsLarger", "linksChoiceLabel", "inputsChoiceLabel"],
        components: {
            links: {
                type: "fluid.checkbox",
                createOnEvent: "afterRender",
                container: "{that}.container",
                options: {
                    gradesNames: ["fluid.uiOptions.modelRelay"],
                    selectors: {
                        input: "{linksControls}.options.selectors.links",
                        label: "{linksControls}.options.selectors.linksChoiceLabel"
                    },
                    protoTree: {
                        input: "${value}",
                        label: {messagekey: "linksChoiceLabel"}
                    },
                    mergePolicy: {
                        sourceApplier: "nomerge"
                    },
                    sourceApplier: "{linksControls}.applier",
                    parentBundle: "{linksControls}.options.parentBundle",
                    rules: {
                        "links": "value"
                    },
                    listeners: {
                        "{linksControls}.events.afterRender": "{that}.refreshView"
                    },
                    renderOnInit: true
                }
            },
            inputsLarger: {
                type: "fluid.checkbox",
                container: "{that}.container",
                createOnEvent: "afterRender",
                options: {
                    gradesNames: ["fluid.uiOptions.modelRelay"],
                    selectors: {
                        input: "{linksControls}.options.selectors.inputsLarger",
                        label: "{linksControls}.options.selectors.inputsChoiceLabel"
                    },
                    protoTree: {
                        input: "${value}",
                        label: {messagekey: "inputsChoiceLabel"}
                    },
                    mergePolicy: {
                        sourceApplier: "nomerge"
                    },
                    sourceApplier: "{linksControls}.applier",
                    parentBundle: "{linksControls}.options.parentBundle",
                    rules: {
                        "inputsLarger": "value"
                    },
                    listeners: {
                        "{linksControls}.events.afterRender": "{that}.refreshView"
                    }
                }
            }
        },
        protoTree: {
            label: {messagekey: "linksLabel"}
        }
    });


When using subcomponents, it really seems like a lot of work to get the configuration right. Most of this stems from the need to set up a modelRelay between the subComponents and parent. NOTE: I didn't actually get this one working properly. 

Thanks
Justin




More information about the fluid-work mailing list