1(function ($) { 2 var logcount = 0; 3 4 function getCookie(cname) { 5 var name = cname + "="; 6 var ca = document.cookie.split(';'); 7 for (var i = 0; i < ca.length; i++) { 8 var c = ca[i]; 9 while (c.charAt(0) === ' ') { 10 c = c.substring(1); 11 } 12 if (c.indexOf(name) === 0) { 13 return c.substring(name.length, c.length); 14 } 15 } 16 return ""; 17 } 18 19 var useEnglish = getCookie("Fast2User_language") === 'en'; 20 21 // Internal scope 22 var fast2 = { 23 24 wc: "[data-widget]" 25 26 , events: { 27 widgetLoad: "fast2-widget-load" 28 , widgetFail: "fast2-widget-fail" 29 , widgetAlways: "fast2-widget-always" 30 , widgetReady: "fast2-widget-ready" 31 , postbackBefore: "fast2-widget-postback-before" 32 , postbackEmptyRequiredFields: "fast2-widget-postback-empty-required-fields" 33 , postbackAfter: "fast2-widget-postback-after" 34 , postbackSuccess: "fast2-widget-postback-success" 35 , postbackFail: "fast2-widget-postback-error" 36 , postbackAlways: "fast2-widget-postback-always" 37 , onFileuploadComplete: "fast2-widget-fileupload-complete" 38 , onFileUploadFail: "fast2-widget-fileupload-fail" 39 , onFileUploadAlways: "fast2-widget-fileupload-always" 40 } 41 42 , scriptUrl: "" 43 , serviceUrl: "/widgets/" 44 45 , log: function () { 46 if (window.f2widgetdebug && typeof console != 'undefined') { 47 console.log("(" + (logcount++) + ") fast2 widget factory:: ", Array.prototype.slice.call(arguments)); 48 } 49 } 50 51 /** 52 * @returns samtliga widget-ID på sidan som strängar 53 */ 54 , widgetIds: function () { 55 var widgets = fast2.widgets(); 56 var widgetIds = []; 57 for (var i = 0; i < widgets.length; i++) { 58 widgetIds.push(widgets[i].data('widget')); 59 } 60 return widgetIds; 61 } 62 63 /** 64 * @returns samtliga widgets på sidan om jquery-objekt 65 */ 66 , widgets: function () { 67 var widgets = []; 68 $('[data-widget]').each(function () { 69 var widget = $(this); 70 fast2.log(widget); 71 widgets.push(widget); 72 }); 73 return widgets; 74 } 75 76 77 /** 78 * Debug function used for adding all available mustache template variables 79 * to a page using {{#templatevariables}}{{/templatevariables}} 80 */ 81 , templatevariables: function (text, render) { 82 var result = fast2.describe('', this); 83 return result; 84 } 85 86 /** 87 * toString() for mustache template variable objects 88 */ 89 , describe: function (prefix, obj, indentation) { 90 indentation = indentation || ''; 91 var result = ''; 92 93 var shouldIterate = typeof obj === 'object'; 94 if (!shouldIterate) { 95 result = result + (indentation + "{{.}} = " + obj + "<br />"); 96 } else if ($.isArray(obj)) { 97 result = result + ("{{#.}}"); 98 var s = obj.length; 99 result = result + (" (" + s + " elements)<br>"); 100 result = result + (s === 0 ? "" : fast2.describe('', obj[0], " ")); 101 result = result + ("{{/.}}<br>"); 102 } else { 103 for (var item in obj) { 104 var isObject = typeof obj[item] === 'object'; 105 var isFunction = typeof obj[item] === 'function'; 106 fast2.log(item, isObject, typeof obj[item]); 107 if ($.isArray(obj[item])) { 108 result = result + ("{{#" + prefix + item + "}}"); 109 var size = obj[item].length; 110 result = result + (" (" + size + " elements)<br>"); 111 result = result + (size === 0 ? "" : fast2.describe('', obj[item][0], " ")); 112 result = result + ("{{/" + prefix + item + "}}<br>"); 113 } else if (isObject) { 114 result = result + fast2.describe(item + '.', obj[item]); 115 } else if (isFunction) { 116 // skip 117 } else { 118 // "(" + typeof obj[item] + ") 119 result = result + (indentation + "{{" + prefix + item + "}} = " + obj[item] + "<br />"); 120 } 121 } 122 } 123 return result; 124 } 125 126 , widgetsLoaded: function (data) { 127 $.ajaxSetup({ 128 type: 'POST', 129 headers: { 130 CSRF: data.CSRFtoken 131 } 132 }); 133 fast2.log("Kör widgetsLoaded ", data); 134 var widgets = fast2.widgets(); 135 136 if (typeof data !== 'undefined') { 137 // Check for GA-events (must be done before redirect 138 // Register GA-Events 139 if (typeof _gaq !== 'undefined' && data.events !== 'undefined' && data.events.length !== 0) { 140 $.each(data.events, function (index, obj) {
141 _gaq.push(['trackEvent', obj.category, obj.action, obj.label, obj.value, obj.nonInteraction]); 142 }); 143 } 144 // Is new window requested ? 145 if (typeof data.openWindow != 'undefined' && data.openWindow !== null && 146 typeof data.openWindow.url != 'undefined' && data.openWindow.url !== null) { 147 fast2.log("Nytt fönster öppnas med URL till " + data.openWindow.url); 148 window.open(data.openWindow.url, data.openWindow.windowName, data.openWindow.features); 149 // Fortsätt exekvera - vi kan både öppna nytt fönster och ladda widgets på sidan 150 } 151 // Is replace ? 152 if (typeof data.replaceUrl != 'undefined' && data.replaceUrl !== null) { 153 fast2.log("URL replace till " + data.replaceUrl); 154 window.location.replace(data.replaceUrl); 155 return; 156 } 157 // Is redirect ? 158 if (typeof data.redirectUrl != 'undefined' && data.redirectUrl !== null) { 159 fast2.log("Redirect till " + data.redirectUrl); 160 window.location = data.redirectUrl; 161 return; 162 } 163 // Is Reload page ? 164 if (typeof data.reload != 'undefined' && data.reload !== null) { 165 fast2.log("Reload page då det finns alert message"); 166 location.reload(); 167 } 168 169 var widgetIdsToBindFormEventsOn = []; 170 171 for (var i = 0; i < widgets.length; i++) { 172 var widgetId = widgets[i].data('widget') 173 , html = ''; 174 if (typeof data.data[widgetId] === 'undefined' && typeof data.html[widgetId] === 'undefined') { 175 fast2.log("Hoppar över - ingen data för ", widgetId); 176 continue; 177 } 178 fast2.log("Kör ", widgetId); 179 if (widgets[i].html().indexOf("{{") >= 0 || widgets[i].data('tmpl')) { 180 if (typeof data.data[widgetId] === 'undefined') { 181 // Data not defined 182 continue; 183 } 184 if (!widgets[i].data('tmpl')) { 185 // Cache template 186 widgets[i].data('tmpl', widgets[i].html()); 187 } 188 var inlineTemplateData = data.data[widgetId]; 189 // Allow template variable output using {{#templatevariables}}{{/templatevariables}} 190 inlineTemplateData.templatevariables = function () { 191 return fast2.templatevariables; 192 }; 193 fast2.log(data.data, widgetId, data.data[widgetId]); 194 fast2.log("Inline template finns, använder inner html för widget " + widgetId, widgets[i].data('tmpl'), inlineTemplateData); 195 if (typeof inlineTemplateData !== 'undefined') { 196 html = Mustache.render(widgets[i].data('tmpl'), inlineTemplateData); 197 } else if (fast2.debug) { 198 if (useEnglish) { 199 html = 'Error: Data from service is missing for ' + widgetId; 200 } else { 201 html = 'Fel: Data från tjänst saknas för ' + widgetId; 202 } 203 } 204 } else if (typeof data.html[widgetId] !== 'undefined') { 205 fast2.log("html finns för widget " + widgetId); 206 html = data.html[widgetId]; 207 } else { 208 fast2.log("template saknas, använder inner html för widget " + widgetId); 209 html = Mustache.render(widgets[i].html(), data); 210 } 211 212 fast2.log("Append HTML, size: " + html.length); 213 widgets[i].html(html); 214 if (html === '') { 215 widgets[i].addClass('NoContent'); 216 } else { 217 widgets[i].removeClass('NoContent'); 218 } 219 widgets[i].removeClass('Loading');
220 // Add actionId field to identify button 221 $('form:not(.standalone-form):has([data-action])', widgets[i]).append('<input type="hidden" name="actionId" />'); 222 // Add listener for toggle of help message on form elements 223 $('.HelperIcon', widgets[i]).click(function (event) { 224 $(event.target).parent('.controls').find('.HiddenHelperText').toggle(400); 225 }); 226 227 228 // Markdown-konvertering 229 if (typeof (Markdown) !== 'undefined') { 230 231 if (widgets[i].attr('data-markdown') == 'yes') { 232 233 $(widgets[i]).find('.Markdown').each(function () { 234 235 // Plocka ut text detta id 236 var message = $(this).text(); 237 238 // Kör markdown-plugin på texten 239 var converter = new Markdown.Converter(); 240 var output = converter.makeHtml(message); 241 242 // Ersätt text med den konverterade texten 243 $(this).html(output); 244 245 }); 246 247 } 248 249 } 250 251 252 var widgetIdAlreadyExistsInBindArray = widgetIdsToBindFormEventsOn.indexOf(widgetId) !== -1; 253 if (!widgetIdAlreadyExistsInBindArray) { 254 widgetIdsToBindFormEventsOn.push(widgetId); 255 } 256 257 // Trigger onload for widget 258 fast2.onWidgetsLoaded(data, widgetId); 259 } 260 261 for (var prop in widgetIdsToBindFormEventsOn) { 262 if (widgetIdsToBindFormEventsOn.hasOwnProperty(prop)) { 263 fast2.bindFormEvents(widgetIdsToBindFormEventsOn[prop]); 264 } 265 } 266 267 if (typeof data.html.timing !== 'undefined') { 268 console.log(data.html.timing); 269 $('body').append(data.html.timing); 270 } 271 272 $('span.btn.disabled i.icon-refresh').each(function () { 273 var $laddar = $(this).parent(); 274 var $submit = $laddar.prev(); 275 $submit.data('handled', false); 276 $submit.show(); 277 $laddar.remove(); 278 }); 279 } 280 281 $('[data-widget] form[method=post]').find('[type=submit]').click(function () { 282 var parentForm = $(this).parents('form'); 283 if (this.attributes["data-no-validation"] && this.attributes["data-no-validation"].value === "true") { 284 $(parentForm).attr('data-no-validation', 'true'); 285 } 286 $('[type=submit]', parentForm).removeAttr('clicked'); 287 $(this).attr('clicked', 'true'); 288 }); 289 290 // File uploads 291 if ($.isFunction($.fn.fileupload)) { 292 $('input.FileUpload').fileupload({ 293 limitMultiFileUploads: 1, 294 singleFileUploads: true, 295 sequentialUploads: true, 296 dataType: 'json', 297 xhrFields: { 298 withCredentials: true 299 }, 300 formData: function (form) { 301 var flowId = $(form).data('flow'); 302 if (typeof flowId !== 'undefined') { 303 form = $('form[data-flow="flow.skapafelanmalan"]'); 304 } 305 return form.serializeArray(); 306 }, 307 always: function (e, data) { 308 fast2.trigger(fast2.events.onFileuploadComplete); 309 if (typeof data.result === 'undefined') { 310 fast2.fileuploadIframeReload(); //fail 311 } else { 312 fast2.widgetsLoaded(data.result); //success 313 } 314 }, 315 progressall: function (e, data) { 316 fast2.log(data.loaded, data.total); 317 }, 318 add: function (e, data) { 319 fast2.log("add file", data); 320 // Fil vald - gör enable på knapp om sådan finns 321 var submitButton = $(".FileUploadSubmit", data.form); 322 var fileChooserButton = $(".fileinput-button", data.form); 323 fast2.log("add", submitButton, fileChooserButton); 324 if (submitButton.length === 0) { 325 // Hittar ingen submit-knapp, antar auto-submit 326 fast2.submitOnce(fileChooserButton); 327 data.submit(); 328 return true; 329 } 330 submitButton.prop('disabled', false); 331 fileChooserButton.prop('disabled', true); 332 fileChooserButton.addClass('btn-info'); 333 fileChooserButton.removeClass('btn-primary'); 334 var filename = ''; 335 try { 336 fast2.log(data.files); 337 filename = data.files[0].name; 338 } catch (err) { 339 fast2.log('Saknar file-API?', err); 340 } 341 fileChooserButton.find("span").text(fileChooserButton.data('fil-vald') + " " + filename); 342 submitButton.on('click', function () { 343 fast2.submitOnce(fileChooserButton); 344 data.submit(); 345 return false;
346 }); 347 } 348 }).prop('disabled', !$.support.fileInput) 349 .parent().addClass($.support.fileInput ? undefined : 'disabled'); 350 } 351 352 353 // Hitta alla länkar som skall registrera GA-event och lägg till click 354 if (typeof _gaq !== 'undefined') { 355 $('a[data-gacategory],input[data-gacategory]').each(function () { 356 var $elem = $(this); 357 var category = $elem.data('gacategory'); 358 var action = $elem.data('gaaction'); 359 360 $elem.click(function () { 361 _gaq.push(['trackEvent', category, action]); 362 }); 363 }); 364 } 365 366 // Klicka på tabellrad i kompakta listor 367 $('.kompakt-lista__rad').click(function () { 368 href = $(this).attr('data-href'); 369 if (href !== undefined) { 370 window.location = href; 371 } 372 }); 373 374 // Klicka på tabellrad i bostadsbyte kompakt, behövs? 375 $('.objektlistabosbytekompakt__post').click(function () { 376 href = $(this).attr('data-href'); 377 window.location = href; 378 }); 379 380 // Klicka på tabellrad i kompakta listor (bostadsbytemeddelande), behövs? 381 $('.bostadsbyte-meddelandelista.table').click(function () { 382 href = $('.table__row', this).attr('data-href'); 383 window.location = href; 384 }); 385 386 // Klicka på tabellrad i publiceringstatisik, behövs? 387 $('.Publiceringstatistik.tabell').click(function () { 388 href = $('.tabell__rad', this).attr('data-href'); 389 window.location = href; 390 }); 391 392 $('[class*="__fieldset"] select,[class*="__fieldset"] [type="text"], [class*="__fieldset"] [type="tel"], ' + 393 '[class*="__fieldset"] [type="email"], [class*="__fieldset"] [type="checkbox"], [class*="__fieldset"] [type="password"]').each(function () { 394 $(this).on('blur', function () { 395 fast2.wcagClientValidation(this); 396 }); 397 }); 398 }, 399 bindFormEvents: function (widgetId) { 400 var $selector = $('[data-widget="' + widgetId + '"] form[method=post]'); 401 $selector.find('[type=submit]').click(fast2.updateFormsAttributes); 402 $selector.on('submit', fast2.onSubmitFormsEvent); 403 }, 404 updateFormsAttributes: function () { 405 var parentForm = $(this).parents('form'); 406 if (this.attributes["data-no-validation"] && this.attributes["data-no-validation"].value === "true") { 407 $(parentForm).attr('data-no-validation', 'true'); 408 } 409 $('[type=submit]', parentForm).removeAttr('clicked'); 410 $(this).attr('clicked', 'true'); 411 }, 412 onSubmitFormsEvent: function (e) { 413 // Filtrera bort formulär som har egen action, t.ex. eavtal 414 if ($(this).attr("action") !== undefined) { 415 return; 416 } 417 418 fast2.log("Onsubmit handler"); 419 if (!fast2.trigger(fast2.events.postbackBefore)) { 420 fast2.log("Cancel Onsubmit handler by custom event"); 421 // Cancel event 422 return false; 423 } 424 425 // I fall där flera formulär hänger ihop med data-flow 426 // så skall alla fält valideras tillsammans 427 var dataFlow = $(this).data('flow'); 428 if (dataFlow) { 429 forms = $('form[data-flow="' + dataFlow + '"]'); 430 fast2.log("data-flow-attribut finns på widget-formulär, postar flöde " + dataFlow + " tillsammans", forms); 431 } else { 432 forms = this; 433 } 434 //var $widget = $(this).closest('[data-widget]'); 435 //var widget = $widget.data('widget'); 436 437 438 var validateData = !(e.target && e.target.attributes['data-no-validation']); 439 if (validateData && !fast2.validateForms()) return false;
440 441 // Add eventId 442 var actionId = $('[type=submit][clicked=true]', this).data('action'); 443 fast2.log("actionId = " + actionId); 444 $('[name="actionId"]', this).val(actionId); 445 446 fast2.log("Event skickat!"); 447 fast2.log(fast2.serviceUrl); 448 449 var serializedForm = fast2.getSerializedForm(forms); 450 var widgetIds = fast2.getWidgetIdsFromForms(forms); 451 452 var $submitbutton = $('[type=submit][clicked=true]', this); 453 fast2.submitOnce($submitbutton, forms); 454 455 fast2.postFormsToBackend(serializedForm, widgetIds); 456 return false; 457 }, 458 submitForms: function (forms, validateData, widgetsToUpdate) { 459 if (validateData && !fast2.validateForms()) return false; 460 var serializedForm = fast2.getSerializedForm(forms); 461 var widgetIds = fast2.getWidgetIdsFromForms(forms, widgetsToUpdate); 462 fast2.postFormsToBackend(serializedForm, widgetIds); 463 return true; 464 }, 465 getSerializedForm: function (forms) { 466 var serializedForm = $(forms).serialize(); 467 fast2.log("Formulär", serializedForm); 468 return serializedForm; 469 }, 470 getWidgetIdsFromForms: function (forms, widgetsToUpdate) { 471 if (!widgetsToUpdate) widgetsToUpdate = []; 472 // Hämta samtliga widgets som har ett submittat form i sig 473 var widgetIds = { 474 'widgets[]': $(forms).parents('[data-widget]').map(function () { 475 return $(this).data('widget'); 476 }).get().concat(widgetsToUpdate) 477 }; 478 fast2.log("Widget ID:s", widgetIds); 479 return widgetIds; 480 }, 481 validateForms: function (forms) { 482 var wcag = $('[class*="__fieldset"]').length > 0; 483 484 // Required validering 485 // Check required fields 486 $(".required:visible", forms).removeClass("error"); 487 $required = $(".required:visible input, .required:visible select[value='']", forms) 488 .filter(function () { 489 return wcag || !this.value; 490 }); 491 //$required = $.merge($required, $(".required:visible input[value=''][data-required-for-widget='" + widget + "'], .required:visible select[value=''][data-required-for-widget'" + widget + "']")); 492 // Checkbox and radio 493 $required_checkboxes = $(".required:visible input:checkbox:not(:checked)", forms); 494 fast2.log("Required checkbox", $required_checkboxes); 495 if ($required_checkboxes.length > 0) { 496 $required = $.merge($required, $required_checkboxes); 497 } 498 499 $required_radio = $(".required:visible input[type='radio']", forms); 500 fast2.log("Required radio", $required_radio); 501 if ($required_radio.length > 0) { 502 var _items = {}; 503 $required_radio.each(function () { 504 var $this = $(this); 505 var name = $this.attr('name'); 506 fast2.log("Required radio", $this.attr('id'), name, _items); 507 if (_items[name] !== true) { 508 if ($this.is(':checked')) { 509 _items[name] = true; 510 } else if (_items[name] === undefined) { 511 _items[name] = this; 512 } 513 } 514 }); 515 for (var e in _items) { 516 if (_items[e] !== true) 517 $required.push(_items[e]); 518 } 519 } 520 521 $requiredMatching = $("input[requirematching]", forms); 522 if ($requiredMatching.length > 0) { 523 $requiredMatching.each(function (index, mainElement) { 524 var verificationElement = $("#" + mainElement.attributes.requirematching.value); 525 if (verificationElement.length > 0 && mainElement.value != verificationElement[0].value) { 526 $required.push(mainElement); 527 $required.push(verificationElement); 528 } 529 }); 530 } 531 532 if ($required.length > 0) {
533 var $focusFieldElement = null; 534 var setFocusFieldElement = function (el) { 535 $focusFieldElement = $focusFieldElement || el; 536 el.parents(".control-group").addClass("error"); 537 }; 538 if (wcag) { 539 $required.each(function () { 540 var $this = $(this); 541 fast2.wcagClientValidation(this); 542 if ($this.hasClass('validation-error')) { 543 setFocusFieldElement($this); 544 } 545 }); 546 } else { 547 fast2.log("Not all required fields are filled out", $required); 548 $required.each(function () { 549 setFocusFieldElement($(this)); 550 }); 551 } 552 if ($focusFieldElement !== null) { 553 // Set focus to first required field 554 if (!$focusFieldElement.is("[type=checkbox], [type=radio]")) { 555 $focusFieldElement.focus(); 556 } 557 $focusFieldElement = fast2.getElementLabelFromContext($focusFieldElement, forms) || $focusFieldElement; 558 fast2.scrollTo($focusFieldElement, 0.3); 559 fast2.trigger(fast2.events.postbackEmptyRequiredFields); 560 return false; 561 } 562 } 563 return true; 564 }, 565 566 wcagClientValidation: function (el) { 567 var $el = $(el); 568 if ($el.attr('readonly')) return; 569 var message = ''; 570 var required = $el.parent().hasClass('required') || $el.attr('required'); 571 if ($el.attr('type') === 'checkbox') { 572 fast2.removeErrorMessage(el); 573 if (required && !$el.is(':checked')) { 574 fast2.addErrorMessage(el, message); 575 } 576 return; 577 } 578 var id = $el.attr('id'); 579 var match = id.match(/^((huvudsokande|medsokande|hyresgast\d)_)?(\w+)_value$/); 580 if (!match) return; 581 var part = match[2]; 582 var field = match[3].toLowerCase(); 583 var value = $el.val(); 584 if (value === '') { 585 if (required) { 586 fast2.addErrorMessage(el, useEnglish ? 'The field must not be left blank' : 'Fältet får inte lämnas tomt'); 587 } 588 return; 589 } 590 var pattern = $el.prop('pattern'); 591 var regex = ''; 592 var matchedRegex = ''; 593 if (pattern) { 594 regex = new RegExp(pattern, 'gu'); 595 matchedRegex = value.match(regex); 596 } 597 fast2.removeErrorMessage(el); 598 599 if (matchedRegex) { 600 fast2.patternMatched(el, matchedRegex); 601 return; 602 } else if (field === 'bekraftaepost') { 603 if (value === $('#' + part + '_epost_value').val()) { 604 fast2.patternMatched(el, value); 605 return; 606 } 607 608 value = undefined; 609 } else if (field === 'confirmnewpassword') { 610 if (value === $('#newPassword_value').val()) { 611 fast2.patternMatched(el, value); 612 return; 613 } 614 615 value = undefined; 616 } else { 617 switch (field) { 618 case 'kundnummer': 619 case 'kundnr': 620 value = value.replace(/\D/g, ''); 621 break; 622 623 case 'fnamn': 624 case 'fornamn': 625 case 'enamn': 626 case 'efternamn': 627 value = value.replace(/[0-9]/g, ''); 628 value = value.charAt(0).toUpperCase() + value.substring(1); 629 break; 630 631 case 'adress': 632 case 'ort': 633 value = value.charAt(0).toUpperCase() + value.substring(1); 634 break; 635 636 case 'postnr': 637 value = value.replace(/[^\d-]/g, ''); 638 break; 639 640 case 'telefonbostad': 641 case 'telefondagtid': 642 case 'telefonkvallstid': 643 case 'telefonmobil': 644 case 'mobilnr': 645 case 'epost': 646 case 'bekraftaepost': 647 case 'newpassword': 648 value = undefined; 649 break; 650 651 default: 652 return; 653 } 654 } 655 if (value === undefined || !fast2.wcagFieldValidation(el, value, regex)) { 656 fast2.addErrorMessage(el, message); 657 } 658 }, 659 660 wcagFieldValidation: function (el, value, regex) { 661 var $el = $(el); 662 if (regex === '') { 663 return true; 664 } 665 var matchedRegex = value.match(regex); 666 if (matchedRegex) { 667 $el.val(matchedRegex); 668 return true; 669 } 670 $el.val(value); 671 return false;
672 }, 673 674 patternMatched: function (el, matchedRegex) { 675 fast2.removeErrorMessage(el); 676 $(el).val(matchedRegex); 677 }, 678 679 addErrorMessage: function (el, message) { 680 var $el = $(el); 681 var $parent = $el.parent(); 682 if (message === '') { 683 message = $el.attr('data-validationmessage') || (useEnglish ? 'The field must be filled out correctly' : 'Fältet behöver vara korrekt ifyllt'); 684 } 685 $el.removeClass('validation-success').addClass('validation-error'); 686 $parent.find('.validation-error__message').remove(); 687 $parent.append('<span role="alert" class="validation-error__message">' + message + '</span>'); 688 }, 689 removeErrorMessage: function (el) { 690 var $el = $(el); 691 $el.removeClass('validation-error').addClass('validation-success'); 692 $el.parent().find('.validation-error__message').remove(); 693 }, 694 695 scrollTo: function (el, position, speed) { 696 position = position === undefined || position < 0.0 ? 0.0 : (position > 1.0 ? 1.0 : position); 697 var windowHeight = $(window).height(); 698 var offset = el.offset().top; 699 var elHeight = el.height(); 700 if (elHeight < windowHeight) offset -= (windowHeight - elHeight) * position; 701 $('html, body').animate({scrollTop: offset}, speed === undefined ? 700 : speed); 702 }, 703 704 getElementLabelFromContext: function (element, context) { 705 var elementId = element.attr('id'); 706 var label; 707 708 if (!elementId) { 709 return null; 710 } 711 712 label = $("label[for='" + elementId + "']", context).first(); 713 714 return label.length > 0 ? label : null; 715 }, 716 postFormsToBackend: function (serializedForm, widgetIds) { 717 $.ajax({ 718 url: fast2.serviceUrl + fast2.getWindowLocationSearch(), 719 type: 'POST', 720 dataType: 'jsonp', 721 data: serializedForm + "&" + $.param(widgetIds), 722 success: function (data, textStatus) { 723 fast2.log('Success!', data, textStatus); 724 fast2.trigger(fast2.events.postbackSuccess); 725 }, 726 crossDomain: false, 727 xhrFields: { 728 withCredentials: true 729 } 730 }).done(fast2.widgetsLoaded).fail(function () { 731 fast2.log("Widget fail", arguments); 732 fast2.trigger(fast2.events.postbackFail); 733 }).always(function () { 734 fast2.log("Widget always", arguments); 735 fast2.trigger(fast2.events.postbackAlways); // Cowboy firing 736 }); 737 fast2.log("Formulär postat!"); 738 }, 739 740 submitOnce: function (element, forms) { 741 var submitOnceText = $(element).data("f2-once"); 742 if (submitOnceText !== undefined && $(element).data('handled') !== true) { // && (forms == undefined || $(".required:visible", forms).size() > 0) 743 $(element).data('handled', true); 744 // Get any pull-classes 745 var addClasses = $(element).attr('class') === undefined ? '' : fast2.findAndReturnMatchingClasses(element, ['pull-left', 'pull-right']); 746 $(element).after('<span class="btn disabled ' + addClasses + '"><i class="icon-refresh"></i> ' + (submitOnceText.length > 0 ? submitOnceText : useEnglish ? 'Loading...' : 'Laddar...') + '</span>'); 747 $(element).hide(); 748 } 749 }, 750 findAndReturnMatchingClasses: function (element, searchClasses) { 751 var $elem = $(element); 752 var classes = ""; 753 754 for (var i = 0; i < searchClasses.length; i++) { 755 if ($elem.attr('class').indexOf(searchClasses[i]) !== -1) { 756 classes += " " + searchClasses[i]; 757 } 758 } 759 return classes; 760 }, 761 762 /** 763 * Plockar ut data-param-key=value från widgets och 764 * skickar med dessa i ajax-anropet som 765 * widget-ID.key=value 766 * Viss justering görs med lowercase/uppercase på param-namnet 767 * om detta innehåller flera - 768 */ 769 widgetParamData: function (requestData, widgetIds) { 770 for (var i = 0; i < widgetIds.length; i++) { 771 var widgetId = widgetIds[i]; 772 var widget = $('[data-widget="' + widgetId + '"]'); 773 var attributes = widget.data(); 774 if ($.isPlainObject(attributes)) { 775 for (var key in attributes) { 776 if (key.indexOf('param') === 0) { 777 var paramName = widgetId + "." + key.replace('param', '').toLowerCase(); 778 fast2.log("Lägger till parameter " + paramName + "=" + attributes[key] + " för widget " + widgetId); 779 requestData[paramName] = attributes[key]; 780 } 781 } 782 } 783 } 784 return requestData; 785 }, 786 787 loadWidgets: function (serviceUrl) { 788 fast2.log("Kör fast2.loadWidgets ", serviceUrl); 789 fast2.trigger(fast2.events.widgetLoad); 790 fast2.serviceUrl = serviceUrl; 791 var widgetIds = fast2.widgetIds(); 792 var requestData = { 793 'widgets': widgetIds 794 }; 795 requestData = fast2.widgetParamData(requestData, widgetIds); 796 797 $.ajax({ 798 url: fast2.serviceUrl + fast2.getWindowLocationSearch(), 799 dataType: 'jsonp', 800 data: requestData,
801 crossDomain: false, 802 xhrFields: { 803 withCredentials: true 804 } 805 }).done(function (data) { 806 fast2.log(data); 807 808 if (data.javascripts && data.javascripts.length > 0) { 809 // Load logic scripts for widgets 810 fast2.loadLogicScripts(data); 811 } else { 812 fast2.widgetsLoaded(data); 813 } 814 815 }).fail(function () { 816 // TODO: Vad ska hända om inte widgeten hittas??? 817 fast2.log("Widget failed", arguments); 818 fast2.trigger(fast2.events.widgetFail); 819 }).always(function () { 820 // Alla widgetts är klara och levde lyckliga alla sina dagar 821 fast2.log("Widgets ready", arguments); 822 fast2.trigger(fast2.events.widgetAlways); 823 }); 824 } 825 826 /** Callback **/ 827 // Borde heta onWidgetLoaded - anropas en gång för varje widget... 828 , onWidgetsLoaded: function (data, wid) { 829 fast2.log("onWidgetsLoaded", fast2.events.widgetReady); 830 fast2.trigger(fast2.events.widgetReady, {data: data}, wid); // Cowboy firing 831 832 // Captcha-stöd 833 $('div[data-captcha]').each(function () { 834 fast2.log('captcha', this); 835 Recaptcha.create($(this).data('captcha'), 836 this, 837 { 838 // Options : https://developers.google.com/recaptcha/docs/customization 839 theme: "white", 840 callback: Recaptcha.focus_response_field 841 } 842 ); 843 }); 844 845 } 846 847 , trigger: function (eventName, eventData, eventTarget) { 848 fast2.log("trigger " + eventName, eventData, eventTarget); 849 if (typeof eventTarget == "undefined") { 850 eventTarget = fast2.wc; 851 } else { 852 eventTarget = '[data-widget="' + eventTarget + '"]'; 853 } 854 var defaultEventData = {ok: true, message: ""}; 855 eventData = $.extend({}, defaultEventData, eventData); 856 var e = new jQuery.Event(eventName, [eventData]); 857 // Back reference to prop 858 e.f2 = function () { 859 return this[0]; 860 }; 861 fast2.log("trigger " + eventName, e); 862 $(eventTarget).trigger(e); 863 // Event response 864 fast2.log("trigger response " + eventName, eventData); 865 return eventData.ok; 866 } 867 868 , addPostBackBehavior: function () { 869 870 } 871 872 , loadLogicScripts: function (data) { 873 var callback = (function () { 874 var result = data.javascripts.slice(); 875 return function (scriptUrl, ok) { 876 result.pop(); 877 if (result.length === 0) { 878 fast2.widgetsLoaded(data); 879 } 880 }; 881 })(); 882 883 for (var item = 0; item < data.javascripts.length; item++) { 884 fast2.getSupportingScripts(callback, data.javascripts [item]); 885 } 886 887 } 888 889 , getSupportingScripts: function (callback, scriptUrl) { 890 if (scriptUrl.substring(0, 2) == '//') { 891 scriptUrl = window.location.protocol + scriptUrl; 892 } else { 893 scriptUrl = fast2.scriptUrl + scriptUrl; 894 } 895 if ($('[src="' + scriptUrl + '"]').length === 0) { 896 $.getScript(scriptUrl, function (data, textStatus, jqxhr) { 897 callback(scriptUrl, true); 898 }).fail(function (jqxhr, settings, exception) { 899 // Hitta alert 900 callback(scriptUrl, false); 901 }); 902 } else { 903 window.setTimeout(function () { 904 callback(scriptUrl, true); 905 }, 1); 906 } 907 } 908 909 , fileuploadIframeReload: function () { 910 var url = location.href; 911 var separator = ""; 912 if (url[url.length - 1] === '?') { 913 separator = ""; 914 } else if (url.indexOf('?') > 0) { 915 separator = "&"; 916 } else { 917 separator = "?"; 918 } 919 location.replace(url + separator + "fileuploadiframereload=true"); 920 } 921 922 , getWindowLocationSearch: function () { 923 var search = window.location.search; 924 if (search.indexOf('callback') != -1) { 925 search = search.replace(/([?&])callback=[^&]*&?/g, "$1"); 926 if (search != window.location.search) { 927 if (search === '?') search = ''; 928 var url = window.location.href.split('?')[0] + search; 929 window.history.pushState('', document.title, url); 930 } 931 } 932 return search; 933 } 934 935 , stopEvent: function (e) { 936 if (e.preventDefault !== undefined) e.preventDefault(); 937 if (e.stopPropagation !== undefined) e.stopPropagation(); 938 } 939 940 }; 941 942 window.fast2 = fast2; 943 944 $(function () { 945 // Check for service url on script elements 946 var $serviceScript = $('script[data-widget-service]'); 947 if ($serviceScript && $serviceScript.attr("src") !== undefined && $serviceScript.attr("src").split('/').length > 3) { 948 fast2.scriptUrl = '//' + $serviceScript.attr("src").split('/')[2]; 949 fast2.serviceUrl = '//' + $serviceScript.attr("src").split('/')[2] + fast2.serviceUrl; 950 } 951 fast2.log("fast2 loadWidgets" + fast2.serviceUrl); 952 fast2.loadWidgets(fast2.serviceUrl); 953 }); 954 955})(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.