Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / static / fusion / js / layout / debug.js
1 /**
2  *      debugData
3  *
4  *      Pass me a data structure {} and I'll output all the key/value pairs - recursively
5  *
6  *      @example var HTML = debugData( oElem.style, "Element.style", { keys: "top,left,width,height", recurse: true, sort: true, display: true, returnHTML: true });    
7  *
8  *      @param Object   o_Data   A JSON-style data structure
9  *      @param String   s_Title  Title for dialog (optional)
10  *      @param Hash     options  Pass additional options in a hash
11  */
12 function debugData (o_Data, s_Title, options) {
13         options = options || {};
14         var
15                 str=(s_Title||s_Title==='' ? s_Title : 'DATA')
16         ,       dType=$.type(o_Data)
17         //      maintain backward compatibility with OLD 'recurseData' param
18         ,       recurse=($.type(options)==='boolean' ? options : options.recurse !==false)
19         ,       keys=(options.keys?','+options.keys+',':false)
20         ,       display=options.display !==false
21         ,       html=options.returnHTML !==false
22         ,       sort=!!options.sort
23         ,       prefix=options.indent ? '    ' : ''
24         ,       D=[], i=0 // Array to hold data, i=counter
25         ,       hasSubKeys = false
26         ,       k, t, skip, x, type     // loop vars
27         ;
28         if (dType!=='object' && dType!=='array') {
29                 if (options.display) alert( (s_Title || 'debugData') +': '+ o_Data );
30                 return o_Data;
31         }
32         if (dType==='object' && $.isPlainObject(o_Data))
33                 dType='hash';
34
35         if (o_Data.jquery) {
36                 str=s_Title+'jQuery Collection ('+ o_Data.length +')\n    context="'+ o_Data.context +'"';
37         }
38         else if (o_Data.nodeName) {
39                 str=s_Title+o_Data.tagName;
40                 var id = o_Data.id, cls=o_Data.className, src=o_Data.src, hrf=o_Data.href;
41                 if (id)  str+='\n    id="'+             id+'"';
42                 if (cls) str+='\n    class="'+  cls+'"';
43                 if (src) str+='\n    src="'+    src+'"';
44                 if (hrf) str+='\n    href="'+   hrf+'"';
45         }
46         else {
47                 parse(o_Data,prefix,dType); // recursive parsing
48                 if (sort && !hasSubKeys) D.sort(); // sort by keyName - but NOT if has subKeys!
49                 if (str) str += '\n***'+ '****************************'.substr(0,str.length) +'\n';
50                 str += D.join('\n'); // add line-breaks
51         }
52
53         if (display) alert(str); // display data
54         if (html) str=str.replace(/\n/g, ' <br>').replace(/  /g, ' &nbsp;'); // format as HTML
55         return str;
56
57         function parse ( data, prefix, parentType ) {
58                 var first = true;
59                 try {
60                         $.each( data, function (key, val) {
61                                 skip = (keys && keys.indexOf(','+key+',') === -1);
62                                 type = $.type(val);
63                                 if (type==='object' && $.isPlainObject(val))
64                                         type = 'hash';
65                                 k = prefix + (first ? '    ' : ',   ');
66                                 first = false;
67
68                                 if (parentType!=='array') // no key-names for array items
69                                         k += key+':  '; // NOT an array
70
71                                 if (type==="date" || type==="regexp") {
72                                         val  = val.toString();
73                                         type = "string";
74                                 }
75                                 if (type==="string") {                          // STRING
76                                         if (!skip) D[i++] = k +'"'+ val +'"';
77                                 }
78                                                                                                         // NULL, UNDEFINED, NUMBER or BOOLEAN
79                                 else if (/^(null|undefined|number|boolean)/.test(type)) {
80                                         if (!skip) D[i++] = k + val;
81                                 }
82                                 else if (type==="function") {           // FUNCTION
83                                         if (!skip) D[i++] = k +'function()';
84                                 }
85                                 else if (type==="array") {                      // ARRAY
86                                         if (!skip) {
87                                                 D[i++] = k +'[';
88                                                 parse( val, prefix+'    ',type); // RECURSE
89                                                 D[i++] = prefix +'    ]';
90                                         }
91                                 }
92                                 else if (val.jquery) {                          // JQUERY OBJECT
93                                         if (!skip) D[i++] = k +'jQuery ('+ val.length +') context="'+ val.context +'"';
94                                 }
95                                 else if (val.nodeName) {                        // DOM ELEMENT
96                                         var id = val.id, cls=val.className, src=val.src, hrf=val.href;
97                                         if (skip) D[i++] = k +' '+
98                                                 id  ? 'id="'+   id+'"' :
99                                                 src ? 'src="'+  src+'"' :
100                                                 hrf ? 'href="'+ hrf+'"' :
101                                                 cls ? 'class="'+cls+'"' :
102                                                 '';
103                                 }
104                                 else if (type==="hash") {                       // JSON
105                                         if (!recurse || $.isEmptyObject(val)) { // show an empty hash
106                                                 if (!skip) D[i++] = k +'{ }';
107                                         }
108                                         else { // recurse into JSON hash - indent output
109                                                 D[i++] = k +'{';
110                                                 parse( val, prefix+'    ',type); // RECURSE
111                                                 D[i++] = prefix +'    }';
112                                         }
113                                 }
114                                 else {                                                          // OBJECT
115                                         if (!skip) D[i++] = k +'OBJECT'; // NOT a hash
116                                 }
117                         });
118                 } catch (e) {}
119         }
120 };
121
122 function debugStackTrace (s_Title, options) {
123         var
124                 callstack = []
125         ,       isCallstackPopulated = false
126         ;
127         try {
128                 i.dont.exist += 0; // doesn't exist- that's the point
129         } catch(e) {
130                 if (e.stack) { // Firefox
131                         var lines = e.stack.split('\n');
132                         for (var i=0, len=lines.length; i<len; i++) {
133                                 if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
134                                         callstack.push(lines[i]);
135                                 }
136                         }
137                         //Remove call to printStackTrace()
138                         callstack.shift();
139                         isCallstackPopulated = true;
140                 }
141                 else if (window.opera && e.message) { // Opera
142                         var lines = e.message.split('\n');
143                         for (var i=0, len=lines.length; i<len; i++) {
144                                 if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
145                                         var entry = lines[i];
146                                         //Append next line also since it has the file info
147                                         if (lines[i+1]) {
148                                                 entry += ' at ' + lines[i+1];
149                                                 i++;
150                                         }
151                                         callstack.push(entry);
152                                 }
153                         }
154                         //Remove call to printStackTrace()
155                         callstack.shift();
156                         isCallstackPopulated = true;
157                 }
158         }
159
160         if (!isCallstackPopulated) { // IE and Safari
161                 var currentFunction = arguments.callee.caller;
162                 while (currentFunction) {
163                         var fn = currentFunction.toString();
164                         var fname = fn.substring(fn.indexOf('function') + 8, fn.indexOf('')) || 'anonymous';
165                         callstack.push(fname);
166                         currentFunction = currentFunction.caller;
167                 }
168         }
169
170         debugData( callstack, s_Title, options );
171 };
172
173 if (!window.console) window.console = { log: debugData };
174
175 if (!window.console.trace)
176         window.console.trace  = function (s_Title) {
177                 window.console.log( debugStackTrace(s_Title, { display: false, returnHTML: false, sort: false }) );
178         };
179
180 // add method to output 'hash data' inside an string
181 window.console.data = function (data, title) {
182         var     w               = { array: ['[',']'], object: ['{','}'], string: ['"','"'], number: ['',''], function: ['','()'] }
183         ,       x               = $.type( data )
184         ,       obj             = x.match(/(object|array)/)
185         ,       delim   = !obj ? ['',''] : x === 'object' ? ['{\n','\n}'] : ['[\n','\n]']
186         ,       opts    = { display: false, returnHTML: false, sort: false }
187         ,       debug   = debugData( data, '', opts)
188         ;
189         console.log(
190                 (title ? title +' = ' : '')
191         +       delim[0]
192         +       ($.type(debug) === 'string' ? debug.replace(/    /g, '\t') : debug)
193         +       delim[1]
194         );
195 };
196
197
198 /**
199  *      timer
200  *
201  *      Utility for debug timing of events
202  *      Can track multiple timers and returns either a total time or interval from last event
203  *      @param String   timerName       Name of the timer - defaults to debugTimer
204  *      @param String   action          Keyword for action or return-value...
205  *      action: 'reset' = reset; 'clear' = delete; 'total' = ms since init; 'step' or '' = ms since last event
206  */
207 /**
208  *      timer
209  *
210  *      Utility method for timing performance
211  *      Can track multiple timers and returns either a total time or interval from last event
212  *
213  *      returns time-data: {
214  *              start:  Date Object
215  *      ,       last:   Date Object
216  *      ,       step:   99 // time since 'last'
217  *      ,       total:  99 // time since 'start'
218  *      }
219  *
220  *      USAGE SAMPLES
221  *      =============
222  *      timer('name'); // create/init timer
223  *      timer('name', 'reset'); // re-init timer
224  *      timer('name', 'clear'); // clear/remove timer
225  *      var i = timer('name');  // how long since last timer request?
226  *      var i = timer('name', 'total'); // how long since timer started?
227  *
228  *      @param String   timerName       Name of the timer - defaults to debugTimer
229  *      @param String   action          Keyword for action or return-value...
230  *      @param Hash             options         Options to customize return data
231  *      action: 'reset' = reset; 'clear' = delete; 'total' = ms since init; 'step' or '' = ms since last event
232  */
233 function timer (timerName, action, options) {
234         var
235                 name    = timerName || 'debugTimer'
236         ,       Timer   = window[ name ]
237         ,       defaults = {
238                         returnString:   true
239                 ,       padNumbers:             true
240                 ,       timePrefix:             ''
241                 ,       timeSuffix:             ''
242                 }
243         ;
244
245         // init the timer first time called
246         if (!Timer || action == 'reset') { // init timer
247                 Timer = window[ name ] = {
248                         start:  new Date()
249                 ,       last:   new Date()
250                 ,       step:   0 // time since 'last'
251                 ,       total:  0 // time since 'start'
252                 ,       options: $.extend({}, defaults, options)
253                 };
254         }
255         else if (action == 'clear') { // remove timer
256                 window[ name ] = null;
257                 return null;
258         }
259         else { // update existing timer
260                 Timer.step      = (new Date()) - Timer.last;  // time since 'last'
261                 Timer.total     = (new Date()) - Timer.start; // time since 'start'
262                 Timer.last      = new Date();
263         }
264
265         var
266                 time = (action == 'total') ? Timer.total : Timer.step
267         ,       o = Timer.options // alias
268         ;
269
270         if (o.returnString) {
271                 time += ""; // convert integer to string
272                 // pad time to 4 chars with underscores
273                 if (o.padNumbers)
274                         switch (time.length) {
275                                 case 1: time = "&ensp;&ensp;&ensp;"+ time;      break;
276                                 case 2: time = "&ensp;&ensp;"+ time;    break;
277                                 case 3: time = "&ensp;"+ time;  break;
278                         }
279                 // add prefix and suffix
280                 if (o.timePrefix || o.timeSuffix)
281                         time = o.timePrefix + time + o.timeSuffix;
282         }
283
284         return time;
285 };
286
287
288 /**
289  *      showOptions
290  *
291  *      Pass a layout-options object, and the pane/key you want to display
292  */
293 function showOptions (Layout, key, debugOpts) {
294         var data = Layout.options;
295         $.each(key.split("."), function() {
296                 data = data[this]; // recurse through multiple key-levels
297         });
298         debugData( data, 'options.'+key, debugOpts );
299 };
300
301 /**
302  *      showState
303  *
304  *      Pass a layout-options object, and the pane/key you want to display
305  */
306 function showState (Layout, key, debugOpts) {
307         var data = Layout.state;
308         $.each(key.split("."), function() {
309                 data = data[this]; // recurse through multiple key-levels
310         });
311         debugData( data, 'state.'+key, debugOpts );
312 };
313
314
315
316
317 function debugWindow ( content, options ) {
318         var defaults = {
319                 css: {
320                         position:       'fixed'
321                 ,       top:            0
322                 }
323         };
324         $.extend( true, (options || {}), defaults );
325         var $W  = $('<div></div>')
326                 .html( content.replace(/\n/g, '<br>').replace(/  /g, ' &nbsp;') ) // format as HTML
327                 .css( options.css )
328                 ;
329 };