diff options
Diffstat (limited to 'jarmon/jarmon.js')
-rw-r--r-- | jarmon/jarmon.js | 329 |
1 files changed, 268 insertions, 61 deletions
diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 1dda6a8..6177853 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -27,6 +27,206 @@ if(typeof jarmon == 'undefined') { var jarmon = {}; } +// A VBScript and Javascript helper function to convert IE responseBody to a +// byte string. +// http://miskun.com/javascript/internet-explorer-and-binary-files-data-access/ +var IEBinaryToArray_ByteStr_Script = + "<!-- IEBinaryToArray_ByteStr -->\r\n"+ + "<script type='text/vbscript'>\r\n"+ + "Function IEBinaryToArray_ByteStr(Binary)\r\n"+ + " IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+ + "End Function\r\n"+ + "Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+ + " Dim lastIndex\r\n"+ + " lastIndex = LenB(Binary)\r\n"+ + " if lastIndex mod 2 Then\r\n"+ + " IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+ + " Else\r\n"+ + " IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+ + " End If\r\n"+ + "End Function\r\n"+ + "</script>\r\n"; +document.write(IEBinaryToArray_ByteStr_Script); + +jarmon.GetIEByteArray_ByteStr = function(IEByteArray) { + if(typeof(jarmon.ByteMapping) == 'undefined') { + jarmon.ByteMapping = {}; + for ( var i = 0; i < 256; i++ ) { + for ( var j = 0; j < 256; j++ ) { + jarmon.ByteMapping[ String.fromCharCode( i + j * 256 ) ] = + String.fromCharCode(i) + String.fromCharCode(j); + } + } + } + + var rawBytes = IEBinaryToArray_ByteStr(IEByteArray); + var lastChr = IEBinaryToArray_ByteStr_Last(IEByteArray); + return rawBytes.replace(/[\s\S]/g, + function( match ) { return jarmon.ByteMapping[match]; }) + lastChr; +}; + +/* + * BinaryFile over XMLHttpRequest + * Part of the javascriptRRD package + * Copyright (c) 2009 Frank Wuerthwein, fkw@ucsd.edu + * MIT License [http://www.opensource.org/licenses/mit-license.php] + * + * Original repository: http://javascriptrrd.sourceforge.net/ + * + * Based on: + * Binary Ajax 0.1.5 + * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, + * http://blog.nihilogic.dk/ + * MIT License [http://www.opensource.org/licenses/mit-license.php] + */ + +// ============================================================ +// Exception class +jarmon.InvalidBinaryFile = function(msg) { + this.message=msg; + this.name="Invalid BinaryFile"; +}; + +// pretty print +jarmon.InvalidBinaryFile.prototype.toString = function() { + return this.name + ': "' + this.message + '"'; +}; + +// ===================================================================== +// BinaryFile class +// Allows access to element inside a binary stream +jarmon.BinaryFile = function(strData, iDataOffset, iDataLength) { + + var data = strData; + var dataOffset = iDataOffset || 0; + var dataLength = 0; + // added + var doubleMantExpHi=Math.pow(2,-28); + var doubleMantExpLo=Math.pow(2,-52); + var doubleMantExpFast=Math.pow(2,-20); + + if (typeof strData == "string") { + dataLength = iDataLength || data.length; + } else { + throw new jarmon.InvalidBinaryFile( + "Unsupported type " + (typeof strData)); + } + + this.getRawData = function() { + return data; + }; + + this.getByteAt = function(iOffset) { + return data.charCodeAt(iOffset + dataOffset) & 0xFF; + }; + + this.getLength = function() { + return dataLength; + }; + + this.getSByteAt = function(iOffset) { + var iByte = this.getByteAt(iOffset); + if (iByte > 127) + return iByte - 256; + else + return iByte; + }; + + this.getShortAt = function(iOffset) { + var iShort = ( + this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset); + if (iShort < 0) iShort += 65536; + return iShort; + }; + this.getSShortAt = function(iOffset) { + var iUShort = this.getShortAt(iOffset); + if (iUShort > 32767) + return iUShort - 65536; + else + return iUShort; + }; + this.getLongAt = function(iOffset) { + var iByte1 = this.getByteAt(iOffset), + iByte2 = this.getByteAt(iOffset + 1), + iByte3 = this.getByteAt(iOffset + 2), + iByte4 = this.getByteAt(iOffset + 3); + + var iLong = (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1; + if (iLong < 0) iLong += 4294967296; + return iLong; + }; + this.getSLongAt = function(iOffset) { + var iULong = this.getLongAt(iOffset); + if (iULong > 2147483647) + return iULong - 4294967296; + else + return iULong; + }; + this.getStringAt = function(iOffset, iLength) { + var aStr = []; + for (var i=iOffset,j=0;i<iOffset+iLength;i++,j++) { + aStr[j] = String.fromCharCode(this.getByteAt(i)); + } + return aStr.join(""); + }; + + // Added + this.getCStringAt = function(iOffset, iMaxLength) { + var aStr = []; + for (var i=iOffset,j=0;(i<iOffset+iMaxLength) && + (this.getByteAt(i)>0);i++,j++) { + aStr[j] = String.fromCharCode(this.getByteAt(i)); + } + return aStr.join(""); + }; + + // Added + this.getDoubleAt = function(iOffset) { + var iByte1 = this.getByteAt(iOffset), + iByte2 = this.getByteAt(iOffset + 1), + iByte3 = this.getByteAt(iOffset + 2), + iByte4 = this.getByteAt(iOffset + 3), + iByte5 = this.getByteAt(iOffset + 4), + iByte6 = this.getByteAt(iOffset + 5), + iByte7 = this.getByteAt(iOffset + 6), + iByte8 = this.getByteAt(iOffset + 7); + var iSign=iByte8 >> 7; + var iExpRaw=((iByte8 & 0x7F)<< 4) + (iByte7 >> 4); + var iMantHi=((((((iByte7 & 0x0F) << 8) + iByte6) << 8) + iByte5) << 8) + iByte4; + var iMantLo=((((iByte3) << 8) + iByte2) << 8) + iByte1; + + if (iExpRaw==0) return 0.0; + if (iExpRaw==0x7ff) return undefined; + + var iExp=(iExpRaw & 0x7FF)-1023; + + var dDouble = ((iSign==1)?-1:1)*Math.pow(2,iExp)*(1.0 + iMantLo*doubleMantExpLo + iMantHi*doubleMantExpHi); + return dDouble; + }; + // added + // Extracts only 4 bytes out of 8, loosing in precision (20 bit mantissa) + this.getFastDoubleAt = function(iOffset) { + var iByte5 = this.getByteAt(iOffset + 4), + iByte6 = this.getByteAt(iOffset + 5), + iByte7 = this.getByteAt(iOffset + 6), + iByte8 = this.getByteAt(iOffset + 7); + var iSign=iByte8 >> 7; + var iExpRaw=((iByte8 & 0x7F)<< 4) + (iByte7 >> 4); + var iMant=((((iByte7 & 0x0F) << 8) + iByte6) << 8) + iByte5; + + if (iExpRaw==0) return 0.0; + if (iExpRaw==0x7ff) return undefined; + + var iExp=(iExpRaw & 0x7FF)-1023; + + var dDouble = ((iSign==1)?-1:1)*Math.pow(2,iExp)*(1.0 + iMant*doubleMantExpFast); + return dDouble; + }; + + this.getCharAt = function(iOffset) { + return String.fromCharCode(this.getByteAt(iOffset)); + }; +}; jarmon.downloadBinary = function(url) { /** @@ -34,39 +234,38 @@ jarmon.downloadBinary = function(url) { * * @method downloadBinary * @param url {String} The url of the object to be downloaded - * @return {Object} A deferred which will callback with an instance of javascriptrrd.BinaryFile + * @return {Object} A deferred which will callback with an instance of + * javascriptrrd.BinaryFile */ var d = new MochiKit.Async.Deferred(); - $.ajax({ - _deferredResult: d, url: url, dataType: 'text', - cache: false, - beforeSend: function(request) { - try { - request.overrideMimeType('text/plain; charset=x-user-defined'); - } catch(e) { - // IE doesn't support overrideMimeType - } + mimeType: 'text/plain; charset=x-user-defined', + xhr: function() { + // Save a reference to the native xhr object - we need it later + // in IE to access the binary data from responseBody + this._nativeXhr = jQuery.ajaxSettings.xhr(); + return this._nativeXhr; }, - success: function(data) { - try { - this._deferredResult.callback(new BinaryFile(data)); - } catch(e) { - this._deferredResult.errback(e); + success: function(data, textStatus, jqXHR) { + // In IE we return the responseBody + if(typeof(this._nativeXhr.responseBody) != 'undefined') { + d.callback( + new jarmon.BinaryFile( + jarmon.GetIEByteArray_ByteStr( + this._nativeXhr.responseBody))); + } else { + d.callback(new jarmon.BinaryFile(data)); } }, error: function(xhr, textStatus, errorThrown) { - // Special case for IE which handles binary data slightly - // differently. - if(textStatus == 'parsererror') { - if (typeof xhr.responseBody != 'undefined') { - return this.success(xhr.responseBody); - } - } - this._deferredResult.errback(new Error(xhr.status)); + d.errback(new Error(xhr.status)); + }, + complete: function(jqXHR, textStatus) { + this._nativeXhr = null; + delete this._nativeXhr; } }); return d; @@ -240,10 +439,10 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam var val; var timestamp = startRowTime; - for(var i=startRowIndex; i<endRowIndex; i++) { - val = rra.getEl(i, dsIndex) + for(i=startRowIndex; i<endRowIndex; i++) { + val = rra.getEl(i, dsIndex); flotData.push([timestamp*1000.0, val]); - timestamp += step + timestamp += step; } // Now get the date of the earliest record in entire rrd file, ie that of @@ -429,7 +628,7 @@ jarmon.Chart = function(template, recipe, downloader) { 2: 'M', 3: 'G', 4: 'T' - } + }; var si = 0; while(true) { if( Math.pow(1000, si+1)*0.9 > axis.max ) { @@ -446,7 +645,7 @@ jarmon.Chart = function(template, recipe, downloader) { var stepSize, decimalPlaces = 0; for(var i=0; i<stepSizes.length; i++) { - stepSize = stepSizes[i] + stepSize = stepSizes[i]; if( realStep < stepSize ) { if(stepSize < 10) { decimalPlaces = 2; @@ -460,7 +659,7 @@ jarmon.Chart = function(template, recipe, downloader) { } var tickMin = minVal - minVal % stepSize; - var tickMax = maxVal - maxVal % stepSize + stepSize + var tickMax = maxVal - maxVal % stepSize + stepSize; var ticks = []; for(var j=tickMin; j<=tickMax; j+=stepSize) { @@ -543,7 +742,7 @@ jarmon.Chart.prototype.setTimeRange = function(startTime, endTime) { this.startTime = startTime; this.endTime = endTime; return this.draw(); -} +}; jarmon.Chart.prototype.draw = function() { /** @@ -698,8 +897,8 @@ jarmon.RrdChooser.prototype.drawRrdUrlForm = function() { value: this.data.rrdUrl }) ), - $('<input/>', {type: 'submit', value: 'download'}), - $('<div/>', {class: 'next'}) + $('<input/>', {'type': 'submit', value: 'download'}), + $('<div/>', {'class': 'next'}) ) ).submit( function(e) { @@ -738,7 +937,7 @@ jarmon.RrdChooser.prototype.drawRrdUrlForm = function() { return false; } ).appendTo(this.$tpl); -} +}; jarmon.RrdChooser.prototype.drawDsLabelForm = function() { var self = this; @@ -772,7 +971,7 @@ jarmon.RrdChooser.prototype.drawDsLabelForm = function() { } ), $('<input/>', {type: 'submit', value: 'save'}), - $('<div/>', {class: 'next'}) + $('<div/>', {'class': 'next'}) ).submit( function(e) { self.data.dsLabel = this['dsLabel'].value; @@ -931,7 +1130,7 @@ jarmon.ChartEditor.prototype._extractRowValues = function($row) { function(i, el) { return el.value; } - ) + ); }; @@ -1044,7 +1243,7 @@ jarmon.TabbedInterface = function($tpl, recipe) { 'value': $originalLink.text(), 'name': 'editTabTitle', 'type': 'text' - }) + }); $originalLink.replaceWith($input); $input.focus(); } @@ -1060,7 +1259,7 @@ jarmon.TabbedInterface = function($tpl, recipe) { $('<a/>', { href: ['#', this.value].join('') }).text(this.value) - ) + ); self.setup(); self.$tabBar.data("tabs").click(this.value); } @@ -1114,7 +1313,7 @@ jarmon.buildTabbedChartUi = function ($chartTemplate, chartRecipes, /** * Setup chart date range controls and all charts **/ - var p = new jarmon.Parallimiter(1); + var p = new jarmon.Parallimiter(2); function serialDownloader(url) { return p.addCallable(jarmon.downloadBinary, [url]); } @@ -1304,10 +1503,10 @@ jarmon.ChartCoordinator = function(ui, charts) { // Populate a list of tzoffset options if the element is present in the // template as a select list - tzoffsetEl = this.ui.find('[name="tzoffset"]'); + var tzoffsetEl = this.ui.find('[name="tzoffset"]'); if(tzoffsetEl.is('select')) { var label, val; - for(var i=-12; i<=12; i++) { + for(i=-12; i<=12; i++) { label = 'UTC'; val = i; if(val >= 0) { @@ -1389,29 +1588,37 @@ jarmon.ChartCoordinator = function(ui, charts) { // XXX: is there a better way to check for valid date? currentDate = new Date($(this).siblings(input_selector).val()); if(currentDate.getTime() != NaN) { - $(this).data('dateinput')._input_selector = input_selector; - $(this).data('dateinput')._initial_val = currentDate.getTime(); + $(this).data( + 'dateinput')._initial_val = currentDate.getTime(); $(this).data('dateinput').setValue(currentDate); break; } } }) - .bind('onHide', function(e) { - // Called after a calendar date has been chosen by the user. - - // Use the sibling selector that we generated above before opening - // the calendar - var input_selector = $(this).data('dateinput')._input_selector; - var oldStamp = $(this).data('dateinput')._initial_val; - var newDate = $(this).data('dateinput').getValue(); - // Only update the form field if the date has changed. - if(oldStamp != newDate.getTime()) { - $(this).siblings(input_selector).val( - newDate.toString().split(' ').slice(1,5).join(' ')); - // Trigger a change event which should automatically update the - // graphs and change the timerange drop down selector to - // "custom" - $(this).siblings(input_selector).trigger('change'); + .bind( + 'onHide', + {self: this}, + function(e) { + var self = e.data.self; + // Called after a calendar date has been chosen by the user. + // Use the sibling selector that we generated above + // before opening the calendar + var oldStamp = $(this).data('dateinput')._initial_val; + var newDate = $(this).data('dateinput').getValue(); + // Only update the form field if the date has changed. + if(oldStamp != newDate.getTime()) { + // Update the prepared time range select box to + // value "custom" + self.ui.find('[name="from_standard"]').val('custom'); + var from = null; + var to = null; + if($(this).hasClass('from_custom')){ + from = newDate.getTime(); + } else { + to = newDate.getTime(); + } + self.setTimeRange(from, to); + self.update(); } }); @@ -1457,7 +1664,7 @@ jarmon.ChartCoordinator.prototype.update = function() { var now = new Date().getTime(); for(var i=0; i<jarmon.timeRangeShortcuts.length; i++) { if(jarmon.timeRangeShortcuts[i][0] == selection) { - range = jarmon.timeRangeShortcuts[i][1](now); + var range = jarmon.timeRangeShortcuts[i][1](now); this.setTimeRange(range[0], range[1]); break; } @@ -1475,7 +1682,7 @@ jarmon.ChartCoordinator.prototype.update = function() { this.rangePreviewOptions.xaxis.tzoffset = tzoffset; var chartsLoading = []; - for(var i=0; i<this.charts.length; i++){ + for(i=0; i<this.charts.length; i++){ this.charts[i].options.xaxis.tzoffset = tzoffset; // Don't render charts which are not currently visible if(this.charts[i].template.is(':visible')) { @@ -1519,7 +1726,7 @@ jarmon.ChartCoordinator.prototype.update = function() { MONTH, MONTH*3, MONTH*6, YEAR]; var range = ranges.xaxis.to - ranges.xaxis.from; - for(var i=0; i<periods.length; i++) { + for(i=0; i<periods.length; i++) { if(range <= periods[i]) { i++; break; |