Completed
Push — master ( 17ec8d...3c3c2c )
by Chris
01:14
created

flask_jsondash/static/js/app.js   F

Complexity

Total Complexity 77
Complexity/F 1.75

Size

Lines of Code 415
Function Count 44

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 0 Features 1
Metric Value
cc 0
c 12
b 0
f 1
dl 0
loc 415
rs 3.8125
nc 1
wmc 77
mnd 11
bc 66
fnc 44
bpm 1.5
cpm 1.75
noi 19

24 Functions

Rating   Name   Duplication   Size   Complexity  
A app.js ➔ isModalButton 0 3 1
A app.js ➔ togglePanel 0 5 1
A app.js ➔ getModuleWidgetByGUID 0 3 1
B app.js ➔ addDomEvents 0 34 1
A app.js ➔ updateWidget 0 11 1
A app.js ➔ addChartContainers 0 8 1
A app.js ➔ initGrid 0 16 1
A app.js ➔ addWidget 0 13 2
A app.js ➔ refreshWidget 0 8 1
A app.js ➔ unload 0 4 1
A app.js ➔ saveModule 0 19 4
A app.js ➔ refreshableType 0 4 2
A app.js ➔ getModuleByGUID 0 3 1
A app.js ➔ previewAPIRoute 0 14 1
B app.js ➔ updateEditForm 0 27 2
A app.js ➔ loader 0 4 1
A app.js ➔ deleteModule 0 14 2
A app.js ➔ addRefreshers 0 10 1
B app.js ➔ updateModule 0 33 1
A app.js ➔ getValidParamString 0 13 1
B app.js ➔ loadDashboard 0 43 1
A app.js ➔ prettyCode 0 4 2
D app.js ➔ loadWidgetData 0 45 15
A app.js ➔ handleInputs 0 20 1

How to fix   Complexity   

Complexity

Complex classes like flask_jsondash/static/js/app.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/** global: d3 */
2
/** global: freewall */
3
/**
4
 * Bootstrapping functions, event handling, etc... for application.
5
 */
6
7
var jsondash = function() {
8
    var my = {};
9
    var dashboard_data = null;
10
    var chart_wall = null;
11
    var $API_ROUTE_URL = '[name="dataSource"]';
12
    var $API_PREVIEW = '#api-output';
13
    var $API_PREVIEW_BTN = '#api-output-preview';
14
    var $MODULE_FORM = '#module-form';
15
    var $VIEW_BUILDER = '#view-builder';
16
    var $ADD_MODULE = '#add-module';
17
    var $MAIN_CONTAINER = '#container';
18
    var $EDIT_MODAL = '#chart-options';
19
    var $DELETE_BTN = '#delete-widget';
20
    var $DELETE_DASHBOARD = '.delete-dashboard';
21
    var $SAVE_MODULE = '#save-module';
22
    var $EDIT_CONTAINER = '#edit-view-container';
23
24
    function addWidget(container, model) {
25
        if(document.querySelector('[data-guid="' + model.guid + '"]')) return d3.select('[data-guid="' + model.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...
26
        return d3.select(container).select('div')
27
            .append('div')
28
            .classed({item: true, widget: true})
29
            .attr('data-guid', model.guid)
30
            .attr('data-refresh', model.refresh)
31
            .attr('data-refresh-interval', model.refreshInterval)
32
            .style('width', model.width + 'px')
33
            .style('height', model.height + 'px')
34
            .html(d3.select('#chart-template').html())
35
            .select('.widget-title').text(model.name);
36
    }
37
38
    function previewAPIRoute(e) {
39
        e.preventDefault();
40
        // Shows the response of the API field as a json payload, inline.
41
        $.ajax({
42
            type: 'get',
43
            url: $($API_ROUTE_URL).val().trim(),
44
            success: function(d) {
45
               $($API_PREVIEW).html(prettyCode(d));
46
            },
47
            error: function(d, status, error) {
48
                $($API_PREVIEW).html(error);
49
            }
50
        });
51
    }
52
53
    function refreshableType(type) {
54
        if(type === 'youtube') return 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...
55
        return true;
56
    }
57
58
    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...
59
        var data     = jsondash.util.serializeToJSON($($MODULE_FORM).serializeArray());
60
        var last     = $('.modules').find('input').last();
0 ignored issues
show
Unused Code introduced by
The assignment to variable last seems to be never used. Consider removing it.
Loading history...
61
        var newfield = $('<input class="form-control" type="text">');
62
        var id       = jsondash.util.guid();
63
        // Add a unique guid for referencing later.
64
        data['guid'] = id;
65
        // Add family for lookups
66
        data['family'] = $($MODULE_FORM).find('select option:selected').data().family;
67
        if(!data.refresh || !refreshableType(data.type)) data['refresh'] = 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...
68
        if(!data.override) data['override'] = 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...
69
        newfield.attr('name', 'module_' + id);
70
        newfield.val(JSON.stringify(data));
71
        $('.modules').append(newfield);
72
        // Add new visual block to view grid
73
        addWidget($VIEW_BUILDER, data);
74
        // Refit the grid
75
        chart_wall.fitWidth();
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
        if(isModalButton(e)) {
86
            module_form.find('input').each(function(_, input){
87
                $(input).val('');
88
            });
89
            $($API_PREVIEW).empty();
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 data = $(e.relatedTarget).closest('.item.widget').data();
96
        var guid = data.guid;
97
        var module = getModuleByGUID(guid);
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
    }
109
110
    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...
111
        var module_form = $($MODULE_FORM);
112
        // Updates the module input fields with new data by rewriting them all.
113
        var guid = module_form.attr('data-guid');
114
        var active = getModuleByGUID(guid);
115
        // Update the modules values to the current input values.
116
        module_form.find('input').each(function(_, input){
117
            var name = $(input).attr('name');
118
            if(name) {
119
                if(name === 'override' || name === 'refresh') {
120
                    // Convert checkbox to json friendly format.
121
                    active[name] = $(input).is(':checked');
122
                } else {
123
                    active[name] = $(input).val();
124
                }
125
            }
126
        });
127
        // Update bar chart type
128
        var chart_type = module_form.find('select');
129
        active[chart_type.attr('name')] = chart_type.val();
130
        // Clear out module input values
131
        $('.modules').empty();
132
        $.each(dashboard_data.modules, function(i, module){
133
            var val = JSON.stringify(module, module);
134
            var input = $('<input type="text" name="module_' + i + '" class="form-control">');
135
            input.val(val);
136
            $('.modules').append(input);
137
        });
138
        updateWidget(active);
139
        $($EDIT_CONTAINER).collapse();
140
        // Refit the grid
141
        setTimeout(chart_wall.fitWidth, 100);
142
    }
143
144
    function updateWidget(config) {
145
        // Trigger update form into view since data is dirty
146
        // Update visual size to existing widget.
147
        var widget = getModuleWidgetByGUID(config.guid);
148
        widget.style({
149
            height: config.height + 'px',
150
            width: config.width + 'px'
151
        });
152
        widget.select('.widget-title').text(config.name);
153
        loadWidgetData(widget, config);
154
    }
155
156
    function refreshWidget(e) {
157
        e.preventDefault();
158
        var container = $(this).closest('.widget');
159
        var guid = container.attr('data-guid');
160
        var config = getModuleByGUID(guid);
161
        var widget = addWidget($MAIN_CONTAINER, config);
162
        loadWidgetData(widget, config);
163
    }
164
165
    function addChartContainers(container, data) {
166
        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...
167
            // Closure to maintain each chart data value in loop
168
            (function(config){
169
                var config = data.modules[name];
0 ignored issues
show
introduced by
The variable name is changed by the for-each loop on line 166. Only the value of the last iteration will be visible in this function if it is called outside of the loop.
Loading history...
170
                // Add div wrappers for js grid layout library,
171
                // and add title, icons, and buttons
172
                var widget = addWidget(container, config);
173
                // Determine how to load this widget
174
                loadWidgetData(widget, config);
175
            })(data.modules[name]);
176
        }
177
    }
178
179
    function getModuleWidgetByGUID(guid) {
180
        return d3.select('.item.widget[data-guid="' + guid + '"]');
181
    }
182
183
    function getModuleByGUID(guid) {
184
        return dashboard_data.modules.find(function(n){return n['guid'] === guid});
185
    }
186
187
    function deleteModule(e) {
188
        e.preventDefault();
189
        if(!confirm('Are you sure?')) return;
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...
190
        var guid = $($MODULE_FORM).attr('data-guid');
191
        var module = getModuleByGUID(guid);
0 ignored issues
show
Unused Code introduced by
The variable module seems to be never used. Consider removing it.
Loading history...
192
        // Remove form input and visual widget
193
        $('.modules').find('#' + guid).remove();
194
        $('.item.widget[data-guid="' + guid + '"]').remove();
195
        $($EDIT_MODAL).modal('hide');
196
        // Redraw wall to replace visual 'hole'
197
        chart_wall.fitWidth();
198
        // Trigger update form into view since data is dirty
199
        $($EDIT_CONTAINER).collapse('in');
200
    }
201
202
    function addDomEvents() {
203
        // TODO: debounce/throttle
204
        $($API_ROUTE_URL).on('change.charts', previewAPIRoute);
205
        $($API_PREVIEW_BTN).on('click.charts', previewAPIRoute);
206
        // Save module popup form
207
        $($SAVE_MODULE).on('click.charts.module', saveModule);
208
        // Edit existing modules
209
        $($EDIT_MODAL).on('show.bs.modal', updateEditForm);
210
        $('#update-module').on('click.charts.module', updateModule);
211
        // Allow swapping of edit/update events
212
        // for the add module button and form modal
213
        $($ADD_MODULE).on('click.charts', function(){
214
            $('#update-module')
215
            .attr('id', $SAVE_MODULE.replace('#', ''))
216
            .text('Save module')
217
            .off('click.charts.module')
218
            .on('click.charts', saveModule);
219
        });
220
        // Allow swapping of edit/update events
221
        // for the edit button and form modal
222
        $('.widget-edit').on('click.charts', function(){
223
            $($SAVE_MODULE)
224
            .attr('id', 'update-module')
225
            .text('Update module')
226
            .off('click.charts.module')
227
            .on('click.charts', updateModule);
228
        });
229
        // Add delete button for existing widgets.
230
        $($DELETE_BTN).on('click.charts', deleteModule);
231
        // Add delete confirm for dashboards.
232
        $($DELETE_DASHBOARD).on('submit.charts', function(e){
233
            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...
234
        });
235
    }
236
237
    function togglePanel(e) {
0 ignored issues
show
introduced by
The function togglePanel does not seem to be used and can be removed.
Loading history...
238
        e.preventDefault();
239
        var el = $(this).attr('href');
240
        $(el).toggleClass('open');
241
    }
242
243
    function initGrid(container) {
244
        // http://vnjs.net/www/project/freewall/#options
245
        chart_wall = new freewall(container);
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like freewall should be capitalized.
Loading history...
246
        chart_wall.reset({
247
            selector: '.item',
248
            fixSize: 1, // Important! Fixes the widgets to their configured size.
249
            gutterX: 2,
250
            gutterY: 2,
251
            draggable: false,
252
            onResize: function() {
253
                chart_wall.fitWidth();
254
            }
255
        });
256
        $('.item.widget').removeClass('hidden');
257
        chart_wall.fitWidth();
258
    }
259
260
    function loader(container) {
261
        container.select('.loader-overlay').classed({hidden: false});
262
        container.select('.widget-loader').classed({hidden: false});
263
    }
264
265
    function unload(container) {
266
        container.select('.loader-overlay').classed({hidden: true});
267
        container.select('.widget-loader').classed({hidden: true});
268
    }
269
270
    function handleInputs(widget, config) {
271
        var inputs_selector = '[data-guid="' + config.guid + '"] .chart-inputs';
272
        // Load event handlers for these newly created forms.
273
        $(inputs_selector).find('form').on('submit', function(e){
274
            e.preventDefault();
275
            // Just create a new url for this, but use existing config.
276
            // The global object config will not be altered.
277
            // The first {} here is important, as it enforces a deep copy,
278
            // not a mutation of the original object.
279
            var url = config.dataSource;
280
            var params = getValidParamString($(this).serializeArray());
281
            var _config = $.extend({}, config, {
282
                dataSource: url.replace(/\?.+/, '') + '?' + params
283
            });
284
            // Otherwise reload like normal.
285
            loadWidgetData(widget, _config);
286
            // Hide the form again
287
            $(inputs_selector).removeClass('in');
288
        });
289
    }
290
291
    function getValidParamString(arr) {
292
        // Jquery $.serialize and $.serializeArray will
293
        // return empty query parameters, which is undesirable and can
294
        // be error prone for RESTFUL endpoints.
295
        // e.g. `foo=bar&bar=` becomes `foo=bar`
296
        var param_str = '';
297
        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...
298
        $.each(arr, function(i, param){
299
            param_str += (param.name + '=' + param.value);
300
            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...
301
        });
302
        return param_str;
303
    }
304
305
    function loadWidgetData(widget, config) {
306
        loader(widget);
307
        try {
308
            // Handle any custom inputs the user specified for this module.
309
            // They map to standard form inputs and correspond to query
310
            // arguments for this dataSource.
311
            if(config.inputs) {handleInputs(widget, config);}
312
313
            if(config.type === 'datatable') {
314
                jsondash.handlers.handleDataTable(widget, config);
315
            }
316
            else if(jsondash.util.isSparkline(config.type)) {
317
                jsondash.handlers.handleSparkline(widget, config);
318
            }
319
            else if(config.type === 'iframe') {
320
                jsondash.handlers.handleIframe(widget, config);
321
            }
322
            else if(config.type === 'timeline') {
323
                jsondash.handlers.handleTimeline(widget, config);
324
            }
325
            else if(config.type === 'venn') {
326
                jsondash.handlers.handleVenn(widget, config);
327
            }
328
            else if(config.type === 'number') {
329
                jsondash.handlers.handleSingleNum(widget, config);
330
            }
331
            else if(config.type === 'youtube') {
332
                jsondash.handlers.handleYoutube(widget, config);
333
            }
334
            else if(config.type === 'custom') {
335
                jsondash.handlers.handleCustom(widget, config);
336
            }
337
            else if(config.type === 'plotly-any') {
338
                jsondash.handlers.handlePlotly(widget, config);
339
            }
340
            else if(jsondash.util.isD3Subtype(config)) {
341
                jsondash.handlers.handleD3(widget, config);
342
            } else {
343
                jsondash.handlers.handleC3(widget, config);
344
            }
345
        } catch(e) {
346
            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...
347
            unload(widget);
348
        }
349
    }
350
351
    function prettyCode(code) {
352
        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...
353
        return JSON.stringify(JSON.parse(code), null, 4);
354
    }
355
356
    function addRefreshers(modules) {
357
        $.each(modules, function(_, module){
358
            if(module.refresh && module.refreshInterval) {
359
                var container = d3.select('[data-guid="' + module.guid + '"]');
360
                setInterval(function(){
361
                    loadWidgetData(container, module);
362
                }, parseInt(module.refreshInterval, 10));
363
            }
364
        });
365
    }
366
367
    function loadDashboard(data) {
368
        // Load the grid before rendering the ajax, since the DOM
369
        // is rendered server side.
370
        initGrid($MAIN_CONTAINER);
371
        // Add actual ajax data.
372
        addChartContainers($MAIN_CONTAINER, data);
373
        dashboard_data = data;
374
375
        // Add event handlers for widget UI
376
        $('.widget-refresh').on('click.charts', refreshWidget);
377
378
        // Setup refresh intervals for all widgets that specify it.
379
        addRefreshers(data.modules);
380
381
        // Format json config display
382
        $('#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...
383
            var code = $(this).find('code').text();
384
            $(this).find('code').text(prettyCode(code));
385
        });
386
387
        // Reformat the code inside of the raw json field, to pretty print
388
        // for the user.
389
        $('#raw-config').text(prettyCode($('#raw-config').text()));
390
391
        // Setup responsive handlers
392
        var jres = jRespond([
393
        {
394
            label: 'handheld',
395
            enter: 0,
396
            exit: 767
397
        }
398
        ]);
399
        jres.addFunc({
400
            breakpoint: 'handheld',
401
            enter: function() {
402
                $('.widget').css({
403
                    'max-width': '100%',
404
                    'width': '100%',
405
                    'position': 'static'
406
                });
407
            }
408
        });
409
    }
410
    my.config = {
411
        WIDGET_MARGIN_X: 20,
412
        WIDGET_MARGIN_Y: 60
413
    };
414
    my.loadDashboard = loadDashboard;
415
    my.handlers = {};
416
    my.util = {};
417
    my.loader = loader;
418
    my.unload = unload;
419
    my.addDomEvents = addDomEvents;
420
    return my;
421
}();
422