1/** 2 * FW_Form helpers 3 * Dependencies: jQuery 4 * Note: You can include this script in frontend (for e.g. to make you contact forms ajax submittable) 5 */ 6 7var fwForm = { 8 /** 9 * Make forms ajax submittable 10 * @param {Object} [opts] You can overwrite any 11 */ 12 initAjaxSubmit: function(opts) { 13 var opts = jQuery.extend({ 14 selector: 'form[data-fw-form-id]', 15 ajaxUrl: (typeof ajaxurl != 'undefined') 16 ? ajaxurl 17 : ((typeof fwAjaxUrl != 'undefined') 18 ? fwAjaxUrl // wp_localize_script('fw-form-helpers', 'fwAjaxUrl', admin_url( 'admin-ajax.php', 'relative' )); 19 : '/wp-admin/admin-ajax.php' 20 ), 21 loading: function (elements, show) { 22 elements.$form.css('position', 'relative'); 23 elements.$form.find('> .fw-form-loading').remove(); 24 25 if (show) { 26 elements.$form.append( 27 '<div'+ 28 ' class="fw-form-loading"'+ 29 ' style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.1);"'+ 30 '></div>' 31 ); 32 } 33 }, 34 afterSubmitDelay: function(elements){}, 35 onErrors: function (elements, data) { 36 if (isAdmin) { 37 fwForm.backend.showFlashMessages( 38 fwForm.backend.renderFlashMessages({error: data.errors}) 39 ); 40 } else { 41 // Frontend 42 jQuery.each(data.errors, function (inputName, message) { 43 message = '<p class="form-error" style="color: #9b2922;">{message}</p>' 44 .replace('{message}', message); 45 46 var $input = elements.$form.find('[name="' + inputName + '"]').last(); 47 48 if (!$input.length) { 49 // maybe input name has array format, try to find by prefix: name[ 50 $input = elements.$form.find('[name^="'+ inputName +'["]').last(); 51 } 52 53 if ($input.length) { 54 // error message under input 55 $input.parent().after(message); 56 } else { 57 // if input not found, show message in form 58 elements.$form.prepend(message); 59 } 60 }); 61 } 62 }, 63 hideErrors: function (elements) { 64 elements.$form.find('.form-error').remove(); 65 }, 66 onAjaxError: function(elements, data) { 67 console.error(data.jqXHR, data.textStatus, data.errorThrown); 68 alert('Ajax error (more details in console)'); 69 }, 70 onSuccess: function (elements, ajaxData) { 71 if (isAdmin) { 72 fwForm.backend.showFlashMessages( 73 fwForm.backend.renderFlashMessages(ajaxData.flash_messages) 74 ); 75 } else { 76 var html = fwForm.frontend.renderFlashMessages(ajaxData.flash_messages); 77 78 if (!html.length) { 79 html = '<p>Success</p>'; 80 } 81 82 elements.$form.fadeOut(function(){ 83 elements.$form.html(html).fadeIn(); 84 }); 85 86 // prevent multiple submit 87 elements.$form.on('submit', function(e){ e.preventDefault(); e.stopPropagation(); }); 88 } 89 } 90 }, opts || {}), 91 isAdmin = (typeof adminpage != 'undefined' && jQuery(document.body).hasClass('wp-admin')), 92 isBusy = false; 93 94 jQuery(document.body).on('submit', opts.selector, function(e){ 95 e.preventDefault(); 96 97 if (isBusy) { 98 console.warn('Working... Try again later.'); 99 return; 100 } 101 102 var $form = jQuery(this); 103 104 if (!$form.is('form[data-fw-form-id]')) { 105 console.error('This is not a FW_Form', 'Selector:'. opts.selector, 'Form:', $form); 106 return; 107 } 108 109 // get submit button 110 { 111 var $submitButton = $form.find(':submit:focus'); 112 113 if (!$submitButton.length) { 114 // in case you use this solution http://stackoverflow.com/a/5721762 115 $submitButton = $form.find('[clicked]:submit'); 116 } 117 118 // make sure to remove the "clicked" attribute to prevent accidental settings reset 119 $form.find('[clicked]:submit').removeAttr('clicked'); 120 } 121 122 var elements = { 123 $form: $form, 124 $submitButton: $submitButton 125 }; 126 127 opts.hideErrors(elements); 128 129 var delaySubmit = parseInt( 130 opts.loading( 131 elements, 132 /** 133 * If you want to submit your ajaxified Theme Settings form without 134 * any notification for the user add class fw-silent-submit to 135 * the form element itself. This class will be removed 136 * automatically after this particular submit, so that popup will 137 * show when the user will press Submit button next time. 138 */ 139 ! $form.hasClass('fw-silent-submit') 140 ) 141 ); 142 delaySubmit = (isNaN(delaySubmit) || delaySubmit < 0) ? 0 : delaySubmit; 143 144 $form.removeClass('fw-silent-submit'); 145 146 isBusy = true; 147 148 setTimeout(function(){ 149 if (delaySubmit) { 150 opts.afterSubmitDelay(elements); 151 } 152 153 jQuery.ajax({ 154 type: "POST", 155 url: opts.ajaxUrl, 156 data: $form.serialize() + ( 157 $submitButton.length 158 ? '&'+ $submitButton.attr('name') +'='+ $submitButton.attr('value') 159 : '' 160 ), 161 dataType: 'json' 162 }).done(function(r){ 163 isBusy = false;
164 opts.loading(elements, false); 165 166 if (r.success) { 167 opts.onSuccess(elements, r.data); 168 } else { 169 opts.onErrors(elements, r.data); 170 } 171 }).fail(function(jqXHR, textStatus, errorThrown){ 172 isBusy = false; 173 opts.loading(elements, false); 174 opts.onAjaxError(elements, { 175 jqXHR: jqXHR, 176 textStatus: textStatus, 177 errorThrown: errorThrown 178 }); 179 }); 180 }, delaySubmit); 181 }); 182 }, 183 backend: { 184 showFlashMessages: function(messagesHtml) { 185 var $pageTitle = jQuery('.wrap h2:first'); 186 187 while ($pageTitle.next().is('.fw-flash-messages, .fw-flash-message, .updated, .update-nag, .error')) { 188 $pageTitle.next().remove(); 189 } 190 191 $pageTitle.after('<div class="fw-flash-messages">'+ messagesHtml +'</div>'); 192 193 jQuery(document.body).animate({scrollTop: 0}, 300); 194 }, 195 /** 196 * Html structure should be the same as generated by FW_Flash_Messages::_print_backend() 197 * @param {Object} flashMessages 198 * @returns {string} 199 */ 200 renderFlashMessages: function(flashMessages) { 201 var html = [], 202 typeHtml = [], 203 messageClass = ''; 204 205 jQuery.each(flashMessages, function(type, messages){ 206 typeHtml = []; 207 208 switch (type) { 209 case 'error': 210 messageClass = 'error'; 211 break; 212 case 'warning': 213 messageClass = 'update-nag'; 214 break; 215 default: 216 messageClass = 'updated'; 217 } 218 219 jQuery.each(messages, function(messageId, message){ 220 typeHtml.push('<div class="'+ messageClass +' fw-flash-message"><p>'+ message +'</p></div>'); 221 }); 222 223 if (typeHtml.length) { 224 html.push( 225 '<div class="fw-flash-type-'+ type +'">'+ typeHtml.join('</div><div class="fw-flash-type-'+ type +'">') +'</div>' 226 ); 227 } 228 }); 229 230 return html.join(''); 231 } 232 }, 233 frontend: { 234 /** 235 * Html structure is the same as generated by FW_Flash_Messages::_print_frontend() 236 * @param {Object} flashMessages 237 * @returns {string} 238 */ 239 renderFlashMessages: function(flashMessages) { 240 var html = [], 241 typeHtml = [], 242 messageClass = ''; 243 244 jQuery.each(flashMessages, function(type, messages){ 245 typeHtml = []; 246 247 jQuery.each(messages, function(messageId, message){ 248 typeHtml.push('<li class="fw-flash-message">'+ message +'</li>'); 249 }); 250 251 if (typeHtml.length) { 252 html.push( 253 '<ul class="fw-flash-type-'+ type +'">'+ typeHtml.join('</ul><ul class="fw-flash-type-'+ type +'">') +'</ul>' 254 ); 255 } 256 }); 257 258 return html.join(''); 259 } 260 } 261}; 262 263// Usage example 264if (false) { 265 jQuery(function ($) { 266 fwForm.initAjaxSubmit({ 267 selector: 'form[data-fw-form-id][data-fw-ext-forms-type="contact-forms"]', 268 ajaxUrl: ajaxurl 269 }); 270 }); 271}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.