PageSourceSearch

https://edgewateryachtclub.com/public/assets/js/catch-all/common/custom-fields.js

js edgewateryachtclub.com collected 2026-10-09 22:59:46 UTC 40,111 bytes, 815 lines download raw bytes

1function applyPricingUIToCustomFieldOptionsInDOM( currency ){
2    $('option').each(function(){
3        var thisAmount = $(this).data('adjustment-amount');
4        if( thisAmount ){
5            var amountString = '';
6            if( thisAmount > 0){
7                var niceAmount = formatPriceForCurrency(currency, thisAmount);
8                amountString += ' ( + '+niceAmount+' )';
9            }else if(thisAmount < 0){
10                var niceAmount = formatPriceForCurrency(currency, thisAmount);
11                amountString += ' ( '+niceAmount+' )';
12            }
13            $(this).html( sanitize_string( $(this).data('response') + amountString ) );
14        }
15    });
16    $('.checkmarkCard').each(function(){
17        var thisAmount = $(this).data('adjustment-amount');
18        if( thisAmount ){
19            var amountString = '';
20            if( thisAmount > 0){
21                var niceAmount = formatPriceForCurrency(currency, thisAmount);
22                amountString += ' ( + '+niceAmount+' )';
23            }else if(thisAmount < 0){
24                var niceAmount = formatPriceForCurrency(currency, thisAmount);
25                amountString += ' ( '+niceAmount+' )';
26            }
27            $(this).find('p').text( $(this).find('p').text() + amountString );
28        }
29    });
30}
31
32function custom_field_has_cost(customFieldObject){
33    var options = customFieldObject.get('dropdownOptionsArray') || [];
34    var hasCost = false;
35    for (var i = 0; i <= options.length - 1; i++) {
36        var thisOption = options[i];
37        if( thisOption.get('amount') ){
38            hasCost = true;
39        }
40    }
41    return hasCost;
42}
43
44function returnMarkupForCustomFieldResponse( customFieldObject, locked_if_field_has_cost ){
45    var content = '';
46    if( customFieldObject ){
47        let locked = false;
48        if( locked_if_field_has_cost && custom_field_has_cost(customFieldObject) ){
49            locked = true;
50        }
51        content += '<div class="flexNoWrap tinyPaddingTop inline-pair inline-pair_'+ customFieldObject.id +'" data-type="custom-field" data-locked="'+ locked +'" data-admin-only="'+ customFieldObject.get('admin_only') +'">' +
52            '<p class="inline-label">';
53            if( locked ){
54                content += '<i class="fa-regular fa-lock" style="padding-right:3px;"></i>';
55            }
56            content +=  customFieldObject.get('name') + '</p>' +
57            '<p class="flexGrowOne inline-value marginLeft" data-custom-field-id="'+ customFieldObject.id +'"></p>' +
58        '</div>';
59    }
60    return content;
61}
62
63function returnMarkupForCustomFieldResponse_v2( customFieldObject, customFieldResponseObject ){
64    var content = '';
65    if( customFieldObject && customFieldResponseObject){
66        content += '<div class="flexNoWrap tinyPaddingTop inline-pair inline-pair_'+ customFieldObject.id +'" data-type="custom-field" data-admin-only="'+ customFieldObject.get('admin_only') +'">' +
67            '<p class="inline-label">' + customFieldResponseObject + '</p>' +
68            '<p class="flexGrowOne inline-value marginLeft" data-custom-field-id="'+ customFieldObject.id +'"></p>' +
69        '</div>';
70    }
71    return content;
72}
73
74function plugCustomFieldResponsesWithinWrapper( wrapper, customFieldResponseArray ){
75    $(wrapper + ' .inline-value').each(function(){
76        var customFieldID = $(this).data('custom-field-id');
77        if( customFieldID && customFieldResponseArray ){
78            for (var c = customFieldResponseArray.length - 1; c >= 0; c--) {
79                var thisPair = customFieldResponseArray[c];
80                if(thisPair){
81                    if( thisPair.customFieldID == customFieldID ){
82                        if( thisPair.optionsObjectIDsArray ){
83                            //it's a radio situation
84                            var string = returnStringForCustomFieldDropdownSelections( thisPair );
85                            if( string.length >= 1 ){
86                                $(this).text( string );
87                                $(this).removeClass('incomplete');
88                            }
89                        }else if( thisPair.url ){
90                            //it's a file
91                            $(this).html( "<a target='_blank' href="+ thisPair.url +">Click to view</a>" );
92                            $(this).removeClass('incomplete');
93                        }else if( thisPair.response ){
94                            $(this).text( thisPair.response );
95                            $(this).removeClass('incomplete');
96                        }
97                    }
98                }
99            }
100        }
101        if( ! $(this).text() ){
102            $(this).text("Not provided");
103            $(this).addClass('incomplete');
104        }
105    });
106}
107
108//a field filed under an archived category reads as uncategorized
109function return_membership_custom_field_category(custom_field) {
110    const category_object = custom_field.get("categoryObject");
111    if (!category_object || category_object.get("archived") === true) {
112        return null;
113    }
114    return category_object;
115}
116
117//categorized fields are ordered by category_priority and uncategorized fields by the legacy
118//priority, but both markers are optional: a field with neither keeps the position it had in the
119//array it was loaded from (historically membership_settings.customFieldsArray), so clubs that
120//never reordered anything keep the order they already had
121function return_membership_custom_field_priority(custom_field, source_index) {
122    if (typeof custom_field.get("category_priority") === "number") {
123        return custom_field.get("category_priority");
124    }
125    if (typeof custom_field.get("priority") === "number") {
126        return custom_field.get("priority");
127    }
128    return source_index;
129}
130
131function return_membership_custom_fields_for_member(params) {
132    const {
133        membership_settings,
134        member_object,
135        member_facing,
136    } = params;
137    const custom_fields = membership_settings
138        ? membership_settings.get("customFieldsArray") || []
139        : [];
140    const filtered_custom_fields = custom_fields.filter((custom_field) => {
141        const applies_to_members =
142            custom_field.get("applies_to") === "applicants_and_members" ||
143            custom_field.get("applies_to") === "members";
144        if (
145            !applies_to_members ||
146            custom_field.get("archived")
147        ) {
148            return false;
149        }
150        if (!member_facing) {
151            return true;
152        }
153        const applies_to_primary =
154            !custom_field.get("primary_only") ||
155            (
156                member_object &&
157                member_object.get("primary")
158            );
159        return (
160            applies_to_primary &&
161            custom_field.get("active") !== false &&
162            custom_field.get("hide_from_member") !== true
163        );
164    });
165    return sort_membership_custom_fields(filtered_custom_fields);
166}
167
168//This is the one place membership custom field order is defined: uncategorized fields first, then
169//a section per category. Pass custom_field_categories to render a section for every category the
170//club has, including the empty ones - the configuration UI needs that, display views do not.
171function return_membership_custom_field_sections(custom_fields, custom_field_categories) {
172    const priority_by_field = new Map();
173    const categories_by_id = new Map();
174    const fields_by_category_id = new Map();
175    const uncategorized_fields = [];
176    (custom_fields || []).forEach((custom_field, index) => {
177        priority_by_field.set(custom_field, return_membership_custom_field_priority(custom_field, index));
178        const category_object = return_membership_custom_field_category(custom_field);
179        if (!category_object) {
180            uncategorized_fields.push(custom_field);
181            return;
182        }
183        categories_by_id.set(category_object.id, category_object);
184        if (!fields_by_category_id.has(category_object.id)) {
185            fields_by_category_id.set(category_object.id, []);
186        }
187        fields_by_category_id.get(category_object.id).push(custom_field);
188    });
189    (custom_field_categories || []).forEach((category_object) => {
190        if (category_object.get("archived") !== true) {
191            categories_by_id.set(category_object.id, category_object);
192        }
193    });
194
195    const sections = [];
196    if (uncategorized_fields.length > 0 || custom_field_categories) {
197        sections.push({
198            category_object: null,
199            name: "Uncategorized",
200            custom_fields: uncategorized_fields,
201        });
202    }
203    Array.from(categories_by_id.values()).sort((first_category, second_category) => {
204        return (first_category.get("priority") || 0) - (second_category.get("priority") || 0)
205            || (first_category.get("name") || "").localeCompare(second_category.get("name") || "")
206            || first_category.id.localeCompare(second_category.id);
207    }
207).forEach((category_object) => {
208        sections.push({
209            category_object: category_object,
210            name: category_object.get("name"),
211            custom_fields: fields_by_category_id.get(category_object.id) || [],
212        });
213    });
214    sections.forEach((section) => {
215        section.custom_fields.sort((first_field, second_field) => {
216            return priority_by_field.get(first_field) - priority_by_field.get(second_field)
217                || first_field.id.localeCompare(second_field.id);
218        });
219    });
220    return sections;
221}
222
223function sort_membership_custom_fields(custom_fields) {
224    return return_membership_custom_field_sections(custom_fields).reduce((sorted_fields, section) => {
225        return sorted_fields.concat(section.custom_fields);
226    }, []);
227}
228
229function returnCustomFieldsForType(clubObject, type, primary) {
230    const custom_fields_array = clubObject.get("membership_settings").get("customFieldsArray") || [];
231    const custom_fields = custom_fields_array.filter((custom_field) => {
232        if (
233            custom_field.get("archived") ||
234            custom_field.get("active") === false ||
235            (!primary && custom_field.get("primary_only"))
236        ) {
237            return false;
238        }
239        return (
240            custom_field.get("applies_to") === "applicants_and_members" ||
241            custom_field.get("applies_to") === type
242        );
243    });
244    return sort_membership_custom_fields(custom_fields);
245}
246
247function returnMembershipCustomFieldsArrayForClub(clubObject, memberObject) {
248    let primary = true;
249    if (memberObject && !memberObject.get("primary")) {
250        primary = false;
251    }
252    return returnCustomFieldsForType(clubObject, "members", primary);
253}
254
255function returnSelectedOptionsForRadioCustomField(customFieldInput){
256    var array = [];
257    if( customFieldInput ){
258        customFieldInput.find('.checkmarkCard').each(function(){
259            if( $(this).data('option-id') && $(this).hasClass('active') ){
260                array.push( $(this).data('option-id') );
261            }
262        });
263    }
264    return array;
265}
266
267function returnSelectedOptionStringsForRadioCustomField(customFieldInput){
268    var array = [];
269    if( customFieldInput ){
270        customFieldInput.find('.checkmarkCard').each(function(){
271            if( $(this).find('p').text() && $(this).hasClass('active') ){
272                array.push( $(this).find('p').text() );
273            }
274        });
275    }
276    return array;
277}
278
279function returnCustomFieldSelectionsWithinWrapper(wrapper){
280    var customFieldsArray = [];
281    var classSituation = '.customFieldInput';
282    if(wrapper){
283        classSituation = wrapper+' .customFieldInput';
284    }
285    $(classSituation).each(function(){
286        var hidden = false;
287        if( $(this).parents('.inputWrap') ){
288            if( $(this).parents('.inputWrap').hasClass('hidden') ){
289                hidden = true;
290            }
291        }
292        if( ! hidden ){
293            var customFieldID = $(this).data('custom-field-id');
294            if(customFieldID){
295                var selectedDropdownOptionID, selectedDropdownOptionIDsArray, response, optionsStringsArray;
296                if( $(this).is( 'select' ) ){
297                    selectedDropdownOptionID = $(this).find('option:selected').data('option-id');
298                    response = $(this).find('option:selected').text();
299                }else if( $(this).hasClass('radioWrap') ){
300                    //figure out array of selections
301                    selectedDropdownOptionIDsArray = returnSelectedOptionsForRadioCustomField( $(this) );
302                    optionsStringsArray = returnSelectedOptionStringsForRadioCustomField( $(this) );
303                }else if( $(this).attr('type') == "file" ){
304                    response = $(this).data('url');
305                }else{
306                    response = $(this).val();
307                }
308                customFieldsArray.push({
309                    'customFieldID': customFieldID, 
310                    'response': response, 
311                    'optionObjectID': selectedDropdownOptionID, 
312                    'optionsObjectIDsArray': selectedDropdownOptionIDsArray,
313                    'optionsStringsArray': optionsStringsArray,
314                    'url': $(this).data('url')
315                });
316            }
317        }
318    });
319    return customFieldsArray;
320}
321
322function returnSelectedOptionIDForCustomField(customFieldObject, idPrefix) {
323    var optionID;
324    if(customFieldObject){
325        if( !idPrefix ){
326            idPrefix = 'customFieldInput_';
327        }
328        if( $('#'+idPrefix+customFieldObject.id).length >= 1 ){
329            //find the selected option
330            optionID = $('#'+idPrefix+customFieldObject.id).find('option:selected').data('option-id');
331        }
332    }
333    return optionID;
334}
335
336function returnSelectedOptionIDForCustomFieldV2(customFieldObject) {
337    var optionID;
338    if(customFieldObject){
339        if( $('.customFieldInput_'+customFieldObject.id).length >= 1 ){
340            //find the selected option
341            optionID = $('.customFieldInput_'+customFieldObject.id).find('option:selected').data('option-id');
342        }
343    }
344    return optionID;
345}
346
347function plugCustomFieldResponsesForObject(customFieldsArray, inputString){
348    if(customFieldsArray && inputString){
349        for (var c = customFieldsArray.length - 1; c >= 0; c--) {
350            var thisPair = customFieldsArray[c];
351            if(thisPair){
352                if( thisPair.customFieldID ){
353                    if( $('#'+inputString+'_'+thisPair.customFieldID).length >= 1 ){
354                        if( $('#'+inputString+'_'+thisPair.customFieldID).hasClass('radioWra
354p') ){
355                            //it's a multi select situation (div)
356                            var optionsObjectIDsArray = thisPair.optionsObjectIDsArray;
357                            if(optionsObjectIDsArray){
358                                $('#'+inputString+'_'+thisPair.customFieldID).find('.checkmarkCard').each(function(){
359                                    var thisID = $(this).data('option-id');
360                                    if(thisID){
361                                        if( optionsObjectIDsArray.indexOf(thisID) > -1 ){
362                                            $(this).addClass('active');
363                                        }
364                                    }
365                                });
366                            }
367                        }else if( $('#'+inputString+'_'+thisPair.customFieldID).is('select') ){
368                            if( thisPair.optionObjectID ){
369                                $('#'+inputString+'_'+thisPair.customFieldID).val( thisPair.optionObjectID ).change();
370                            }else{
371                                $('#'+inputString+'_'+thisPair.customFieldID).val( thisPair.response ).change();
372                            }
373                        }else{
374                            //it's an input or textarea
375                            $('#'+inputString+'_'+thisPair.customFieldID).val( thisPair.response ).change();
376                        }
377                    }
378                }
379            }
380        }
381    }
382}
383
384function returnResponseObjectForCustomFieldID( customFieldsArray, customFieldID ){
385    var object = {};
386    if( customFieldsArray && customFieldID ){
387        for (var i = customFieldsArray.length - 1; i >= 0; i--) {
388            var thisPair = customFieldsArray[i];
389            if( thisPair ){
390                if( thisPair.customFieldID == customFieldID ){
391                    object = thisPair;
392                }
393            }
394        }
395    }
396    return object;
397}
398
399function plugCustomFieldResponsesV2(customFieldsArray, wrapper){
400    if(customFieldsArray && wrapper){
401        $(wrapper+' .customFieldInput').each(function(){
402            var customFieldID = $(this).data('custom-field-id');
403            if( customFieldID ){
404                var object = returnResponseObjectForCustomFieldID( customFieldsArray , customFieldID );
405                if( $(this).hasClass('radioWrap') ){
406                    //it's a multi select situation (div)
407                    var optionsObjectIDsArray = object.optionsObjectIDsArray;
408                    if(optionsObjectIDsArray){
409                        $(this).find('.checkmarkCard').each(function(){
410                            var thisID = $(this).data('option-id');
411                            if(thisID){
412                                if( optionsObjectIDsArray.indexOf(thisID) > -1 ){
413                                    $(this).addClass('active');
414                                }
415                            }
416                        });
417                    }
418                }else if( $(this).is('select') ){
419                    if( object.optionObjectID ){
420                        $(this).val( object.optionObjectID ).change();
421                    }else{
422                        $(this).val( object.response ).change();
423                    }
424                }else if( $(this).attr('type') == "file" ){
425                    if( object.url ){
426                        $(this).data('url', object.url);
427                        $(this).change();
428                    }
429                }else{
430                    //it's an input or textarea
431                    $(this).val( object.response ).change();
432                }
433            }
434        });
435    }
436}
437
438function returnStringForCustomFieldDropdownSelections( customFieldResponseObject ){
439    var string = '';
440    if( customFieldResponseObject ){
441        var optionsStringsArray = customFieldResponseObject.optionsStringsArray;
442        if(optionsStringsArray){
443            for (var i = 0; i <= optionsStringsArray.length - 1; i++) {
444                var thisString = optionsStringsArray[i];
445                if( string.length >= 1 ){
446                    string += ', ' + thisString;
447                }else{
448                    string += thisString;
449                }
450            }
451        }
452    }
453    return string;
454}
455
456function returnMarkupForCustomFieldV2(customFieldObject, inputClasses, currency){
457    var content = '';
458    if(customFieldObject){
459        //handle input class
460        if( !inputClasses ){
461            inputClasses = '';
462        }
463        if( customFieldObject.get('required') ){
464            inputClasses += ' required';
465        }
466        //add for identification
467        inputClasses += ' customFieldInput_'+customFieldObject.id;
468        //now generate more markup
469        if( customFieldObject.get('type') == 'select' || customFieldObject.get('type') == 'searchable_select' ){
470            var optionsArray = customFieldObject.get('dropdownOptionsArray');
471            if(optionsArray){
472                if(optionsArray.length >= 1){
473                    if( customFieldObject.get('name').length <= 30 ) {
474                        //short name
475                        content += '<div class="inputWrap smallMarginBottom"><label class="inputLabel easeFast">'+customFieldObject.get('name')+'</label><select data-custom-field-id="'+customFieldObject.id+'" class="customFieldInput '+inputClasses+'">';
476                        content += '<option data-non-option="true"></option>';
477                        for (var o = 0; o <= optionsArray.length - 1; o++) {
478                            var thisOption = optionsArray[o];
479                            if(thisOption){
480                                if( thisOption.get('name') ){
481                                    //handle additional amounts
482                                    var amountString = '';
483                                    var thisAmount;
484                                    if( currency ){
485                                        thisAmount = thisOption.get('amount');
486                                        if(thisAmount > 0){
487                                            var niceAmount = formatPriceForCurrency(currency, thisAmount);
488                                            amountString += ' ( + '+niceAmount+' )';
489                                        }else if(thisAmount < 0){
490                                            var niceAmount = formatPriceForCurrency(currency, thisAmount);
491                                            amountString += ' ( '+niceAmount+' )';
492                                        }
493                                    }
494                                    //plug it in
495                                    content += '<option data-option-id="'+thisOption.id+'" data-adjustment-amount="'+thisAmount+'" value="'+thisOption.id+'">'+thisOption.get('name')+amountString+'</option>';
496                                }
497                            }
498                        }
499                        content += '</select></div>';
500                    } else {
501                        //long name
502                        content += '<p class="secondaryCardSubtext smallMarginBottom">'+ customFieldObject.get('name') +'</p>';
503                        content += '<div class="inputWrap smallMarginBottom"><label class="inputLabel easeFast">Click to enter</label><select data-custom-field-id="'+customFieldObject.id+'" class="customFieldInput '+inputClasses+'">';
504                        content += '<option data-non-option="true"></option>';
505                        for (var o = 0; o <= optionsArray.length - 1; o++) {
506                            var thisOption = optionsArray[o];
507                            if(thisOption){
508                                if( thisOption.get('name') ){
509                                    //handle additional amounts
510                                    var amountString = '';
511                                    var thisAmount;
512                                    if( currency ){
513                                        thisAmount = thisOption.get('amount');
514                                        if(thisAmount > 0){
515                                            var niceAmount = formatPriceForCurrency(currency, thisAmount);
516                                            amountString += ' ( + '+niceAmount+' )';
517                                        }else if(thisAmount < 0){
518                                            var niceAmount = formatPriceForCurrency(currency, thisAmount);
519                                            amountString += ' ( '+niceAmount+' )';
520                                        }
521                                    }
522                                    //plug it in
523                                    content += '<option data-option-id="'+thisOption.id+'" data-adjustment-amount="'+thisAmount+'" value="'+thisOption.id+'">'+thisOption.get('name')+amountString+'</option>';
524                                }
525                            }
526                        }
527                        content += '</select></div>';
528                    }
529                }
530            }
531        }else if( customFieldObject.get('type') == 'textarea' ){
532            content += '<div><p class="secondaryCardSubtext tinyMarginBottom">'+customFieldObject.get('name')+'</p><div class="textareaWrap marginBottom"><textarea data-custom-field-id="'+customFieldObject.id+'" class="customFieldInput '+inputClasses+'"></textarea></div></div>';
533        }else if( customFieldObject.get('type') == 'radio' ){
534            //multi select
535            var optionsArray = customFieldObject.get('dropdownOptionsArray');
536            if(optionsArray){
537                if(optionsArray.length >= 1){
538                    content += '<p class="secondaryCardSubtext tinyMarginBottom">'+customFieldObject.get('name')+'</p><div data-custom-field-id="'+customFieldObject.id+'" class="customFieldInput radioWra
538p flexWrapLeftAlign '+inputClasses+'">';
539                    for (var o = 0; o <= optionsArray.length - 1; o++) {
540                        var thisOption = optionsArray[o];
541                        if(thisOption){
542                            if( thisOption.get('name') ){
543                                //plug it in
544                                content += '<div data-option-id="'+thisOption.id+'" value="'+thisOption.id+'" class="checkmarkCard easeFast flexNoWrap"><div class="checkmark tinyIcon"></div><p>'+thisOption.get('name')+'</p></div>';
545                            }
546                        }
547                    }
548                    content += '</div>';
549                }
550            }
551        }else if( customFieldObject.get('type') == 'file_upload' ){
552            content += '<p class="secondaryCardSubtext smallMarginBottom">'+ customFieldObject.get('name') +'</p>' +
553            '<div class="inputWrap wider centeredBlock smallMarginBottom">' +
554                '<label class="inputLabel">Click to upload</label>' +
555                '<input data-custom-field-id="'+ customFieldObject.id +'" class="customFieldInput absoluteInput" type="file" accept="application/pdf, image/*">' +
556                '<div class="successfulFileUploadWrap flexNoWrap">' +
557                    '<div class="tinyIcon successIcon"></div>' +
558                    '<p>File selected</p>' +
559                '</div>' +
560            '</div>';
561        }else if (customFieldObject.get('type') == 'date') {
562            content += `
563              <div>
564                <p class="secondaryCardSubtext tinyMarginBottom">${customFieldObject.get('name')}</p>
565                <div class="inputWrap wider centeredBlock smallMarginBottom">
566                    <input 
567                        data-custom-field-id="${customFieldObject.id}" 
568                        class="customFieldInput ${inputClasses}" 
569                        type="date"
570                    >
571                </div>
572              </div>
573            `;
574          }else{
575            //numbers and text treated the same because of complications with numbers on safari
576            if( customFieldObject.get('name').length <= 30 ) {
577                //short name
578                content += '<div class="inputWrap wider centeredBlock smallMarginBottom"><label class="inputLabel easeFast">'+ customFieldObject.get('name') +'</label><input data-custom-field-id="'+ customFieldObject.id +'" class="customFieldInput '+inputClasses+'" autocomplete="disabled,off"></div>';
579            } else {
580                //long name
581                content += '<p class="secondaryCardSubtext smallMarginBottom">'+ customFieldObject.get('name') +'</p>';
582                content += '<div class="inputWrap wider centeredBlock smallMarginBottom"><label class="inputLabel easeFast">Click to enter</label><input data-custom-field-id="'+ customFieldObject.id +'" class="customFieldInput '+inputClasses+'" autocomplete="disabled,off"></div>';
583            }
584        }
585    }
586    return content;
587}
588
589function returnMarkupForCustomFieldJSON(customFieldObject, currency) {
590    //uses JSON object instead of Parse object for vue compatibility
591    var content = '';
592    var readOnly = false;
593    if (customFieldObject) {
594        // Handle input class
595        var inputClasses = '';
596        if (customFieldObject.required) {
597            inputClasses += ' required';
598        }
599
600        // Check if any dropdown option has a price adjustment
601        if ((customFieldObject.type === 'select' || customFieldObject.type === 'searchable_select') && customFieldObject.dropdownOptionsArray) {
602            customFieldObject.dropdownOptionsArray.forEach(function (thisOption) {
603                if (thisOption && thisOption.amount) {
604                    readOnly = true; // A price adjustment exists, set to readOnly
605                }
606            });
607        }
608
609        // Add readOnly and unclickable classes if necessary
610        var extraClasses = readOnly ? ' readOnly unclickable' : '';
611        if (extraClasses){
612            inputClasses += extraClasses;
613        }
614
615        // Add for identification
616        inputClasses += ' customFieldInput_' + customFieldObject.objectId;
617
618        // Now generate markup based on type
619        if (customFieldObject.type === 'select' || customFieldObject.type === 'searchable_select') {
620            var optionsArray = customFieldObject.dropdownOptionsArray;
621            if (optionsArray && optionsArray.length >= 1) {
622                if (customFieldObject.name.length <= 30) {
623                    // Short name
624                    content += '<div class="inputWrap smallMarginBottom"><label class="inputLabel easeFast">' + customFieldObject.name + '</label><select data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput ' +  inputClasses + '"' + (readOnly ? ' disabled' : '') + '>';
625                    content += '<option data-non-option="true"></option>';
626                    optionsArray.forEach(function(thisOption) {
627                        if (thisOption && thisOption.name) {
628                            // Handle additional amounts
629                            var amountString = '';
630                            var thisAmount = thisOption.amount;
631                            if (currency) {
632                                if (thisAmount > 0) {
633                                    var niceAmount = formatPriceForCurrency(currency, thisAmount);
634                                    amountString += ' ( + ' + niceAmount + ' )';
635                                } else if (thisAmount < 0) {
636                                    var niceAmount = formatPriceForCurrency(currency, thisAmount);
637                                    amountString += ' ( ' + niceAmount + ' )';
638                                }
639                                // Need to add the class unclickable to the dic for the input wrap if readonly is true
640                            }
641                            // Plug it in
642                            content += '<option data-option-id="' + thisOption.objectId + '" data-adjustment-amount="' + thisAmount + '" value="' + thisOption.objectId + '">' + thisOption.name + amountString + '</option>';
643                        }
644                    });
645                    content += '</select></div>';
646                } else {
647                    // Long name
648                    content += '<p class="secondaryCardSubtext smallMarginBottom">' + customFieldObject.name + '</p>';
649                    content += '<div class="inputWrap smallMarginBottom"><label class="inputLabel easeFast">Click to enter</label><select data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput ' + inputClasses + '">';
650                    content += '<option data-non-option="true"></option>';
651                    optionsArray.forEach(function(thisOption) {
652                        if (thisOption && thisOption.name) {
653                            // Handle additional amounts
654                            var amountString = '';
655                            var thisAmount = thisOption.amount;
656                            if (currency) {
657                                if (thisAmount > 0) {
658                                    var niceAmount = formatPriceForCurrency(currency, thisAmount);
659                                    amountString += ' ( + ' + niceAmount + ' )';
660                                } else if (thisAmount < 0) {
661                                    var niceAmount = formatPriceForCurrency(currency, thisAmount);
662                                    amountString += ' ( ' + niceAmount + ' )';
663                                }
664                            }
665                            // Plug it in
666                            content += '<option data-option-id="' + thisOption.objectId + '" data-adjustment-amount="' + thisAmount + '" value="' + thisOption.objectId + '">' + thisOption.name + amountString + '</option>';
667                        }
668                    });
669                    content += '</select></div>';
670                }
671            }
672        } else if (customFieldObject.type === 'textarea') {
673            content += '<div><p class="secondaryCardSubtext tinyMarginBottom">' + customFieldObject.name + '</p><div class="textareaWrap marginBottom"><textarea data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput ' + inputClasses + '"></textarea></div></div>';
674        } else if (customFieldObject.type === 'radio') {
675            // Multi-select
676            var optionsArray = customFieldObject.dropdownOptionsArray;
677            if (optionsArray && optionsArray.length >= 1) {
678                content += '<p class="secondaryCardSubtext tinyMarginBottom">' + customFieldObject.name + '</p><div data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput radioWra
678p flexWrapLeftAlign ' + inputClasses + '">';
679                optionsArray.forEach(function(thisOption) {
680                    if (thisOption && thisOption.name) {
681                        // Plug it in
682                        content += '<div data-option-id="' + thisOption.objectId + '" value="' + thisOption.objectId + '" class="checkmarkCard easeFast flexNoWrap"><div class="checkmark tinyIcon"></div><p>' + thisOption.name + '</p></div>';
683                    }
684                });
685                content += '</div>';
686            }
687        } else if (customFieldObject.type === 'file_upload') {
688            content += '<p class="secondaryCardSubtext smallMarginBottom">' + customFieldObject.name + '</p>' +
689                '<div class="inputWrap wider centeredBlock smallMarginBottom">' +
690                '<label class="inputLabel">Click to upload</label>' +
691                '<input data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput absoluteInput" type="file" accept="application/pdf, image/*">' +
692                '<div class="successfulFileUploadWrap flexNoWrap">' +
693                '<div class="tinyIcon successIcon"></div>' +
694                '<p>File selected</p>' +
695                '</div>' +
696                '</div>';
697        } else {
698            // Numbers and text treated the same because of complications with numbers on Safari
699            if (customFieldObject.name.length <= 30) {
700                // Short name
701                content += '<div class="inputWrap wider centeredBlock smallMarginBottom"><label class="inputLabel easeFast">' + customFieldObject.name + '</label><input data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput ' + inputClasses + '" autocomplete="disabled,off"></div>';
702            } else {
703                // Long name
704                content += '<p class="secondaryCardSubtext smallMarginBottom">' + customFieldObject.name + '</p>';
705                content += '<div class="inputWrap wider centeredBlock smallMarginBottom"><label class="inputLabel easeFast">Click to enter</label><input data-custom-field-id="' + customFieldObject.objectId + '" class="customFieldInput ' + inputClasses + '" autocomplete="disabled,off"></div>';
706            }
707        }
708    }
709    return content;
710}
711
712
713function returnRelevantCustomFieldsForCampClasses( classes, campObject ){
714    var array = [];
715    if( ! classes ){
716        classes = [];
717    }
718    var ids = [];
719    if(campObject){
720        //check custom fields array
721        var customFieldsArray = campObject.get('customFieldsArray');
722        if(customFieldsArray){
723            if(customFieldsArray.length >= 1){
724                for (var i = 0; i <= customFieldsArray.length - 1; i++) {
725                    var thisCustomField = customFieldsArray[i];
726                    if(thisCustomField){
727                        if( ids.indexOf( thisCustomField.id ) == -1 ){
728                            var campClassesArray = thisCustomField.get('campClassesArray');
729                            if( thisCustomField.get('allClasses') ){
730                                array.push( thisCustomField );
731                                ids.push( thisCustomField.id );
732                            }else if(campClassesArray){
733                                for (var c = campClassesArray.length - 1; c >= 0; c--) {
734                                    var thisCampClass = campClassesArray[c];
735                                    if(thisCampClass){
736                                        for (var g = classes.length - 1; g >= 0; g--) {
737                                            var thisClass = classes[g];
738                                            if( thisClass ){
739                                                if( thisClass.id == thisCampClass.id ){
740                                                    array.push( thisCustomField );
741                                                    ids.push( thisCustomField.id );
742                                                }
743                                            }
744                                        }
745                                    }
746                                }
747                            }
748                        }
749                    }
750                }           
751            }
752        }
753    }
754    return array;
755}
756
757function returnRelevantCustomFieldsForBoatClass( boatClassObject, regattaObject ){
758    var array = [];
759    var ids = [];
760    if(regattaObject && boatClassObject){
761        //check custom fields array
762        var customFieldsArray = regattaObject.get('customFieldsArray');
763        if(customFieldsArray){
764            if(customFieldsArray.length >= 1){
765                for (var i = 0; i <= customFieldsArray.length - 1; i++) {
766                    var thisCustomField = customFieldsArray[i];
767                    if(thisCustomField){
768                        if( ids.indexOf( thisCustomField.id ) == -1 ){
769                            var boatClassesArray = thisCustomField.get('boatClassesArray');
770                            if( thisCustomField.get('allClasses') ){
771                                array.push( thisCustomField );
772                                ids.push( thisCustomField.id );
773                            }else if(boatClassesArray){
774                                for (var c = boatClassesArray.length - 1; c >= 0; c--) {
775                                    var thisBoatClass = boatClassesArray[c];
776                                    if(thisBoatClass){
777                                        if( thisBoatClass.id == boatClassObject.id ){
778                                            array.push( thisCustomField );
779                                            ids.push( thisCustomField.id );
780                                        }
781                                    }
782                                }
783                            }
784                        }
785                    }
786                }           
787            }
788        }
789    }
790    return array;
791}
792
793$(document).ready(function(){
794    $(document).on('change', '.customFieldInput.absoluteInput', function(){
795        //check if there's something in the input
796        var file = $(this).prop('files')[0];
797        if(file){
798            var timestamp = Date.now();
799            var client_id = generateClientID();
800            var newFileName = "upload_" + client_id + "_" + timestamp;
801            //upload it
802            uploadFileToAWS(file, newFileName, (url) => {
803                //add the url
804                $(this).data('url', url);
805            });
806        }
807    });
808
809    $(document).on('click', '.customFieldInput.absoluteInput', function(){
810        //reset data
811        $(this).data('url', null);
812        $('#confirmUniversalEdit').removeClass('inactive');
813    });
814
815});

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.