Code Duplication    Length = 858-906 lines in 2 locations

resources/assets/js/app.js 1 location

@@ 7-912 (lines=906) @@
4
5
// =============================================================================
6
7
(function($) {
8
9
    // Add isValid()
10
11
        $.fn.isValid = function(){
12
            return this[0].checkValidity()
13
        }
14
15
    // Root
16
17
        var $root = $('html, body');
18
19
    // User Agent Data Attributes ==============================================
20
    
21
        var ua = navigator.userAgent;
22
        ua = ua.toString();
23
        console.log("hello");
24
        $('body').attr('id', ua);
25
26
    $(document).ready(function() {
27
28
        // Accordion Handlers ==================================================
29
30
            function accordionTrigger(trigger) {
31
                if ($(trigger).parent(".accordion").hasClass("active")) {
32
                    $(trigger).attr("aria-expanded", "false");
33
                    $(trigger).parent(".accordion").removeClass("active");
34
                    $(trigger).parent(".accordion").find(".accordion-content").attr("aria-hidden", "true");
35
                }
36
                else {
37
                    $(trigger).attr("aria-expanded", "true");
38
                    $(trigger).parent(".accordion").addClass("active");
39
                    $(trigger).parent(".accordion").find(".accordion-content").attr("aria-hidden", "false");
40
                }
41
            }
42
43
            $(document).on("click", ".accordion-trigger", function(e){
44
45
                accordionTrigger(this);
46
47
            });
48
49
            $(document).on("keyup", ".accordion-trigger", function(e){
50
51
                if(e.which == 13) {
52
                    accordionTrigger(this);
53
                }
54
55
            });
56
57
        // Modal Handlers ======================================================
58
59
            function openModal(trigger) {
60
61
                var modalID = $(trigger).attr("data-modal-id");
62
                var modal = $(".modal[data-modal-id="+modalID+"]");
63
                var modalObject = $(trigger).parents(".modal-target-object");
64
                $(".modal-overlay").addClass("active");
65
                modal.addClass("active");
66
                $("body").css("overflow", "hidden");
67
68
                // Tab Items
69
70
                var focusableItems = modal.find(":focusable");
71
72
                var firstInput = focusableItems.first();
73
                var lastInput = focusableItems.last();
74
75
                if (modal.find("form").length == 0) {
76
                    lastInput.focus();
77
                }
78
                else {
79
                    firstInput.focus();
80
                }
81
82
                modalTabHandler(firstInput, lastInput);
83
                modalDeleteTrigger(trigger, modal, modalObject);
84
                escapeModalHandler();
85
86
            }
87
88
            $(document).on("click", ".modal-trigger", function(e){
89
90
                openModal(this);
91
92
            });
93
94
            $(document).on("keyup", ".modal-trigger", function(e){
95
96
                if(e.which == 13) {
97
                    openModal(this);
98
                }
99
100
            });
101
102
103
            function closeModal(trigger) {
104
105
                $(".modal-overlay").removeClass("active");
106
                $(".modal").removeClass("active");
107
                $("body").css("overflow", "visible");
108
109
            }
110
111
            $(document).on("click", ".modal-cancel-trigger", function(e){
112
113
                closeModal(this);
114
115
            });
116
117
            $(document).on("keyup", ".modal-cancel-trigger", function(e){
118
119
                if(e.which == 13) {
120
                    closeModal(this);
121
                }
122
123
            });
124
125
            // Delete Trigger ==================================================
126
127
                function modalDeleteTrigger(trigger, modal, object) {
128
129
                    $(document).on("click", ".modal-delete-trigger", function(e){
130
131
                        closeModal(trigger);
132
133
                        $(object).remove();
134
135
                    });
136
137
                }
138
139
            // Tab Handler =====================================================
140
141
                function modalTabHandler(first, last) {
142
143
                    $(document).on("keydown", function(e){
144
145
                        var keyCode = e.keyCode || e.which;
146
147
                        if (keyCode == 9 && !e.shiftKey) {
148
149
                            if ($(last).is(":focus")) {
150
                                e.preventDefault();
151
                                $(first).focus();
152
                            }
153
154
                        }
155
                        else if (keyCode == 9 && e.shiftKey) {
156
157
                            if($(first).is(":focus")) {
158
                                e.preventDefault();
159
                                $(last).focus();
160
                            }
161
162
                        }
163
164
                    });
165
166
                }
167
168
            // Escape Handler ==================================================
169
170
                function escapeModalHandler() {
171
172
                    $(document).on("keyup", function(e){
173
174
                        if((e.key==='Escape'||e.key==='Esc'||e.keyCode===27)){
175
176
                            $(".modal-overlay").removeClass("active");
177
                            $(".modal").removeClass("active");
178
                            $("body").css("overflow", "visible");
179
180
                            // FF and compatible
181
                            if (e.stopPropagation) {
182
                                e.stopPropagation();
183
                                e.preventDefault();
184
                            }
185
186
                        }
187
188
                    });
189
190
                }
191
192
        // Form Handlers =======================================================
193
194
            // Required Fields
195
196
                function requiredFields() {
197
                    $("input:required, textarea:required").each(function(e) {
198
                        $(this).parent().addClass("required");
199
                        $(this).parent().find("label").append("<span class='form__required'><i class='fa fa-asterisk' aria-label='Asterisk'></i></span>");
200
                    });
201
                }
202
203
                requiredFields();
204
205
            // Label Handers ===================================================
206
207
                function labelHandlers() {
208
209
                    $("[class*='form__input-wrapper'] input, [class*='form__input-wrapper'] textarea").focusin(function(e) {
210
                        $(this).parent().addClass("active");
211
                    });
212
213
                    $("[class*='form__input-wrapper'] input, [class*='form__input-wrapper'] textarea").focusout(function(e) {
214
215
                        // Check for existing value.
216
217
                            if ($(this).val() == "") {
218
                                $(this).parent().removeClass("active");
219
                            }
220
221
                        // Check Validity
222
223
                            if ($(this).isValid() == true) {
224
225
                                if ($(this).val() == "" || $(this).attr("type") == "password") {
226
                                    $(this).parent().removeClass("valid");
227
                                    $(this).parent().removeClass("invalid");
228
                                }
229
                                else {
230
                                    $(this).parent().addClass("valid");
231
                                    $(this).parent().removeClass("invalid");
232
                                }
233
234
                            }
235
                            else {
236
237
                                if ($(this).attr("type") == "password") {
238
                                    return false;
239
                                }
240
                                else {
241
                                    $(this).parent().addClass("invalid");
242
                                    $(this).parent().removeClass("valid");
243
                                }
244
245
                            }
246
247
                    });
248
249
                }
250
251
                labelHandlers();
252
253
        // Individualizing repeater name and id attributes======================
254
255
                //Individualize template attributes
256
                function appendToAttributes(parent, attribute, suffix, conditions = null) {
257
                    var selector = "*[" + attribute + "]";
258
259
                    //If conditions is set, only modify attributes that also
260
                    //satisfy that selector
261
                    if (conditions) {
262
                        selector = conditions + selector;
263
                    }
264
265
                    parent.find(selector).each(function() {
266
                        $(this).attr(attribute, $(this).attr(attribute) + suffix);
267
                    });
268
                }
269
270
                //Individualize template attributes
271
                function replaceInAttributes(parent, attribute, oldString, newString, conditions = null) {
272
                    var selector = "*[" + attribute + "]";
273
274
                    //If conditions is set, only modify attributes that also
275
                    //satisfy that selector
276
                    if (conditions) {
277
                        selector = conditions + selector;
278
                    }
279
280
                    parent.find(selector).each(function() {
281
                        //replaces only the first instance of a match in a string
282
                        $(this).attr(attribute, $(this).attr(attribute).replace(oldString, newString));
283
                    });
284
                }
285
286
                //Return the next unused idAttr value
287
                function getNextItemId(parent, idAttr = "data-item-id") {
288
                    var maxId = 0;
289
                    parent.find("*[" + idAttr + "]").each(function() {
290
                        var id = parseInt( $(this).attr(idAttr) );
291
                        if (id > maxId) {
292
                            maxId = id;
293
                        }
294
                    });
295
                    return maxId + 1;
296
                }
297
298
                //The all in one function to set proper ids and form names
299
                function individualizeFormIdsAndNames(template, wrapper) {
300
                    // Get New ID
301
                    var newId = getNextItemId(wrapper);
302
303
                    //Set date-item-id, used to track which newId's are taken
304
                    template.attr('data-item-id', newId);
305
306
                    //Differentiate real forms from templates
307
308
                    // filter, if we only want to affect certain results
309
                    var filter = '';
310
311
                    replaceInAttributes(template, 'id', ':template', 'new', filter);
312
                    replaceInAttributes(template, 'for', ':template', 'new', filter);
313
                    replaceInAttributes(template, 'name', ':template', 'new', filter);
314
                    replaceInAttributes(template, 'submit', ':template', 'new', filter);
315
                    replaceInAttributes(template, 'value', ':template', 'new', filter+'[name=submit]');
316
317
                    replaceInAttributes(template, 'id', ':id', newId, filter);
318
                    replaceInAttributes(template, 'for', ':id', newId, filter);
319
                    replaceInAttributes(template, 'name', ':id', newId, filter);
320
                    replaceInAttributes(template, 'submit', ':id', newId, filter);
321
                    replaceInAttributes(template, 'value', ':id', newId, filter+'[name=submit]');
322
                }
323
324
        // Profile List Handlers ===============================================
325
326
            // Add Profile Element
327
                function addProfileElement(trigger) {
328
329
                    // Get Parent
330
                        var parent = $(trigger).parents(".profile-list");
331
332
                    // Get List Wrapper
333
                        var wrapper = parent.find(".profile-element-list");
334
335
                    // Set Null to Hidden
336
                        parent.find(".profile-null").removeClass("active");
337
338
                    // Get Template
339
                        var template = parent.find(".profile-element.template").clone();
340
341
                    // Remove Template Class
342
                        template.removeClass("template");
343
344
                    //Set ids and form names to be unique
345
                    individualizeFormIdsAndNames(template, wrapper);
346
347
                    // Prepend Clone to the Wrapper
348
                    wrapper.prepend(template);
349
350
                    // Reactivate Required Fields
351
                        requiredFields();
352
353
                    // Reactivate Labels
354
                        labelHandlers();
355
356
                    // Reactivate Nested Relatives
357
                        loadProfileRelatives();
358
359
                }
360
361
                // Click Trigger
362
                    $(".profile-list__add-element-trigger").on("click", function(e) {
363
364
                        // Prevent Default Functions
365
                            e.preventDefault();
366
367
                        // Add Profile Elements
368
                            addProfileElement(this);
369
370
                    });
371
372
                // Enter Key Trigger
373
                    $(".profile-list__add-element-trigger").on("keyup", function(e) {
374
375
                        if(e.which == 13) {
376
377
                            // Prevent Default Functions
378
                                e.preventDefault();
379
380
                            // Add Profile Elements
381
                                addProfileElement(this);
382
383
                        }
384
385
                    });
386
387
            // Remove Profile Element
388
389
            // Add Profile Relative
390
                function addProfileRelative(trigger) {
391
392
                    // Get Parent
393
                        var parent = $(trigger).parents(".profile-relative-list");
394
395
                    // Get List Wrapper
396
                        var wrapper = parent.find(".profile-relative-list__wrapper");
397
398
                    // Set Null to Hidden
399
                        // parent.find(".profile-null").removeClass("active");
400
401
                    // Get Template
402
                        var template = parent.find(".profile-relative.template").clone();
403
404
                    // Remove Template Class
405
                        template.removeClass("template");
406
407
                    //Set ids and form names to be unique
408
                    individualizeFormIdsAndNames(template, wrapper);
409
410
                    // Append Clone to the Wrapper
411
                    wrapper.append(template);
412
413
                    // Reactivate Required Fields
414
                        requiredFields();
415
416
                    // Reactivate Labels
417
                        labelHandlers();
418
419
                    // Reactivate Nested Relatives
420
                        loadProfileRelativeDeletion();
421
422
                }
423
424
                // Load Function
425
                    function loadProfileRelatives() {
426
427
                        // Click Trigger
428
                            $(".profile-relative__add-trigger").off("click");
429
430
                            $(".profile-relative__add-trigger").on("click", function(e) {
431
432
                                // Prevent Default Functions
433
                                    e.preventDefault();
434
435
                                // Add Profile Relative
436
                                    addProfileRelative(this);
437
438
                            });
439
440
                        // Enter Key Trigger
441
                            $(".profile-relative__add-trigger").off("keyup");
442
443
                            $(".profile-relative__add-trigger").on("keyup", function(e) {
444
445
                                if(e.which == 13) {
446
447
                                    // Prevent Default Functions
448
                                        e.preventDefault();
449
450
                                    // Add Profile Relative
451
                                        addProfileRelative(this);
452
453
                                }
454
455
                            });
456
457
                    }
458
459
                    loadProfileRelatives();
460
461
            // Remove Profile Relative
462
                function deleteProfileRelative(trigger) {
463
464
                    $(trigger).parents(".profile-relative").remove();
465
466
                }
467
468
                // Load Function
469
                    function loadProfileRelativeDeletion() {
470
471
                        // Click Trigger
472
                            $(".profile-relative__remove-trigger").on("click", function(e) {
473
474
                                // Prevent Default Functions
475
                                    e.preventDefault();
476
477
                                // Delete Profile Relative
478
                                    deleteProfileRelative(this);
479
480
                            });
481
482
                        // Enter Key Trigger
483
                            $(".profile-relative__remove-trigger").on("keyup", function(e) {
484
485
                                if(e.which == 13) {
486
487
                                    // Prevent Default Functions
488
                                        e.preventDefault();
489
490
                                    // Delete Profile Relative
491
                                        deleteProfileRelative(this);
492
493
                                }
494
495
                            });
496
497
                    }
498
499
                    loadProfileRelativeDeletion();
500
501
        // Experience Handlers =================================================
502
503
            // Degrees
504
505
                function addDegree(trigger) {
506
507
                    // Get Wrapper
508
                    var wrapper = $(".application-post__experience-wrapper");
509
510
                    // Get Template
511
                    var template = $(".application-post__accordion--degree.template").clone();
512
513
                    // Remove Template Class
514
                    template.removeClass("template");
515
516
                    //Set ids and form names to be unique
517
                    individualizeFormIdsAndNames(template, wrapper);
518
519
                    // Append Clone to the Wrapper
520
                    wrapper.append(template);
521
522
                    requiredFields();
523
                    labelHandlers();
524
525
                }
526
527
                $("#addDegreeButton").on("click", function(e) {
528
529
                    e.preventDefault();
530
531
                    addDegree(this);
532
533
                });
534
535
                $("#addDegreeButton").on("keyup", function(e) {
536
537
                    if(e.which == 13) {
538
                        e.preventDefault();
539
                        addDegree(this);
540
                    }
541
542
                });
543
544
            // Courses
545
546
                function addCourse(trigger) {
547
548
                    // Get Wrapper
549
                    var wrapper = $(".application-post__experience-wrapper");
550
551
                    // Get Template
552
                    var template = $(".application-post__accordion--course.template").clone();
553
554
                    // Remove Template Class
555
                    template.removeClass("template");
556
557
                    //Set ids and form names to be unique
558
                    individualizeFormIdsAndNames(template, wrapper);
559
560
                    // Append Clone to the Wrapper
561
                    wrapper.append(template);
562
563
                    requiredFields();
564
                    labelHandlers();
565
566
                }
567
568
                $("#addCourseButton").on("click", function(e) {
569
570
                    e.preventDefault();
571
572
                    addCourse(this);
573
574
                });
575
576
                $("#addCourseButton").on("keyup", function(e) {
577
578
                    if(e.which == 13) {
579
                        e.preventDefault();
580
                        addCourse(this);
581
                    }
582
583
                });
584
585
            // Work
586
587
                function addWork(trigger) {
588
589
                    // Get Wrapper
590
                    var wrapper = $(".application-post__experience-wrapper");
591
592
                    // Get Template
593
                    var template = $(".application-post__accordion--work.template").clone();
594
595
                    // Remove Template Class
596
                    template.removeClass("template");
597
598
                    //Set ids and form names to be unique
599
                    individualizeFormIdsAndNames(template, wrapper);
600
601
                    // Append Clone to the Wrapper
602
                    wrapper.append(template);
603
604
                    requiredFields();
605
                    labelHandlers();
606
607
                }
608
609
                $("#addWorkButton").on("click", function(e) {
610
611
                    e.preventDefault();
612
613
                    addWork(this);
614
615
                });
616
617
                $("#addWorkButton").on("keyup", function(e) {
618
619
                    if(e.which == 13) {
620
                        e.preventDefault();
621
                        addWork(this);
622
                    }
623
624
                });
625
626
        // Create Job Handlers =================================================
627
628
            // Tasks
629
630
                function addTask(trigger) {
631
632
                    // Get Wrapper
633
                    var wrapper = $(".manager-jobs__create-task-wrapper");
634
635
                    // Get Template
636
                    var template = $(".manager-jobs__create-task.template").clone();
637
638
                    console.log(wrapper.find(".manager-jobs__create-task"));
639
640
                    // Get New ID
641
                    if (wrapper.find(".manager-jobs__create-task").length == 0) {
642
                        var newID = parseInt(template.attr("data-task-id")) + 1;
643
                    }
644
                    else {
645
                        var newID = parseInt(wrapper.find("[class*='manager-jobs__create-task']").last().attr("data-task-id")) + 1;
646
                    }
647
648
                    // Remove Template Class
649
                    template.removeClass("template");
650
651
                    //TODO: replace with call to individualizeFormIdsAndNames(template, wrapper);
652
                    //TODO: This requires changes to JobController@create, because the id would change places
653
654
                    // Assign the New ID
655
                    template.attr("data-task-id", newID);
656
657
                    // Add newID as suffix to all "id" and "for" attributes
658
                    template.find("*[id]").each(function() { $(this).attr("id", this.id + newID)});
659
                    template.find("*[for]").each(function() { $(this).attr("for",  $(this).attr("for") + newID)});
660
661
                    // Replace :id with newID in all form names
662
                    template.find("*[name]").each(function() { $(this).attr('name', $(this).attr("name").replace(":id", newID))});
663
664
                    // Task (English)
665
                    //template.find("[data-form-id*='task-english']").find("label").attr("for", "taskEN" + newID);
666
                    //template.find("[data-form-id*='task-english']").find("input").attr("id", "taskEN" + newID);
667
668
                    // Task (French)
669
                    //template.find("[data-form-id*='task-french']").find("label").attr("for", "taskFR" + newID);
670
                    //template.find("[data-form-id*='task-french']").find("input").attr("id", "taskFR" + newID);
671
672
                    // Append Clone to the Wrapper
673
                    wrapper.append(template);
674
675
                    requiredFields();
676
                    labelHandlers();
677
                    deleteTaskTrigger();
678
679
                }
680
681
                $("#addTaskButton").on("click", function(e) {
682
683
                    e.preventDefault();
684
685
                    addTask(this);
686
687
                });
688
689
                $("#addTaskButton").on("keyup", function(e) {
690
691
                    if(e.which == 13) {
692
                        e.preventDefault();
693
                        addTask(this);
694
                    }
695
696
                });
697
698
                // Task Deletion
699
700
                function deleteTask(trigger) {
701
702
                    $(trigger).parents(".manager-jobs__create-task").remove();
703
704
                }
705
706
                function deleteTaskTrigger() {
707
708
                    $(".manager-jobs__delete-task-button").on("click", function(e) {
709
710
                        e.preventDefault();
711
712
                        deleteTask(this);
713
714
                    });
715
716
                    $(".manager-jobs__delete-task-button").on("keyup", function(e) {
717
718
                        if(e.which == 13) {
719
                            e.preventDefault();
720
                            deleteTask(this);
721
                        }
722
723
                    });
724
725
                }
726
727
                deleteTaskTrigger();
728
729
            // Skills
730
731
                function addSkill(trigger) {
732
733
                    // Get Parent
734
                    var parent = $(trigger).parents(".manager-jobs__skill-wrapper");
735
736
                    // Get Wrapper
737
                    var wrapper = parent.find(".manager-jobs__create-skill-wrapper");
738
739
                    // Get Template
740
                    var template = parent.find(".manager-jobs__create-skill.template").clone();
741
742
                    console.log(wrapper.find(".manager-jobs__create-skill"));
743
744
                    // Remove Template Class
745
                    template.removeClass("template");
746
747
                    //Set ids and form names to be unique
748
                    individualizeFormIdsAndNames(template, wrapper);
749
750
                    // Append Clone to the Wrapper
751
                    wrapper.append(template);
752
753
                    requiredFields();
754
                    labelHandlers();
755
                    deleteSkillTrigger();
756
757
                }
758
759
                $(".manager-jobs__add-skill-button").on("click", function(e) {
760
761
                    e.preventDefault();
762
763
                    addSkill(this);
764
765
                });
766
767
                $(".manager-jobs__add-skill-button").on("keyup", function(e) {
768
769
                    if(e.which == 13) {
770
                        e.preventDefault();
771
                        addSkill(this);
772
                    }
773
774
                });
775
776
                // Skill Deletion
777
778
                function deleteSkill(trigger) {
779
780
                    $(trigger).parents(".manager-jobs__create-skill").remove();
781
782
                }
783
784
                function deleteSkillTrigger() {
785
786
                    $(".manager-jobs__delete-skill-button").on("click", function(e) {
787
788
                        e.preventDefault();
789
790
                        deleteSkill(this);
791
792
                    });
793
794
                    $(".manager-jobs__delete-skill-button").on("keyup", function(e) {
795
796
                        if(e.which == 13) {
797
                            e.preventDefault();
798
                            deleteSkill(this);
799
                        }
800
801
                    });
802
803
                }
804
805
                deleteSkillTrigger();
806
807
            // Questions
808
809
                function addQuestion(trigger) {
810
811
                    // Get Wrapper
812
                    var wrapper = $(".manager-jobs__create-question-wrapper");
813
814
                    // Get Template
815
                    var template = $(".manager-jobs__create-question.template").clone();
816
817
                    console.log(wrapper.find(".manager-jobs__create-question"));
818
819
                    // Get New ID
820
                    if (wrapper.find(".manager-jobs__create-question").length == 0) {
821
                        var newID = parseInt(template.attr("data-question-id")) + 1;
822
                    }
823
                    else {
824
                        var newID = parseInt(wrapper.find("[class*='manager-jobs__create-question']").last().attr("data-question-id")) + 1;
825
                    }
826
827
                    // Remove Template Class
828
                    template.removeClass("template");
829
830
                    //TODO: replace with call to individualizeFormIdsAndNames(template, wrapper);
831
                    //TODO: This requires changes to JobController@create, because the id would change places
832
833
                    // Assign the New ID
834
                    template.attr("data-question-id", newID);
835
836
                    // Add newID as suffix to all "id" and "for" attributes
837
                    template.find("*[id]").each(function() { $(this).attr("id", this.id + newID)});
838
                    template.find("*[for]").each(function() { $(this).attr("for",  $(this).attr("for") + newID)});
839
840
                    // Replace :id with newID in all form names
841
                    template.find("*[name]").each(function() { $(this).attr('name', $(this).attr("name").replace(":id", newID))});
842
843
                    // Edit Form IDs
844
                        //
845
                        // // Queestion (English)
846
                        // template.find("[data-form-id*='question-english']").find("label").attr("for", "questionEN" + newID);
847
                        // template.find("[data-form-id*='question-english']").find("input").attr("id", "questionEN" + newID);
848
                        //
849
                        // // Queestion (French)
850
                        // template.find("[data-form-id*='question-french']").find("label").attr("for", "questionFR" + newID);
851
                        // template.find("[data-form-id*='question-french']").find("input").attr("id", "questionFR" + newID);
852
853
                    // Append Clone to the Wrapper
854
                    wrapper.append(template);
855
856
                    requiredFields();
857
                    labelHandlers();
858
                    deleteQuestionTrigger();
859
860
                }
861
862
                $("#addQuestionButton").on("click", function(e) {
863
864
                    e.preventDefault();
865
866
                    addQuestion(this);
867
868
                });
869
870
                $("#addQuestionButton").on("keyup", function(e) {
871
872
                    if(e.which == 13) {
873
                        e.preventDefault();
874
                        addQuestion(this);
875
                    }
876
877
                });
878
879
                // Question Deletion
880
881
                function deleteQuestion(trigger) {
882
883
                    $(trigger).parents(".manager-jobs__create-question").remove();
884
885
                }
886
887
                function deleteQuestionTrigger() {
888
889
                    $(".manager-jobs__delete-question-button").on("click", function(e) {
890
891
                        e.preventDefault();
892
893
                        deleteQuestion(this);
894
895
                    });
896
897
                    $(".manager-jobs__delete-question-button").on("keyup", function(e) {
898
899
                        if(e.which == 13) {
900
                            e.preventDefault();
901
                            deleteQuestion(this);
902
                        }
903
904
                    });
905
906
                }
907
908
                deleteQuestionTrigger();
909
910
    });
911
912
})(jQuery);
913

public/js/app.js 1 location

@@ 76-933 (lines=858) @@
73
74
/***/ }),
75
/* 1 */
76
/***/ (function(module, exports) {
77
78
// =============================================================================
79
80
// Utilities JavaScript (jQuery)
81
82
// =============================================================================
83
84
(function ($) {
85
86
    // Add isValid()
87
88
    $.fn.isValid = function () {
89
        return this[0].checkValidity();
90
    };
91
92
    // Root
93
94
    var $root = $('html, body');
95
96
    // User Agent Data Attributes ==============================================
97
98
    var ua = navigator.userAgent;
99
    ua = ua.toString();
100
    console.log("hello");
101
    $('body').attr('id', ua);
102
103
    $(document).ready(function () {
104
105
        // Accordion Handlers ==================================================
106
107
        function accordionTrigger(trigger) {
108
            if ($(trigger).parent(".accordion").hasClass("active")) {
109
                $(trigger).attr("aria-expanded", "false");
110
                $(trigger).parent(".accordion").removeClass("active");
111
                $(trigger).parent(".accordion").find(".accordion-content").attr("aria-hidden", "true");
112
            } else {
113
                $(trigger).attr("aria-expanded", "true");
114
                $(trigger).parent(".accordion").addClass("active");
115
                $(trigger).parent(".accordion").find(".accordion-content").attr("aria-hidden", "false");
116
            }
117
        }
118
119
        $(document).on("click", ".accordion-trigger", function (e) {
120
121
            accordionTrigger(this);
122
        });
123
124
        $(document).on("keyup", ".accordion-trigger", function (e) {
125
126
            if (e.which == 13) {
127
                accordionTrigger(this);
128
            }
129
        });
130
131
        // Modal Handlers ======================================================
132
133
        function openModal(trigger) {
134
135
            var modalID = $(trigger).attr("data-modal-id");
136
            var modal = $(".modal[data-modal-id=" + modalID + "]");
137
            var modalObject = $(trigger).parents(".modal-target-object");
138
            $(".modal-overlay").addClass("active");
139
            modal.addClass("active");
140
            $("body").css("overflow", "hidden");
141
142
            // Tab Items
143
144
            var focusableItems = modal.find(":focusable");
145
146
            var firstInput = focusableItems.first();
147
            var lastInput = focusableItems.last();
148
149
            if (modal.find("form").length == 0) {
150
                lastInput.focus();
151
            } else {
152
                firstInput.focus();
153
            }
154
155
            modalTabHandler(firstInput, lastInput);
156
            modalDeleteTrigger(trigger, modal, modalObject);
157
            escapeModalHandler();
158
        }
159
160
        $(document).on("click", ".modal-trigger", function (e) {
161
162
            openModal(this);
163
        });
164
165
        $(document).on("keyup", ".modal-trigger", function (e) {
166
167
            if (e.which == 13) {
168
                openModal(this);
169
            }
170
        });
171
172
        function closeModal(trigger) {
173
174
            $(".modal-overlay").removeClass("active");
175
            $(".modal").removeClass("active");
176
            $("body").css("overflow", "visible");
177
        }
178
179
        $(document).on("click", ".modal-cancel-trigger", function (e) {
180
181
            closeModal(this);
182
        });
183
184
        $(document).on("keyup", ".modal-cancel-trigger", function (e) {
185
186
            if (e.which == 13) {
187
                closeModal(this);
188
            }
189
        });
190
191
        // Delete Trigger ==================================================
192
193
        function modalDeleteTrigger(trigger, modal, object) {
194
195
            $(document).on("click", ".modal-delete-trigger", function (e) {
196
197
                closeModal(trigger);
198
199
                $(object).remove();
200
            });
201
        }
202
203
        // Tab Handler =====================================================
204
205
        function modalTabHandler(first, last) {
206
207
            $(document).on("keydown", function (e) {
208
209
                var keyCode = e.keyCode || e.which;
210
211
                if (keyCode == 9 && !e.shiftKey) {
212
213
                    if ($(last).is(":focus")) {
214
                        e.preventDefault();
215
                        $(first).focus();
216
                    }
217
                } else if (keyCode == 9 && e.shiftKey) {
218
219
                    if ($(first).is(":focus")) {
220
                        e.preventDefault();
221
                        $(last).focus();
222
                    }
223
                }
224
            });
225
        }
226
227
        // Escape Handler ==================================================
228
229
        function escapeModalHandler() {
230
231
            $(document).on("keyup", function (e) {
232
233
                if (e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) {
234
235
                    $(".modal-overlay").removeClass("active");
236
                    $(".modal").removeClass("active");
237
                    $("body").css("overflow", "visible");
238
239
                    // FF and compatible
240
                    if (e.stopPropagation) {
241
                        e.stopPropagation();
242
                        e.preventDefault();
243
                    }
244
                }
245
            });
246
        }
247
248
        // Form Handlers =======================================================
249
250
        // Required Fields
251
252
        function requiredFields() {
253
            $("input:required, textarea:required").each(function (e) {
254
                $(this).parent().addClass("required");
255
                $(this).parent().find("label").append("<span class='form__required'><i class='fa fa-asterisk' aria-label='Asterisk'></i></span>");
256
            });
257
        }
258
259
        requiredFields();
260
261
        // Label Handers ===================================================
262
263
        function labelHandlers() {
264
265
            $("[class*='form__input-wrapper'] input, [class*='form__input-wrapper'] textarea").focusin(function (e) {
266
                $(this).parent().addClass("active");
267
            });
268
269
            $("[class*='form__input-wrapper'] input, [class*='form__input-wrapper'] textarea").focusout(function (e) {
270
271
                // Check for existing value.
272
273
                if ($(this).val() == "") {
274
                    $(this).parent().removeClass("active");
275
                }
276
277
                // Check Validity
278
279
                if ($(this).isValid() == true) {
280
281
                    if ($(this).val() == "" || $(this).attr("type") == "password") {
282
                        $(this).parent().removeClass("valid");
283
                        $(this).parent().removeClass("invalid");
284
                    } else {
285
                        $(this).parent().addClass("valid");
286
                        $(this).parent().removeClass("invalid");
287
                    }
288
                } else {
289
290
                    if ($(this).attr("type") == "password") {
291
                        return false;
292
                    } else {
293
                        $(this).parent().addClass("invalid");
294
                        $(this).parent().removeClass("valid");
295
                    }
296
                }
297
            });
298
        }
299
300
        labelHandlers();
301
302
        // Individualizing repeater name and id attributes======================
303
304
        //Individualize template attributes
305
        function appendToAttributes(parent, attribute, suffix) {
306
            var conditions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
307
308
            var selector = "*[" + attribute + "]";
309
310
            //If conditions is set, only modify attributes that also
311
            //satisfy that selector
312
            if (conditions) {
313
                selector = conditions + selector;
314
            }
315
316
            parent.find(selector).each(function () {
317
                $(this).attr(attribute, $(this).attr(attribute) + suffix);
318
            });
319
        }
320
321
        //Individualize template attributes
322
        function replaceInAttributes(parent, attribute, oldString, newString) {
323
            var conditions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
324
325
            var selector = "*[" + attribute + "]";
326
327
            //If conditions is set, only modify attributes that also
328
            //satisfy that selector
329
            if (conditions) {
330
                selector = conditions + selector;
331
            }
332
333
            parent.find(selector).each(function () {
334
                //replaces only the first instance of a match in a string
335
                $(this).attr(attribute, $(this).attr(attribute).replace(oldString, newString));
336
            });
337
        }
338
339
        //Return the next unused idAttr value
340
        function getNextItemId(parent) {
341
            var idAttr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "data-item-id";
342
343
            var maxId = 0;
344
            parent.find("*[" + idAttr + "]").each(function () {
345
                var id = parseInt($(this).attr(idAttr));
346
                if (id > maxId) {
347
                    maxId = id;
348
                }
349
            });
350
            return maxId + 1;
351
        }
352
353
        //The all in one function to set proper ids and form names
354
        function individualizeFormIdsAndNames(template, wrapper) {
355
            // Get New ID
356
            var newId = getNextItemId(wrapper);
357
358
            //Set date-item-id, used to track which newId's are taken
359
            template.attr('data-item-id', newId);
360
361
            //Differentiate real forms from templates
362
363
            // filter, if we only want to affect certain results
364
            var filter = '';
365
366
            replaceInAttributes(template, 'id', ':template', 'new', filter);
367
            replaceInAttributes(template, 'for', ':template', 'new', filter);
368
            replaceInAttributes(template, 'name', ':template', 'new', filter);
369
            replaceInAttributes(template, 'submit', ':template', 'new', filter);
370
            replaceInAttributes(template, 'value', ':template', 'new', filter + '[name=submit]');
371
372
            replaceInAttributes(template, 'id', ':id', newId, filter);
373
            replaceInAttributes(template, 'for', ':id', newId, filter);
374
            replaceInAttributes(template, 'name', ':id', newId, filter);
375
            replaceInAttributes(template, 'submit', ':id', newId, filter);
376
            replaceInAttributes(template, 'value', ':id', newId, filter + '[name=submit]');
377
        }
378
379
        // Profile List Handlers ===============================================
380
381
        // Add Profile Element
382
        function addProfileElement(trigger) {
383
384
            // Get Parent
385
            var parent = $(trigger).parents(".profile-list");
386
387
            // Get List Wrapper
388
            var wrapper = parent.find(".profile-element-list");
389
390
            // Set Null to Hidden
391
            parent.find(".profile-null").removeClass("active");
392
393
            // Get Template
394
            var template = parent.find(".profile-element.template").clone();
395
396
            // Remove Template Class
397
            template.removeClass("template");
398
399
            //Set ids and form names to be unique
400
            individualizeFormIdsAndNames(template, wrapper);
401
402
            // Prepend Clone to the Wrapper
403
            wrapper.prepend(template);
404
405
            // Reactivate Required Fields
406
            requiredFields();
407
408
            // Reactivate Labels
409
            labelHandlers();
410
411
            // Reactivate Nested Relatives
412
            loadProfileRelatives();
413
        }
414
415
        // Click Trigger
416
        $(".profile-list__add-element-trigger").on("click", function (e) {
417
418
            // Prevent Default Functions
419
            e.preventDefault();
420
421
            // Add Profile Elements
422
            addProfileElement(this);
423
        });
424
425
        // Enter Key Trigger
426
        $(".profile-list__add-element-trigger").on("keyup", function (e) {
427
428
            if (e.which == 13) {
429
430
                // Prevent Default Functions
431
                e.preventDefault();
432
433
                // Add Profile Elements
434
                addProfileElement(this);
435
            }
436
        });
437
438
        // Remove Profile Element
439
440
        // Add Profile Relative
441
        function addProfileRelative(trigger) {
442
443
            // Get Parent
444
            var parent = $(trigger).parents(".profile-relative-list");
445
446
            // Get List Wrapper
447
            var wrapper = parent.find(".profile-relative-list__wrapper");
448
449
            // Set Null to Hidden
450
            // parent.find(".profile-null").removeClass("active");
451
452
            // Get Template
453
            var template = parent.find(".profile-relative.template").clone();
454
455
            // Remove Template Class
456
            template.removeClass("template");
457
458
            //Set ids and form names to be unique
459
            individualizeFormIdsAndNames(template, wrapper);
460
461
            // Append Clone to the Wrapper
462
            wrapper.append(template);
463
464
            // Reactivate Required Fields
465
            requiredFields();
466
467
            // Reactivate Labels
468
            labelHandlers();
469
470
            // Reactivate Nested Relatives
471
            loadProfileRelativeDeletion();
472
        }
473
474
        // Load Function
475
        function loadProfileRelatives() {
476
477
            // Click Trigger
478
            $(".profile-relative__add-trigger").off("click");
479
480
            $(".profile-relative__add-trigger").on("click", function (e) {
481
482
                // Prevent Default Functions
483
                e.preventDefault();
484
485
                // Add Profile Relative
486
                addProfileRelative(this);
487
            });
488
489
            // Enter Key Trigger
490
            $(".profile-relative__add-trigger").off("keyup");
491
492
            $(".profile-relative__add-trigger").on("keyup", function (e) {
493
494
                if (e.which == 13) {
495
496
                    // Prevent Default Functions
497
                    e.preventDefault();
498
499
                    // Add Profile Relative
500
                    addProfileRelative(this);
501
                }
502
            });
503
        }
504
505
        loadProfileRelatives();
506
507
        // Remove Profile Relative
508
        function deleteProfileRelative(trigger) {
509
510
            $(trigger).parents(".profile-relative").remove();
511
        }
512
513
        // Load Function
514
        function loadProfileRelativeDeletion() {
515
516
            // Click Trigger
517
            $(".profile-relative__remove-trigger").on("click", function (e) {
518
519
                // Prevent Default Functions
520
                e.preventDefault();
521
522
                // Delete Profile Relative
523
                deleteProfileRelative(this);
524
            });
525
526
            // Enter Key Trigger
527
            $(".profile-relative__remove-trigger").on("keyup", function (e) {
528
529
                if (e.which == 13) {
530
531
                    // Prevent Default Functions
532
                    e.preventDefault();
533
534
                    // Delete Profile Relative
535
                    deleteProfileRelative(this);
536
                }
537
            });
538
        }
539
540
        loadProfileRelativeDeletion();
541
542
        // Experience Handlers =================================================
543
544
        // Degrees
545
546
        function addDegree(trigger) {
547
548
            // Get Wrapper
549
            var wrapper = $(".application-post__experience-wrapper");
550
551
            // Get Template
552
            var template = $(".application-post__accordion--degree.template").clone();
553
554
            // Remove Template Class
555
            template.removeClass("template");
556
557
            //Set ids and form names to be unique
558
            individualizeFormIdsAndNames(template, wrapper);
559
560
            // Append Clone to the Wrapper
561
            wrapper.append(template);
562
563
            requiredFields();
564
            labelHandlers();
565
        }
566
567
        $("#addDegreeButton").on("click", function (e) {
568
569
            e.preventDefault();
570
571
            addDegree(this);
572
        });
573
574
        $("#addDegreeButton").on("keyup", function (e) {
575
576
            if (e.which == 13) {
577
                e.preventDefault();
578
                addDegree(this);
579
            }
580
        });
581
582
        // Courses
583
584
        function addCourse(trigger) {
585
586
            // Get Wrapper
587
            var wrapper = $(".application-post__experience-wrapper");
588
589
            // Get Template
590
            var template = $(".application-post__accordion--course.template").clone();
591
592
            // Remove Template Class
593
            template.removeClass("template");
594
595
            //Set ids and form names to be unique
596
            individualizeFormIdsAndNames(template, wrapper);
597
598
            // Append Clone to the Wrapper
599
            wrapper.append(template);
600
601
            requiredFields();
602
            labelHandlers();
603
        }
604
605
        $("#addCourseButton").on("click", function (e) {
606
607
            e.preventDefault();
608
609
            addCourse(this);
610
        });
611
612
        $("#addCourseButton").on("keyup", function (e) {
613
614
            if (e.which == 13) {
615
                e.preventDefault();
616
                addCourse(this);
617
            }
618
        });
619
620
        // Work
621
622
        function addWork(trigger) {
623
624
            // Get Wrapper
625
            var wrapper = $(".application-post__experience-wrapper");
626
627
            // Get Template
628
            var template = $(".application-post__accordion--work.template").clone();
629
630
            // Remove Template Class
631
            template.removeClass("template");
632
633
            //Set ids and form names to be unique
634
            individualizeFormIdsAndNames(template, wrapper);
635
636
            // Append Clone to the Wrapper
637
            wrapper.append(template);
638
639
            requiredFields();
640
            labelHandlers();
641
        }
642
643
        $("#addWorkButton").on("click", function (e) {
644
645
            e.preventDefault();
646
647
            addWork(this);
648
        });
649
650
        $("#addWorkButton").on("keyup", function (e) {
651
652
            if (e.which == 13) {
653
                e.preventDefault();
654
                addWork(this);
655
            }
656
        });
657
658
        // Create Job Handlers =================================================
659
660
        // Tasks
661
662
        function addTask(trigger) {
663
664
            // Get Wrapper
665
            var wrapper = $(".manager-jobs__create-task-wrapper");
666
667
            // Get Template
668
            var template = $(".manager-jobs__create-task.template").clone();
669
670
            console.log(wrapper.find(".manager-jobs__create-task"));
671
672
            // Get New ID
673
            if (wrapper.find(".manager-jobs__create-task").length == 0) {
674
                var newID = parseInt(template.attr("data-task-id")) + 1;
675
            } else {
676
                var newID = parseInt(wrapper.find("[class*='manager-jobs__create-task']").last().attr("data-task-id")) + 1;
677
            }
678
679
            // Remove Template Class
680
            template.removeClass("template");
681
682
            //TODO: replace with call to individualizeFormIdsAndNames(template, wrapper);
683
            //TODO: This requires changes to JobController@create, because the id would change places
684
685
            // Assign the New ID
686
            template.attr("data-task-id", newID);
687
688
            // Add newID as suffix to all "id" and "for" attributes
689
            template.find("*[id]").each(function () {
690
                $(this).attr("id", this.id + newID);
691
            });
692
            template.find("*[for]").each(function () {
693
                $(this).attr("for", $(this).attr("for") + newID);
694
            });
695
696
            // Replace :id with newID in all form names
697
            template.find("*[name]").each(function () {
698
                $(this).attr('name', $(this).attr("name").replace(":id", newID));
699
            });
700
701
            // Task (English)
702
            //template.find("[data-form-id*='task-english']").find("label").attr("for", "taskEN" + newID);
703
            //template.find("[data-form-id*='task-english']").find("input").attr("id", "taskEN" + newID);
704
705
            // Task (French)
706
            //template.find("[data-form-id*='task-french']").find("label").attr("for", "taskFR" + newID);
707
            //template.find("[data-form-id*='task-french']").find("input").attr("id", "taskFR" + newID);
708
709
            // Append Clone to the Wrapper
710
            wrapper.append(template);
711
712
            requiredFields();
713
            labelHandlers();
714
            deleteTaskTrigger();
715
        }
716
717
        $("#addTaskButton").on("click", function (e) {
718
719
            e.preventDefault();
720
721
            addTask(this);
722
        });
723
724
        $("#addTaskButton").on("keyup", function (e) {
725
726
            if (e.which == 13) {
727
                e.preventDefault();
728
                addTask(this);
729
            }
730
        });
731
732
        // Task Deletion
733
734
        function deleteTask(trigger) {
735
736
            $(trigger).parents(".manager-jobs__create-task").remove();
737
        }
738
739
        function deleteTaskTrigger() {
740
741
            $(".manager-jobs__delete-task-button").on("click", function (e) {
742
743
                e.preventDefault();
744
745
                deleteTask(this);
746
            });
747
748
            $(".manager-jobs__delete-task-button").on("keyup", function (e) {
749
750
                if (e.which == 13) {
751
                    e.preventDefault();
752
                    deleteTask(this);
753
                }
754
            });
755
        }
756
757
        deleteTaskTrigger();
758
759
        // Skills
760
761
        function addSkill(trigger) {
762
763
            // Get Parent
764
            var parent = $(trigger).parents(".manager-jobs__skill-wrapper");
765
766
            // Get Wrapper
767
            var wrapper = parent.find(".manager-jobs__create-skill-wrapper");
768
769
            // Get Template
770
            var template = parent.find(".manager-jobs__create-skill.template").clone();
771
772
            console.log(wrapper.find(".manager-jobs__create-skill"));
773
774
            // Remove Template Class
775
            template.removeClass("template");
776
777
            //Set ids and form names to be unique
778
            individualizeFormIdsAndNames(template, wrapper);
779
780
            // Append Clone to the Wrapper
781
            wrapper.append(template);
782
783
            requiredFields();
784
            labelHandlers();
785
            deleteSkillTrigger();
786
        }
787
788
        $(".manager-jobs__add-skill-button").on("click", function (e) {
789
790
            e.preventDefault();
791
792
            addSkill(this);
793
        });
794
795
        $(".manager-jobs__add-skill-button").on("keyup", function (e) {
796
797
            if (e.which == 13) {
798
                e.preventDefault();
799
                addSkill(this);
800
            }
801
        });
802
803
        // Skill Deletion
804
805
        function deleteSkill(trigger) {
806
807
            $(trigger).parents(".manager-jobs__create-skill").remove();
808
        }
809
810
        function deleteSkillTrigger() {
811
812
            $(".manager-jobs__delete-skill-button").on("click", function (e) {
813
814
                e.preventDefault();
815
816
                deleteSkill(this);
817
            });
818
819
            $(".manager-jobs__delete-skill-button").on("keyup", function (e) {
820
821
                if (e.which == 13) {
822
                    e.preventDefault();
823
                    deleteSkill(this);
824
                }
825
            });
826
        }
827
828
        deleteSkillTrigger();
829
830
        // Questions
831
832
        function addQuestion(trigger) {
833
834
            // Get Wrapper
835
            var wrapper = $(".manager-jobs__create-question-wrapper");
836
837
            // Get Template
838
            var template = $(".manager-jobs__create-question.template").clone();
839
840
            console.log(wrapper.find(".manager-jobs__create-question"));
841
842
            // Get New ID
843
            if (wrapper.find(".manager-jobs__create-question").length == 0) {
844
                var newID = parseInt(template.attr("data-question-id")) + 1;
845
            } else {
846
                var newID = parseInt(wrapper.find("[class*='manager-jobs__create-question']").last().attr("data-question-id")) + 1;
847
            }
848
849
            // Remove Template Class
850
            template.removeClass("template");
851
852
            //TODO: replace with call to individualizeFormIdsAndNames(template, wrapper);
853
            //TODO: This requires changes to JobController@create, because the id would change places
854
855
            // Assign the New ID
856
            template.attr("data-question-id", newID);
857
858
            // Add newID as suffix to all "id" and "for" attributes
859
            template.find("*[id]").each(function () {
860
                $(this).attr("id", this.id + newID);
861
            });
862
            template.find("*[for]").each(function () {
863
                $(this).attr("for", $(this).attr("for") + newID);
864
            });
865
866
            // Replace :id with newID in all form names
867
            template.find("*[name]").each(function () {
868
                $(this).attr('name', $(this).attr("name").replace(":id", newID));
869
            });
870
871
            // Edit Form IDs
872
            //
873
            // // Queestion (English)
874
            // template.find("[data-form-id*='question-english']").find("label").attr("for", "questionEN" + newID);
875
            // template.find("[data-form-id*='question-english']").find("input").attr("id", "questionEN" + newID);
876
            //
877
            // // Queestion (French)
878
            // template.find("[data-form-id*='question-french']").find("label").attr("for", "questionFR" + newID);
879
            // template.find("[data-form-id*='question-french']").find("input").attr("id", "questionFR" + newID);
880
881
            // Append Clone to the Wrapper
882
            wrapper.append(template);
883
884
            requiredFields();
885
            labelHandlers();
886
            deleteQuestionTrigger();
887
        }
888
889
        $("#addQuestionButton").on("click", function (e) {
890
891
            e.preventDefault();
892
893
            addQuestion(this);
894
        });
895
896
        $("#addQuestionButton").on("keyup", function (e) {
897
898
            if (e.which == 13) {
899
                e.preventDefault();
900
                addQuestion(this);
901
            }
902
        });
903
904
        // Question Deletion
905
906
        function deleteQuestion(trigger) {
907
908
            $(trigger).parents(".manager-jobs__create-question").remove();
909
        }
910
911
        function deleteQuestionTrigger() {
912
913
            $(".manager-jobs__delete-question-button").on("click", function (e) {
914
915
                e.preventDefault();
916
917
                deleteQuestion(this);
918
            });
919
920
            $(".manager-jobs__delete-question-button").on("keyup", function (e) {
921
922
                if (e.which == 13) {
923
                    e.preventDefault();
924
                    deleteQuestion(this);
925
                }
926
            });
927
        }
928
929
        deleteQuestionTrigger();
930
    });
931
})(jQuery);
932
933
/***/ }),
934
/* 2 */
935
/***/ (function(module, exports) {
936