4

I'm working on a Dashboard widget from which users can submit entries for review from a Garnish HUD, like so...

Garnish HUD without a footer.

I've started by placing a hidden form next to each little Submit button...

<form method="post" class="approval-request-form hidden" action="/actions/plugin/submitPost">
    <input type="hidden" name="entryId" value="{{ element.id }}">
    {{ forms.textareaField({
        name: 'notes',
        label: 'Review Note',
        instructions: 'Add a note for the person reviewing your work.',
        maxlength: 140
    }) }}

    <div class="buttons right">
        <div class="btn cancel">Cancel</div>
        <input type="submit" class="btn submit" value="Submit for Review">
    </div>
</form>

Once that little button is clicked, I clone the form into a new Garnish HUD with delightful ease:

jQuery(function(){
    $('.request-approval').click(function(e){
        e.preventDefault();
        var $form = $(e.target).siblings('.approval-request-form').first().clone().removeClass('hidden');
        var hud = new Garnish.HUD(e.target, $form);
    });
});

This works great! I can post to my controller and all is well. Moments later, it occurs to me that I need some field validation and that it'd be nice to use a HUD footer (with its gray backdrop) and hook up my cancel button...

The new goal: Garnish HUD with footer.

I wrap my form's buttons in class="hud-footer", which applies exactly the style I want...

<form method="post" class="approval-request-form hidden" action="/actions/plugin/submitPost">
    <input type="hidden" name="entryId" value="{{ element.id }}">
    {{ forms.textareaField({
        name: 'notes',
        label: 'Review Note',
        instructions: 'Add a note for the person reviewing your work.',
        maxlength: 140
    }) }}
    <div class="hud-footer">
        <div class="buttons right">
            <div class="btn cancel">Cancel</div>
            <input type="submit" class="btn submit" value="Submit for Review">
        </div>
    </div>
</form>

This is where the pain starts, because my submit button looks fantastic yet does nothing. After a while I realize it's because HUD.js redraws things and pulls the action buttons out of my <form> element where they would have known what to do...

<div class="hud has-footer">
    <div class="tip tip-top"></div>
    <form class="body">
        <div class="main-container">
            <div class="main">
                <form method="post" class="approval-request-form last" action="/actions/plugin/submitPost">
                ... my form elements without .buttons ...
                </form>
                <object tabindex="-1" type="text/html" data="about:blank" style="display: block; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; border: none; padding: 0px; margin: 0px; opacity: 0; z-index: -1000; pointer-events: none;"></object>
            </div>
        </div>
        <div class=""></div>
    </form>
    <div class="hud-footer">
        <div class="buttons right last">
            <div class="btn cancel" tabindex="0">Cancel</div>
            <input type="submit" class="btn submit" value="Submit for Review">
        </div>
    </div>
</div>

After some trial and error, I wind up sneaking a hidden submit button into my form and "clicking" it with JavaScript via the HUD's onSubmit property...

jQuery(function(){
    $('.request-approval').click(function(e){
        e.preventDefault();
        var $form = $(e.target).siblings('.approval-request-form').first().clone().removeClass('hidden');
        var hud = new Garnish.HUD(e.target, $form, { closeBtn: $form.find('.cancel'), onSubmit: submitForm });

        function checkForm() {
            $form.find('.submit').trigger('click');
        }
    });
});

That successfully reaches into my form and submits it (and allows me to add some validation logic later), but how can I use the HUD's footer button to submit the form in .main without the questionable hackery of triggering a click on a hidden button?

I suspect I'm either missing something or not thinking quite like the Garnish HUD wants me to. The closest example I've found is the element editor you'd see working with Assets, which serializes and posts its form data via AJAX. I could mimic that instead, but I'd rob myself and our fair Stack Exchange of a learning opportunity.

3

Since the shuffled markup is the root of the problem, one might follow examples from the Craft control panel source that serialize the form's data and submit via AJAX (and often $.proxy() to help with scope).

This is a lot of work, however, for minor stylistic gain. If the problem is limited to presentation, the solution should be too. @narration_sd helped me see how fragile the jQuery hack is compared to a CSS hack, and so in lieu of The Perfect Answer I've created a pseudo-hud-footer class to wrap my action buttons. It's inelegant, looks identical, and it's less risky than my previous workaround:

.approval-request-form .field { margin-top: 0; margin-bottom: 0; }
.pseudo-hud-footer {
    position: relative;
    left: -24px;
    bottom: -24px;
    border-radius: 0 0 4px 4px;
    padding: 6px 24px 10px 24px;
    width: 100%;
    height: 35px;
    background-image: -webkit-linear-gradient(#ecedef, #e9eaec);
    background-image: -moz-linear-gradient(#ecedef, #e9eaec);
    background-image: -ms-linear-gradient(#ecedef, #e9eaec);
    background-image: -o-linear-gradient(#ecedef, #e9eaec);
    background-image: linear-gradient(#ecedef, #e9eaec);
    -webkit-box-shadow: inset 0 2px 1px -2px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: inset 0 2px 1px -2px rgba(0, 0, 0, 0.2);
    box-shadow: inset 0 2px 1px -2px rgba(0, 0, 0, 0.2);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.