Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / utils.js @ 60376c36

History | View | Annotate | Download (13.6 kB)

1
;(function(root){
2
    
3
    var root = root;
4
    var snf = root.synnefo = root.synnefo || {};
5
    
6
    snf.i18n = {};
7

    
8
    // Logging namespace
9
    var logging = snf.logging = snf.logging || {};
10

    
11
    // logger object
12
    var logger = logging.logger = function(ns, level){
13
        var levels = ["debug", "info", "error"];
14
        var con = window.console;
15
        
16
        this.level = level || synnefo.logging.level;
17
        this.ns = ns || "";
18

    
19
        this._log = function(lvl) {
20
            if (lvl >= this.level && con) {
21
                var args = Array.prototype.slice.call(arguments[1]);
22
                var level_name = levels[lvl];
23
                    
24
                if (this.ns) {
25
                    args = ["["+this.ns+"] "].concat(args);
26
                }
27

    
28
                log = con.log
29
                if (con[level_name])
30
                    log = con[level_name]
31

    
32
                try {
33
                    con && log.apply(con, Array.prototype.slice.call(args));
34
                } catch (err) {}
35
            }
36
        }
37

    
38
        this.debug = function() {
39
            var args = [0]; args.push.call(args, arguments);
40
            this._log.apply(this, args);
41
        }
42

    
43
        this.info = function() {
44
            var args = [1]; args.push.call(args, arguments);
45
            this._log.apply(this, args);
46
        }
47

    
48
        this.error = function() {
49
            var args = [2]; args.push.call(args, arguments);
50
            this._log.apply(this, args);
51
        }
52

    
53
    };
54
    
55
    synnefo.collect_user_data = function() {
56
        var data = {}
57
        
58
        try {
59
            data.client = {'browser': $.browser, 'screen': $.extend({}, screen), 'client': $.client}
60
        } catch (err) { data.client = err }
61
        try {
62
            data.calls = synnefo.api.requests;
63
        } catch (err) { data.calls = err }
64
        try {
65
            data.errors = synnefo.api.errors;
66
        } catch (err) { data.errors = err }
67
        try {
68
            data.data = {};
69
        } catch (err) { data.data = err }
70
        try {
71
            data.data.vms = synnefo.storage.vms.toJSON();
72
        } catch (err) { data.data.vms = err }
73
        try {
74
            data.data.networks = synnefo.storage.networks.toJSON();
75
        } catch (err) { data.data.networks = err }
76
        //try {
77
            //data.data.images = synnefo.storage.images.toJSON();
78
        //} catch (err) { data.data.images = err }
79
        //try {
80
            //data.data.flavors = synnefo.storage.flavors.toJSON();
81
        //} catch (err) { data.data.flavors = err }
82
        try {
83
            data.date = new Date;
84
        } catch (err) { data.date = err }
85

    
86
        return data;
87
    }
88

    
89
    // default logger level (debug)
90
    synnefo.logging.level = 0;
91

    
92
    // generic logger
93
    synnefo.log = new logger({'ns':'SNF'});
94

    
95
    // synnefo config options
96
    synnefo.config = synnefo.config || {};
97
    synnefo.config.api_url = "/api/v1.1";
98
    
99
    // Util namespace
100
    synnefo.util = synnefo.util || {};
101

    
102
    // Extensions and Utility functions
103
    synnefo.util.ISODateString = function(d){
104
        function pad(n){
105
            return n<10 ? '0'+n : n
106
        }
107
         return d.getUTCFullYear()+'-'
108
         + pad(d.getUTCMonth()+1)+'-'
109
         + pad(d.getUTCDate())+'T'
110
         + pad(d.getUTCHours())+':'
111
         + pad(d.getUTCMinutes())+':'
112
         + pad(d.getUTCSeconds())+'Z'
113
    }
114

    
115
 
116
    synnefo.util.parseUri = function(sourceUri) {
117
        var uriPartNames = ["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];
118
        var uriParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri);
119
        var uri = {};
120
        
121
        for(var i = 0; i < 10; i++){
122
            uri[uriPartNames[i]] = (uriParts[i] ? uriParts[i] : "");
123
        }
124
    
125
        // Always end directoryPath with a trailing backslash if a path was present in the source URI
126
        // Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key
127
        if(uri.directoryPath.length > 0){
128
            uri.directoryPath = uri.directoryPath.replace(/\/?$/, "/");
129
        }
130
        
131
        return uri;
132
    }
133

    
134
    synnefo.util.equalHeights = function() {
135
        var max_height = 0;
136
        var selectors = _.toArray(arguments);
137
            
138
        _.each(selectors, function(s){
139
            console.log($(s).height());
140
        })
141
        // TODO: implement me
142
    }
143

    
144
    synnefo.util.ClipHelper = function(cont, clear) {
145
        this.force_empty = clear || false;
146
        this.cont = cont || $('<div class="clip-copy"></div>');
147
        this.clip = new ZeroClipboard.Client();
148
        this.clip.setHandCursor(true);
149

    
150
        this.el = this.cont;
151
        if (this.force_empty) {
152
            this.cont.empty();
153
        }
154
        this.el.append(this.clip.getHTML(20,20));
155

    
156
        this.setText = function(t) {
157
            this.clip.setText(t);
158
        }
159

    
160
        var copy_prompt = "Click to copy to clipboard";
161
        this.el.attr({title: copy_prompt});
162
        this.el.tooltip();
163
        var el = this.el;
164

    
165
        this.clip.addEventListener('complete', _.bind(function(client, text) {
166
            var tip = el.data("tooltip")
167
            tip.hide().getTip().text("Copied");
168
            
169
            window.setTimeout(function() {
170
                tip.show();
171
            }, 70)
172

    
173
            window.setTimeout(function() {
174
                tip.hide().getTip().text(copy_prompt);
175
            }, 3000)
176
        }, this));
177
    }
178

    
179
    synnefo.util.truncate = function(string, size, append, words) {
180
        if (string === undefined) { return "" };
181
        if (string.length <= size) {
182
            return string;
183
        }
184

    
185
        if (append === undefined) {
186
            append = "...";
187
        }
188
        
189
        if (!append) { append = "" };
190
        // TODO: implement word truncate
191
        if (words === undefined) {
192
            words = false;
193
        }
194
        
195
        len = size - append.length;
196
        return string.substring(0, len) + append;
197
    }
198

    
199
    synnefo.util.readablizeBytes = function(bytes) {
200
        var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB'];
201
        var e = Math.floor(Math.log(bytes)/Math.log(1024));
202
        return (bytes/Math.pow(1024, Math.floor(e))).toFixed(2)+" "+s[e];
203
    }
204
    
205
    synnefo.i18n.API_ERROR_MESSAGES = {
206
        'timeout': {
207
            'message': 'TIMEOUT', 
208
            'allow_report': false,
209
            'type': 'Network'
210
        },
211
        
212
        'error': {
213
            'message': 'API error'
214
        }, 
215

    
216
        'abort': {},
217
        'parserror': {},
218
        '413': {
219
            'title': "Account warning"
220
        }
221
    }
222
    
223
    synnefo.util.array_diff = function(arr1, arr2) {
224
        var removed = [];
225
        var added = [];
226

    
227
        _.each(arr1, function(v) {
228
            if (arr2.indexOf(v) == -1) {
229
                removed[removed.length] = v;
230
            }
231
        })
232

    
233

    
234
        _.each(arr2, function(v) {
235
            if (arr1.indexOf(v) == -1) {
236
                added[added.length] = v;
237
            }
238
        })
239

    
240
        return {del: removed, add: added};
241
    }
242

    
243
    synnefo.util.open_window = function(url, name, specs) {
244
        // default specs
245
        var opts = _.extend({
246
            scrollbars: 'no',
247
            menubar: 'no',
248
            toolbar: 'no',
249
            status: 'no',
250
            top: 'no',
251
            left: 'no',
252
            height: screen.height,
253
            width: screen.width,
254
            fullscreen: 'yes',
255
            channelmode: 'yes',
256
            directories: 'no',
257
            left: 0,
258
            location: 'no',
259
            top: 0
260
        }, opts)
261
        
262
        window.open(url, name, opts);
263
    }
264

    
265
    synnefo.util.stacktrace = function() {
266
        try {
267
            var obj = {};
268
            if (window.Error && Error.captureStackTrace) {
269
                Error.captureStackTrace(obj, synnefo.util.stacktrace);
270
                return obj.stack;
271
            } else {
272
                return printStackTrace().join("<br /><br />");
273
            }
274
        } catch (err) {}
275
        return "";
276
    },
277
    
278
    synnefo.util.array_combinations = function(arr) {
279
        if (arr.length == 1) {
280
            return arr[0];
281
        } else {
282
            var result = [];
283

    
284
            // recur with the rest of array
285
            var allCasesOfRest = synnefo.util.array_combinations(arr.slice(1));  
286
            for (var i = 0; i < allCasesOfRest.length; i++) {
287
                for (var j = 0; j < arr[0].length; j++) {
288
                    result.push(arr[0][j] + "-" + allCasesOfRest[i]);
289
                }
290
            }
291
            return result;
292
        }
293
    }
294

    
295
    synnefo.util.parse_api_error = function() {
296
        if (arguments.length == 1) { arguments = arguments[0] };
297

    
298
        var xhr = arguments[0];
299
        var error_message = arguments[1];
300
        var error_thrown = arguments[2];
301
        var ajax_settings = _.last(arguments) || {};
302
        var call_settings = ajax_settings.error_params || {};
303
        var json_data = undefined;
304

    
305
        var critical = ajax_settings.critical === undefined ? true : ajax_settings.critical;
306

    
307
        if (xhr.responseText) {
308
            try {
309
                json_data = JSON.parse(xhr.responseText)
310
            } catch (err) {}
311
        }
312
        
313
        module = "API"
314

    
315
        try {
316
            path = synnefo.util.parseUri(ajax_settings.url).path.split("/");
317
            path.splice(0,3)
318
            module = path.join("/");
319
        } catch (err) {
320
            console.error("cannot identify api error module");
321
        }
322
        
323
        defaults = {
324
            'message': 'Api error',
325
            'type': 'API',
326
            'allow_report': true,
327
            'fatal_error': ajax_settings.critical || false,
328
            'non_critical': !critical
329
        }
330

    
331
        var code = -1;
332
        try {
333
            code = xhr.status || "undefined";
334
        } catch (err) {console.error(err);}
335
        var details = "";
336
        
337
        if ([413].indexOf(code) > -1) {
338
            defaults.non_critical = true;
339
            defaults.allow_report = false;
340
            defaults.allow_reload = false;
341
            error_message = "limit_error";
342
        }
343

    
344
        if (critical) {
345
            defaults.allow_report = true;
346
        }
347
        
348
        if (json_data) {
349
            $.each(json_data, function(key, obj) {
350
                code = obj.code;
351
                details = obj.details.replace("\n","<br>");
352
                error_message = obj.message;
353
            })
354
        }
355

    
356
        extra = {'URL': ajax_settings.url};
357
        options = {};
358
        options = _.extend(options, {'details': details, 'message': error_message, 'ns': module, 'extra_details': extra});
359
        options = _.extend(options, call_settings);
360
        options = _.extend(options, synnefo.i18n.API_ERROR_MESSAGES[error_message] || {});
361
        options = _.extend(options, synnefo.i18n.API_ERROR_MESSAGES[code] || {});
362
        
363
        if (window.ERROR_OVERRIDES && window.ERROR_OVERRIDES[options.message]) {
364
            options.message = window.ERROR_OVERRIDES[options.message];
365
        }
366
        
367
        if (code && window.ERROR_OVERRIDES && window.ERROR_OVERRIDES[code]) {
368
            options.message = window.ERROR_OVERRIDES[code];
369
        }
370

    
371
        options = _.extend(defaults, options);
372
        options.code = code;
373

    
374
        return options;
375
    }
376

    
377

    
378
    // Backbone extensions
379
    //
380
    // super method
381
    Backbone.Model.prototype._super = Backbone.Collection.prototype._super = Backbone.View.prototype._super = function(funcName){
382
        return this.constructor.__super__[funcName].apply(this, _.rest(arguments));
383
    }
384

    
385
    // simple string format helper 
386
    // http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format
387
    String.prototype.format = function() {
388
        var formatted = this;
389
        for (var i = 0; i < arguments.length; i++) {
390
            var regexp = new RegExp('\\{'+i+'\\}', 'gi');
391
            formatted = formatted.replace(regexp, arguments[i]);
392
        }
393
        return formatted;
394
    };
395

    
396

    
397
    $.fn.setCursorPosition = function(pos) {
398
        if ($(this).get(0).setSelectionRange) {
399
          $(this).get(0).setSelectionRange(pos, pos);
400
        } else if ($(this).get(0).createTextRange) {
401
          var range = $(this).get(0).createTextRange();
402
          range.collapse(true);
403
          range.moveEnd('character', pos);
404
          range.moveStart('character', pos);
405
          range.select();
406
        }
407
    }
408

    
409
    // trim prototype for IE
410
    if(typeof String.prototype.trim !== 'function') {
411
        String.prototype.trim = function() {
412
            return this.replace(/^\s+|\s+$/g, '');
413
        }
414
    }
415

    
416
    // http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area 
417
    $.fn.setCursorPosition = function(pos) {
418
        // not all browsers support setSelectionRange
419
        // put it in try/catch, fallback to no text selection
420
        try {
421
            if ($(this).get(0).setSelectionRange) {
422
              $(this).get(0).setSelectionRange(pos, pos);
423
            } else if ($(this).get(0).createTextRange) {
424
              var range = $(this).get(0).createTextRange();
425
              range.collapse(true);
426
              range.moveEnd('character', pos);
427
              range.moveStart('character', pos);
428
              range.select();
429
            }
430
        } catch (err) {
431
        }
432
    }
433

    
434
    // indexOf prototype for IE
435
    if (!Array.prototype.indexOf) {
436
      Array.prototype.indexOf = function(elt /*, from*/) {
437
        var len = this.length;
438
        var from = Number(arguments[1]) || 0;
439
        from = (from < 0)
440
             ? Math.ceil(from)
441
             : Math.floor(from);
442
        if (from < 0)
443
          from += len;
444

    
445
        for (; from < len; from++) {
446
          if (from in this &&
447
              this[from] === elt)
448
            return from;
449
        }
450
        return -1;
451
      };
452
    }
453

    
454
})(this);