1(function($) { 2 3 $(document).on('click', 'button.does-activate-fullscreen', function(e) { 4 e.preventDefault(); 5 6 $(this).closest('.submission').fullscreen({ 7 overflow: 'auto' 8 }); 9 10 return false; 11 }); 12 13 $(document).on('click', 'button.does-deactivate-fullscreen', function(e) { 14 e.preventDefault(); 15 16 $.fullscreen.exit(); 17 18 return false; 19 }); 20 21 $(document).on('fscreenopen', '.submission', function() { 22 $(this).addClass('is-fullscreen'); 23 $('body').addClass('contains-fullscreen-content'); 24 }); 25 26 $(document).on('fscreenclose', '.submission', function() { 27 $(this).removeClass('is-fullscreen'); 28 $('body').removeClass('contains-fullscreen-content'); 29 }); 30 31 $(document).on('click', 'button.does-trigger-submission-start', function(e) { 32 e.preventDefault(); 33 34 $(this).closest('.submission').addClass('has-started'); 35 $(this).closest('.submission').find('.contains-form').submission('start'); 36 37 return false; 38 }); 39 40 $(document).on('fieldhighlight', '.submission-form-field', function() { 41 var element = $(this); 42 43 $('body').animate({ scrollTop: element.offset().top - 120 }, 500); 44 45 element.addClass('is-highlighted'); 46 47 setTimeout(function() { 48 element.removeClass('is-highlighted'); 49 }, 1000); 50 }); 51 52 $.widget("tff.submission", { 53 54 // http://davidwalsh.name/javascript-debounce-function 55 // Returns a function, that, as long as it continues to be invoked, will not 56 // be triggered. The function will be called after it stops being called for 57 // N milliseconds. If `immediate` is passed, trigger the function on the 58 // leading edge, instead of the trailing. 59 _debounce: function(func, wait, immediate) { 60 var timeout; 61 return function() { 62 var context = this, args = arguments; 63 var later = function() { 64 timeout = null; 65 if (!immediate) func.apply(context, args); 66 }; 67 var callNow = immediate && !timeout; 68 clearTimeout(timeout); 69 timeout = setTimeout(later, wait); 70 if (callNow) func.apply(context, args); 71 }; 72 }, 73 74 _postRenderDependingFields: function(callback) { 75 function update_dependent_field(field) { 76 if (field.css('display') != 'none') { 77 field.closest('.alpaca-fieldset-item-container').removeClass('hidden-submission-form-field'); 78 } else { 79 field.closest('.alpaca-fieldset-item-container').addClass('hidden-submission-form-field'); 80 } 81 } 82 83 this.onDependentConceal = function() { 84 update_dependent_field(this.getEl()); 85 }; 86 87 this.onDependentReveal = function() { 88 update_dependent_field(this.getEl()); 89 }; 90 91 update_dependent_field(this.getEl()); 92 93 callback(); 94 }, 95 96 _updateButtons: function(controller) { 97 var currentStep = $('.alpaca-wizard-status-bar li').index($('.alpaca-wizard-status-bar li.current')) + 1; 98 99 var valid = true; 100 101 $.each(controller.wizardConfigs.bindings, function(propertyId, step) { 102 if (step == currentStep) { 103 valid = valid && controller.childrenByPropertyId[propertyId].validate(true); 104 } 105 }); 106 107 if (valid) { 108 $('.alpaca-wizard-button-next, .alpaca-wizard-button-done') 109 .removeClass('is-disabled') 110 .removeAttr('disabled'); 111 } else { 112 $('.alpaca-wizard-button-next, .alpaca-wizard-button-done') 113 .addClass('is-disabled') 114 .attr('disabled', 'disabled'); 115 } 116 }, 117 118 _create: function() { 119 var _this = this; 120 121 if (_this.options.unload) { 122 $(window).off('beforeunload'); 123 $(window).on('beforeunload', function() { 124 if (_this.element.is(':visible')) { 125 if (_this.options.restore) { 126 var data = $.totalStorage(_this.options.restore.namespace); 127 if (!data) { 128 return; 129 } 130 } 131 132 return _this.options.unload; 133 } 134 }); 135 } 136 137 if (_this.options.restore) { 138 var data = $.totalStorage(_this.options.restore.namespace); 139 if (data) { 140 $("html, body").scrollTop(0); 141 142 setTimeout(function () { 143 vex.dialog.buttons.YES.text = _this.options.restore.ok; 144 vex.dialog.buttons.NO.text = _this.options.restore.cancel; 145 vex.dialog.confirm({ 146 message: _this.options.restore.message, 147 className: 'vex-theme-plain tff-submission-dialog', 148 callback: function(value) { 149 if (value) { 150 _this._setup(data); 151 } else { 152 $.totalStorage(_this.options.restore.namespace, null); 153 _this._setup(); 154 } 155 } 156 }); 157 }, 100); 158 } else { 159 _this._setup(); 160 } 161 } else { 162 _this._setup(); 163 } 164 }, 165 166 _isFullscreen: function() { 167 return this.element.closest('.submission').hasClass('is-fullscreen'); 168 }, 169 170 _getScrollingContext: function() { 171 if (this._isFullscreen()) { 172 return this.element.closest('.submission'); 173 } 174 175 return $('html,body'); 176 }, 177 178 _scrollTo: function(destination) { 179 var context = this._getScrollingContext(); 180 181 setTimeout(function() { 182 context.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function(){ 183 context.stop(); 184 }); 185 186 context.animate({ scrollTop: (destination.offset().top - 120) }, 857, function() { 187 context.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove"); 188 }); 189 }, 131); 190 }, 191 192 _getWizardSteps: function() { 193 return this.options.steps.length; 194 }, 195 196 _createWizardBindings: function() { 197 var bindings = {}; 198 199 $.each(this.options.steps, function(i, step) { 200 $.each(step.bindings, function(j, binding) { 201 bindings[binding] = (i + 1); 202 }); 203 }); 204 205 return bindings; 206 }, 207 208 _createWizardTitles: function() { 209 var titles = []; 210 211 $.each(this.options.steps, function(i, step) { 212 titles.push({ 213 'title': step.title 214 }); 215 }); 216 217 return titles; 218 }, 219 220 _augmentFieldOptions: function(values) { 221 var _this = this; 222 223 for (var i in values) { 224 if (i == 'dependencies') { 225 values['postRender'] = _this._postRenderDependingFields; 226 } 227 228 if (typeof values[i] == 'object') { 229 _this._augmentFieldOptions(values[i]); 230 } 231 } 232 233 return values; 234 }, 235 236 _handleDefaultCase: function(control) {
237 $(control.container).closest('.supports-progress-loading').trigger('showprogress'); 238 239 if (this.options.restore) { 240 $.totalStorage(this.options.restore.namespace, null); 241 } 242 243 if (this.options.unload) { 244 $(window).off('beforeunload'); 245 } 246 247 return true; 248 }, 249 250 _createHandler: function(control) { 251 var _this = this; 252 253 if (!!window['FormData']) { 254 return function() { 255 $(control.container).closest('.supports-progress-loading').trigger('showprogress'); 256 257 try { 258 var data = new FormData(control.form.field[0]); 259 data.append('programmatic', true); 260 261 $.ajax({ 262 url: _this.options.endpoint, 263 type: 'POST', 264 processData: false, 265 contentType: false, 266 data: data 267 }) 268 .fail(function(err) { 269 // TODO show error? 270 console.warn(err); 271 }) 272 .done(function(result) { 273 console.log(JSON.stringify(result, null, 4)); 274 275 if (_this.options.restore && !!result.success) { 276 $.totalStorage(_this.options.restore.namespace, null); 277 } 278 279 if (_this.options.unload) { 280 $(window).off('beforeunload'); 281 } 282 283 if (typeof result == 'object' && !!result.url) { 284 window.location.href = result.url; 285 } else { 286 console.warn(result); 287 $(control.container).closest('.supports-progress-loading').trigger('dismissprogress'); 288 } 289 }); 290 291 return false; 292 } catch (err) { 293 console.warn(err); 294 // return _this._handleDefaultCase(control); 295 } 296 }; 297 } 298 299 return function() { 300 return _this._handleDefaultCase(control); 301 }; 302 }, 303 304 _submit: function() { 305 var _this = this; 306 307 vex.dialog.buttons.NO.text = _this.options.submit.cancel; 308 vex.dialog.buttons.YES.text = _this.options.submit.ok; 309 vex.dialog.confirm({ 310 message: _this.options.submit.message, 311 className: 'vex-theme-plain tff-submission-dialog tff-submission-confirmation-dialog', 312 callback: function(value) { 313 if (value) { 314 _this.element.find('form').submit(); 315 } 316 } 317 }); 318 }, 319 320 _setup: function(data) { 321 var _this = this; 322 323 $.alpaca.__isValEmpty = $.alpaca.isValEmpty; 324 $.alpaca.isValEmpty = function(val) { 325 if ($.alpaca.isString(val)) { 326 val = $.trim(val); 327 } 328 329 return $.alpaca.__isValEmpty(val); 330 }; 331 332 $.alpaca.registerMessages({ 333 'notOptional': tff_submission.i18n.validation_notOptional, 334 'invalidPattern': tff_submission.i18n.validation_invalidPattern, 335 'stringNotAnInteger': tff_submission.i18n.validation_notAnInteger, 336 'stringNotANumber': tff_submission.i18n.validation_notANumber, 337 'stringValueTooSmall': tff_submission.i18n.validation_integerBelowBound, 338 'stringTooLong': tff_submission.i18n.validation_stringTooLong, 339 'invalidAtLeast': tff_submission.i18n.validation_atLeastSelections, 340 'invalidAtMost': tff_submission.i18n.validation_atMostSelections, 341 'invalidAtLeastAndAtMost': tff_submission.i18n.validation_betweenSelections, 342 'invalidEmail': tff_submission.i18n.validation_invali
342dEmail, 343 'invalidURLFormat': tff_submission.i18n.validation_invalidURL 344 }); 345 346 $.alpaca.registerTemplate("controlFieldSelect", '<select id="${id}" {{if options.readonly}}readonly="readonly"{{/if}} {{if options.multiple}}multiple{{/if}} {{if options.size}}size="${options.size}"{{/if}} {{if name}}name="${name}"{{/if}}>{{if !removeDefaultNone}}<option value="">—</option>{{/if}}{{each(i,value) selectOptions}}<option value="${value}" {{if value == data}}selected="selected"{{/if}}>${text}</option>{{/each}}</select>'); 347 348 $.alpaca.registerTemplate("htmlControl", '<div class="alpaca-html-control submission-form-field takes-all-the-space">{{html options.html}}</div>'); 349 350 data = $.extend(true, 351 $.extend(true, _this.options.bootstrap, _this.options.defaults || {}), 352 data || {}); 353 354 data = $.extend(true, data, { 355 'lang': _this.options.lang, 356 'action': _this.options.action, 357 'nonce': _this.options.nonce, 358 'safeguard': _this.options.safeguard, 359 'legal': { 360 'privacy': '', 361 'regulation': '', 362 } 363 }); 364 365 _this.element.alpaca({ 366 'data': data, 367 'schema': { 368 'type': 'object', 369 'properties': $.extend(true, { 370 'lang': { 371 'type': 'string', 372 }, 373 'action': { 374 'type': 'string', 375 }, 376 'nonce': { 377 'type': 'string', 378 }, 379 'safeguard': { 380 'type': 'string', 381 } 382 }, _this.options.schema) 383 }, 384 'options': { 385 'renderForm': true, 386 'fields': $.extend(true, { 387 'lang': { 388 'type': 'hidden', 389 'containerClass': ['hidden-submission-form-field'], 390 }, 391 'action': { 392 'type': 'hidden', 393 'containerClass': ['hidden-submission-form-field'], 394 }, 395 'nonce': { 396 'type': 'hidden', 397 'containerClass': ['hidden-submission-form-field'], 398 }, 399 'safeguard': { 400 'type': 'hidden', 401 'containerClass': ['hidden-submission-form-field'], 402 } 403 }, _this._augmentFieldOptions(_this.options.options)), 404 'form': { 405 'attributes': { 406 'action': _this.options.endpoint, 407 'method': 'post', 408 'enctype': 'multipart/form-data', 409 } 410 } 411 }, 412 'view': { 413 'templates': { 414 'wizardPreButton': '<button>' + tff_submission.i18n.previous + '</button>', 415 'wizardNextButton': '<button>' + tff_submission.i18n.next + '</button>', 416 'wizardDoneButton': '<button>' + tff_submission.i18n.done + '</button>', 417 }, 418 'wizard': { 419 'renderWizard': true, 420 'statusBar': true, 421 'validation': true, 422 'steps': _this._getWizardSteps(), 423 'bindings': _this._createWizardBindings(), 424 'stepTitles': _this._createWizardTitles(), 425 'buttons': { 426 'prev': { 427 'onClick': function() { 428 _this._scrollTo(_this.element); 429 $(_this.element).trigger('stepchanged'); 430 } 431 }, 432 'next': { 433 'onInvalid': function() { 434 _this._scrollTo(_this.element.find('.alpaca-controlfield-message:visible:first').closest('.submission-form-field')); 435 }, 436 'onClick': function() { 437 _this._scrollTo(_this.element); 438 $(_this.element).trigger('stepchanged'); 439 } 440 }, 441 'done': { 442 'onInvalid': function() { 443 _this._scrollTo(_this.element.find('.alpaca-controlfield-message:visible:first').closest('.submission-form-field')); 444 }, 445 'onClick': function() { 446 _this.control.validate(true); 447 448 if (!_this.control.isValid(true)) { 449 let invalidFields = []; 450
451 var fetchInvalidFields = function (field) { 452 if (!field.isValid()) { 453 invalidFields.push({ 454 name: field.name, 455 label: field.options.label 456 }); 457 } 458 459 if (field.children) { 460 field.children.forEach(function (child) { 461 fetchInvalidFields(child); 462 }); 463 } 464 }; 465 466 fetchInvalidFields(_this.control); 467 468 vex.dialog.buttons.YES.text = tff_submission.i18n.ok; 469 vex.dialog.alert({ 470 message: tff_submission.i18n.validation_invalidFields.replace('{0}', invalidFields.map(function (entry) { return entry.label; }).join(', ')), 471 className: 'vex-theme-plain tff-submission-dialog tff-submission-confirmation-dialog' 472 }); 473 } else { 474 if (_this._isFullscreen()) { 475 _this.element.closest('.submission').one('fscreenclose', function() { 476 _this._submit(); 477 }); 478 479 $.fullscreen.exit(); 480 } else { 481 _this._submit(); 482 } 483 } 484 } 485 } 486 } 487 } 488 }, 489 'postRender': function(control) { 490 _this.control = control; 491 492 _this.element.find('.alpaca-controlfield-message').remove(); 493 _this.element.siblings('.contains-loading-message').remove(); 494 495 $(control.container).on('keyup', 'input, textarea', _this._debounce(function(e) { 496 var field = control.allFieldInstances()[$(this).attr('id')]; 497 if (field) { 498 field.validate(); 499 field.refreshValidationState(); 500 } 501 }, 751)); 502 503 $(control.container).on('paste', 'input, textarea', _this._debounce(function(e) { 504 var value = $(this).val(); 505 $(this).val('').val(value); 506 $(this).trigger('change'); 507 }, 251)); 508 509 $(control.container).on('click', 'button.alpaca-fieldset-array-item-toolbar-disabled', function(e) { 510 e.preventDefault(); 511 e.stopPropagation(); 512 return false; 513 }); 514 515 $(control.container).on('stepchanged', function() { 516 _this._updateButtons(control); 517 }); 518 519 $(control.container).on('fieldupdate', '.alpaca-field', function() { 520 var field = control.allFieldInstances()[$(this).attr('alpaca-field-id')]; 521 if (field && field.type != 'object') { 522 field.validate(true); 523 field.refreshValidationState(true); 524 } 525 526 _this._updateButtons(control); 527 528 if (_this.options.restore) { 529 $.totalStorage(_this.options.restore.namespace, control.getValue()); 530 } 531 }); 532 533 control.on('validated', function() { 534 _this._updateButtons(control); 535 }); 536 537 control.on('invalidated', function() { 538 _this._updateButtons(control); 539 }); 540 541 control.form.registerSubmitHandler(_this._createHandler(control)); 542 543 $(control.container).closest('.submission').addClass('is-ready'); 544 } 545 }); 546 }, 547 548 start: function() { 549 this._scrollTo(this.element); 550 }, 551 552 scrollTo: function(destination) { 553 if (destination.is(':visible')) { 554 this._scrollTo(destination); 555 } 556 } 557 558 }); 559})(jQuery);
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.