Completed
Push — master ( 69e1dd...052d93 )
by Chris
01:26
created

app.js ➔ loadDashboard   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 1
c 1
b 1
f 1
nc 1
nop 1
dl 0
loc 55
rs 9.7692

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/** global: d3 */
2
/**
3
 * Bootstrapping functions, event handling, etc... for application.
4
 */
5
6
var jsondash = function() {
7
    var my = {
8
        chart_wall: null,
9
        widgets: {}
10
    };
11
    var dashboard_data    = null;
12
    var $API_ROUTE_URL    = '[name="dataSource"]';
13
    var $API_PREVIEW      = '#api-output';
14
    var $API_PREVIEW_BTN  = '#api-output-preview';
15
    var $MODULE_FORM      = '#module-form';
16
    var $VIEW_BUILDER     = '#view-builder';
0 ignored issues
show
Unused Code introduced by
The variable $VIEW_BUILDER seems to be never used. Consider removing it.
Loading history...
17
    var $ADD_MODULE       = '#add-module';
18
    var $MAIN_CONTAINER   = '#container';
19
    var $EDIT_MODAL       = '#chart-options';
20
    var $DELETE_BTN       = '#delete-widget';
21
    var $DELETE_DASHBOARD = '.delete-dashboard';
22
    var $SAVE_MODULE      = '#save-module';
23
    var $EDIT_CONTAINER   = '#edit-view-container';
24
    var $MAIN_FORM        = '#save-view-form';
25
    var $JSON_DATA        = '#raw-config';
26
27
    function addWidget(container, config) {
28
        if(document.querySelector('[data-guid="' + config.guid + '"]')) return d3.select('[data-guid="' + config.guid + '"]');
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...
29
        return d3.select(container).select('div')
30
            .append('div')
31
            .classed({item: true, widget: true})
32
            .attr('data-guid', config.guid)
33
            .attr('data-refresh', config.refresh)
34
            .attr('data-refresh-interval', config.refreshInterval)
35
            .style('width', config.width + 'px')
36
            .style('height', config.height + 'px')
37
            .html(d3.select('#chart-template').html())
38
            .select('.widget-title .widget-title-text').text(config.name);
39
    }
40
41
    function previewAPIRoute(e) {
42
        e.preventDefault();
43
        // Shows the response of the API field as a json payload, inline.
44
        $.ajax({
45
            type: 'get',
46
            url: $($API_ROUTE_URL).val().trim(),
47
            success: function(d) {
48
               $($API_PREVIEW).html(prettyCode(d));
49
            },
50
            error: function(d, status, error) {
51
                $($API_PREVIEW).html(error);
52
            }
53
        });
54
    }
55
56
    function refreshableType(type) {
57
        if(type === 'youtube') {return false;}
58
        return true;
59
    }
60
61
    function saveModule(e){
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
62
        var config   = jsondash.util.serializeToJSON($($MODULE_FORM).serializeArray());
63
        var newfield = $('<input class="form-control" type="text">');
64
        var id       = jsondash.util.guid();
65
        // Add a unique guid for referencing later.
66
        config['guid'] = id;
67
        // Add family for lookups
68
        config['family'] = $($MODULE_FORM).find('[name="type"]').find('option:selected').data().family;
69
        if(!config.refresh || !refreshableType(config.type)) {config['refresh'] = false;}
70
        if(!config.override) {config['override'] = false;}
71
        newfield.attr('name', 'module_' + id);
72
        newfield.val(JSON.stringify(config));
73
        $('.modules').append(newfield);
74
        // Save immediately.
75
        $($MAIN_FORM).submit();
76
    }
77
78
    function isModalButton(e) {
79
        return e.relatedTarget.id === $ADD_MODULE.replace('#', '');
80
    }
81
82
    function updateEditForm(e) {
83
        var module_form = $($MODULE_FORM);
84
        // If the modal caller was the add modal button, skip populating the field.
85
        $($API_PREVIEW).text('...');
86
        if(isModalButton(e)) {
87
            module_form.find('input').each(function(_, input){
88
                $(input).val('');
89
            });
90
            $($DELETE_BTN).hide();
91
            return;
92
        }
93
        $($DELETE_BTN).show();
94
        // Updates the fields in the edit form to the active widgets values.
95
        var item = $(e.relatedTarget).closest('.item.widget');
96
        var guid = item.data().guid;
97
        var module = getModule(item);
98
        // Update the modal window fields with this one's value.
99
        $.each(module, function(field, val){
100
            if(field === 'override' || field === 'refresh') {
101
                module_form.find('[name="' + field + '"]').prop('checked', val);
102
            } else {
103
                module_form.find('[name="' + field + '"]').val(val);
104
            }
105
        });
106
        // Update with current guid for referencing the module.
107
        module_form.attr('data-guid', guid);
108
        populateOrderField(module);
109
    }
110
111
    function populateOrderField(module) {
112
        var module_form = $($MODULE_FORM);
113
        var widgets = $('.item.widget');
114
        // Add the number of items to order field.
115
        var order_field = module_form.find('[name="order"]');
116
        var max_options = widgets.length > 0 ? widgets.length + 1 : 2;
117
        order_field.find('option').remove();
118
        // Add empty option.
119
        order_field.append('<option value=""></option>');
120
        d3.map(d3.range(1, max_options), function(i){
121
            var option = $('<option></option>');
122
            option.val(i).text(i);
123
            order_field.append(option);
124
        });
125
        order_field.val(module && module.order ? module.order : '');
126
    }
127
128
    function updateModule(e){
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
129
        var module_form = $($MODULE_FORM);
130
        // Updates the module input fields with new data by rewriting them all.
131
        var guid = module_form.attr('data-guid');
132
        var active = getModuleByGUID(guid);
133
        // Update the modules values to the current input values.
134
        module_form.find('input').each(function(_, input){
135
            var name = $(input).attr('name');
136
            if(name) {
137
                if(name === 'override' || name === 'refresh') {
138
                    // Convert checkbox to json friendly format.
139
                    active[name] = $(input).is(':checked');
140
                } else {
141
                    active[name] = $(input).val();
142
                }
143
            }
144
        });
145
        // Update bar chart type
146
        active['type'] = module_form.find('[name="type"]').val();
147
        // Update order
148
        active['order'] = parseInt(module_form.find('[name="order"]').val(), 10);
149
        // Clear out module input values
150
        $('.modules').empty();
151
        $.each(dashboard_data.modules, function(i, module){
152
            var val = JSON.stringify(module, module);
153
            var input = $('<input type="text" name="module_' + i + '" class="form-control">');
154
            input.val(val);
155
            $('.modules').append(input);
156
        });
157
        updateWidget(active);
158
        $($EDIT_CONTAINER).collapse();
159
        // Refit the grid
160
        fitGrid();
161
    }
162
163
    function updateWidget(config) {
164
        // Trigger update form into view since data is dirty
165
        // Update visual size to existing widget.
166
        var widget = my.widgets[config.guid].el;
167
        loader(widget);
168
        widget.style({
169
            height: config.height + 'px',
170
            width: config.width + 'px'
171
        });
172
        widget.select('.widget-title .widget-title-text').text(config.name);
173
        loadWidgetData(widget, config);
174
    }
175
176
    function refreshWidget(e) {
177
        e.preventDefault();
178
        var config = getModule($(this).closest('.widget'));
179
        var widget = addWidget($MAIN_CONTAINER, config);
180
        loadWidgetData(widget, config);
181
        fitGrid();
182
    }
183
184
    function addChartContainers(container, data) {
185
        for(var name in data.modules){
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
186
            // Closure to maintain each chart data value in loop
187
            (function(config){
188
                var config = data.modules[name];
0 ignored issues
show
introduced by
The variable name is changed by the for-each loop on line 185. Only the value of the last iteration will be visible in this function if it is called outside of the loop.
Loading history...
189
                // Add div wrappers for js grid layout library,
190
                // and add title, icons, and buttons
191
                var widget = addWidget(container, config);
192
                my.widgets[config.guid] = {el: widget, config: config};
193
            })(data.modules[name]);
194
        }
195
        fitGrid();
196
        for(var guid in my.widgets){
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
197
            var widg = my.widgets[guid];
198
            loadWidgetData(widg.el, widg.config);
199
        }
200
    }
201
202
    function getModuleByGUID(guid) {
203
        return my.widgets[guid].config;
204
    }
205
206
    function deleteModule(e) {
207
        e.preventDefault();
208
        if(!confirm('Are you sure?')) {return;}
209
        var guid = $($MODULE_FORM).attr('data-guid');
210
        // Remove form input and visual widget
211
        $('.modules').find('#' + guid).remove();
212
        $('.item.widget[data-guid="' + guid + '"]').remove();
213
        $($EDIT_MODAL).modal('hide');
214
        // Redraw wall to replace visual 'hole'
215
        fitGrid();
216
        // Trigger update form into view since data is dirty
217
        $($EDIT_CONTAINER).collapse('show');
218
    }
219
220
    function addDomEvents() {
221
        // TODO: debounce/throttle
222
        $($API_ROUTE_URL).on('change.charts', previewAPIRoute);
223
        $($API_PREVIEW_BTN).on('click.charts', previewAPIRoute);
224
        // Save module popup form
225
        $($SAVE_MODULE).on('click.charts.module', saveModule);
226
        // Edit existing modules
227
        $($EDIT_MODAL).on('show.bs.modal', updateEditForm);
228
        $('#update-module').on('click.charts.module', updateModule);
229
        // Allow swapping of edit/update events
230
        // for the add module button and form modal
231
        $($ADD_MODULE).on('click.charts', function(){
232
            $('#update-module')
233
            .attr('id', $SAVE_MODULE.replace('#', ''))
234
            .text('Save module')
235
            .off('click.charts.module')
236
            .on('click.charts', saveModule);
237
        });
238
        // Allow swapping of edit/update events
239
        // for the edit button and form modal
240
        $('.widget-edit').on('click.charts', function(){
241
            $($SAVE_MODULE)
242
            .attr('id', 'update-module')
243
            .text('Update module')
244
            .off('click.charts.module')
245
            .on('click.charts', updateModule);
246
        });
247
        // Add delete button for existing widgets.
248
        $($DELETE_BTN).on('click.charts', deleteModule);
249
        // Add delete confirm for dashboards.
250
        $($DELETE_DASHBOARD).on('submit.charts', function(e){
251
            if(!confirm('Are you sure?')) e.preventDefault();
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...
252
        });
253
    }
254
255
    function initGrid(container) {
0 ignored issues
show
Unused Code introduced by
The parameter container 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...
256
        fitGrid({
257
            columnWidth: 5,
258
            itemSelector: '.item',
259
            transitionDuration: 0,
260
            fitWidth: true
261
        }, true);
262
        $('.item.widget').removeClass('hidden');
263
    }
264
265
    function fitGrid(opts, init) {
266
        var valid_options = $.isPlainObject(opts);
0 ignored issues
show
Unused Code introduced by
The variable valid_options seems to be never used. Consider removing it.
Loading history...
267
        var options = $.extend({}, opts, {});
268
        if(init) {
269
            my.chart_wall = $('#container').packery(options);
270
            items = my.chart_wall.find('.item').draggable({
0 ignored issues
show
Bug introduced by
The variable items seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.items.
Loading history...
271
                scroll: true,
272
                handle: '.dragger',
273
                stop: function(){
274
                    $($EDIT_CONTAINER).collapse('show');
275
                    updateModuleOrder();
276
                    my.chart_wall.packery(options);
277
                }
278
            });
279
            my.chart_wall.packery('bindUIDraggableEvents', items);
280
        } else {
281
            my.chart_wall.packery(options);
282
        }
283
    }
284
285
    function updateModuleOrder() {
286
        var items = my.chart_wall.packery('getItemElements');
287
        // Update module order
288
        $.each(items, function(i, el){
0 ignored issues
show
Unused Code introduced by
The parameter el 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...
289
            var module = getModule($(this));
290
            var config = $.extend(module, {order: i});
291
            updateModuleInput(config);
292
        });
293
    }
294
295
    function getModule(el) {
296
        // Return module by element
297
        var data = el.data();
298
        var guid = data.guid;
299
        return getModuleByGUID(guid);
300
    }
301
302
    function loader(container) {
303
        container.select('.loader-overlay').classed({hidden: false});
304
        container.select('.widget-loader').classed({hidden: false});
305
    }
306
307
    function unload(container) {
308
        container.select('.loader-overlay').classed({hidden: true});
309
        container.select('.widget-loader').classed({hidden: true});
310
    }
311
312
    function handleInputs(widget, config) {
313
        var inputs_selector = '[data-guid="' + config.guid + '"] .chart-inputs';
314
        // Load event handlers for these newly created forms.
315
        $(inputs_selector).find('form').on('submit', function(e){
316
            e.stopImmediatePropagation();
317
            e.preventDefault();
318
            // Just create a new url for this, but use existing config.
319
            // The global object config will not be altered.
320
            // The first {} here is important, as it enforces a deep copy,
321
            // not a mutation of the original object.
322
            var url = config.dataSource;
323
            // Ensure we don't lose params already save on this endpoint url.
324
            var existing_params = url.split('?')[1];
325
            var params = getValidParamString($(this).serializeArray());
326
            var _config = $.extend({}, config, {
327
                dataSource: url.replace(/\?.+/, '') + '?' + existing_params + '&' + params
328
            });
329
            // Otherwise reload like normal.
330
            loadWidgetData(widget, _config);
331
            // Hide the form again
332
            $(inputs_selector).removeClass('in');
333
        });
334
    }
335
336
    function getValidParamString(arr) {
337
        // Jquery $.serialize and $.serializeArray will
338
        // return empty query parameters, which is undesirable and can
339
        // be error prone for RESTFUL endpoints.
340
        // e.g. `foo=bar&bar=` becomes `foo=bar`
341
        var param_str = '';
342
        arr = arr.filter(function(param, i){return param.value !== '';});
0 ignored issues
show
Unused Code introduced by
The parameter i 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...
343
        $.each(arr, function(i, param){
344
            param_str += (param.name + '=' + param.value);
345
            if(i < arr.length - 1 && arr.length > 1) param_str += '&';
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...
346
        });
347
        return param_str;
348
    }
349
350
    function loadWidgetData(widget, config) {
351
        loader(widget);
352
353
        try {
354
            // Handle any custom inputs the user specified for this module.
355
            // They map to standard form inputs and correspond to query
356
            // arguments for this dataSource.
357
            if(config.inputs) {handleInputs(widget, config);}
358
359
            if(config.type === 'datatable') {
360
                jsondash.handlers.handleDataTable(widget, config);
361
            }
362
            else if(jsondash.util.isSparkline(config.type)) {
363
                jsondash.handlers.handleSparkline(widget, config);
364
            }
365
            else if(config.type === 'iframe') {
366
                jsondash.handlers.handleIframe(widget, config);
367
            }
368
            else if(config.type === 'timeline') {
369
                jsondash.handlers.handleTimeline(widget, config);
370
            }
371
            else if(config.type === 'venn') {
372
                jsondash.handlers.handleVenn(widget, config);
373
            }
374
            else if(config.type === 'number') {
375
                jsondash.handlers.handleSingleNum(widget, config);
376
            }
377
            else if(config.type === 'youtube') {
378
                jsondash.handlers.handleYoutube(widget, config);
379
            }
380
            else if(config.type === 'graph'){
381
                jsondash.handlers.handleGraph(widget, config);
382
            }
383
            else if(config.type === 'custom') {
384
                jsondash.handlers.handleCustom(widget, config);
385
            }
386
            else if(config.type === 'plotly-any') {
387
                jsondash.handlers.handlePlotly(widget, config);
388
            }
389
            else if(jsondash.util.isD3Subtype(config)) {
390
                jsondash.handlers.handleD3(widget, config);
391
            } else {
392
                jsondash.handlers.handleC3(widget, config);
393
            }
394
        } catch(e) {
395
            if(console && console.error) console.error(e);
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...
396
            unload(widget);
397
        }
398
        addResizeEvent(widget, config);
399
    }
400
401
    function addResizeEvent(widget, config) {
402
        // Add resize event
403
        $(widget[0]).resizable({
404
            helper: 'resizable-helper',
405
            minWidth: 200,
406
            minHeight: 200,
407
            stop: function(event, ui) {
408
                // Update the configs dimensions.
409
                config = $.extend(config, {width: ui.size.width, height: ui.size.height});
410
                updateModuleInput(config);
411
                loadWidgetData(widget, config);
412
                fitGrid();
413
                // Open save panel
414
                $($EDIT_CONTAINER).collapse('show');
415
            }
416
        });
417
    }
418
419
    function updateModuleInput(config) {
420
        $('input[id="' + config.guid + '"]').val(JSON.stringify(config));
421
    }
422
423
    function prettyCode(code) {
424
        if(typeof code === "object") return JSON.stringify(code, null, 4);
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...
425
        return JSON.stringify(JSON.parse(code), null, 4);
426
    }
427
428
    function addRefreshers(modules) {
429
        $.each(modules, function(_, module){
430
            if(module.refresh && module.refreshInterval) {
431
                var container = d3.select('[data-guid="' + module.guid + '"]');
432
                setInterval(function(){
433
                    loadWidgetData(container, module);
434
                }, parseInt(module.refreshInterval, 10));
435
            }
436
        });
437
    }
438
439
    function loadDashboard(data) {
440
        // Load the grid before rendering the ajax, since the DOM
441
        // is rendered server side.
442
        initGrid($MAIN_CONTAINER);
443
        // Add actual ajax data.
444
        addChartContainers($MAIN_CONTAINER, data);
445
        dashboard_data = data;
446
447
        // Add event handlers for widget UI
448
        $('.widget-refresh').on('click.charts', refreshWidget);
449
450
        // Setup refresh intervals for all widgets that specify it.
451
        addRefreshers(data.modules);
452
453
        // Format json config display
454
        $('#json-output').on('show.bs.modal', function(e){
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
455
            var code = $(this).find('code').text();
456
            $(this).find('code').text(prettyCode(code));
457
        });
458
459
        // Add event for downloading json config raw.
460
        // Will provide decent support but still not major: http://caniuse.com/#search=download
461
        $('[href="#download-json"]').on('click', function(e){
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
462
            var datestr = new Date().toString().replace(/ /gi, '-');
463
            var json_data = $($JSON_DATA).val();
464
            var data = encodeURIComponent(JSON.stringify(json_data, null, 4));
465
            data = "data:text/json;charset=utf-8," + data;
466
            $(this).attr('href', data);
467
            $(this).attr('download', 'charts-config-raw-' + datestr + '.json');
468
        });
469
470
        // Reformat the code inside of the raw json field, to pretty print
471
        // for the user.
472
        $($JSON_DATA).text(prettyCode($($JSON_DATA).text()));
473
474
        // Setup responsive handlers
475
        var jres = jRespond([
476
        {
477
            label: 'handheld',
478
            enter: 0,
479
            exit: 767
480
        }
481
        ]);
482
        jres.addFunc({
483
            breakpoint: 'handheld',
484
            enter: function() {
485
                $('.widget').css({
486
                    'max-width': '100%',
487
                    'width': '100%',
488
                    'position': 'static'
489
                });
490
            }
491
        });
492
        populateOrderField();
493
    }
494
    my.config = {
495
        WIDGET_MARGIN_X: 20,
496
        WIDGET_MARGIN_Y: 60
497
    };
498
    my.loadDashboard = loadDashboard;
499
    my.handlers = {};
500
    my.util = {};
501
    my.loader = loader;
502
    my.unload = unload;
503
    my.addDomEvents = addDomEvents;
504
    return my;
505
}();
506