Completed
Pull Request — master (#52)
by Bui Quang
02:42
created

form.js ➔ ... ➔ this._initilizeTooltip   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
import Section from './section.js';
2
import Layout from './layout.js';
3
import Sortable from 'sortablejs';
4
5
var Form = function(id) {
6
7
    /**
8
     * form variable is created to represent Form instance.
9
     */
10
    var form = this;
11
12
    /**
13
     * element variable is created to be a master element of the Form, all the variables will be found via element variable
14
     * Eg: element.find('.btn-add')
15
     */
16
    var element = $(id);
17
18
    /**
19
     * addButton variable is created to represent Add Section Button of the Form.
20
     */
21
    var addButton = element.find('#add_section_button');
22
23
    /**
24
     * saveButton variable is created to represent Save Button of the Form.
25
     */
26
    var saveButton = element.find('#save_form_button');
27
28
    /**
29
     * sections variable is created to represent all sections exist on the Form.
30
     */
31
    var sections = [];
32
33
    /**
34
     * sectionWrapper variable is created to represent wrapper element of all sections exist on Form.
35
     */
36
    var sectionWrapper = element.find('#section_wrapper');
37
38
    /**
39
     * errorWrapper variable is created to represent wrapper element of errors all exist on Form.
40
     */
41
    var errorWrapper = element.find('#error_wrapper');
42
43
    /**
44
     * errors variable is created to temporary store all the errors of the Form.
45
     */
46
    var errors = [];
47
48
    /**
49
     * sectionClass variable is created to represent section class, for better readable.
50
     */
51
    var sectionClass = '.item-option';
52
53
    /** 
54
     * layout variable is created to handle all rendering layout stuff for the Form.
55
     */
56
    var layout = new Layout();
57
58
    /**
59
     * Initialize actions when create a single instance of Form.
60
     */
61
    this.init = function() {
62
        /* Reindex all the sections (if needed). */
63
        form._reindexSections();
64
        /* Assign all exist sections to sections variable. */
65
        form._assignExistSections();
66
        /* Initialize Sortable JS to reorder form's sections. */
67
        form._initilizeSortable();
68
        /* Initialize Tooltip. */
69
        form._initilizeTooltip();
70
        /* Validate all the data when submit the Form. */
71
        form._validate();
72
        /* Bind add new section feature when click on Add Section Button. */
73
        form._addNewSection();
74
    }
75
76
    /**
77
     * Add new section actions when user click on Add Section Button.
78
     */
79
    this._addNewSection = function() {
80
81
        addButton.click(function(e) {
82
            e.preventDefault();
83
            /* First: count total sections, assign it to a temporary variable totalSection. */
84
            var totalSection = form._countTotalSections();
85
            /* Second: disable add button, don't let user click multiple times. */
86
            form._disableAddButton();
87
            /* Third: 
88
             *    Call an AJAX to get a default layout of a section .
89
             *    Display the default layout we just received in the bottom of the section wrapper.
90
             *    Initialize new section.
91
             *    Update Form's section variable.
92
             *    Enable add button.
93
             */
94
            layout.getDefaultSectionLayout(totalSection + 1).done(function(html){
95
96
                form._addNewLayout(html);
97
98
                var section = new Section(totalSection+1, form);
99
                section.init();
100
101
                form._updateSectionVariable(section);
102
103
                form._enableAddButton();
104
105
                form._initilizeTooltip();
106
107
            });
108
            
109
110
        });
111
112
    }
113
114
    /**
115
     * Validate all the data when submit the Form
116
     */
117
    this._validate = function() {
118
119
        saveButton.click(function(e){
120
            e.preventDefault();
121
            
122
            /* Check if form input is valid or not. */
123
            if(form._validateSections()) {
124
                /* If yes: submit the form. */
125
                form._submit();
126
            } else {
127
                /**
128
                 * If no:
129
                 *    Remove all exist errors on FE.
130
                 *    Add new errors on FE.
131
                 *    Truncate errors variable after display error on FE.
132
                 */
133
                form._removeExistErrors();
134
                form._addNewErrors();
135
                form._truncateErrorsVariable();
136
            }
137
            
138
        });
139
    }
140
141
    /**
142
     * Validate data from all the sections
143
     */
144
    this._validateSections = function() {
145
        /**
146
         * Create a loop to loop through all exist sections.
147
         * Validate the sections, return false if any section is invalid.
148
         * Store all errors of all sections.
149
         * Truncate the current errors of all sections
150
         */
151
        var flag = true;
152
        sections.forEach(function(section){
153
            if(!section.validate()) 
154
                flag = false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
155
                form._updateErrors(section.getErrors());
156
                section.truncateErrors();
157
        });
158
159
        return flag;
160
    }
161
162
    /**
163
     * Remove all current exits errors on FE.
164
     */
165
    this._removeExistErrors = function() {
166
167
        errorWrapper.empty();
168
    
169
    }
170
171
    /**
172
     * Truncate errors variables
173
     */
174
    this._truncateErrorsVariable = function() {
175
        errors = [];
176
    }
177
178
    /**
179
     * Add new error on FE
180
     */
181
    this._addNewErrors = function() {
182
        /**
183
         * Create a loop to loop through all exist errors.
184
         * For each error, create a list item to display the error.
185
         * Display the new errors in error wrapper on FE.
186
         */
187
        /* Get error listing wrapper */
188
        var errorListingWrapper = layout.getErrorListingWrapperLayout();
189
        var errorListing = '';
190
        /* Get error listing */
191
        errors.forEach(function(error){
192
            errorListing += layout.getErrorSingleListingLayout(error);
193
        });
194
        /* Get errors layout by replace markup in error listing wrapper with error listing */
195
        var errorsLayout = errorListingWrapper.replace('%error-list-markup%', errorListing);
196
        /* Display errors layout */
197
        errorWrapper.append(errorsLayout);
198
    }
199
200
    /**
201
     * Update value for errors variable of the Form.
202
     */
203
    this._updateErrors = function(error) {
204
        error.forEach(function(err){
205
206
            errors.push(err);
207
208
        });
209
210
    }
211
212
    /**
213
     * Add new layout to the Form
214
     */
215
    this._addNewLayout = function(html) {
216
        /* Display the layout passed via parameter to the bottom of section wrapper. */
217
        $(JSON.parse(html)).appendTo(sectionWrapper);
218
219
    }
220
221
    /**
222
     * Assign all exist section to section variable
223
     */
224
    this._assignExistSections = function() {
225
226
        element.find(sectionClass).each(function() {
227
228
            var sectionIndex = $(this).attr('data-index');
229
            var section = new Section(sectionIndex, form);
230
            section.init();
231
232
            form._updateSectionVariable(section);
233
234
        });
235
236
    }
237
238
    /**
239
     * Initialize Sortable to reorder form's sections.
240
     */
241
    this._initilizeSortable = function() {
242
243
        Sortable.create(section_wrapper, { 
0 ignored issues
show
Bug introduced by
The variable section_wrapper seems to be never declared. If this is a global, consider adding a /** global: section_wrapper */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
244
245
            animation: 150,
246
            // Element dragging ended
247
            onEnd: function (evt) {
248
249
                var droppedIndex = evt.oldIndex;
250
                var draggedIndex = evt.newIndex;
251
                var indexDifferent = (droppedIndex != draggedIndex);
252
                /* Check if old index is not the same as old index. */
253
                if(indexDifferent) {
254
                    /* Swap two element. */
255
                    form._sortSectionsVariable();
256
                    form._reindexSections();
257
258
                    /** 
259
                     * Check if the draggedIndex or droppedIndex equal to 0.
260
                     * It mean that draggedSectionElement or droppedSectionElement is the first section. 
261
                     * Add delete button on the new first section and remove delete button on the opposite section.
262
                     * Bind delete event on the new first section.
263
                     */
264
                    var draggElFirst = (draggedIndex == 0);
265
                    var droppElFirst = (droppedIndex == 0);
266
                    if(draggElFirst || droppElFirst) {
267
268
                        if(draggElFirst) {
269
270
                            sections[draggedIndex].removeDeleteButton();
271
                            sections[droppedIndex].addDeleteButton();
272
                            sections[droppedIndex].onDelete();
273
274
                        } else if (droppElFirst) {
275
276
                            sections[droppedIndex].removeDeleteButton();
277
                            sections[draggedIndex].addDeleteButton();
278
                            sections[draggedIndex].onDelete();
279
280
                        }
281
282
                    } 
283
                
284
                }
285
            
286
            },
287
288
        });
289
290
    }
291
292
    this._initilizeTooltip = function() {
293
        $('[data-toggle="tooltip"]').tooltip();
294
    }
295
296
    /**
297
     * Count total number of sections.
298
     */
299
    this._countTotalSections = function() {
300
301
        return sections.length;
302
303
    }
304
305
    /**
306
     * Update value for sections variable of the Form.
307
     */
308
    this._updateSectionVariable = function(section) {
309
310
        sections.push(section);
311
312
    }
313
314
    /**
315
     * Submit the Form.
316
     */
317
    this._submit = function() {
318
319
        element.submit();
320
321
    }
322
323
    /**
324
     * Remove a section from the Form.
325
     */
326
    this.removeSection = function(sectionIndex) {
327
328
        /**
329
         * First: we need to remove the section from sections variable.
330
         * Second: we need to reindex all the sections element of the Form (Html).
331
         * Third: we need to reindex all the sections object of the Form (Javascript Object).
332
         */
333
        form._rmSectionInSectionsVar(sectionIndex);
334
        form._reindexSections();
335
336
    }
337
338
    /**
339
     * Remove a section from sections variable.
340
     */
341
    this._rmSectionInSectionsVar = function(sectionIndex) {
342
343
        sections.splice(sectionIndex, 1);
344
345
    }
346
347
    /**
348
     * Check and reindex all sections.
349
     */
350
    this._reindexSections = function() {
351
352
        /**
353
         * Loop through all exist section element.
354
         * Reindex the section via index of the element.
355
         */
356
        sections.forEach(function(section, index, _arr){
0 ignored issues
show
Unused Code introduced by
The parameter _arr is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
357
            
358
            var sectionIndex = index + 1;
359
            var indexDifferent = (sectionIndex != section.getIndex());
360
            if(indexDifferent) {
361
                section.reindex(sectionIndex);
362
            }
363
364
        })
365
366
    }
367
368
    /**
369
     * Disable add button.
370
     */
371
    this._disableAddButton = function() {
372
373
        addButton.css('pointer-events', 'none');
374
375
    }
376
377
    /**
378
     * Enable add button.
379
     */
380
    this._enableAddButton = function() {
381
382
        addButton.css('pointer-events', 'visible');
383
384
    }
385
386
    /**
387
     * Sort section variable after drag and drop.
388
     */
389
    this._sortSectionsVariable = function() {
390
391
        var tempSection = [];
392
        element.find(sectionClass).each(function(elementIndex){
393
394
            var sectionElement = $(this);
395
            var oldIndex = sectionElement.attr('data-index') - 1;
396
            var newIndex = elementIndex;
397
            var indexDifferent = (oldIndex != newIndex);
398
            if(indexDifferent) {
399
                tempSection[newIndex] = sections[newIndex];
400
                if(typeof tempSection[oldIndex] == 'undefined') {
401
                    sections[newIndex] = sections[oldIndex];
402
                } else {
403
                    sections[newIndex] = tempSection[oldIndex];
404
                }
405
            }
406
407
        });
408
409
    }
410
411
}
412
413
export default Form;