/* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */ (function(){var initializing=false;var fnTest=/var xyz/.test(function(){var xyz;})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend = function(prop) {var _super = this.prototype;initializing = true;var prototype = new this();initializing = false;for (var name in prop) {if( typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ){prototype[name] = (function(name,fn){return function() {var tmp=this._super;this._super=_super[name];var ret=fn.apply(this,arguments);this._super=tmp;return ret;};})(name,prop[name]);}else{prototype[name] = prop[name];}}function Class(){if(!initializing && this.init){this.init.apply(this,arguments);}}Class.prototype=prototype;Class.prototype.constructor=Class;Class.extend=arguments.callee;return Class;};})(); /* jQuery Scrollstop Plugin v1.2.0 * https://github.com/ssorallen/jquery-scrollstop */ !function(factory){"function"==typeof define&&define.amd?define(["jquery"],factory):"object"==typeof exports?module.exports=factory(require("jquery")):factory(jQuery)}(function($){var dispatch=$.event.dispatch||$.event.handle,special=$.event.special,uid1="D"+ +new Date,uid2="D"+(+new Date+1);special.scrollstart={setup:function(data){var timer,_data=$.extend({latency:special.scrollstop.latency},data),handler=function(evt){var _self=this,_args=arguments;timer?clearTimeout(timer):(evt.type="scrollstart",dispatch.apply(_self,_args)),timer=setTimeout(function(){timer=null},_data.latency)};$(this).bind("scroll",handler).data(uid1,handler)},teardown:function(){$(this).unbind("scroll",$(this).data(uid1))}},special.scrollstop={latency:250,setup:function(data){var timer,_data=$.extend({latency:special.scrollstop.latency},data),handler=function(evt){var _self=this,_args=arguments;timer&&clearTimeout(timer),timer=setTimeout(function(){timer=null,evt.type="scrollstop",dispatch.apply(_self,_args)},_data.latency)};$(this).bind("scroll",handler).data(uid2,handler)},teardown:function(){$(this).unbind("scroll",$(this).data(uid2))}}}); //--------------------------------------------------------------------------------------------------------------------------------- // Utils //--------------------------------------------------------------------------------------------------------------------------------- function isEventSupported(eventName,tag) { var el = document.createElement(tag); eventName = 'on' + eventName; var isSupported = (eventName in el); if (!isSupported) { el.setAttribute(eventName, 'return;'); isSupported = typeof el[eventName] == 'function'; } el = null; return isSupported; } var iAmTouchy = isEventSupported('touchstart','div'); if( iAmTouchy ){ var click_event_name = 'touchstart'; }else{ var click_event_name = 'click'; } window.mobileAndTabletcheck = function() { var check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera); return check; } var iAmMobile = mobileAndTabletcheck(); $.fn.goTo = function() { $('html, body').animate({ scrollTop: $(this).offset().top + 'px' }, 'fast'); return this; // for chaining... } Number.prototype.nf = function( decimals ) { var nStr = this.toFixed( decimals ) + ''; var x = nStr.split('.'); var x1 = x[0]; var x2 = (x.length > 1)? (','+x[1]) : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + '.' + '$2'); } return x1 + x2; } Array.prototype.in_array = function( needle ) { for( var i=0; i < this.length; i++ ) { if( this[i] === needle ) { return true; } } return false; } function onlyUnique(value, index, self) { return self.indexOf(value) === index; } var date_l = new Array("Sonntag","Montag","Dienstag","Mittwoch","Donnerstag", "Freitag","Samstag"); var date_D = new Array("Son","Mon","Die","Mit","Don","Fre","Sam"); var date_F = new Array("Januar","Februar","März","April","Mai","Juni","Juli", "August","September","Oktober","November","Dezember"); var date_M = new Array("Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep", "Okt","Nov","Dez"); getDateString = function ( date, format ) { var dateparts = []; var cur_part = ''; for(var ind = 0; ind < format.length; ind++){ if( format[ind] == '#' ){ if(cur_part != ''){ dateparts.push(cur_part); cur_part = ''; } if(ind < (format.length-1)){ dateparts.push(format[ind+1]); } ind++; }else{ cur_part = cur_part+format[ind]; } } if(cur_part != ''){ dateparts.push(cur_part); cur_part = ''; } for(var ind in dateparts){ switch(dateparts[ind]) { case 'd': var j = date.getDate(); dateparts[ind] = (j < 10)? '0'+j : j; break; case 'j': dateparts[ind] = date.getDate(); break; case 'D': var w = date.getDay(); dateparts[ind] = date_D[w]; break; case 'l': var w = date.getDay(); dateparts[ind] = date_l[w]; break; case 'm': var n = date.getMonth()+1; dateparts[ind] = (n < 10)? '0'+n : n; break; case 'F': var n = date.getMonth(); dateparts[ind] = date_F[n]; break; case 'M': var n = date.getMonth(); dateparts[ind] = date_M[n]; break; case 'Y': var Y = date.getFullYear(); dateparts[ind] = Y; break; case 'H': var G = date.getHours(); dateparts[ind] = (G < 10)? '0'+G : G; break; case 'i': var i = date.getMinutes(); dateparts[ind] = (i < 10)? '0'+i : i; break; case 's': var s = date.getSeconds(); dateparts[ind] = (s < 10)? '0'+s : s; break; case 'y': var y = ''+date.getFullYear(); dateparts[ind] = y.substring(2); break; case 'n': var n = date.getMonth()+1; dateparts[ind] = n; break; case 'G': var G = date.getHours(); dateparts[ind] = G; break; case 'N': var w = date.getDay(); dateparts[ind] = (w==0)? 7 : w; break; case 'w': dateparts[ind] = date.getDay(); break; } } var datestring = dateparts.join(''); return datestring; } function showMessage( text, time ){ document.getElementById('user_message_content').innerHTML = text; var elem = document.getElementById('user_message'); // make sure the element is visible elem.style.display = "block"; elem.className = 'visible'; if( time ){ setTimeout( hideMessage, time ); } } function hideMessage(){ var elem = document.getElementById('user_message'); elem.className = 'hidden'; setTimeout( function(){ // if the message hasn't been reopened in the meantime, hide it completely after the fading out is done if(elem.className == 'hidden'){ this.elem.style.display = "none"; } }.bind({elem: elem}), 1000 ); } function urlFriendly( s ){ s = s.replace(/ä/gi,'ae').replace(/ö/gi,'oe').replace(/ü/gi,'ue').replace('ß','ss'); s = (''+s).toLowerCase(); s = s.replace(/(\/|:)/g,' ').replace(':',' '); s = s.replace(/\s+/g, '-'); s = s.replace(/[^a-z0-9-]/g,''); s = s.replace(/-+/g, '-'); return s; } //--------------------------------------------------------------------------------------------------------------------------------- // Elements //--------------------------------------------------------------------------------------------------------------------------------- var Elem = Class.extend({ /** * Creates an Elem Object * because the value that will be used as the element's id is not necessarily unique, * the custom attribute data-id will be used * * @param tag * @param id * @param elem */ init : function ( tag, id, elem ) { if( elem ){ this.element = elem; }else{ this.element = document.createElement( tag ); } this.element.setAttribute( 'data-id', id ); this.intervalID = false; this.timer_class; this.content; this.id = id; }, /** * get the content of the element. Usually the inner HTML (but not necessarily) */ getContent : function(){ return this.content; }, /** * get the HTML element of this Elem Object */ getElement : function(){ return this.element; }, /** * get the Id (the data-id attribute) of the HTML element */ getId : function(){ return this.id; }, /** * update the content of this element. Per default the inner HTML will be overwritten. * * @returns {Boolean} true if the content was changed. Otherwise false. * * @param content */ update : function( content ){ if(this.content && this.content != content){ this.element.innerHTML = content; this.content = content; return true; } return false; }, /** * remove this element */ removeElement : function(){ this.element.parentNode.removeChild( this.element ); }, /** * test if the HTML element has a given class name * * @param class_name * * @returns {Boolean} true, if the element has the given class, otherwise false */ hasClass : function( class_name ){ var class_names = this.element.className.split(/\s+/); if( class_names.indexOf(class_name) > -1 ){ return true; } return false; }, /** * add a given class name to the HTML element. * * @param class_name */ addClass : function( class_name ){ if( this.element.className.indexOf(class_name) > -1){ return; } new_class_name = this.element.className; if( new_class_name ){ new_class_name += ' '; } new_class_name += class_name; this.element.className = new_class_name; }, /** * remove a given class name from the HTML element * * @param class_name */ removeClass : function( class_name ){ var changed = false; var class_names = this.element.className.split(/\s+/); var new_class_name = ''; for( var i = 0; i < class_names.length; i++ ) { if (!class_names[i]){ continue; } if( class_names[i] != class_name ) { if( new_class_name ){ new_class_name += ' '; } new_class_name += class_names[i]; } else { changed = true; } } if( changed ) { this.element.className = new_class_name; } }, /** * remove a set of class names from the HTML element * * @param class_names */ removeClasses : function( class_names ){ for ( var i = 0; i < class_names.length; i++ ) { this.removeClass( class_names[i] ); } }, /** * swap one class name (or a set of class names) for another * * @param from_class * @param to_class */ swapClass : function( from_class, to_class ){ var class_names = this.element.className.split(/\s+/); var new_class_names = ""; var changed = false; if( from_class.constructor === Array ){ for( var i = 0; i < class_names.length; i++ ) { if( !class_names[i] || class_names[i] == to_class || from_class.indexOf(class_names[i]) > -1 ){ continue; }else{ new_class_names = new_class_names + class_names[i] + " "; } } }else{ for( var i = 0; i < class_names.length; i++ ) { if( !class_names[i] || class_names[i] == to_class || class_names[i] == from_class ){ continue; }else{ new_class_names = new_class_names + class_names[i] + " "; } } } new_class_names = new_class_names + to_class; this.element.className = new_class_names; }, /** * add a class for a certain length of time * * @param class_name * @param seconds */ addTimedClass : function( class_name, seconds ){ this.stopTimedClass(); this.addClass( class_name ); this.timer_class = class_name; this.intervalID = window.setInterval( function() { this.stopTimedClass(); }.bind( this ), seconds * 1000 ); }, /** * remove the timed class from the HTML element */ stopTimedClass : function(){ if( this.intervalId != false ){ this.removeClass( this.timer_class ); window.clearInterval( this.intervalID ); this.intervalID = false; } } }); var StockTimeUpdateElem = Elem.extend({ init : function( id, stock_id, format, date, elem ){ this._super( 'span', id, elem ); this.format = format; this.date = date; var datestring = getDateString(date, this.format); this.content = datestring; tdfUM.registerStockElement(this, stock_id, null, 't'); if( !elem ){ this.element.innerHTML = this.content; } }, update : function( date ) { if( this.date.getTime() != date.getTime() ){ this.date = date; var datestring = getDateString(date, this.format); this.content = datestring; this.element.innerHTML = this.content; } } }); var StockUpdateElem = Elem.extend({ init : function( id, stock_id, type, number, digits, prefix, postfix, showSignum, defaultValue, boundary, elem ){ this._super( 'span', id, elem ); this.prefix = prefix this.postfix = postfix; this.digits = digits; this.showSignum = showSignum; this.boundary = boundary; number = parseFloat(number); if( !isNaN(number) ){ this.number = number; if( this.number >= 0 && this.showSignum ){ this.content = "+" + this.prefix + this.number.nf( this.digits ) + this.postfix; }else{ this.content = '' +this.prefix + this.number.nf( this.digits ) + this.postfix; } }else{ this.number = - Number.MAX_VALUE; this.content = defaultValue; } if( !elem ){ this.container.innerHTML = this.content; } tdfUM.registerStockElement(this, stock_id, boundary, type); }, update : function( number ) { var changed = false; number = parseFloat(number); if ( !isNaN(number) ) { if ( number > this.number ) { this.addTimedClass( 'up', 0.8 ); changed = true; } else if ( number < this.number ) { this.addTimedClass( 'down', 0.8 ); changed = true; } this.number = number; if( this.number >= 0 && this.showSignum ){ this.content = "+" + this.prefix + this.number.nf( this.digits ) + this.postfix; }else{ this.content = '' + this.prefix + this.number.nf( this.digits ) + this.postfix; } this.element.innerHTML = this.content; } return changed; }, getValue : function(){ return this.number; } }); var RadarBox = Elem.extend({ init : function ( id, elem, type, ajax ){ this._super( 'section', id, elem ); this.is_getting = false; var items = $('#'+id+' .radar-update-item'); this.update_items = {}; for( var i = 0; i < items.length; i++){ var signal = (items[i]).getAttribute('data-id'); var type = (items[i]).getAttribute('data-type'); if(signal && type){ if( this.update_items.hasOwnProperty(signal) ){ this.update_items[signal].push({'element':items[i],'type':type}); }else{ this.update_items[signal] = [{'element':items[i],'type':type}]; } } } if( !type ){ type = 'all'; } this.radar = type; this.select_list = $('#'+id+' select.radar-list'); this.select_time = $('#'+id+' select.radar-time'); this.link_items; if(ajax){ this.link_items = $('#'+id+' .radar-link-item'); this.select_list.on('change',{'self' : this},function( event ){ event.data.self.getRadar( ); // and change urls of all link items var select = $(this); var list_id = select.val(); var list_slug = select.find('option:selected').attr('data-slug');; var replace = list_id+'-'+list_slug; event.data.self.link_items.each(function(){ this.href = this.href.replace(/[0-9]+-[a-z0-9-]+/,replace); }) }); if( this.select_time ){ this.select_time.on('change',{'self' : this},function( event ){ event.data.self.getRadar( ); }); } } this.periodical = setInterval( this.getRadar.bind(this), 30000 ); }, getRadar : function(){ if( this.is_getting ){ setTimeout(this.getRadar.bind(this),200); return; } this.is_getting = true; list_id = this.select_list.val(); var data = { 'list_id' : list_id }; if( this.type ){ data['type'] = this.type; } if( this.select_time ){ data['time'] = this.select_time.val(); } var self = this; $.ajax( { type: 'POST', url: base+"ajax/getRadar.php", dataType: "text", data: data, self: self, success: function( transport ){ try{ if( transport.length > 0 && transport != "stop" ){ var data = JSON.parse( transport ); // will work for IE8+ for ( var id in data ){ if(this.self.update_items.hasOwnProperty(id)){ var items = this.self.update_items[id]; for( var i = 0; i < items.length; i++ ){ if( items[i].type == 'amount' ){ items[i].element.innerHTML = data[id]['amount']; }else if( items[i].type == 'track' ){ items[i].element.innerHTML = data[id]['track']; }else if( items[i].type == 'right' ){ items[i].element.innerHTML = Math.round(data[id]['right'])+"%"; } } } } } } catch(err){} this.self.is_getting = false; }, error: function(jqXHR, textStatus, errorThrown){ this.self.is_getting = false; } } ) ; } }); var IndexSignalTicker = Elem.extend({ init : function ( id, elem, type, signals, ajax ){ this._super( 'section', id, elem ); this.is_getting = false; if( !type ){ type = 'all'; } this.type = type; this.signal_table = new SignalOverviewTable('insert_'+id, signals, 'register', 'time', 'desc', true); this.select_list = $('#'+id+' select.signal-list'); if(ajax){ this.select_list.on('change',{'self' : this},function( event ){ event.data.self.getSignals( ); }); } this.periodical = setInterval( this.getSignals.bind(this), 30000 ); }, getSignals : function(){ if( this.is_getting ){ setTimeout(this.getSignals.bind(this),200); return; } this.is_getting = true; list_id = this.select_list.val(); var data = { 'template_id' : list_id }; if( this.type ){ data['type'] = this.type; } if( this.select_time ){ data['time'] = this.select_time.val(); } var self = this; $.ajax( { type: 'POST', url: base+"ajax/getWingman.php", dataType: "text", data: data, self: self, success: function( transport ){ try{ if( transport.length > 0 && transport != "stop" ){ var data = JSON.parse( transport ); // will work for IE8+ var changed = false; // delete outdated signals for( var i = this.self.signal_table.rowIDs.length-1; i >= 0; i--){ if( !data.hasOwnProperty(''+this.self.signal_table.rowIDs[i]) ){ this.self.signal_table.removeRow(this.self.signal_table.rowIDs[i]); } } // add new signals for ( var id in data ){ if ( typeof data[id] == 'object' && this.self.signal_table.rowIDs.indexOf(id) < 0 ){ this.self.signal_table.insertDataAsRow( data[id] ); changed = true; } } if(changed){ var sorted = this.self.signal_table.doSort(); var chart_rows = []; for(var i = 0; i < sorted.length; i++){ if(sorted[i][0]){ var id = sorted[i][0]; if( data.hasOwnProperty(''+id) ){ chart_rows.push(data[id]); if(chart_rows.length > 1){ break; } } } } if( chart_rows.length > 0 ){ $(this.self.element).trigger('signal:new', chart_rows); } } } } catch(err){ } this.self.is_getting = false; }, error: function(jqXHR, textStatus, errorThrown){ this.self.is_getting = false; } } ) ; } }); var compare_search_first = null; var compare_selected = true; var stock_compare_element; var stock_compare_id_element; var FinanceChartUpdateElem = Elem.extend({ init : function( id, default_settings, settings, style, elem, load_div, use_storage, has_short_controls, has_long_controls ){ this._super( 'img', id, elem ); this.default_settings = default_settings; this.settings = settings; this.load_div = load_div; if( this.load_div ){ $(this.element).on('load',{'load_div':load_div}, function(event){ event.data.load_div.style.display = 'none'; }); } this.style = style; // short controls this.has_short_controls = has_short_controls; this.short_time_controls; // long controls this.has_long_controls = has_long_controls; this.controls; this.updateButtons; this.storeButtons; this.resetButtons; this.is_resetting = false; this.use_storage = use_storage; this.has_unstored_changes = false; this.addShortControls(); this.addLongControls(); }, addShortControls : function(){ if( !this.has_short_controls ){ return; } var self = this; // Short Menu with only different time ranges to chose from this.short_time_controls = $('.'+this.id+'-menu.short-menu button.chart-control'); this.short_time_controls.each(function(){ // make sure the control element has the correct value var value = this.getAttribute("data-value"); if( ( self.settings.hasOwnProperty('time_range') && self.settings['time_range'] == value ) || ( !self.settings.hasOwnProperty('time_range') && self.default_settings.hasOwnProperty('time_range') && self.default_settings['time_range'] == value ) ){ if( !$(this).hasClass('active') ){ $(this).addClass('active'); } }else{ $(this).removeClass('active'); } // add functionality $(this).click({chart : self}, function(event){ if( !$(this).hasClass('active') ){ event.data.chart.short_time_controls.each(function(){ $(this).removeClass('active'); }); var value = this.getAttribute("data-value"); $(this).addClass('active'); var changed = false; if(event.data.chart.controls){ event.data.chart.controls.each(function(){ var chart_control = $(this); var name = chart_control.attr("name"); if( name == 'time_range' ){ chart_control.val(value); chart_control.change(); changed = true; } }); } if(!changed){ // when there is no time_range control that could handle the // parameter change, make sure the parameter is set event.data.chart.setParam('time_range',value,true); } } }); }); }, addLongControls : function(){ // elaborate menu with all controls if( !this.has_long_controls ){ return; } var self = this; this.controls = $('.'+this.id+'-menu.long-menu .chart-control'); this.controls.each(function(){ // make sure the control element has the correct value var chart_control = $(this); var name = this.getAttribute("name"); var type = ( this.tagName.toLowerCase() == 'input' && this.type.toLowerCase() == 'checkbox' )? 'checkbox' : 'input'; var value = (type == 'checkbox')? chart_control.is(":checked") : chart_control.val(); if( self.settings.hasOwnProperty(name) && self.settings[name] != value ){ if( type == 'checkbox' ){ chart_control.click(); }else{ chart_control.val(self.settings[name]); chart_control.change(); } }else if(!self.settings.hasOwnProperty(name) && self.default_settings.hasOwnProperty(name) && self.default_settings[name] != value ){ if( type == 'checkbox' ){ chart_control.click(); }else{ chart_control.val(self.default_settings[name]); chart_control.change(); } } // add functionality if( name == 'time_range' && self.has_short_controls ){ $(this).change({chart : self}, function(event){ var chart_control = $(this); var value = chart_control.val(); var do_update = !chart_control.hasClass('no-update'); event.data.chart.setParam('time_range',value,do_update); event.data.chart.storeSettings(); if(event.data.chart.short_time_controls) { event.data.chart.short_time_controls.each(function(){ var val = this.getAttribute("data-value"); $(this).removeClass('active'); if( val == value ){ $(this).addClass('active'); } }); } }); }else if( name == 'upper_indicator' ){ $(this).change({chart : self}, function(event){ var chart_control = $(this); var value = chart_control.val(); var do_update = !chart_control.hasClass('no-update'); event.data.chart.setParam('upper_indicator',value,false); var upper1 = {}; var upper2 = {} if( value == 'None' ){ upper1 = {'value':'','disabled':true}; upper2 = {'value':'','disabled':true}; }else if( value == 'BB' ){ upper1 = {'value':'20','disabled':false}; upper2 = {'value':'2','disabled':false}; }else if( value == 'DC' ){ upper1 = {'value':'20','disabled':false}; upper2 = {'value':'','disabled':true}; }else if( value == 'Envelop' ){ upper1 = {'value':'20','disabled':false}; upper2 = {'value':'0.1','disabled':false}; } if(event.data.chart.controls){ event.data.chart.controls.each(function(){ var name = this.getAttribute('name'); if( name == 'upper_indicator1' ){ this.value = upper1['value']; this.disabled = upper1['disabled']; event.data.chart.setParam('upper_indicator1',upper1['value'],false); }else if( name == 'upper_indicator2' ){ this.value = upper2['value']; this.disabled = upper2['disabled']; event.data.chart.setParam('upper_indicator2',upper2['value'],false); } }); } event.data.chart.storeSettings(); if(do_update){ event.data.chart.update(); } }); }else{ $(this).change({chart : self}, function(event){ var chart_control = $(this); var name = chart_control.attr("name"); var value = chart_control.val(); var do_update = !chart_control.hasClass('no-update'); if( this.tagName.toLowerCase() == 'input' && this.type.toLowerCase() == 'checkbox' ){ value = chart_control.is(":checked"); } event.data.chart.setParam(name,value,do_update); event.data.chart.storeSettings(); }); } }); // store checkboxes (toggle between using storage and not using it) this.storeButtons = $('.'+this.id+'-store'); this.storeButtons.each(function(){ var chart_control = $(this); // make sure the control element has the correct value var value = chart_control.is(":checked"); if( value != self.use_storage ){ chart_control.click(); } chart_control.change({chart : self}, function(event){ var chart_control = $(this); var name = chart_control.attr("name"); var value = chart_control.is(":checked"); event.data.chart.use_storage = value; event.data.chart.setParam(name,value); event.data.chart.storeSettings(); }); }); // reset buttons this.resetButtons = $('.'+this.id+'-reset'); this.resetButtons.each(function(){ $(this).click({chart : self}, function(event){ if( event.data.chart.is_resetting ){ return; } // deactivate all clear buttons event.data.chart.is_resetting = true; // set all control buttons to their default value event.data.chart.controls.each(function(){ var chart_control = $(this); var name = this.getAttribute("name"); var type = ( this.tagName.toLowerCase() == 'input' && this.type.toLowerCase() == 'checkbox' )? 'checkbox' : 'input'; var value = (type == 'checkbox')? chart_control.is(":checked") : chart_control.val(); if(event.data.chart.default_settings.hasOwnProperty(name) && event.data.chart.default_settings[name] != value ){ if( type == 'checkbox' ){ chart_control.click(); }else{ chart_control.val(self.default_settings[name]); chart_control.change(); } event.data.chart.setParam(name,event.data.chart.default_settings[name],false,false) } }); // repaint event.data.chart.update(); // delete settings event.data.chart.is_resetting = false; }); }); // add autocomplete functionality for the stock compare element stock_compare_element = $("#stock_compare"); stock_compare_id_element = $("#stock_compare_id"); if( stock_compare_element.length && stock_compare_id_element.length ){ stock_compare_element.autocomplete( { minLength: 0, appendTo: $("#chart_menu"), source: function( request, response ) { if( request.term.length > 1 ){ $.ajax( { url: base+"ajax/searchStocks.php", dataType: "json", data: { term: request.term }, success: function( data ) { response( data ); } } ) ; }else{ this.close(); stock_compare_id_element.val(''); stock_compare_id_element.change(); compare_search_first = null; } }, focus: function(event, ui) { if( iAmTouchy ){ compare_selected = true; compare_search_first = null; stock_compare_element.val(ui.item.name); stock_compare_element.change(); stock_compare_id_element.val(ui.item.id); stock_compare_id_element.change(); this.close(); } // prevent autocomplete from updating the textbox event.preventDefault(); }, response: function(event, ui){ compare_selected = false; if( typeof ui == 'object' && ui.hasOwnProperty('content') && ui.content.length > 0 ){ compare_search_first = ui.content[0]; }else{ compare_search_first = null; } }, select: function( event, ui ) { compare_selected = true; compare_search_first = null; stock_compare_element.val(ui.item.name); stock_compare_element.change(); stock_compare_id_element.val(ui.item.id); stock_compare_id_element.change(); } }).data("ui-autocomplete")._renderItem = function(ul, item) { var $a = $(""); $("").text(" ").appendTo($a); $("").text(item.name).appendTo($a); $("").text(item.wkn+",").appendTo($a); $("").text(item.source).appendTo($a); return $("
  • ").append($a).appendTo(ul); }; stock_compare_element.focus(function() { if( iAmTouchy && Math.abs(window.orientation) == 90 ){ // JQuery's test for landscape $(this).goTo(); } $(this).select(); } ); } // buttons to update the chart this.updateButtons = $('.'+this.id+'-update'); if( stock_compare_element.length && stock_compare_id_element.length ){ this.updateButtons.each(function(){ $(this).click({chart : self}, function(event){ event.preventDefault(); if( compare_selected === false ){ if( compare_search_first !== null && compare_search_first !== undefined ){ stock_compare_element.val(compare_search_first.name); stock_compare_element.change(); stock_compare_id_element.val(compare_search_first.id); stock_compare_id_element.change(); compare_selected = true; compare_search_first = null; }else{ stock_compare_element.val(""); stock_compare_element.change(); stock_compare_id_element.val(""); stock_compare_id_element.change(); } } event.data.chart.storeSettings(); event.data.chart.update(); return false; }); }); }else{ this.updateButtons.each(function(){ $(this).click({chart : self}, function(event){ event.preventDefault(); event.data.chart.storeSettings(); event.data.chart.update(); return false; }); }); } }, getValue : function(){ if( this.style == 'dark' ){ var url = base+'img/finance-chart-dark.php?'; }else if( this.style == 'signal' ){ var url = base+'img/signal.php?'; }else{ var url = base+'img/finance-chart.php?'; } if( this.settings.hasOwnProperty('width') ){ var width = this.settings['width']; if( this.settings['width'] == 'auto'){ width = 1.5 * this.element.parentNode.offsetWidth; } url = url + "width=" + width + "&"; if( this.settings.hasOwnProperty('height') ){ var height = this.settings['height']; if( this.settings['height'] == 'auto' ){ height = 1.5 * this.element.parentNode.offsetHeight; }else if( this.settings['height'] < 1 ){ height = this.settings['height'] * width; } url = url + "height=" + height + "&"; } } for( id in this.settings ){ if( id != 'width' && id != 'height' ){ url = url + id + "=" + this.settings[id] + "&"; } } var time = new Date().getTime(); url = url + 'time=' + time; return url; }, setParam : function(key, value, do_update, show_load_div){ if( (this.settings && this.settings.hasOwnProperty(key) && this.settings[key] != value) || !this.settings || !this.settings.hasOwnProperty(key) ){ this.settings[key] = value; this.has_unstored_changes = true; if(show_load_div){ this.load_div.style.display = 'block'; } if(do_update){ this.update(); } } }, update : function( ){ var src = this.getValue(); this.element.setAttribute("src", src); }, getImage : function(){ return this.element; }, unbindLoadEvents : function(){ var element = $(this.element); element.unbind('load'); if( this.load_div ){ element.on('load',{'load_div':this.load_div}, function(event){ event.data.load_div.style.display = 'none'; }); } }, storeSettings : function(){ if( !this.has_unstored_changes ){ return; } if( this.use_storage ){ // json encode the settings and store them saveSettingsVar('chart_settings', JSON.stringify(this.settings)); }else{ var stored_settings = {'chart_settings_store' : false}; saveSettingsVar('chart_settings', JSON.stringify(stored_settings)); } this.has_unstored_changes = false; }, resetSettings : function(){ } }); var UpdateManager = Elem.extend({ init : function () { this.table_counter = 0; this.tables = {}; this.table_types = {}; this.tabs = {}; this.stock_periodical; this.stock_is_getting = false; this.stock_cnt = 0; this.stocks_to_update = {}; this.stocks_update_string = ''; // charts are only going to be updated one by one, never all at once. // loading of one image will trigger the loading of the next. // if after several seconds the image has not finished loading, the next image // will be loaded. this.chart_periodical; this.chart_is_getting = false; this.chart_load_abort = false; this.charts = []; this.charts_current = 0; this.time_periodical; this.time_elements = []; }, registerTimeElement : function ( obj, format ) { this.time_elements.push( {'obj' : obj, 'format' : format} ); }, startTimePeriodical : function () { this.time_periodical = setInterval( this.updateTimeElements.bind(this), 1000 ); }, updateTimeElements : function () { var date = new Date(); for( var ind in this.time_elements ){ var row = this.time_elements[ind]; if( typeof row == 'object' ){ if(row.hasOwnProperty('obj') && row.hasOwnProperty('format')){ var datestring = getDateString(date, row.format); // 'l H:i' row.obj.innerHTML = datestring; } } } }, registerTab : function ( insert_id, tab ){ if( this.tabs.hasOwnProperty(insert_id) ){ return; } this.tabs[ insert_id ] = tab; }, setTabData : function ( insert_id, data) { if( !this.tabs.hasOwnProperty(insert_id) ){ return; } this.tabs[insert_id].setData( data ); }, openTab : function ( insert_id, tab ){ if( !this.tabs.hasOwnProperty(insert_id) ){ return; } this.tabs[insert_id].openTab( tab ); }, getTabData : function( insert_id ){ if( !this.tabs.hasOwnProperty(insert_id) ){ return null; } return this.tabs[insert_id].getData(); }, registerTable : function ( insert_id, table, type ){ if( this.tables.hasOwnProperty(insert_id) ){ return; } this.tables[ insert_id ] = table; this.table_types[ insert_id ] = type; // add table sorting functionality $('#'+insert_id+' thead button.sort').click(function(e) { var button_elem = $(this); var insert_id = button_elem.attr('data-table'); var sort_by = button_elem.attr('data-sort'); var pref_order = button_elem.attr('data-order'); var table = tdfUM.tables[insert_id]; table.toggleSort(sort_by, pref_order); }); }, clearTable : function ( insert_id ) { if( !this.tables.hasOwnProperty( insert_id ) ){ return; } var table = this.tables[insert_id]; var type = this.table_types[insert_id]; table.clear(); if( type == 'stock' || type == 'event' ){ var stocks_to_update = this.stocks_to_update for( var stock_id in stocks_to_update ){ var update_items = stocks_to_update[stock_id]; for( var i = (update_items.length - 1); i >= 0 ; i-- ){ if( update_items[i].t == insert_id ){ update_items.splice(i,1); } } if( update_items.length == 0 ){ delete stocks_to_update[stock_id]; }else{ stocks_to_update[stock_id] = update_items; } } this.stocks_to_update = stocks_to_update; this.recalcStocksUpdateString(); } }, updateTable : function ( insert_id, data ){ if( !this.tables.hasOwnProperty( insert_id ) ){ return; } table = this.tables[ insert_id ]; table.update( data ); }, setActiveRow : function ( insert_id, row ){ if( !this.tables.hasOwnProperty( insert_id ) ){ return; } this.tables[insert_id].setActiveRow( row ); }, registerStockTR : function ( stock_id, table_id, row_id, boundary, type, id ){ // updates for value/perf if( !stock_id || !table_id || !this.tables.hasOwnProperty( table_id ) ){ return; } if( !row_id ){ row_id = stock_id; } if( !boundary ){ boundary = 0; } if( !type ){ type = ['v','p']; } if(!id){ id = table_id+"_"+stock_id; } if( this.stocks_to_update.hasOwnProperty(stock_id) ){ this.stocks_to_update[stock_id].push( { 't' : table_id, 'r' : row_id, 'bnd' : boundary, 'u' : type, 'id' : id } ); }else{ this.stocks_to_update[stock_id] = [ { 't' : table_id, 'r' : row_id, 'bnd' : boundary, 'u' : type, 'id' : id } ]; } }, deRegisterStockTR : function( stock_id, table_id, row_id ){ if( !stock_id || !table_id || !row_id ){ return; } if( this.stocks_to_update.hasOwnProperty(stock_id) ){ var update_items = this.stocks_to_update[stock_id]; for( var i = (update_items.length - 1); i >= 0; i-- ){ if( update_items[i].t == table_id && update_items[i].r == row_id ){ update_items.splice(i,1); } } this.stocks_to_update[stock_id] = update_items; } }, registerStockElement : function ( obj, stock_id, boundary, type, id ){ if( !stock_id ){ return; } if(!id){ id = stock_id+"_"+type; } var update_elem = {'bnd' : boundary, 'id' : id}; update_elem[type] = obj; if( this.stocks_to_update.hasOwnProperty(stock_id) ){ this.stocks_to_update[stock_id].push( update_elem ); }else{ this.stocks_to_update[stock_id] = [ update_elem ]; } }, deregisterStockElement : function ( stock_id, id ){ if(this.stocks_to_update.hasOwnProperty(stock_id)){ var update_items = this.stocks_to_update[stock_id]; for( var i = 0; i < update_items.length; i++ ){ if( update_items[i].id == id ){ update_items.splice(i,1); i--; } } if( update_items.length == 0 ){ delete this.stocks_to_update[stock_id]; }else{ this.stocks_to_update[stock_id] = update_items; } } }, recalcStocksUpdateString : function() { var stocks_update_string = ''; for( var stock_id in this.stocks_to_update ){ stocks_update_string += ','+stock_id; } this.stocks_update_string = stocks_update_string.substring(1); }, startStockPeriodical : function() { this.stock_periodical = setInterval( this.getStockQuotes.bind(this), 1000 ); }, resetStockCounter : function(){ this.stock_cnt = 0; }, getStockQuotes : function() { if(this.stock_is_getting){ return; } if( this.stocks_update_string == '' ){ this.recalcStocksUpdateString(); } this.stock_is_getting = true; var self = this; $.ajax( { type: 'POST', url: base+"ajax/getOverviewQuotes.php", dataType: "text", data: { cnt: self.stock_cnt, ids: self.stocks_update_string }, event_manager : self, success: function( transport ){ try{ if ( transport != "stop" ) { if( transport.length > 0 ){ data = JSON.parse( transport ); // will work for IE8+ var changed_tables = {}; for ( var id in data ) { if ( typeof data[id] == 'object' ) { // get tables containing this stock, if( !this.event_manager.stocks_to_update.hasOwnProperty( id ) ){ continue; } var updateRows = this.event_manager.stocks_to_update[id]; for( var i in updateRows ){ var date = new Date( data[id].t * 1000 ); var to_class = null; var from_class = null; if( updateRows[i].hasOwnProperty('bnd') ){ if( data[id].p > updateRows[i].bnd ){ to_class = 'pos'; from_class = ['neg','neut']; }else if( data[id].p < updateRows[i].bnd ){ to_class = 'neg'; from_class = ['pos','neut']; }else{ to_class = 'neut'; from_class = ['neg','pos']; } } if( updateRows[i].hasOwnProperty('t') && updateRows[i].hasOwnProperty('r') ){ // this is a stock in a table row, update the respective table var t = updateRows[i].t; var r = updateRows[i].r; if( !this.event_manager.tables.hasOwnProperty(t) ){ continue; } var t_obj = this.event_manager.tables[t]; if( updateRows[i].hasOwnProperty('u') ){ if( updateRows[i].u.indexOf('a') > -1 ){ t_obj.setCellValue( r, 'ask', data[id].a, from_class, to_class ); t_obj.setCellValue( r, 'asksize', data[id].as ); } if( updateRows[i].u.indexOf('b') > -1 ){ t_obj.setCellValue( r, 'bid', data[id].b, from_class, to_class ); t_obj.setCellValue( r, 'bidsize', data[id].bs ); } if( updateRows[i].u.indexOf('d') > -1 ){ // difference between some base value and the current stock value if(t_obj.setCellValue( r, 'dif', data[id].v )){ changed_tables[t] = true; }; } if( updateRows[i].u.indexOf('v') > -1 ){ if(t_obj.setCellValue( r, 'value', data[id].v, from_class, to_class )){ changed_tables[t] = true; } } if( updateRows[i].u.indexOf('p') > -1 ){ if(t_obj.setCellValue( r, 'perf', data[id].p, from_class, to_class )){ changed_tables[t] = true; } } if( updateRows[i].u.indexOf('c') > -1 ){ if( from_class && to_class ){ t_obj.setCellValue( r, 'class', data[id].p, from_class, to_class ) } } } } else{ if( updateRows[i].hasOwnProperty('p') ){ // this is an HTML Element that requires performance updates. var elem = updateRows[i].p; elem.update( data[id].p ); if(from_class && to_class){ elem.swapClass( from_class, to_class ); } }else if( updateRows[i].hasOwnProperty('v') ){ // this is an HTML Element that requires value updates. var elem = updateRows[i].v; elem.update( data[id].v ); if(from_class && to_class){ elem.swapClass( from_class, to_class ); } }else if( updateRows[i].hasOwnProperty('a') ){ // this is an HTML Element that requires ask updates. var elem = updateRows[i].a; elem.update( data[id].a ); }else if( updateRows[i].hasOwnProperty('b') ){ // this is an HTML Element that requires bid updates. var elem = updateRows[i].b; elem.update( data[id].b ); }else if( updateRows[i].hasOwnProperty('as') ){ // this is an HTML Element that requires asksize updates. var elem = updateRows[i].as; elem.update( data[id].as ); }else if( updateRows[i].hasOwnProperty('bs') ){ // this is an HTML Element that requires asksize updates. var elem = updateRows[i].bs; elem.update( data[id].bs ); }else if( updateRows[i].hasOwnProperty('t') ){ // this is an HTML Element that requires time updates var elem = updateRows[i].t; elem.update(date); } } } } } for(var t in changed_tables){ t_obj = this.event_manager.tables[t]; var sort_by = t_obj.getSortBy(); if( sort_by && ( sort_by == 'perf' || sort_by == 'value' || sort_by == 'ask' || sort_by == 'bid' || sort_by == 'dif' ) ){ t_obj.doSort(); } } } this.event_manager.stock_cnt++; } }catch(err){} this.event_manager.stock_is_getting = false; }, error: function(jqXHR, textStatus, errorThrown){ this.event_manager.stock_is_getting = false; } } ) ; }, registerChartTR : function(insert_id, row_id, obj){ if( !this.tables.hasOwnProperty( insert_id ) ){ return; } this.charts.push( { 't' : insert_id, 'r' : row_id, 'e' : obj } ); }, registerChartElement : function(id, obj){ this.charts.push( { 'id' : id, 'e' : obj } ); }, setGlobalChartParam : function( key, value, show_load_div ){ this.stopChartPeriodical(); for( var ind in this.charts ){ var row = this.charts[ind]; if( typeof row == 'object' && row.hasOwnProperty('e') && typeof row.e == 'object' ){ row.e.setParam(key, value, false, show_load_div); } } this.startChartPeriodical(); this.updateCharts(); }, removeChartTR : function(insert_id, row_id){ if( !this.tables.hasOwnProperty( insert_id ) ){ return; } for( var i = 0; i < this.charts.length; i++ ){ if( this.charts[i].t == insert_id && this.charts[i].r == row_id ){ this.charts.splice(i,1); break; } } }, removeChartElement : function (id){ for( var i = 0; i < this.charts.length; i++ ){ if( this.charts[i].id == id ){ this.charts.splice(i,1); break; } } }, removeAllCharts : function(){ this.charts = []; this.charts_current = 0; }, startChartPeriodical : function(){ this.chart_load_abort = false; this.chart_periodical = setInterval( this.updateCharts.bind(this), 30000 ); }, stopChartPeriodical : function(){ this.chart_load_abort = true; window.clearInterval( this.chart_periodical ); this.charts_current = 0; this.chart_periodical = null; this.chart_is_getting = false; for( var ind in this.charts ){ var row = this.charts[ind]; if( typeof row == 'object' && row.hasOwnProperty('e') && typeof row.e == 'object' ){ row.e.unbindLoadEvents(); } } /*// abort current image requests if(window.stop !== undefined){ window.stop(); }else if(document.execCommand !== undefined){ document.execCommand("Stop", false); }*/ }, updateCharts : function(){ if( this.chart_is_getting ){ return; } this.chart_is_getting = true; // go over all charts and update them this.charts_current = 0; this.loadChart( 0 ); }, loadChart : function( i ){ // stop loading if: // - image updates are being stopped // - this image has already been updated (may happen if one images takes // a long time to load, causing the next chart to begin loading prematurely) // - the list has finished updating // if( this.chart_load_abort === true || this.charts_current > i || i >= this.charts.length ){ this.chart_is_getting = false; return; } this.charts_current = i+1; // update the image if( this.charts[i].hasOwnProperty('t') && this.charts[i].hasOwnProperty('r') ){ var img = this.charts[i].e; $(img).one('load', { 'self' : this, 'i' : i }, function( event ){ event.data.self.loadChart( event.data.i+1 ); }); var t_obj = this.tables[ this.charts[i].t ]; t_obj.setCellValue( this.charts[i].r, 'chart', 'redraw' ); } else if(this.charts[i].hasOwnProperty('e')){ // get the update information var elem = this.charts[i].e; var img = elem.getImage(); // add one time event so that the update process will continue once the image is loaded $(img).one('load', { 'self' : this, 'i' : i }, function( event ){ event.data.self.loadChart( event.data.i+1 ); }); elem.update(); } // if loading takes too long, load the next one setTimeout(function(){ if( this.self.charts_current == this.i ){ // this image has not finished loading yet this.self.loadChart( this.i+1 ); } }.bind( { 'self': this, 'i' : i } ), 1500); }, }); var tdfUM = new UpdateManager(); //--------------------------------------------------------------------------------------------------------------------------------- // Tab definitions //--------------------------------------------------------------------------------------------------------------------------------- // currently only available in register mode // will also store content and menu items as JQuery Objects for easier event management var Tab = Elem.extend({ init : function( id, data, global_data ){ this._super( 'div', id, document.getElementById( id ) ); this.data = data; this.global_data = global_data; // get menu elements this.tab_menu_items = {} var menu_items = $('#'+id+' .tabs-menu-title'); for( var i = 0; i < menu_items.length; i++ ){ var elem = $(menu_items[i]); var content_id = elem.attr('data-content-id'); this.tab_menu_items[ content_id ] = elem; } // get content elements this.tab_content_items = {} var content_items = $('#'+id+' .tabs-content-item'); for( var i = 0; i < content_items.length; i++ ){ var elem = $(content_items[i]); var content_id = elem.attr('id'); var content_type = elem.attr('data-type'); /* if( content_type == 'img-holder' ){ var content_item = new ImageTabContent( content_id, elem, data, global_data, $(this.element) ); }else{ var content_item = new TabContent( content_id, elem, data, global_data, $(this.element) ); }*/ var content_item = new TabContent( content_id, elem, data, global_data, $(this.element) ); this.tab_content_items[ content_id ] = content_item; } // add open and close events this.addEvents(); }, addEvents : function(){ for( content_id in this.tab_menu_items ){ var menu_item = this.tab_menu_items[content_id]; menu_item.click( {'self' : this}, function( event ){ // as an object, tab is passed in by reference var button_elem = $(this); if( button_elem.is('.hover') ) { // do nothing, there will always be one tab content visible return; } // get the tab Object if( !event.data.hasOwnProperty('self') ){ return; } var self = event.data.self; // get the id of the new active tab var new_content_id = button_elem.attr('data-content-id'); // deactivate active tabs for( content_id in self.tab_menu_items ){ if( self.tab_menu_items[content_id].is('.hover') ){ self.tab_menu_items[content_id].removeClass('hover'); self.tab_content_items[content_id].close() } } // activate new tab button_elem.addClass('hover'); self.tab_content_items[new_content_id].open(); }); } }, setData : function( data ){ if( !data.hasOwnProperty('id') || this.data['id'] == data['id'] ){ return; } this.data = data; for( content_id in this.tab_content_items ){ this.tab_content_items[content_id].setData( data ); } }, getData : function(){ return this.data; }, openTab : function( id ){ if( this.tab_menu_items.hasOwnProperty( id ) ){ this.tab_menu_items[id].click(); } } }); // based on JQuery elements (this class is mainly used for event handling). Only available in register mode // this class is responsible for updating the var TabContent = Class.extend({ init : function( id, elem, data, global_data, tab ){ this.id = id; this.element = elem; this.data = data; this.global_data = global_data; this.tab = tab; this.focus = false; if( (window[this.global_data]).hasOwnProperty('focus') && (window[this.global_data]['focus']).length > 0 ){ var focus = $('#'+window[this.global_data]['focus']); if(focus){ this.focus = focus; } } }, open : function(){ this.element.fadeIn(300).addClass('open'); /*if(this.focus){ this.focus.goTo(); }*/ }, close : function(){ this.element.css('display','none').removeClass('open'); }, setData : function( data ){ this.data = data; }, }); //--------------------------------------------------------------------------------------------------------------------------------- // Table definitions //--------------------------------------------------------------------------------------------------------------------------------- var TD = Elem.extend({ init : function ( id, elem ){ this._super( 'td', id, elem ); }, }); var TR = Elem.extend({ init : function ( id, elem ){ this._super( 'tr', id, elem ); this.cells = {}; }, insert : function( td, mode ){ if( mode != "register" ){ this.element.appendChild( td.getElement() ); } var id = td.getId(); this.cells[id] = td; }, clear : function(){ for ( var i in this.cells ) { this.cells[i].removeElement(); } this.cells = {}; }, hasCell : function( i ){ return this.cells.hasOwnProperty( '' + i ); }, getCellValue : function( i ){ return this.cells[i].getValue(); }, getSortValue : function( i ) { return this.cells[i].getSortValue(); }, setCellValue : function( i, value, from_class, to_class ) { if( from_class && to_class ){ this.cells[i].swapClass( from_class, to_class ); } return this.updateCellValue( i, value ); }, updateCellValue : function( i, value ) { return this.cells[i].update( value ); }, appendMyselfTo : function( parent ){ parent.appendChild( this.element ); }, insertMyselfBefore : function( parent, i ){ parent.insertBefore( this.element, parent.rows[i] ); }, removeMyself : function(){ this.clear(); this.removeElement(); } }); var MultiTR = Class.extend({ init : function ( id, num_rows, elems ){ this.rows = {}; this.num_rows = num_rows this.id = id; if( elems && elems.length == num_rows ){ for( var i = 0; i < this.num_rows; i++ ){ var tr = new TR( this.id + "_row" + i, elems[i] ); this.rows[this.id + "_row" + i] = tr; } }else{ for( var i = 0; i < this.num_rows; i++ ){ var tr = new TR( this.id + "_row" + i, null ); this.rows[this.id + "_row" + i] = tr; } } }, getElement : function(){ var elements = []; for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; elements.push(tr.getElement()); } return elements; }, getId : function(){ return this.id; }, addClass : function( class_name ){ for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; tr.addClass( class_name ); } }, removeClass : function( class_name ){ for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; tr.removeClass( class_name ); } }, removeClasses : function( class_names ){ for ( var i = 0; i < class_names.length; i++ ) { this.removeClass( class_names[i] ); } }, swapClass : function( from_class, to_class ){ this.removeClass(from_class); this.addClass(to_class); }, insert : function( td, row, mode ){ this.rows[this.id + "_row" + row].insert( td, mode ); }, clear : function(){ for ( var i in this.rows ) { this.rows[i].clear(); } this.rows = {}; }, getCellValue : function( i ){ for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; if( tr.hasCell( i ) ){ return tr.getCellValue( i ); } } return null; }, getSortValue : function( i ) { for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; if( tr.hasCell( i ) ){ return tr.getSortValue( i ); } } return null; }, setCellValue : function( i, value, from_class, to_class ) { if( !from_class ){ from_class = null; } if( !to_class ){ to_class = null; } for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; if( tr.hasCell( i ) ){ return tr.setCellValue( i, value ); } } return false; }, updateCellValue : function( i, value ) { for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; if( tr.hasCell( i ) ){ return tr.updateCellValue( i, value ); } } return false; }, appendMyselfTo : function( parent ){ for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; tr.appendMyselfTo( parent ); } }, insertMyselfBefore : function( parent, i ){ for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; tr.insertMyselfBefore( parent, parent.rows[i*this.num_rows] ); } }, removeMyself : function(){ for( var j = 0; j < this.num_rows; j++ ){ var tr = this.rows[this.id + "_row" + j]; tr.removeMyself( ); } } }); var Table = Elem.extend({ init : function( id, doInsertBefore, sort_by, sort_order, header, footer, row_cluster_size, rows ){ if( doInsertBefore ){ this.doInsertBefore = true; }else{ this.doInsertBefore = false; } this.activeRow = null; this.tbody = null; this.rowIDs = new Array(); this.rows = {}; this.sort_by = sort_by; this.sort_order = sort_order; var table_container = document.getElementById( id ); if( !table_container ){ return; } if( !row_cluster_size ){ this.row_cluster_size = 1; }else{ this.row_cluster_size = row_cluster_size; } mode = 'insert'; elem = null; // confirm mode and get table element if possible var children = table_container.children; for( i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'table' ){ elem = children[i]; mode = 'register'; break; } } this._super( 'table', id, elem ); // insert header, tbody, and footer if( mode == 'insert' ){ table_container.appendChild( this.element ); if(header){ this.element.appendChild( header ); } this.tbody = document.createElement( 'tbody' ); this.element.appendChild( this.tbody ); if(footer){ this.element.appendChild( footer ); } }else{ // get the body element var children = this.element.children; for( i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'tbody' ){ this.tbody = children[i]; } } if( !this.tbody ){ this.tbody = document.createElement( 'tbody' ); this.element.appendChild( this.tbody ); } } this.insertRows( rows, mode ); }, hasRow : function( id ){ if( this.rowIDs.indexOf( id ) < 0 ){ return false; } return true; }, insertRows : function( rows, mode ){ // isnert rows if( this.row_cluster_size == 1 ){ if( mode == 'register' ){ var children = this.tbody.children; for( var i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'tr' ){ var row_elem = children[i]; var id = row_elem.getAttribute('data-id'); var row = ( rows.hasOwnProperty(id) )? rows[id] : null; this.registerDataAsRow( row, row_elem ); } } }else{ for( var id in rows ){ this.insertDataAsRow( rows[id] ); } } }else{ if( mode == 'register' ){ var children = this.tbody.children; var multi_elem = new Array(); var j = 0; for( var i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'tr' ){ var row_elem = children[i]; var id_parts = ( row_elem.getAttribute('data-id') ).split('_'); if( id_parts.length < this.row_cluster_size ){ this.tbody.removeChild(row_elem); }else{ if( j < (this.row_cluster_size - 1) ){ multi_elem.push( row_elem ); j++; }else{ multi_elem.push( row_elem ); var row = ( rows.hasOwnProperty(id_parts[0]) )? rows[id_parts[0]] : null; this.registerDataAsRow( row, multi_elem ); var multi_elem = new Array(); j = 0; } } } } }else{ for( var id in rows ){ this.insertDataAsRow(rows[id]); } } } }, insertRow : function( tr, mode ){ if( mode != "register" ){ if( this.doInsertBefore ){ tr.insertMyselfBefore( this.tbody, this.tbody.firstChild ); }else{ tr.appendMyselfTo( this.tbody ); } } this.rows[tr.getId()] = tr; this.rowIDs[this.rowIDs.length] = tr.getId(); }, removeRow : function( tr_id ) { var index = this.rowIDs.indexOf( tr_id ); if( index > -1 ){ this.rows[tr_id].removeMyself(); delete this.rows[tr_id]; this.rowIDs.splice(index, 1); } }, clear : function() { this.tbody.innerHTML = ""; this.rows = {}; this.rowIDs = new Array(); }, getBodyElement : function() { return this.tbody; }, setCellValue : function( tr_id, cell, value, from_class, to_class ) { if ( this.rows[tr_id] == undefined ) { return false; } else { return this.rows[tr_id].setCellValue( cell, value, from_class, to_class ); } }, getCellValue : function( tr_id, cell ){ if ( this.rows[tr_id] == undefined ) { return null; } else { return this.rows[tr_id].getCellValue( cell ); } }, getSortValue : function( tr_id, cell ){ if ( this.rows[tr_id] == undefined ) { return null; } else { return this.rows[tr_id].getSortValue( cell ); } }, getRow : function( tr_id ){ if ( this.rows[tr_id] == undefined ) { return null; } else { return this.rows[tr_id]; } }, getSortOrder : function(){ return this.sort_order; }, getSortBy : function(){ return this.sort_by; }, setSort : function( sort_by, sort_order ) { this.sort_by = sort_by; this.sort_order = sort_order; }, toggleSort : function( col, pref_order ) { var alternative_order = (pref_order === 'asc')? 'desc' : 'asc'; var order = pref_order; if( col === this.sort_by && this.sort_order === pref_order ){ order = alternative_order; } this.setSort( col, order ); this.doSort(); }, doSort : function() { if( !this.sort_by ){ return; } if ( this.rows.length < 2 ) { return; } var sorted = []; for ( var tr_id in this.rows ) { sorted.push( [tr_id, this.rows[tr_id].getSortValue( this.sort_by )] ); } if ( this.sort_order == 'desc' ) { sorted.sort( function(a, b) { var result = 0; if ( a[1] < b[1] ) { result = 1; } if ( a[1] > b[1] ) { result = -1; } return result; } ); } else { sorted.sort( function(a, b) { var result = 0; if ( a[1] < b[1] ) { result = -1; } if ( a[1] > b[1] ) { result = 1; } return result; } ); } var tr_id, i = 0; for ( var j in sorted ) { if ( typeof sorted[j] == 'object' ) { tr_id = sorted[j][0]; this.rows[tr_id].insertMyselfBefore( this.tbody, i ); this.rows[tr_id].removeClass( i%2==1 ? 'odd' : 'even' ); this.rows[tr_id].addClass( i%2==1 ? 'even' : 'odd' ); i++; } } return sorted; }, setActiveRow : function( id ){ if(this.activeRow && this.rows.hasOwnProperty( this.activeRow )){ // inactivate last row this.rows[ this.activeRow ].removeClass('hover'); } if(this.rows.hasOwnProperty( id )){ this.rows[ id ].addClass('hover'); this.activeRow = id; } }, registerDataAsRow : function( row, row_elem ){ if( row && typeof row == 'object' ){ mode = row_elem? 'register' : 'insert'; var tr = new TR( row.id, row_elem ); this.insertRow(tr, mode); }else if( row_elem ){ this.tbody.removeChild(row_elem); } }, insertDataAsRow : function( row ){ this.registerDataAsRow( row, null ); } }); // Special Table cells //--------------------------------------------------------------------------------------------------------------------------------- var SortableTD = TD.extend({ init : function( id, content, sortContent, elem ){ this._super( id, elem ); this.content = content; this.sortContent = sortContent; if( !elem ){ this.element.innerHTML = this.content; } }, getValue : function(){ return this.content; }, getSortValue : function() { if( typeof this.sortContent === 'string'){ return this.sortContent.toLowerCase(); } return this.sortContent; } }); var HighlightTD = TD.extend({ init : function( id, number, digits, prefix, postfix, showSignum, useContainer, defaultValue, boundary, elem, abs_sort ){ this._super( id, elem ); // get the container where the numerical content will be displayed. This is // necessary because table cells cannot be positioned as relative without it // messing up the appearance of borders. Pseudo elements like before or after // which are used to display up or down arrows for values or performances will // need to be positioned absolute with regards to a span element that contains // the cell's actual content. if( useContainer ){ if(elem){ var children = this.element.children; for( var i = 0; i < children.length; i++){ if( children[i].tagName.toLowerCase() == 'span' ){ this.container = children[i]; break; } } }else{ this.container = document.createElement( 'span' ); this.element.appendChild(this.container); } }else{ this.container = this.element; } this.prefix = prefix; this.postfix = postfix; this.digits = digits; this.showSignum = showSignum; this.boundary = boundary; this.abs_sort = (abs_sort)? true : false; number = parseFloat(number); if( !isNaN(number) ){ this.number = number; if( this.number >= 0 && this.showSignum ){ this.content = "+" + this.prefix + this.number.nf( this.digits ) + this.postfix; }else{ this.content = '' + this.prefix + this.number.nf( this.digits ) + this.postfix; } }else{ this.number = - Number.MAX_VALUE; this.content = defaultValue; } if( !elem ){ this.container.innerHTML = this.content; } }, update : function( number ) { var changed = false; number = parseFloat(number); if ( !isNaN(number) ) { if ( number > this.number ) { this.addTimedClass( 'up', 0.8 ); changed = true; } else if ( number < this.number ) { this.addTimedClass( 'down', 0.8 ); changed = true; } if( changed ){ this.number = number; if( this.number >= 0 && this.showSignum ){ this.content = "+" + this.prefix + this.number.nf( this.digits ) + this.postfix; }else{ this.content = '' + this.prefix + this.number.nf( this.digits ) + this.postfix; } this.container.innerHTML = this.content; } } return changed; }, getValue : function() { return this.number; }, getSortValue : function() { if(this.abs_sort){ return Math.abs(this.number); }else{ return this.number; } } }); var NumberTD = TD.extend({ init : function( id, number, digits, prefix, postfix, showSignum, useContainer, defaultValue, elem ){ this._super( id, elem ); // get the container where the numerical content will be displayed. This is // necessary because table cells cannot be positioned as relative without it // messing up the appearance of borders. Pseudo elements like before or after // which are used to display up or down arrows for values or performances will // need to be positioned absolute with regards to a span element that contains // the cell's actual content. if( useContainer ){ if(elem){ this.container = this.element; // fallback in case the cell does not contain a span var children = this.element.children; for( i = 0; i < children.length; i++){ if( children[i].tagName.toLowerCase() == 'span' ){ this.container = children[i]; break; } } }else{ this.container = document.createElement( 'span' ); this.element.appendChild(this.container); } }else{ this.container = this.element; } this.prefix = prefix; this.postfix = postfix; this.digits = digits; this.showSignum = showSignum; number = parseFloat(number); if( !isNaN(number) ){ this.number = number; if( this.number >= 0 && this.showSignum ){ this.content = "+" + this.prefix + this.number.nf( this.digits ) + this.postfix; }else{ this.content = '' + this.prefix + this.number.nf( this.digits ) + this.postfix; } }else{ this.number = - Number.MAX_VALUE; this.content = defaultValue; } if( !elem ){ this.container.innerHTML = this.content; } }, update : function( number ) { var changed = false; number = parseFloat(number); if ( !isNaN(number) ) { if ( number > this.number || number < this.number ) { changed = true; } this.number = number; if( this.number >= 0 && this.showSignum ){ this.content = "+" + this.number.nf( this.digits ) + this.postfix; }else{ this.content = '' + this.number.nf( this.digits ) + this.postfix; } this.container.innerHTML = this.content; } return changed; }, getValue : function() { return this.number; }, getSortValue : function() { return this.number; } }); var ButtonTD = TD.extend({ init : function( id, hover_text, btn_class, func, func_data, elem ){ this._super( id, elem ); if( !elem ){ this.button = document.createElement( 'button' ); this.button.innerHTML = ""; this.button.className = btn_class; this.button.title = hover_text; this.element.appendChild(this.button); $(this.button).click(func_data, func); }else{ // get the body element var children = this.element.children; for( i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'button' ){ this.button = children[i]; break; } } if( !this.button ){ this.button = document.createElement( 'button' ); this.button.innerHTML = ""; this.button.className = btn_class; this.element.appendChild(this.button); } $(this.button).click(func_data, func); } this.content = this.element.innerHTML; }, getValue : function(){ return this.content; }, getSortValue : function() { if( typeof this.sortContent === 'string'){ return this.sortContent.toLowerCase(); } return this.sortContent; } }); var ArticleTD = TD.extend({ init : function( id, time, footer, header, body, elem, header_class ){ this._super( id, elem ); this.sortContent = time; if(footer){ footer = footer.replace('#base#',base); footer = ''; } if(header){ header_class = (header_class)? ' class="'+header_class+'"' : ''; header = header.replace('#base#',base); header = ''+header+''; } if(body){ body = '

    '+body+'

    '; } body = body.replace('#base#',base); this.content = '
    '+footer+header+body+'
    '; if( !elem ){ this.element.innerHTML = this.content; } }, getValue : function(){ return this.content; }, getSortValue : function() { return this.sortContent; } }); var DifferenceTD = TD.extend({ init : function( id, base, value, showSignum, defaultValue, elem, abs_sort ){ this._super( id, elem ); this.showSignum = showSignum; this.base = parseFloat(base); this.value = parseFloat(value); this.abs_sort = (abs_sort)? true : false; if( !isNaN(this.base) && this.base != 0 && !isNaN(this.value) ){ this.difference = 100 * ( (this.value / this.base) - 1 ); if( this.difference >= 0 && this.showSignum ){ this.content = "+" + this.difference.nf( 2 ) + "%"; }else{ this.content = "" + this.difference.nf( 2 ) + "%"; } }else{ this.difference = 0; this.content = defaultValue; } if( !elem ){ this.element.innerHTML = this.content; } }, update : function( number ){ var changed = false; number = parseFloat(number); if ( !isNaN(this.base) && this.base != 0 && !isNaN(number) ) { var difference = 100 * ( (number / this.base) - 1 ); if ( Math.abs(difference) > Math.abs(this.difference) ) { this.addTimedClass( 'down', 0.8 ); changed = true; } else if ( Math.abs(difference) < Math.abs(this.difference) ) { this.addTimedClass( 'up', 0.8 ); changed = true; } if( changed ){ this.difference = difference; if( this.difference >= 0 && this.showSignum ){ this.content = "+" + this.difference.nf( 2 ) + "%"; }else{ this.content = "" + this.difference.nf( 2 ) + "%"; } this.element.innerHTML = this.content; } } return changed; }, getValue : function() { return this.difference; }, getSortValue : function() { if(this.abs_sort){ return Math.abs(this.difference); }else{ return this.difference; } } }); var DifferenceSortTD = TD.extend({ init : function( id, base, value, defaultValue, elem, abs_sort ){ this._super( id, elem ); this.base = parseFloat(base); this.value = parseFloat(value); this.abs_sort = (abs_sort)? true : false; if( isNaN(this.value) ){ this.difference = 0; this.content = defaultValue; }else{ this.content = this.value; if( !isNaN(this.base) ){ this.difference = this.value - this.base; }else{ this.difference = 0; } } if( !elem ){ this.element.innerHTML = this.content; } }, update : function( number ){ var changed = false; number = parseFloat(number); if( !isNaN(number) && number != this.value ){ this.value = number; this.content = this.value; if( !isNaN(this.base) ){ this.difference = this.value - this.base; } this.element.innerHTML = this.content; changed = true; } return changed; }, getValue : function() { return this.difference; }, getSortValue : function() { if(this.abs_sort){ return Math.abs(this.difference); }else{ return this.difference; } } }); var DateTimeTD = TD.extend({ init : function( id, time, format, default_val, elem ){ this._super( id, elem ); if( format ){ this.format = format; }else{ this.format = '#d.#m. #H:#i Uhr' } if( time ){ this.date = new Date(time); this.sortContent = this.date.getTime(); this.content = getDateString( this.date, this.format ); }else{ this.date = null; this.sortContent = -1; this.content = default_val; } if( !elem ){ this.element.innerHTML = this.content; } }, update : function( time ){ if( !time ){ return false; } this.date = new Date(time); this.sortContent = this.date.getTime(); this.content = getDateString( this.date, this.format ); this.element.innerHTML = this.content; }, getValue : function(){ return this.content; }, getSortValue : function() { return this.sortContent; } }); var SignalChartTD = TD.extend({ init : function( id, signal_id, signal_raw, alt, elem ){ this._super( id, elem ); this.signal_id = signal_id; this.signal_raw = signal_raw; this.alt = alt; this.content = ''; if( elem ){ // get the image element var children = this.element.children; for( i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'div' ){ this.container = children[i]; children = this.container.children for( i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'img' ){ this.img = children[i]; break; } } break; } } } if( !this.container ){ this.container = document.createElement("div"); this.element.appendChild( this.container ); } if( !this.img ){ this.img = document.createElement("img"); this.img.setAttribute("alt", alt); this.img.setAttribute("src", ''); this.container.appendChild( this.img ); } }, getURL : function(){ var time = new Date().getTime(); var width = 1.5 * this.container.offsetWidth; var height = 0.5 * width; return base+"img/signal.php?signal_id="+this.signal_id+"&signal_raw="+this.signal_raw+"&width="+width+"&height="+height+"&title=N&height_adj=Y&time="+time; }, update : function( ){ var src = this.getURL(); this.img.setAttribute("src", src); this.updated = true; return true; }, getValue : function(){ return this.img; } }); var BoundaryTD = TD.extend({ init : function( id, number, left, right, elem ){ this._super( id, elem ); this.number = parseFloat(number); this.left = parseFloat(left); this.right = parseFloat(right); this.in_boundary = true; if( !isNaN(this.number) ){ if( !isNaN(this.number) && !isNaN(this.left) && this.number < this.left ){ this.in_boundary = false; this.addClass('outside'); } if( !isNaN(this.number) && !isNaN(this.right) && this.number > this.right ){ this.in_boundary = false; this.addClass('outside'); } } if( this.in_boundary ){ this.removeClass('outside'); } if( !elem ){ this.element.innerHTML = ''; } }, update : function( number ) { var changed = false; number = parseFloat(number); if ( !isNaN(number) ) { if( number != this.number ){ this.number = number; changed = true; this.in_boundary = true; if( !isNaN(this.number) ){ if( !isNaN(this.number) && !isNaN(this.left) && this.number < this.left ){ this.in_boundary = false; this.addClass('outside'); } if( !isNaN(this.number) && !isNaN(this.right) && this.number > this.right ){ this.in_boundary = false; this.addClass('outside'); } } if( this.in_boundary ){ this.removeClass('outside'); } } } return changed; }, getValue : function() { return this.in_boundary; }, getSortValue : function() { if(this.in_boundary){ return 1; }else{ return 0; } } }); // Special Table rows //--------------------------------------------------------------------------------------------------------------------------------- var SignalFunctionTR = TR.extend({ init : function( signal_id, elem, insert_id, signal_name, signal_raw, name, name_content, isin, value, perf, func ){ this._super( signal_id, elem ); var cells = {'signal' : null, 'name' : null, 'perf' : null}; mode = 'insert'; if( elem ){ mode = 'register'; var children = this.element.children; for( var i = 0; i < children.length; i++ ){ if( children[i].tagName.toLowerCase() == 'td' ){ var cell_id = children[i].getAttribute("data-id"); cells[ cell_id ] = children[i]; } } } var signal_td = new SortableTD( 'signal', signal_name, signal_name, cells['name'] ); this.insert( signal_td, mode ); var name_td = new SortableTD( 'name', name_content, name, cells['name'] ); this.insert( name_td, mode ); var perf_td = new HighlightTD( 'perf', perf, 2, '', '%', true, true, '-', 0, cells['perf'] ); this.insert( perf_td, mode ); if( !elem ){ perf_td.addClass( 'perf' ); } $(this.element).click( {'signal_id': signal_id, 'name_content': name_content, 'signal_raw' : signal_raw, 'table' : insert_id}, func ); } }); // Special Tables //--------------------------------------------------------------------------------------------------------------------------------- var SignalFunctionTable = Table.extend({ init : function( insert_id, header, footer, mode, rows, sort_by, sort_order, func ){ this.func = func; // create and register table this._super( insert_id, false, sort_by, sort_order, header, footer, 1, rows ); tdfUM.registerTable( insert_id, this, 'stock' ); if( this.rowIDs ){ this.activeRow = this.rowIDs[0]; } this.doSort(); }, registerDataAsRow : function( row, row_elem ){ if( row && typeof row == 'object' ){ mode = row_elem? 'register' : 'insert'; var tr = new SignalFunctionTR( row.signal_id, row_elem, this.id, row.signal_name, row.signal_raw, row.stock_name, row.name_content, row.isin, row.value, row.perf, this.func ); this.insertRow(tr, mode); tdfUM.registerStockTR( row.id, this.id, row.id, 0, 'p' ); }else if( row_elem ){ this.tbody.removeChild(row_elem); } }, })