render a text field as a skuid icon property field in runtime

  • 1
  • Question
  • Updated 1 year ago
  • In Progress
I'd like to provide users with the same icon-selection experience that we have in the skuid builder to populate an "Icon" field on the runtime side of a skuid page.

Help?
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb

Posted 1 year ago

  • 1
Photo of mB Pat Vachon

mB Pat Vachon, Champion

  • 42,704 Points 20k badge 2x thumb
I once wanted the same thing. I recall that at the time it seemed infeasible.
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Hmm.  I'm wondering if I can just add the skuid builder js files as static resources to the page, and somehow tap into the existing functions.
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Here's a beginning:

var field = arguments[0], value = arguments[1],
$ = skuid.$,
component = skuid.$C('new-item-component'),
props = {id:"icon", label:"Icon", type:"icon"};
field.element.append(skuid.builder.core.propertyRenderers.icon(props,component.element));
Photo of mB Pat Vachon

mB Pat Vachon, Champion

  • 42,704 Points 20k badge 2x thumb
Does it work? If so, that would pretty cool.
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
It doesn't work. It displays a field with the icon button, and if you put the name of an icon in the field the button will show that icon. But clicking the button doesn't deliver the popup (I think because skuid is trying to get the page's xml to get the theme to determine which icon sets to use, but I haven't had time to explore farther).
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Yes, the problem is definitely that skuid tries to get the theme from the page XML, but there is no 'page xml' on runtime. Skuid is running skuid.builder.core.getPageXML().attr("theme"), but .attr("theme") throws an error because .getPageXML() returns null.

I think the only way around this would be to grab all the code that skuid uses up to that point in the creation of the input field and button and icon picker dialog, and the change the call for the function that returns the available icon sets to something that skuid can use... perhaps inserting the current theme instead of asking for the pageXML to get the theme.

Which seems like more trouble than it's worth?
(Edited)
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
It works!!!!!

One caveat is that this seems to only be working if you use a custom theme. In the settings of the javascript resource you'll need to replace "Optimize" and "OptimizeThemeZIP" with the name and resource name for your own custom theme. I'm not sure why, but when I try to use any of the standard skuid themes, no icons show up in the popup.

Proof of concept:
<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="false" useviewportmeta="true" showheader="false">
    <models>
        <model id="Account" limit="1" query="true" createrowifnonefound="true" datasource="salesforce" type="" sobject="Account">
            <fields>
                <field id="Name"/>
                <field id="AccountNumber"/>
                <field id="Jigsaw"/>
            </fields>
            <conditions/>
            <actions/>
        </model>
    </models>
    <components>
        <basicfieldeditor showheader="true" showsavecancel="true" showerrorsinline="true" model="Account" buttonposition="" uniqueid="sk-2TCfqG-165" mode="read">
            <columns>
                <column width="50%">
                    <sections>
                        <section title="Section A" collapsible="no">
                            <fields>
                                <field id="Name"/>
                                <field id="AccountNumber"/>
                            </fields>
                        </section>
                    </sections>
                </column>
                <column width="50%">
                    <sections>
                        <section title="Section B" collapsible="no">
                            <fields>
                                <field id="Jigsaw" valuehalign="" type="CUSTOM" snippet="renderIconSeletor">
                                    <label>Icon</label>
                                </field>
                            </fields>
                        </section>
                    </sections>
                </column>
            </columns>
        </basicfieldeditor>
    </components>
    <resources>
        <labels/>
        <javascript>
            <jsitem location="staticresource" name="BuilderCoreJS" cachelocation="false" url="" namespace="skuid" content_type="text/javascript">var params = arguments[0],
$ = skuid.$;
</jsitem>
            <jsitem location="staticresource" name="SkuidBuildersJS" cachelocation="false" url="" namespace="skuid" content_type="text/javascript">var params = arguments[0],
$ = skuid.$;
</jsitem>
            <jsitem location="inline" name="customIconPickerJS" cachelocation="false" url="">// Icon Picker Javascript
(function(a){
/*
*
* Enter Parameters for your Theme
*
*/
var themeName = "Optimize",
themeResourceName = "OptimizeThemeZIP";
//Global Shortcuts
var $ = a.$,
i = $.each,
j = a.builder.core, 
k = a.utils,
p = {}, 
q = "sk-icon",
r = j.updateState;
/*
*
* Skuid custom field renderer snippet
* Use "renderIconSelector" as the custom renderer on a Text field
* to turn that field into a skuid icon selector.
*
*/
skuid.snippet.registerSnippet('renderIconSeletor',function(field,value){
    var props = {id:"icon", label:"Icon", type:"icon"};
field.element.append(renderIconProp(props,field.editor.element));
var input = field.element.find('input');
if (value) input.val(value);
input.change(function(){
    field.model.updateRow(field.row,field.id,$(this).val(),{initiatorId:field._GUID});
});
})
/*
*
* Edited Skuid Code Below
*
*/
function b(b) {
        var c, d, e, f, g, 
        h = {}, 
        j = themeName, 
        l = a.platform.getEntityFieldNames("theme"), 
        m = {
        Optimize: {
        Name:themeName,
skuid__Resource_Name__c: themeResourceName
}
};
        if (m) {
            if (j ? (i(m, function(a, b) {
                if (b[l.name] === j)
                    return g = b, !1;
            }),
            g &amp;&amp; (l.resource_namespace &amp;&amp; l.resource_name ? (e = g[l.resource_namespace],
            d = g[l.resource_name]) : (e = null,
            d = g[l.name]))) : (f = a.page.runtimeThemeResource.split("__"),
            2 === f.length ? (e = f[0],
            d = f[1]) : (e = null,
            d = f[0])),
            d &amp;&amp; (c = a.platform.themeBuilder.getThemeResourceUrl({
                name: d,
                namespace: e,
                modstamp: (new Date).getTime()
            })),
            c) {
                var o = {
                    Name: d,
                    NamespacePrefix: e
                },
                p = a.$.map(["skuid_theme.json", "resources.json"], function(b) {
                    return a.platform.themeBuilder.getResource(o, b);
                });
                a.$.when.all(p).done(function(a) {
                    var d = {
                        url: c,
                        "skuid_theme.json": k.isString(a[0]) ? JSON.parse(a[0]) : a[0],
                        "resources.json": k.isString(a[1]) ? JSON.parse(a[1]) : a[1]
                    };
                    b &amp;&amp; b(d);
                });
            }
            return h;
        }
    }
    function c(a) {
        a.empty(),
        p &amp;&amp; p[q] &amp;&amp; p[q].icons &amp;&amp; i(p[q].icons, function(b) {
            var c = b.substr(q.length + 1)
              , d = $("&lt;div&gt;").addClass("nx-picker-icon " + q + " " + b).attr("alt", c).attr("title", c)
              , e = $('&lt;div class="nx-picker-icon-label"&gt;').text(c);
            $('&lt;div class="nx-picker-icon-wrapper"&gt;').append(d, e).appendTo(a)
        })
    }
function customBuildIconPicker(a, d, e) {
        function f(a) {
            p = a["skuid_theme.json"].iconsets,
            p &amp;&amp; i(p, function(a, b) {
                var c = $("&lt;div&gt;").addClass("nx-picker-header-category").text(b.label);
                c.data("category", a),
                q === a &amp;&amp; c.addClass("nx-picker-selected"),
                c.data("prefix", a),
                n.append(c)
            }),
            c(m);
        }
        a.addClass("nx-picker-wrapper").appendTo("body");
        var g = $("&lt;div&gt;").addClass("nx-picker-header").appendTo(a), 
        j = $("&lt;input&gt;").addClass("nx-picker-filter-input").attr("type", "text").appendTo(g),
        l = $("&lt;div&gt;").addClass("nx-picker-cancel inline sk-icon sk-icon-cancel").css({
            cursor: "pointer",
            margin: "0px 5px 4px"
        }).skootip("Clear Filter Text").appendTo(g),
        m = $("&lt;div&gt;").addClass("nx-picker-body").appendTo(a),
        n = $("&lt;div&gt;").addClass("nx-picker-header-category-wrapper").appendTo(g);
        $("&lt;label&gt;").text("Filter Icons: ").appendTo(g),
        n.on("click", ".nx-picker-header-category", function() {
            var a = $(this);
            n.find(".nx-picker-selected").removeClass("nx-picker-selected"),
            a.addClass("nx-picker-selected"),
            q = a.data("prefix"),
            c(m)
        }),
        k.delayInputCallback(j, function(a) {
            var b = m.parent();
            a = a.toLowerCase(),
            m.detach(),
            "" === a ? m.find(".nx-picker-icon-wrapper").show() : (m.find("." + q).not('[alt*="' + a + '"]').parent().hide(),
            m.find("." + q + '[alt*="' + a + '"]').filter(":hidden").parent().show()),
            m.appendTo(b)
        }),
        m.skootip(),
        l.click(function() {
            j.val("").change()
        }),
        m.on("click", ".nx-picker-icon-wrapper", function() {
            var b = $(this).children("." + q).first().attr("alt");
            d.val(q + "-" + b).change(),
            e.empty().removeClass().addClass("nx-picker-icon " + q + " inline " + q + "-" + b),
            a.dialog("close")
        }),
        p.length || b(f)
    }
var renderIconProp = function(a, b) {
        var c, 
        e = a.id, 
        f = !0 === a.isStateless, 
        i = e &amp;&amp; b.attr(e) || a.valueFunction &amp;&amp; a.valueFunction() || a.defaultValue || "", 
        j = $("&lt;div&gt;").addClass("nx-pagebuilder-property-button-area"), 
        l = $("&lt;input&gt;").attr("type", "text").addClass("nx-picker-icon-input").val(i).appendTo(j), 
        m = $("&lt;button&gt;").addClass("nx-picker-icon-btn nx-picker-icon-runtime"), 
        n = $("&lt;div&gt;"), 
        o = $("&lt;div&gt;").addClass("nx-pagebuilder-property-button-wrapper");
        if ("" === i ? n.removeClass().addClass("nx-picker-icon").text("?") : n.addClass("nx-picker-icon sk-icon " + i),
        a.readonly) {
            var p = $("&lt;div&gt;").addClass("nx-pagebuilder-property-button-area").append(g.readonly(i));
            return o.append(n).css("margin-top", "6px"),
            [o, p]
        }
        return m.append(n),
        m.on("click", function() {
            c ? c.dialog("open") : (c = $("&lt;div&gt;"),
            customBuildIconPicker(c, l, n),
            c.dialog({
                width: 800,
                height: 400,
                title: "Choose an Icon",
                resizable: !0,
                modal: !0
            }))
        }),
        o.append(m),
        k.delayInputCallback(l, function(c) {
            "" === c ? n.removeClass().addClass("nx-picker-icon inline").text("?") : n.empty().removeClass().addClass("nx-picker-icon sk-icon inline " + c),
            f || r(b, {
                key: e,
                value: c
            }),
            a.onChange &amp;&amp; a.onChange(c)
        }),
        [o, j]
    };
    
})(skuid);</jsitem>
        </javascript>
        <css>
            <cssitem location="staticresource" name="SkuidBuildersCSS" cachelocation="false" url="" namespace="skuid" content_type="text/css"/>
            <cssitem location="inline" name="skuidpicker" cachelocation="false" url="" namespace="" content_type="">.nx-pagebuilder-toolbarpanel-body .nx-editor-contents .nx-pagebuilder-property-item {
    margin: 4px;
    background: #f9f9f9;
    border: null,null,1px solid #f0f0f0,null
}
.nx-pagebuilder-property-button-wrapper {
    float: right;
    margin: 1px
}
.nx-pagebuilder-property-button-area {
    margin-right: 36px
}
.nx-pagebuilder-property-button-area-inner {
    margin-top: 6px;
    word-wrap: break-word
}
.ui-dialog .nx-picker-wrapper.ui-dialog-content {
    padding: 0;
    overflow: hidden
}
.nx-picker-wrapper {
    display: none;
    padding-bottom: 10px
}
.nx-picker-body {
    overflow: auto;
    height: 302px;
    margin: 2px
}
.nx-picker-body .nx-picker-icon-wrapper {
    border: solid 1px #ccc;
    padding: 5px;
    margin: 3px;
    float: left;
    cursor: pointer;
    width: 114px
}
.nx-picker-body .nx-picker-icon-label {
    margin: 4px 4px 4px 3px;
    display: inline-block;
    vertical-align: middle;
    width: 81px;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden
}
.nx-picker-body .nx-picker-icon {
    margin: 4px;
    display: inline-block;
    vertical-align: middle
}
.nx-picker-header {
    margin: 5px 0 5px;
    border-bottom: solid 1px #ccc;
    padding: 10px;
    font-weight: bold
}
.nx-picker-icon-btn {
    cursor: pointer;
    min-height: 26px;
    min-width: 26px;
    background: #F1F1F1;
    border: 1px solid #c0c0c0;
    position: relative;
    top: -2px;
    -webkit-border-radius: 2px;
    -moz-border-radius: 2px;
    border-radius: 2px;
    color: #111;
    border-top-color: transparent;
    border-left-color: transparent;
    border-right-color: #888;
    border-bottom-color: #888
}
.nx-picker-icon-btn:focus {
    outline: none
}
.nx-picker-icon-btn:active {
    border: 1px solid #c0c0c0
}
.nx-picker-icon-btn.nx-disabled {
    opacity: .2;
    cursor: default
}
.nx-picker-input-wrapper input,.nx-picker-input-wrapper label {
    vertical-align: middle
}
.nx-picker-text-output {
    display: inline-block
}
.nx-picker-header-category-wrapper {
    float: right
}
.nx-picker-header-category {
    display: inline-block;
    margin: 2px;
    text-transform: capitalize;
    cursor: pointer;
    padding: 4px 6px;
    border-radius: 4px;
    font-weight: normal;
    font-size: 8pt
}
.nx-picker-selected {
    color: white;
    background: #0288d1
}
</cssitem>
        </css>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
</skuidpage>
Photo of mB Pat Vachon

mB Pat Vachon, Champion

  • 42,704 Points 20k badge 2x thumb
Got it to work as well! Awesome!
Was all the css necessary?
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
I don't know how much of the css is required. I just copied everything from skuid that used a class that the icon picker uses.