window['pipeline_endpoint'] = 'http://beta.api.marketwatch.com/api/livesuite/broker.asmx';window['pickup_endpoint'] = 'http://beta.api.marketwatch.com/api/livesuite/pickup.asmx';window['pipeline_license'] = '088BB296A0A3BBCCA078C6746FD79C3EFE0421F8F860805E884AB98CCCDE87D45136095A01270696DA94E3FA38777EB26B71EF1485CA2F40D39F38329EB82A85D894CDCDB1E4322CE205D25AD8D3CD972F48B8104275551E391C5C0FFBA57C256ACBA87B';
/**
* @class LiveNewsGateway manages the relationship between news updates and page control while
* applying filters to the news feed. Do not call directly. Call LiveNewsGateway.Instance()
* @type {LiveNewsGateway}
* @constructor
*/
function LiveNewsGateway ()
{
var _serviceName = "LiveNews";
var _pipeline = PipelineProtocol.GetPipeline();
var _subscriptions = new Array();
var _pendingBodyRequests = new Array();
var _storyCache = new NewsItemCollection();
var _storyCount = 0;
var _feedID = -1;
this.SubscribeToNews = SubscribeToNews;
this.ReSubscribeToNews = ReSubscribeToNews;
this.UnSubscribeToNews = UnSubscribeToNews;
this.SearchNews = SearchNews;
this.GetStory = getStoryBody;
this.GetFeedByID = GetFeedByID;
this.getStoryByID = getStoryByID;
/**
* Get a full {NewsItem} object from cache if available.
*
* @param {Guid} storyID ID of the story to retrieve
*/
function getStoryByID(storyID)
{
return _storyCache.Items[storyID];
}
/**
* @return Total count of stories received.
* @type {int}
*/
this.getStoryCount = function() { return _storyCount; }
function feedCallback(newsUpdate)
{
if (newsUpdate.Status != null)
{
if (newsUpdate.Status == "stopped")
{
for (var subIdx = 0; subIdx < _subscriptions.length; subIdx++)
{
_pipeline.subscribeToFeed(_serviceName, _subscriptions[subIdx].Criteria);
}
}
}
else
{
// Subscribe response
if (newsUpdate.headlines != null)
{
_storyCount += newsUpdate.headlines.length;
_storyCache.addHeadlines(newsUpdate.headlines);
for (var i = 0; i < _subscriptions.length; i++)
{
if (_subscriptions[i].getIsActive())
{
_subscriptions[i].OnUpdate(newsUpdate.headlines);
}
}
}
}
}
function bodyCallback(bodyUpdate)
{
var update = _storyCache.addStoryBody(bodyUpdate.Story);
_pendingBodyRequests[update.ID](update);
_pendingBodyRequests[update.ID] = null;
}
/**
* @argument {String} feedID The ID returned by the call to {SubscribeToNews}
* @type {LiveNewsSubscriber}
* @return Subscriber object for a given feed ID.
*/
function GetFeedByID(feedID)
{
for (var i = 0; i < _subscriptions.length; i++)
{
if (_subscriptions[i].ID == feedID) return _subscriptions[i];
}
return null;
}
/**
* Binds a given callback method to the news feed filtered by the input criteria. The DocGroup of the license used already provides some DocType filtering.
*
* @argument {String} subscriberName Simple name of a given subscriber
* @argument {function} updateCallback Method to invoke when news matching the criteria is received
* @argument {Object} criteria Object with the properties (valid values are DocType, Keyword, and Symbols) to be passed to the server for filtering (i.e. { "DocType":"343,106" } would limit the news sent to DocTypes 343 and 106)
* @argument {String} filter Parseable string for filtering the display on the client
* @type {int}
* @return Feed ID
*/
function SubscribeToNews(subscriberName, updateCallback, criteria)
{
var feedID = _pipeline.subscribeToFeed(_serviceName, new function() { this.criteria = criteria });
var newSubscriber = new LiveNewsSubscriber(subscriberName, criteria, feedID, updateCallback);
_subscriptions.push(newSubscriber);
return newSubscriber;
}
/**
* Removes the binding of named subscriber to news.
*
* @argument {String} subscriberName Simple name of a given subscriber
*/
function UnSubscribeToNews(subscriberName)
{
var anyActive = false;
for (var i = 0; i < _subscriptions.length; i++)
{
if (_subscriptions[i].Name == subscriberName)
{
_subscriptions[i].setIsActive(false);
}
if (_subscriptions[i].getIsActive()) anyActive = true;
}
if (!anyActive)
{
_pipeline.unSubscribeToFeed(_serviceName);
}
}
/**
* Reactivates a binding for a previously named subscriber.
*
* @argument {String} subscriberName Simple name of a given subscriber
*/
function ReSubscribeToNews(subscriberName)
{
var anyActive = false;
var currentSubscriber = null;
for (var i = 0; i < _subscriptions.length; i++)
{
if (_subscriptions[i].getIsActive()) anyActive = true;
if (_subscriptions[i].Name == subscriberName)
{
currentSubscriber = _subscriptions[i];
currentSubscriber.setIsActive(true);
}
}
if (!anyActive)
{
_pipeline.subscribeToFeed(_serviceName, currentSubscriber.Criteria);
}
}
/**
* @deprecated Search beyond the current feed is not yet available
*/
function SearchNews(updateCallback, criteria)
{
var newSearch = new Action(_serviceName, "search");
newSearch.criteria = criteria;
_pipeline.sendRequest(newSearch, updateCallback);
return newSearch.id;
}
/**
* Returns the HTML of a full story based on the story id and a callback function.
* @argument {String} guid ID property of a headline received.
* @argument {function} callback Method to invoke when the story is returned. Will pass "" if no body exists.
*/
function getStoryBody(guid, callback)
{
if (_storyCache.Items[guid].Body != null)
{
callback(_storyCache.Items[guid]);
}
else
{
_pendingBodyRequests[guid] = callback;
var newSearch = new Action(_serviceName, "detail");
newSearch.criteria = new function() { this.id = guid; };
_pipeline.sendRequest(newSearch, bodyCallback);
}
}
function registerNewsListener()
{
_pipeline.registerService("LiveNews", feedCallback);
window["lng"] = "LiveNews";
}
registerNewsListener();
}//end LiveNewsGateway
/**
* @class LiveNewsSubscriber provide a joining point between a news feed and a control allowing for the addition of a criteria in the subscribe or further filtering on the client. Created internally, but the filter can be updated as desired.
* @constructor
* @type {LiveNewsSubscriber}
* @argument {String} name subscriber name
* @argument {Object} criteria Object with DocType, Symbols, and/or Keywords to filter news broadcast
* @argument {String} filter parseable string that will apply filter to news displayed
* @argument {String} feedID Internally assigned ID
* @argument {function} subscriberCallback Method to invoke when news matching the filter is received.
*/
function LiveNewsSubscriber(name, criteria, feedID, firstCallback)
{
var _feedID = feedID;
var _callbacks = new Array();
var _name = name;
var _isActive = true;
this.ID = _feedID;
this.Name = name;
this.Criteria = (criteria == null) ? new Object() : criteria;
this.getIsActive = getIsActive;
this.setIsActive = setIsActive;
this.OnUpdate = OnUpdate;
if (firstCallback != null)
{
_callbacks.push( new function() { this.callback = firstCallback, this.filter = new Filter} );
}
this.addListener = function(listenerCallback, filterString)
{
var filter = new Filter(filterString);
_callbacks.push( new function() { this.callback = listenerCallback, this.filter = filter} );
return new function() { this.callback = listenerCallback, this.filter = filter};
}
this.updateListener = function(listenerCallback, filterString)
{
_callbacks[listenerCallback] = null;
}
this.stopListener = function(listenerCallback)
{
_callbacks[listenerCallback] = null;
}
/**
* Returns the "Active" state of the subscriber
* @type {bool}
*/
function getIsActive() { return _isActive; }
/**
* Update the active status
* @argument {Boolean} newValue true to false
*/
function setIsActive(newValue) { _isActive = newValue; }
function OnUpdate(updateValues, isUpdate)
{
for (var i = 0; i < _callbacks.length; i++)
{
_callbacks[i].callback(_callbacks[i].filter.findMatches(updateValues));
//_callbacks[i].callback(updateValues);
}
if (updateValues.length > 0)
{
this.Criteria.LastHeadline = updateValues[updateValues.length-1].ID;
}
}
}
function NewsItem(itemElement)
{
var _element = itemElement;
this.Headline = _element.HEADLINE;
this.Time = _element.Time;
this.ID = _element.ID;
this.Body = _element.Body;
this.Abstract = _element.Abstract;
this.Symbols = _element.Symbols;
this.DocType = _element.DocType;
this.Provider = _element.Provider;
this.Author = _element.Author;
this.Channels = _element.Channels;
this.Industries = _element.Industries;
this.Issues = _element.Issues;
this.Products = _element.Products;
this.Keywords = _element.Keywords;
this.PersonalFinance = _element.PersonalFinance;
this.Regions = _element.Regions;
this.URI = _element.URI;
this.ReferenceStoryGuid = _element.ReferenceStoryGuid;
this.Compare = compareItem;
function compareItem(newItem)
{
return (_element.ID == newItem.ID);
}
}
/**
* @class Collection class for managing headlines received.
*/
function NewsItemCollection()
{
var _headlines = new Array();
/**
* Returns the date time of the last update
* @return {Date}
*/
this.RetrieveDate = new Date();
/**
* Returns the list of headlines
* @type {Array}
* @return List of headlines indexed by ID
*/
this.Items = _headlines;
this.addHeadlines = addHeadlines;
this.addHeadline = addHeadline;
this.addStoryBody = addStoryBody;
/**
* Function to join original story object with the full text
* @param {Story} storyBody Story object returned by call to get story body
*/
function addStoryBody(storyBody)
{
if (_headlines[storyBody.ID] != null)
{
_headlines[storyBody.ID].Body = storyBody.Body;
return _headlines[storyBody.ID];
}
else
{
_headlines[storyBody.ID] = new NewsItem(storyBody);
return _headlines[storyBody.ID];
}
}
/**
* Function to add a new headline to the list.
*
* @argument {NewsItem} headlineObject News update received.
*/
function addHeadline(headlineObject)
{
this.RetrieveDate = new Date();
if (_headlines[headlineObject.ID] == null)
{
_headlines[headlineObject.ID] = headlineObject;
}
}
/**
* Function to add a new headline to the list.
*
* @argument {Array} headlineObjects List of {NewsItem} objects received.
*/
function addHeadlines(headlineObjects)
{
this.RetrieveDate = new Date();
for (var i = 0; i < headlineObjects.length; i++)
{
addHeadline(headlineObjects[i]);
}
}
}
/**
* Unitary instance of the LiveNewsGateway object
* Do not call directly - use {LiveNewsGateway.Instance()}
* if you need to search and bind the DOM instead
*/
LiveNewsGateway._Application = null;
/**
* Creates the single LiveNewsGateway instance or returns the existing instance.
* @argument {String} endpoint Full url for system access if default is to be overridden (Not recommended)
*/
LiveNewsGateway.Instance = function()
{
if (LiveNewsGateway._Application == null)
LiveNewsGateway._Application = new LiveNewsGateway();
return LiveNewsGateway._Application;
}///////////////////////////////////////////////////////////
// LiveQuotesGateway.js
// Implementation of the Class LiveQuotesGateway
// Generated by Enterprise Architect
// Created on: 28-Jun-2006 2:37:56 PM
///////////////////////////////////////////////////////////
/**
* Create a new instance of LiveQuotesGateway.
*
* @class This class creates a new LiveQuotesGateway to provide for quote reuests and bindings.
* @return Returns a new LiveQuotesGateway.
* @type {LiveQuotesGateway}
* @constructor
*/
function LiveQuotesGateway ()
{
var _serviceName = "LiveQuotes";
var _pipeline = PipelineProtocol.GetPipeline();
var _bindings = new Array();
this.BindToQuote = BindToQuote;
this.BindToExchangeQuote = BindToExchangeQuote;
this.BindToHybridQuote = BindToHybridQuote;
this.UnBindToQuote = UnBindToQuote;
this.UnBindToExchangeQuote = UnBindToExchangeQuote;
this.UnBindToHybridQuote = UnBindToHybridQuote;
this.RemoveQuote = RemoveQuote;
this.RequestQuote = RequestQuote;
this.Bindings = _bindings;
function feedCallback(QuotesUpdate)
{
if (QuotesUpdate.Status != null)
{
if (QuotesUpdate.Status == "stopped")
{
var rebindString = null;
for (var ticker in _bindings)
{
if (typeof(_bindings[ticker]) == "object")
{
if (rebindString == null)
{
rebindString = ticker;
}
else rebindString = rebindString.concat(',' + ticker);
}
}
if (rebindString.length > 0) _pipeline.subscribeToFeed(_serviceName, new function() { this.ticker = rebindString; this.blank = "nothing"; });
}
}
else
{
if (QuotesUpdate.Tickers != null)
{
for (var i = 0; i < QuotesUpdate.Tickers.length; i++)
{
updateBinding(QuotesUpdate.Tickers[i]);
}
}
else updateBinding(QuotesUpdate.Ticker);
}
}
function updateBinding(quoteUpdate)
{
if (quoteUpdate.t == null || quoteUpdate.p == 0) return;
var tArray = quoteUpdate.t.split(',');
var tempSymbol = quoteUpdate;
for (var i = 0; i < tArray.length; i++)
{
tempSymbol.t = tArray[i];
if (_bindings[quoteUpdate.t] != null)
{
_bindings[quoteUpdate.t].setStatus(QuotedSymbol.StatusEnum.Subscribed);
_bindings[quoteUpdate.t].OnUpdate(quoteUpdate);
}
else
{
for (var bind in _bindings)
{
if (_bindings[bind]._ticker == quoteUpdate.t)
{
_bindings[bind].OnUpdate(quoteUpdate);
}
}
}
}
}
/**
* This function provides a single quote request of one or more ticker symols.
* The tickers will NOT update (@see BindToQuote).
* @argument {String} tickerSymbol Comma separated list of ticker symbols
* @argument {Object} updateCallback Function to call with quote updates
*/
function RequestQuote(tickerSymbol, updateCallback)
{
var newSearch = new Action(_serviceName, "search");
newSearch.criteria = new function() { this.ticker = tickerSymbol; }
_pipeline.sendRequest(newSearch, updateCallback);
return newSearch.id;
}
/**
* Overloaded method to support old pages
* that have no knowledge of new exchanges
*
*
*
**/
function BindToQuote(tickerSymbol, updateCallback)
{
var symbolBinding = null;
symbolBinding = BindToExchangeQuote(tickerSymbol, updateCallback, null);
return symbolBinding;
}
/**
* This function provides a quote request of one or more ticker symols.
* The tickers WILL update (@see RequestQuote).
* @argument {String} tickerSymbol Comma separated list of ticker symbols
* @argument {Object} updateCallback Function to call with quote updates
*/
function BindToExchangeQuote(tickerSymbol, updateCallback, exchangePrefix)
{
var symbolBinding = null;
var tickerText = tickerSymbol.toUpperCase().split(',');
var bindText = new String();
for (var i = 0; i < tickerText.length; i++)
{
if (tickerText[i] == '') continue;
if (exchangePrefix != null) tickerText[i] = exchangePrefix + "!" + tickerText[i];
symbolBinding = _bindings[tickerText[i]];
if (symbolBinding == null)
{
bindText = (bindText == "") ? bindText.concat(tickerText[i]) : bindText.concat("," + tickerText[i]);
symbolBinding = new QuotedSymbol(_bindings.length, tickerText[i]);
symbolBinding.setStatus(QuotedSymbol.StatusEnum.Subscribing);
_bindings[tickerText[i]] = symbolBinding;
}
else
{
if (symbolBinding._pickupItem != null && symbolBinding.getStatus() == QuotedSymbol.StatusEnum.Subscribed)
{
updateCallback(symbolBinding);
}
else if (symbolBinding.getStatus() != QuotedSymbol.StatusEnum.Subscribing)
{
bindText = (bindText == "") ? bindText.concat(tickerText[i]) : bindText.concat("," + tickerText[i]);
}
}
symbolBinding.attach(updateCallback);
}
if (bindText.length > 0)
{
_pipeline.subscribeToFeed(_serviceName, new function() { this.ticker = bindText; this.blank = "nothing"; });
}
return symbolBinding;
}
/**
* This function provides the ability to subscribe to a Hybrid Symbol.
* This requires the symbol you are trying to attach to and there associated
* Exchanges. Current valid Exchange Identifiers are NLs, CSK (Comstock lookup)
* @argument {String} tickerSymbol Comma separated list of ticker symbols
* @argument {Object} updateCallback Function to call with quote updates
* @arguement {String} Comma Seperated list of 3 Character Exchange Codes
*/
function BindToHybridQuote(tickerSymbol, updateCallback, exchanges)
{
var symbolBinding = null;
var result = CreateHybridExchange(exchanges);
symbolBinding = BindToExchangeQuote(tickerSymbol, updateCallback, result);
return symbolBinding;
}
/**
* This function provides the ability to disconnect from an updating ticker.
* The tickers will no longer update (@see BindToQuote). If the number of
* listeners becomes zero, a {RemoveQuote} will be performed.
* @argument {String} tickerSymbol Comma separated list of ticker symbols
* @argument {Object} updateCallback Function to call with quote updates
*/
function UnBindToQuote(tickerSymbol, updateCallback)
{
UnBindToExchangeQuote(tickerSymbol, updateCallback, null);
}
/*
* This function provides the ability to disconnect from an updating ticker.
* The tickers will no longer update (@see BindToQuote). If the number of
* listeners becomes zero, a {RemoveQuote} will be performed.
* @argument {String} tickerSymbol Comma separated list of ticker symbols
* @argument {Object} updateCallback Function to call with quote updates
*/
function UnBindToExchangeQuote(tickerSymbol, updateCallback, exchangePrefix)
{
var symbolBinding;
var tickerText = tickerSymbol.toUpperCase().split(',');
for (var i = 0; i < tickerText.length; i++)
{
if(exchangePrefix != null) tickerText[i] = exchangePrefix + "!" + tickerText[i];
symbolBinding = _bindings[tickerText[i]];
if (symbolBinding != null)
{
symbolBinding.detach(updateCallback);
if (symbolBinding._attached.length == 0)
{
symbolBinding.setStatus(QuotedSymbol.StatusEnum.Unsubscribed);
_pipeline.unSubscribeToFeed(_serviceName, new function() { this.ticker = tickerText[i]; });
}
}
}
}
/**
* This function provides the ability to disconnect from an updating ticker.
* The tickers will no longer update (@see BindToQuote). If the number of
* listeners becomes zero, a {RemoveQuote} will be performed.
* @argument {String} tickerSymbol Comma separated list of ticker symbols
* @argument {Object} updateCallback Function to call with quote updates
* @argument {String} exchanges Comma Seperated List of exchanges.
*/
function UnBindToHybridQuote(tickerSymbol, updateCallback, exchanges)
{
var result = CreateHybridExchange(exchanges);
UnBindToExchangeQuote(tickerSymbol, updateCallback, result);
}
function CreateHybridExchange(exchanges)
{
exchangeText = exchanges.toUpperCase().split(',');
exchangeText.sort();
var exchangeInput = "";
for (var i = 0; i < exchangeText.length; i++)
{
exchangeInput = ( i == 0 ) ? exchangeInput.concat(exchangeText[i]) : exchangeInput.concat( ">" + exchangeText[i]);
}
if(exchangeText.length == 1)
{
exchangeInput.concat(">CSK"); // default to CSK if only one exchange supplied for second exchange
}
return exchangeInput;
}
/**
* This function provides the ability to stop and updating ticker completely.
* It does not affect the binding between a page element and the updates.
* If the ticker is {BindToQuote} is called, all previous elements will reactivate.
* @argument {String} tickerSymbol Comma separated list of ticker symbols
*/
function RemoveQuote(tickerSymbol)
{
var symbolBinding;
var tickerText = tickerSymbol.toUpperCase().split(',');
for (var i = 0; i < tickerText.length; i++)
{
symbolBinding = _bindings[tickerText[i]];
if (symbolBinding != null)
{
symbolBinding.setStatus(QuotedSymbol.StatusEnum.Unsubscribed);
}
}
_pipeline.unSubscribeToFeed(_serviceName, new function() { this.ticker = tickerSymbol; });
}
function registerQuotesListener()
{
_pipeline.registerService(_serviceName, feedCallback);
//_pipeline.subscribeToFeed(_serviceName);
window["lqg"] = _serviceName;
}
registerQuotesListener();
}//end LiveQuotesGateway
// Grafted from livequotes.js 08/08/2006 RJG
/**
* Create a new instance of QuotedSymbol.
*
* @class This class is the basis for a returned ticker value. Created by {LiveQuotesGateway} when an update is received.
* @argument {String} itemId requested ticker symbol
* @argument {Object} Actual JSON encoded return from the server.
* @return Returns a new QuotedSymbol.
* @type {QuotedSymbol}
* @constructor
*/
function QuotedSymbol(itemId, ticker)
{
this._itemId = itemId;
this._ticker = ticker;
this._attached = new Array();
};
QuotedSymbol.StatusEnum = new Object();
QuotedSymbol.StatusEnum.Init = "Init";
QuotedSymbol.StatusEnum.Subscribing = "Subscribing";
QuotedSymbol.StatusEnum.Subscribed = "Subscribed";
QuotedSymbol.StatusEnum.Unsubscribed = "Unsubscribed";
/**
* This property provides a status feature of type {StatusEnum}.
*/
QuotedSymbol.prototype._status = QuotedSymbol.StatusEnum.Init;
/**
* This function returns the originally requested ticker.
*/
QuotedSymbol.prototype.getItemId = function() {return this._itemId;};
/**
* This function returns the actual ticker symbol being tracked.
*/
QuotedSymbol.prototype.getTicker = function() {return this._ticker;};
/**
* This function returns the status.
*/
QuotedSymbol.prototype.getStatus = function() {return this._status;};
/**
* This function sets the status.
*/
QuotedSymbol.prototype.setStatus = function(status) {this._status = status;};
/**
* This function attaches a callback method to a particular symbol already bound. @see {LiveQuotesGateway.BindToQuote}
*
* @argument {function} target The callback method to pass quote updates.
*/
QuotedSymbol.prototype.attach = function(target)
{
for (var i = 0; i < this._attached.length; i++)
{
if (this._attached[i] == target) return;
}
this._attached[this._attached.length] = target;
};
/**
* This function detaches a callback method from a particular symbol already bound. @see {LiveQuotesGateway.UnBindToQuote}
*
* @argument {function} target The callback method to remove from quote updates.
*/
QuotedSymbol.prototype.detach = function(target)
{
for(var index = 0; index != this._attached.length; ++index)
{
if (this._attached[index] == target)
{
this._attached[index] = null;
this._attached.splice(index, 1);
break;
}
}
};
/**
* This internal function is called by the {LiveQuotesGateway} when news values are received.
*
* @argument {Object} item The server created quote item.
*/
QuotedSymbol.prototype.OnUpdate = function(item)
{
this._pickupItem = item;
for(var index = 0; index != this._attached.length; ++index)
{
var target = this._attached[index];
if (target != null)
{
try
{
target(this);
}
catch(ex)
{
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":ex, "location":"QuotedSymbol.prototype.OnUpdate" });
}
}
}
};
/**
* This function returns the time of the last update.
*
*/
QuotedSymbol.prototype.Timestamp = function()
{
var value = new Date(this._pickupItem.T);
value.format = DateFormat;
return value;
};
/**
* This function returns the company name associated with the symbol.
*/
QuotedSymbol.prototype.Name = function()
{
return this._pickupItem.n;
};
/**
* This function returns the last price received.
*/
QuotedSymbol.prototype.Price = function()
{
return this._pickupItem.p;
};
/**
* This function returns the last volume received.
*/
QuotedSymbol.prototype.Volume = function()
{
return this._pickupItem.v;
};
/**
* This function returns the last price change received.
*/
QuotedSymbol.prototype.Change = function()
{
return this._pickupItem.c;
};
/**
* This function returns the last price percentage change received.
*/
QuotedSymbol.prototype.PercentChange = function()
{
return this._pickupItem.P;
};
QuotedSymbol.prototype.ExtendedTimestamp = function()
{
return this.Timestamp();
};
QuotedSymbol.prototype.ExtendedPrice = function()
{
return this.Price();
};
QuotedSymbol.prototype.ExtendedVolume = function()
{
return this.Volume();
};
QuotedSymbol.prototype.ExtendedChange = function()
{
return this.Change();
};
QuotedSymbol.prototype.ExtendedPercentChange = function()
{
return this.PercentChange();
};
QuotedSymbol.prototype.MarketHoursTimestamp = function()
{
return this.Timestamp();
};
QuotedSymbol.prototype.MarketHoursPrice = function()
{
return this.Price();
};
QuotedSymbol.prototype.MarketHoursVolume = function()
{
return this.Volume();
};
QuotedSymbol.prototype.MarketHoursChange = function()
{
return this.Change();
};
QuotedSymbol.prototype.MarketHoursPercentChange = function()
{
return this.PercentChange();
};
// Flags:
// 1 - PreMarket
// 2 - AfterMarket
// 4 - Realtime
// 8 - Halt
QuotedSymbol.prototype.Flags = function()
{
return this._pickupItem.f;
};
QuotedSymbol.prototype.HasFlag = function(flag)
{
return (parseInt(this._pickupItem.f) & flag) == flag;
}
/**
* The QuotedElement clas binds a quoted symbol to an HTML element with custom HTML attributes.
* "mwfield" sets the property to be bound (i.e. Price = {QuotedSymbol.Price})
* "mwformat" sets the display format (i.e. "Date")
*
* @argument {HTML Object} htmlElement Element to be bound.
* @tickerSymbol {QuotedSymbol} ticker returned by {LiveQuotesGateway.BindToQuote} to be bound.
*/
function QuotedElement(htmlElement, tickerSymbol)
{
var _lastPrice = 0.0;
//var _innerSpan = null;
var _flashTimeout = null;
var _htmlElement = (typeof(htmlElement) == "string") ? document.getElementById(htmlElement) : htmlElement;
var _field = _htmlElement.getAttribute("mwfield");
if (_field == null)_field = "Price";
var _format = _htmlElement.getAttribute("mwformat");
var _baseStyleClass = _htmlElement.className;
var _lastFlagClass = "";
var _lastPriceClass = "";
var _lastFieldClass = "";
this.onPickup = onPickup;
/**
* Function to return actual HTML element bound.
*/
this.getHtmlElement = function()
{
return _htmlElement;
}
/**
* Internal - function called by LQ to update the element.
*/
function onPickup(data)
{
// if (_innerSpan == null)
// {
// _innerSpan = document.createElement("span");
// _htmlElement.innerHTML = "";
// _htmlElement.appendChild(_innerSpan);
// }
var fieldValue = data[_field]();
var priceValue = data.Price();
var extendedTick = data.HasFlag(1) || data.HasFlag(2);
if(extendedTick && _field.match(/MarketHours/)) return;
if(!extendedTick && _field.match(/Extended/)) return;
if (fieldValue > 0)
{
_lastFieldClass = "up";
}
else if (fieldValue < 0)
{
_lastFieldClass = "down";
}
else
{
_lastFieldClass = "unchanged";
}
if (_lastPrice != null)
{
if (_lastPrice < priceValue)
{
_lastPriceClass = " tradeup";
}
else if (_lastPrice > priceValue)
{
_lastPriceClass = " tradedown";
}
}
if (data.HasFlag(8))
{
_lastFlagClass = " halt";
}
else if (data.HasFlag(1))
{
_lastFlagClass = " pre";
}
else if (data.HasFlag(2))
{
_lastFlagClass = " after";
}
else if (data.HasFlag(4))
{
_lastFlagClass = " realtime";
}
else
{
_lastFlagClass = " delayed";
}
var fieldString = formatValue(fieldValue);
var mwBind = _htmlElement.getAttribute("mwbind");
if(mwBind != null)
{
_htmlElement.innerHTML = eval(mwBind);
}
else
{
if (_htmlElement.innerHTML != fieldString)
_htmlElement.innerHTML = fieldString;
if (_htmlElement.className != getClassName())
{
_htmlElement.className = getClassName();
setFlashTimeout();
}
}
_lastPrice = priceValue;
//_htmlElement.innerHTML = symbol[_field]().toString();
}
/**
* Internal - function called to apply display formatting.
*/
function formatValue(fieldValue)
{
if (_format == null || _format == "")
return fieldValue.toString();
if (_field == "Flags")
return " ";
if (fieldValue.format != null)
{
return fieldValue.format(_format);
}
var leadingPlus = "";
var trailingPercent = "";
var formatter = new NumberFormat(fieldValue);
formatter.setCommas(false);
for (var index = 0; index != _format.length; ++index)
{
var formatChar = _format.charAt(index);
if (formatChar == ",")
{
formatter.setCommas(true);
}
else if (formatChar == "%")
{
trailingPercent = "%";
}
else if (formatChar == "+")
{
leadingPlus = "+";
}
else if (formatChar >= "0" && formatChar <= "9")
{
formatter.setPlaces(new Number(formatChar));
}
}
if (formatter.toUnformatted() <= 0)
leadingPlus = "";
return leadingPlus + formatter.toFormatted() + trailingPercent;
}
/**
* Internal - function called to flash/unflash on symbol update.
*/
function setFlashTimeout()
{
if (_flashTimeout != null)
{
window.clearTimeout(_flashTimeout);
}
_flashTimeout = window.setTimeout(
function()
{
_flashTimeout = null;
_lastPriceClass = "";
_htmlElement.className = getClassName();
}, 900);
};
/**
* Returns last update type (i.e. tradeup.up)
*/
function getClassName()
{
return (_baseStyleClass == null) ? _lastFieldClass + _lastPriceClass + _lastFlagClass : _baseStyleClass + " " + _lastFieldClass + _lastPriceClass + _lastFlagClass;
}
}
/**
* Unitary instance of the LiveQuotesGateway object
* Do not call directly - use {LiveQuotesGateway.Instance()} or {LiveQuotesGateway.setup()}
* if you need to search and bind the DOM instead
*/
LiveQuotesGateway._Application = null;
/**
* Creates the single LiveQuotesGateway instance or returns the existing instance.
* @argument {String} endpoint Full url for system access if default is to be overridden (Not recommended)
*/
LiveQuotesGateway.Instance = function()
{
if (LiveQuotesGateway._Application == null)
LiveQuotesGateway._Application = new LiveQuotesGateway();
return LiveQuotesGateway._Application;
}
/**
* exchange is an optional string to use to bind to a specific exchange during setup
*/
LiveQuotesGateway.setup = function(exchange)
{
var app = new LiveQuotesGateway.Instance();
var spanElements = document.getElementsByTagName("span");
var blockedTickers = {"us:djia":0, "us:indu":0, "djia":0, "indu":0};
for(var index = 0; index != spanElements.length; ++index)
{
var spanElement = spanElements[index];
var spanElementClassName = spanElement.className;
if (spanElementClassName.toLowerCase() == "mwlivequotes")
{
var ticker = spanElement.getAttribute("mwsymbol");
if( ticker != null && blockedTickers[ticker.toLowerCase()] == 0)
continue;
if (ticker != null)
{
var quotedElement = new QuotedElement(spanElement);
if (exchange && exchange.length > 0)
{
if( exchange.indexOf(',') > 0 )
{
app.BindToHybridQuote(ticker, quotedElement.onPickup, exchange);
}
else
{
app.BindToExchangeQuote(ticker, quotedElement.onPickup, exchange);
}
}
else
app.BindToQuote(ticker, quotedElement.onPickup);
}
}
}
return app;
};
function NumberFormat(num, inputDecimal)
{
this.VERSION = 'Number Format v1.5.4';
this.COMMA = ',';
this.PERIOD = '.';
this.DASH = '-';
this.LEFT_PAREN = '(';
this.RIGHT_PAREN = ')';
this.LEFT_OUTSIDE = 0;
this.LEFT_INSIDE = 1;
this.RIGHT_INSIDE = 2;
this.RIGHT_OUTSIDE = 3;
this.LEFT_DASH = 0;
this.RIGHT_DASH = 1;
this.PARENTHESIS = 2;
this.NO_ROUNDING = -1
this.num;
this.numOriginal;
this.hasSeparators = false;
this.separatorValue;
this.inputDecimalValue;
this.decimalValue;
this.negativeFormat;
this.negativeRed;
this.hasCurrency;
this.currencyPosition;
this.currencyValue;
this.places;
this.roundToPlaces;
this.truncate;
this.setNumber = setNumberNF;
this.toUnformatted = toUnformattedNF;
this.setInputDecimal = setInputDecimalNF;
this.setSeparators = setSeparatorsNF;
this.setCommas = setCommasNF;
this.setNegativeFormat = setNegativeFormatNF;
this.setNegativeRed = setNegativeRedNF;
this.setCurrency = setCurrencyNF;
this.setCurrencyPrefix = setCurrencyPrefixNF;
this.setCurrencyValue = setCurrencyValueNF;
this.setCurrencyPosition = setCurrencyPositionNF;
this.setPlaces = setPlacesNF;
this.toFormatted = toFormattedNF;
this.toPercentage = toPercentageNF;
this.getOriginal = getOriginalNF;
this.moveDecimalRight = moveDecimalRightNF;
this.moveDecimalLeft = moveDecimalLeftNF;
this.getRounded = getRoundedNF;
this.preserveZeros = preserveZerosNF;
this.justNumber = justNumberNF;
this.expandExponential = expandExponentialNF;
this.getZeros = getZerosNF;
this.moveDecimalAsString = moveDecimalAsStringNF;
this.moveDecimal = moveDecimalNF;
this.addSeparators = addSeparatorsNF;
if (inputDecimal == null) {
this.setNumber(num, this.PERIOD);
} else {
this.setNumber(num, inputDecimal);
}
this.setCommas(true);
this.setNegativeFormat(this.LEFT_DASH);
this.setNegativeRed(false);
this.setCurrency(false);
this.setCurrencyPrefix('$');
this.setPlaces(2);
}
function setInputDecimalNF(val)
{
this.inputDecimalValue = val;
}
function setNumberNF(num, inputDecimal)
{
if (inputDecimal != null) {
this.setInputDecimal(inputDecimal);
}
this.numOriginal = num;
this.num = this.justNumber(num);
}
function toUnformattedNF()
{
return (this.num);
}
function getOriginalNF()
{
return (this.numOriginal);
}
function setNegativeFormatNF(format)
{
this.negativeFormat = format;
}
function setNegativeRedNF(isRed)
{
this.negativeRed = isRed;
}
function setSeparatorsNF(isC, separator, decimal)
{
this.hasSeparators = isC;
if (separator == null) separator = this.COMMA;
if (decimal == null) decimal = this.PERIOD;
if (separator == decimal) {
this.decimalValue = (decimal == this.PERIOD) ? this.COMMA : this.PERIOD;
} else {
this.decimalValue = decimal;
}
this.separatorValue = separator;
}
function setCommasNF(isC)
{
this.setSeparators(isC, this.COMMA, this.PERIOD);
}
function setCurrencyNF(isC)
{
this.hasCurrency = isC;
}
function setCurrencyValueNF(val)
{
this.currencyValue = val;
}
function setCurrencyPrefixNF(cp)
{
this.setCurrencyValue(cp);
this.setCurrencyPosition(this.LEFT_OUTSIDE);
}
function setCurrencyPositionNF(cp)
{
this.currencyPosition = cp
}
function setPlacesNF(p, tr)
{
this.roundToPlaces = !(p == this.NO_ROUNDING);
this.truncate = (tr != null && tr);
this.places = (p < 0) ? 0 : p;
}
function addSeparatorsNF(nStr, inD, outD, sep)
{
nStr += '';
var dpos = nStr.indexOf(inD);
var nStrEnd = '';
if (dpos != -1) {
nStrEnd = outD + nStr.substring(dpos + 1, nStr.length);
nStr = nStr.substring(0, dpos);
}
var rgx = /(\d+)(\d{3})/;
while (rgx.test(nStr)) {
nStr = nStr.replace(rgx, '$1' + sep + '$2');
}
return nStr + nStrEnd;
}
function toFormattedNF()
{
var pos;
var nNum = this.num;
var nStr;
var splitString = new Array(2);
if (this.roundToPlaces) {
nNum = this.getRounded(nNum);
nStr = this.preserveZeros(Math.abs(nNum));
} else {
nStr = this.expandExponential(Math.abs(nNum));
}
if (this.hasSeparators) {
nStr = this.addSeparators(nStr, this.PERIOD, this.decimalValue, this.separatorValue);
} else {
nStr = nStr.replace(new RegExp('\\' + this.PERIOD), this.decimalValue);
}
var c0 = '';
var n0 = '';
var c1 = '';
var n1 = '';
var n2 = '';
var c2 = '';
var n3 = '';
var c3 = '';
var negSignL = (this.negativeFormat == this.PARENTHESIS) ? this.LEFT_PAREN : this.DASH;
var negSignR = (this.negativeFormat == this.PARENTHESIS) ? this.RIGHT_PAREN : this.DASH;
if (this.currencyPosition == this.LEFT_OUTSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n1 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n2 = negSignR;
}
if (this.hasCurrency) c0 = this.currencyValue;
} else if (this.currencyPosition == this.LEFT_INSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n0 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n3 = negSignR;
}
if (this.hasCurrency) c1 = this.currencyValue;
}
else if (this.currencyPosition == this.RIGHT_INSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n0 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n3 = negSignR;
}
if (this.hasCurrency) c2 = this.currencyValue;
}
else if (this.currencyPosition == this.RIGHT_OUTSIDE) {
if (nNum < 0) {
if (this.negativeFormat == this.LEFT_DASH || this.negativeFormat == this.PARENTHESIS) n1 = negSignL;
if (this.negativeFormat == this.RIGHT_DASH || this.negativeFormat == this.PARENTHESIS) n2 = negSignR;
}
if (this.hasCurrency) c3 = this.currencyValue;
}
nStr = c0 + n0 + c1 + n1 + nStr + n2 + c2 + n3 + c3;
if (this.negativeRed && nNum < 0) {
nStr = '' + nStr + '';
}
return (nStr);
}
function toPercentageNF()
{
nNum = this.num * 100;
nNum = this.getRounded(nNum);
return nNum + '%';
}
function getZerosNF(places)
{
var extraZ = '';
var i;
for (i=0; i= 0 ? Math.floor(val) : Math.ceil(val);
} else {
val = Math.round(val);
}
val = this.moveDecimalLeft(val);
return val;
}
function preserveZerosNF(val)
{
var i;
val = this.expandExponential(val);
if (this.places <= 0) return val;
var decimalPos = val.indexOf('.');
if (decimalPos == -1) {
val += '.';
for (i=0; i 25)
{
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":"System unavailable or license invalid" } );
}
else if (++_failedPickups > 5)
{
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":"Multiple pickup errors - resubscribing", "location":"PipelineProtocol.streamCallback" } );
_streamActive = false;
_client.isvalid = false;
for (var sub in _subscribers)
{
if (_subscribers[sub].OnUpdate != null)
{
_subscribers[sub].OnUpdate({"Status":"stopped"});
}
}
}
else window.setTimeout(sendStreamRequest, PipelineProtocol.Backoff);
}
else
{
_failedPickups = 0;
_client.isvalid = true;
try
{
if (responseMessage.header.backoff > PipelineProtocol.Backoff)
{
PipelineProtocol.Backoff = responseMessage.header.backoff;
}
_client.proof = responseMessage.header.client.proof;
PipelineProtocol.TotalCount = responseMessage.header.itemcount;
for (var i = 0; i < responseMessage.body.response.length; i++)
{
if (_subscribers[responseMessage.body.response[i].service] != null)
{
if (!isIE)
{
var updateData = responseMessage.body.response[i].toJSONString();
var sub = responseMessage.body.response[i].service;
window.setTimeout("PipelineProtocol._Application.callUpdate('" + sub + "'," + updateData + ")", (PipelineProtocol.Backoff / responseMessage.body.response.length)*i);
}
else window.setTimeout(new function(){var sub = _subscribers[responseMessage.body.response[i].service]; sub.OnUpdate(responseMessage.body.response[i]); }, 250*i);
}
}
PipelineProtocol.On_StatusUpdate({ "Status":"success", "Message":"Responses processed", "location":"PipelineProtocol.streamCallback" } );
}
catch (msg)
{
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":msg, "location":"PipelineProtocol.streamCallback" } );
}
}
_streamInProcess = false;
}
this.callUpdate = function(subName, updateData)
{
var sub = _subscribers[subName];
if (sub != null)
{sub.OnUpdate(updateData);
}
else alert(subName);
}
/**
* Method to initiate an action request with all actions in the queue
* @member {PipelineProtocol}
* @private
*/
function sendActionRequest()
{
if (_actionInProcess) return;
var action;
var idx = 0;
var requestMessage = new PipelineMessage();
try
{
while (action = _actionQueue.pop())
{
if (action == null) continue;
requestMessage.addAction(action);
if (idx++ > 8) break;
}
if (requestMessage.body.actions.length > 0)
{
requestMessage.header.client = _client;
_lastActionSent = new Date();
_actionInProcess = true;
_Request.sendRequestResponse(requestMessage.toJSONString(), actionCallback, _statusObject);
}
}
catch(ex)
{
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":ex, "location":"PipelineProtocol.sendActionRequest" } );
}
}
/**
* Method invoked when an action response is received
* @member {PipelineProtocol}
* @private
*/
function actionCallback(responseMessage)
{
if (_subscribers["System"] != null) _subscribers["System"].OnUpdate(responseMessage);
if (responseMessage == null)
{
_failedPickups++;
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":"Empty action response received", "location":"PipelineProtocol.actionCallback" } );
//if (!_streamActive) window.setTimeout(sendStreamRequest, 30);
}
else if (responseMessage.Exception != null)
{
_failedPickups++;
PipelineProtocol.On_StatusUpdate({ "Status":"exception", "Exception":responseMessage.Exception, "location":"PipelineProtocol.actionCallback" } );
//if (!_streamActive) window.setTimeout(sendStreamRequest, 30);
}
else
{
_client.proof = responseMessage.header.client.proof;
_client.license = "";
_failedPickups = 0;
_client.isvalid = true;
for (var i = 0; i < responseMessage.body.response.length; i++)
{
actionResponse = responseMessage.body.response[i];
actionToProcess = _actionCallbacks[actionResponse.id];
if (actionToProcess != null)
{
actionToProcess(actionResponse);
actionToProcess = null;
}
}
}
_actionInProcess = false;
if (!_streamActive)
{
_streamActive = true;
sendStreamRequest();
}
sendActionRequest();
}
this.sendRequest = function(requestAction, requestCallback)
{
_actionQueue.push(requestAction)
_actionCallbacks[requestAction.id] = requestCallback;
sendActionRequest();
}
this.subscribeToFeed = function(serviceName, criteria)
{
if (_subscribers[serviceName] != null)
{
var serviceAction = new Action(serviceName, "subscribe");
serviceAction.criteria = criteria;
_actionCallbacks[serviceAction.id] = _subscribers[serviceName].OnUpdate;
_actionQueue.push(serviceAction);
sendActionRequest();
return serviceAction.id;
}
}
this.unSubscribeToFeed = function(serviceName, criteria)
{
if (_subscribers[serviceName] != null)
{
var serviceAction = new Action(serviceName, "unsubscribe");
serviceAction.criteria = criteria;
_actionCallbacks[serviceAction.id] = _subscribers[serviceName].OnUpdate;
_actionQueue.push(serviceAction);
sendActionRequest();
return serviceAction.id;
}
}
this.registerService = function(serviceName, serviceCallback)
{
var sub = new PipelineSubscriber(serviceName, serviceCallback);
_subscribers[serviceName] = sub;
}
function setWindowTimeout(timeoutName, interval)
{
var windowTimeout = window.setTimeout(function()
{
if (window[cb] != null)
{
var response = new Object();
response.Status = "exception";
response.Exception = new Object();
response.Exception.message = "request timeout";
window[cb](response);
}
}, 35000);
}
//_client.proof = window['pipeline_proof'];
_client.license = window['pipeline_license'];
PipelineProtocol.On_StatusUpdate({ "Status":"success", "Message":"Pipeline initialized", "location":"PipelineProtocol" } );
}
/**
* Unitary instance of the PipelineProtocol object
* Do not call directly - use {PipelineProtocol.GetPipeline} instead
*/
PipelineProtocol._Application = null;
/**
* Total number of updates received
*/
PipelineProtocol.TotalCount = 0;
/**
* Seconds from the last response system will wait prior to the next request.
* This can be set higher than license value, but a lower value
* will be reset to the license value as a floor.
*/
PipelineProtocol.Backoff = 2000;
/**
* Creates the single protcol instance or returns the existing instance.
* @argument {String} endpoint Full url for system access if default is to be overridden (Not recommended)
*/
PipelineProtocol.GetPipeline = function(endpoint)
{
if (PipelineProtocol._Application == null)
PipelineProtocol._Application = new PipelineProtocol(endpoint);
return PipelineProtocol._Application;
}
/**
* Implement this function to received system status messages
* @argument {Status} statusObject The 'status' property will provide the message text. The 'Exception' property will provide any error information.
*/
PipelineProtocol.On_StatusUpdate = function(statusObject) {}
/**
* Implement this function to received debug messages. Call this method to publish messages.
*
* @argument {String} messageItem Name of debug item - should be unique for a location
* @argument {String} messageText Debug message
* @argument {String} sourceLocation [optional] specific class and method information
*/
PipelineProtocol.On_DebugMessage = function(messageItem, messageText, sourceLocation) {}
/**
* Creates a PipelineSubscriber
* @return {PipelineSubscriber}
* @argument {String} serviceName Name of service to receive messages
* @argument {function} subscriberCallback Method to call on message received from service
* @class Pipeline subscribers are internal classes that manage subscribing services and callback methods
* @constructor
*/
function PipelineSubscriber(serviceName, subscriberCallback)
{
var _serviceName = serviceName;
var _callback = subscriberCallback;
this.OnUpdate = OnUpdate;
function OnUpdate(updateValues)
{
_callback(updateValues);
}
}
/*
* Class to hold individual Filter properties parsed from a filter string
*
* @argument {String} propName
* @argument {String} initialValue
* @argument {String} operation Joins the name and value (i.e. '=')
*/
function FilterProperty(propName, initialValue, operation, notFlag)
{
this.Name = propName;
var _notFlag = notFlag;
var _groupFlag = (operation == 'contains' || operation == 'in');
var _Value = (initialValue == null) ? new Array() : initialValue.toLowerCase().split(',');
var _Operation = (operation == null) ? "contains" : operation;
this.addValue = addValue;
this.removeValue = removeValue;
this.testValue = testValue;
this.ToString = ToString;
function ToString()
{
//return "(" + this.Name + " " + _Operation + " " + _Value.join(',') + ")";
if (_notFlag)
{
return this.Name + " !" + _Operation + " " + _Value.join(',');
}
else return this.Name + " " + _Operation + " " + _Value.join(',');
}
function addValue(valueName)
{
_Value.push(valueName.toLowerCase());
}
function removeValue(valueName)
{
for (var i = 0; i < _Value.length; i++)
{
if (_Value[i] == valueName) _Value[i] = null;
}
}
/**
* Method called to evaluate new data against the filter.
* @argument {Object} valueName Array, String, or Class to run through the filter
*/
function testValue(valueName)
{
var testValue;
if (valueName instanceof Array)
{
testValue = valueName.join(',');
}
else if (typeof(valueName) == "string")
{
testValue = valueName;
}
else
{
testValue = eval('valueName.' + this.Name);
if (testValue == null) return true;
if (testValue instanceof Array)
{
testValue = testValue.join(',');
}
}
if (_groupFlag)
return testGroupValue(testValue);
else
return testSingleValue(testValue);
}
function testSingleValue(valueValue)
{
for (var i = 0; i < _Value.length; i++)
{
switch (_Operation)
{
case "=":
if (valueValue.toLowerCase() == _Value[i]) return !_notFlag;
break;
case ">":
if (valueValue > _Value[i]) return !_notFlag;
break;
case "<":
if (valueValue < _Value[i]) return !_notFlag;
break;
}
}
return false;
}
/**
* Method called to evaluate new data against a group filter (i.e. 'in' or 'contains').
* @argument {Object} valueValue single value to run through the filter
*/
function testGroupValue(valueValue)
{
for (var i = 0; i < _Value.length; i++)
{
if (_notFlag)
{
//if (_Value[i].indexOf(valueValue.toLowerCase()) != -1) return !;
if (valueValue.toLowerCase().indexOf(_Value[i]) != -1) return false;
}
else
{
if (valueValue.toLowerCase().indexOf(_Value[i]) != -1) return true;
}
}
return _notFlag;
}
}
/*
* Class to evaluate individual filter properties parsed from a filter string
*
* @argument {FilterProperty} baseProperty Filter to evaluate
*/
function FilterCondition(baseProperty)
{
var _baseProperty = baseProperty;
var _joinProperty = null;
var _join = null;
this.satisfiesCondition = satisfiesCondition;
this.addProperty = addProperty;
this.ToString = ToString;
function ToString()
{
var expr = "";
if (_joinProperty == null)
{
return (_baseProperty.ToString());
}
else
{
return _baseProperty.ToString() + " " + _join + " " + _joinProperty.ToString();
}
return expr;
}
/**
* Method called to evaluate new data against the filter.
* Calls testValue on each individual {FilterProperty}
* @argument {Object} newItem Array, String, or Class to run through the filter
*/
function satisfiesCondition(newItem)
{
if (_joinProperty == null)
{
return (_baseProperty.testValue(newItem));
}
else
{
switch(_join)
{
case "and":
return _baseProperty.testValue(newItem) && _joinProperty.testValue(newItem);
case "or":
return _baseProperty.testValue(newItem) || _joinProperty.testValue(newItem);
}
}
return true;
}
function addProperty(filterProperty, joinOperation)
{
_join = (joinOperation == null) ? "and" : joinOperation;
_joinProperty = filterProperty;
}
}
/**
* @class Overall object for filtering data
* @constructor
* @argument {String} filterString Parseable string to apply filters (i.e. symbols=MSFT or headline contains 'tech')
*/
function Filter(filterString)
{
var _tokenArray = new Array('(', ')', '=', '!', '>', '<');
var _antiTokenArray = new Array('\"', '\'');
var _functionArray = new Array('=', '!', '<', '>', 'contains', 'in', 'not');
var _joinArray = new Array('and', 'or', '||', '&&');
var _conditionList = new Array();
var _joinList = new Array();
this.isEmpty = isEmpty;
this.isMatch = isMatch;
this.findMatches = findMatches;
this.reset = resetFilterValues;
this.add = addFilterValues;
this.ToString = ToString;
this.Condition = filterString;
function ToString()
{
if (isEmpty()) return "[none]";
var joinIdx = 0;
var joinString = new String();
var expressionString = new String();
for (var i = 0; i < _conditionList.length; i++)
{
expressionString += joinString + "(" + _conditionList[i].ToString() + ")";
joinString = _joinList.length > joinIdx ? " " + _joinList[joinIdx++] + " " : " or ";
}
return expressionString;
}
function addFilterValues(filterString)
{
parseFilterString(filterString)
}
function resetFilterValues()
{
_conditionList = new Array();
}
function isEmpty()
{
return _conditionList.length == 0;
}
function isMatch(newItem)
{
for (var i = 0; i < _conditionList.length; i++)
{
if(_conditionList[i].satisfiesCondition(newItem)) return true;
}
return (_conditionList.length == 0);
}
function findMatches(newItemArray)
{
if (isEmpty()) return newItemArray;
var matchArray = new Array();
for (var key = 0; key < newItemArray.length; key++)
{
if (isMatch(newItemArray[key]))
{
matchArray.push(newItemArray[key]);
}
}
return matchArray;
}
// ((country=us,uk or symbol=msft) and (headline contains Microsoft))
function parseFilterString(filterString)
{
if (filterString == null || filterString.length == 0) return;
var filterArray = tokenizeString(filterString);
var depth = 0;
var hasNot = false;
var currentOperation;
var currentJoin;
var startString;
var afterString;
var currentCondition;
var token;
for (var tokenidx in filterArray)
{
if (typeof(filterArray[tokenidx]) == 'string')
token = filterArray[tokenidx];
else continue;
if (token == '(')
{
depth++;
}
else if (token == ')')
{
depth--;
if (currentCondition != null)
{
_conditionList.push(currentCondition);
currentCondition = null;
currentJoin = startString = afterString = currentOperation = null;
hasNot = false;
}
}
else if (_joinArray.contains(token))
{
if (currentCondition == null)
{
if (startString != null)
{
currentCondition = new FilterCondition(new FilterProperty(startString, afterString, currentOperation, hasNot));
startString = afterString = currentOperation = null;
currentJoin = token;
}
else if (depth > 0)
{
currentJoin = token;
}
else _joinList.push(token);
}
else currentJoin = token;
}
else if (_functionArray.contains(token))
{
if (token == '!' || token == 'not')
hasNot = true;
else currentOperation = token;
}
else
{
if (currentOperation != null)
{
if (currentJoin == null || depth == 0)
{
currentCondition = new FilterCondition(new FilterProperty(startString, token, currentOperation, hasNot));
startString = afterString = currentOperation = null;
hasNot = false;
}
else
{
currentCondition.addProperty(new FilterProperty(startString, token, currentOperation), currentJoin, hasNot);
currentJoin = startString = afterString = currentOperation = null;
hasNot = false;
}
}
else
{
if (currentCondition != null && currentJoin == null)
{
_conditionList.push(currentCondition);
currentCondition = null;
}
if (startString == null)
startString = token;
else afterString = token;
}
}
}
if (currentCondition != null)
{
_conditionList.push(currentCondition);
}
this.Condition = _conditionList;
}
function tokenizeString(filterString)
{
var tempString = new String();
var tokenArray = new Array();
for (var i = 0; i < filterString.length; i++)
{
if (_tokenArray.contains(filterString.charAt(i)))
{
if (tempString.length > 0)
{
tokenArray.push(tempString);
tempString = "";
}
tokenArray.push(filterString.charAt(i));
}
else if (filterString.charAt(i) == ' ')
{
if (tempString.length > 0)
{
tokenArray.push(tempString);
tempString = "";
}
}
else if (_antiTokenArray.contains(filterString.charAt(i)))
{
// eliminate quotes
}
else
{
tempString += filterString.charAt(i);
}
}
if (tempString.length > 0) tokenArray.push(tempString);
return tokenArray;
}
function parseFilterObject(filterObject)
{
for (var o in filterObject)
{
if (filterObject[o] instanceof String)
{
}
else if (filterObject[o] instanceof Array)
{
}
else
{
}
}
}
if (typeof(filterString) == "string")
parseFilterString(filterString);
else parseFilterObject(filterString);
}//end Filter
/**
* @argument {String} elementId ID of HTML location element to bind
* @argument {String} templateId ID of HTML template element to base binding
* @argument {int} itemCount Maximum number of visible items for the control (e.g. # of Template elements cloned)
* @constructor
* @class Base control for template based controls
* @type {TemplateExpansionItem}
*/
function TemplateExpansion(elementId, templateId, itemCount)
{
var _baseElement = document.getElementById(elementId);
var _templateElement = document.getElementById(templateId);
var _itemCount = (itemCount == null) ? 0 : itemCount;
var _listItems = new Array();
var _paused = false;
// Here we insert an empty span element where the template element was to keep
// track of where we need to insert new items. Then, we remove the template node
var _templateElement = document.getElementById(templateId);
//var _parentElement = _templateElement.parentNode;
var _insertPlaceholder = document.createElement("span");
//_parentElement.insertBefore(_insertPlaceholder, _templateElement);
//_parentElement.removeChild(_templateElement);
this.clearItems = clearItems;
this.callback = updateIncomingHeadlineItems;
this.setPaused = setPaused;
this.getPaused = getPaused;
/**
* @type {bool}
* @return Returns whether the control is or is not paused
*/
function getPaused()
{
return _paused;
}
/**
* Sets the pause state of the control
* @argument {bool} isPaused true = pause
*/
function setPaused(isPaused)
{
_paused = isPaused;
}
/**
* Clears visible templates
*/
function clearItems()
{
while(_listItems.length > 0)
{
var listItem = _listItems.shift();
listItem.removeData(updateIncomingHeadlineItems);
_baseElement.removeChild(listItem.baseElement);
}
}
function updateIncomingHeadlineItem(dataElement, listElement)
{
_baseElement.insertBefore(dataElement, _insertPlaceholder.nextSibling);
_listItems.push(listElement);
while(_listItems.length > _itemCount)
{
var listItem = _listItems.shift();
listItem.removeData(updateIncomingHeadlineItems);
_baseElement.removeChild(listItem.baseElement);
}
}
function updateIncomingHeadlineItems(dataArray)
{
if (_baseElement == null) return true;
if (_paused)
{
return;
}
if (_itemCount == 0) return updateStaticTemplate(dataArray);
var newElem = null;
var newListItem = null;
if (dataArray.length == null)
{
newElem = _templateElement.cloneNode(true);
newElem.id = "";
newListItem = new TemplateExpansionItem(newElem);
newListItem.newData(dataArray);
updateIncomingHeadlineItem(newElem, newListItem);
}
else
{
for (var idx = 0; idx < dataArray.length; idx++)
{
newElem = _templateElement.cloneNode(true);
newElem.id = "";
newListItem = new TemplateExpansionItem(newElem);
newListItem.newData(dataArray[idx]);
updateIncomingHeadlineItem(newElem, newListItem);
}
}
}
function updateStaticTemplate(dataArray)
{
var newListItem;
if (_listItems.length == 0)
{
var newElem = _templateElement.cloneNode(true);
newElem.id = "";
_listItems[0] = new TemplateExpansionItem(newElem);
}
newListItem = _listItems[0];
if (dataArray.length == null)
{
newListItem.newData(dataArray);
}
else
{
for (var idx = 0; idx < dataArray.length; idx++)
{
newListItem.newData(dataArray[idx]);
//window.setTimeout(function() {newListItem.newData(dataArray[idx]);}, idx * 1000);
}
}
_baseElement.appendChild(newListItem.baseElement);
}
}
/**
* @argument {HTML Element} element Actual HTML element to bind
* @constructor Internal - called by {TemplateExpansion}
* @class Cloned template to be bound and displayed
* @type {TemplateExpansionItem}
*/
function TemplateExpansionItem(baseElement)
{
var element = baseElement;
var data = null;
this.newData = newData;
this.removeData = removeData;
this.baseElement = element;
function getData()
{
return this.data;
}
function newData(dataItem)
{
data = dataItem;
if(dataItem != null)
{
updateTemplateItems(element, "mwbind");
if (element.getAttribute("mwonupdate") != null)
{
eval(element.getAttribute("mwonupdate"));
}
}
}
function removeData(dataCallback)
{
var mwBind = element.getAttribute( "mwunbind");
if(mwBind != null)
{
element.innerHTML = eval(mwBind);
}
element.data = null;
}
function updateTemplateItems(node, attributeName)
{
for(var i = 0; i < node.childNodes.length; ++i)
{
var child = node.childNodes[i];
if(child.nodeType == 1)
{
if(child.childNodes.length > 0)
updateTemplateItems(child, attributeName);
var mwBind = child.getAttribute(attributeName);
if(mwBind != null)
{
child.innerHTML = eval(mwBind);
}
//child.data = data;
}
}
}
}
/**
* @private
*/
function ScriptSrc_Gateway(endpoint)
{
ScriptSrc_Gateway._nonce = 1;
var _endpoint = endpoint + '?';
this.sendRequestResponse = function(src, callbackMethod, callbackState)
{
var nonce = ++ScriptSrc_Gateway._nonce;
var cb = "_ls_cb" + nonce;
var scriptElement = document.createElement("script");
// scriptElement.id = id;
scriptElement.type = "text/javascript";
scriptElement.src = _endpoint + src + "&cb=" + cb;
var appendComplete = false;
var callbackComplete = false;
var windowTimeout = null;
var callTiming = new Date();
window[cb] = function(response)
{
if (windowTimeout != null)
{
window.clearTimeout(windowTimeout);
windowTimeout = null;
}
callbackComplete = true;
callTiming = new Date() - callTiming;
if (appendComplete)
{
document.body.removeChild(scriptElement);
window[cb] = null;
}
try
{
if (response == null)
{
response = new Object();
response.Status = "exception";
response.Exception = new Object();
response.Exception.message = "null response received";
}
response.Duration = callTiming;
PipelineProtocol.On_StatusUpdate({ "Status":"success", "Response":response.toJSONString()});
callbackMethod(response, callbackState);
}
catch(ex)
{
var callException = new Object();
callException.Exception = new Object();
callException.Exception.description = "callback error";
callException.Exception.message = ex.Message;
callbackMethod(callException, callbackState);
};
};
windowTimeout = window.setTimeout(function()
{
if (window[cb] != null)
{
var response = new Object();
response.Status = "exception";
response.Exception = new Object();
response.Exception.message = "request timeout";
window[cb](response);
}
}, 35000);
document.body.appendChild(scriptElement);
appendComplete = true;
if (callbackComplete)
{
document.body.removeChild(scriptElement);
window[cb] = null;
}
}
}
/**
* @private
*/
function XmlHttp_Gateway(endpoint)
{
XmlHttp_Gateway.nullFunction = function() {}
var _endpoint = endpoint + '?';
this.sendRequestResponse = function(src, callbackMethod, callbackState)
{
var xmlhttp = null;
if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
try
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(ex1)
{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
};
}
var windowTimeout = null;
xmlhttp.open("GET", _endpoint + src + "&r=" + Math.random(), true);
try
{
xmlhttp.setRequestHeader("Cookie", "none");
xmlhttp.setRequestHeader("Cookie", "");
} catch(ex) {};
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState==4)
{
if (windowTimeout != null)
{
window.clearTimeout(windowTimeout);
windowTimeout = null;
}
xmlhttp.onreadystatechange = XmlHttp_Gateway.nullFunction;
var responseText = xmlhttp.responseText;
xmlhttp = null;
try
{
var response;
try
{
PipelineProtocol.On_StatusUpdate({ "Status":"success", "Response":responseText});
if (responseText == "")
{
response = null;
}
else response = eval('(' + responseText + ')');
}
catch(parseEx)
{
response = new Object();
response.Exception = new Object();
response.Exception.message = "parse error: " + parseEx.message;
try
{
response.Exception.detail = responseText;
}catch(ex5){};
};
callbackMethod(response, callbackState);
}
catch(ex)
{
var callException = new Object();
callException.Exception = new Object();
callException.Exception.message = "callback error";
callbackMethod(callException, callbackState);
}
}
};
// windowTimeout = window.setTimeout(function()
// {
// if (windowTimeout != null)
// {
// windowTimeout = null;
// try
// {
// xmlhttp.onreadystatechange = XmlHttp_Gateway.nullFunction;
// xmlhttp.abort();
// }
// catch(ex5)
// {
// };
// xmlhttp = null;
// var timeoutResponse = new Object();
// timeoutResponse.Exception = new Object();
// timeoutResponse.Exception.message = "request timeout";
// try
// {
// callbackMethod(timeoutResponse, callbackState);
// }
// catch(ex3)
// {
// };
// }
// }, 25000);
xmlhttp.send(null);
}
}
// from JSON.js
(function () {
var m = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
s = {
array: function (x) {
var a = ['['], b, f, i, l = x.length, v;
for (var i = 0; i < l; i += 1) {
v = x[i];
f = s[typeof v];
if (f) {
v = f(v);
if (typeof v == 'string') {
if (b) {
a[a.length] = ',';
}
a[a.length] = v;
b = true;
}
}
}
a[a.length] = ']';
return a.join('');
},
'boolean': function (x) {
return String(x);
},
'null': function (x) {
return "null";
},
number: function (x) {
return isFinite(x) ? String(x) : 'null';
},
object: function (x) {
if (x) {
if (x instanceof Array) {
return s.array(x);
}
var a = ['{'], b, f, i, v;
for (var i in x) {
v = x[i];
f = s[typeof v];
if (f) {
v = f(v);
if (typeof v == 'string') {
if (b) {
a[a.length] = ',';
}
a.push(s.string(i), ':', v);
b = true;
}
}
}
a[a.length] = '}';
return a.join('');
}
return 'null';
},
string: function (x) {
if (/["\\\x00-\x1f]/.test(x)) {
x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
var c = m[b];
if (c) {
return c;
}
c = b.charCodeAt();
return '\\u00' +
Math.floor(c / 16).toString(16) +
(c % 16).toString(16);
});
}
return '"' + x + '"';
}
};
Object.prototype.toJSONString = function () {
return s.object(this);
};
Array.prototype.toJSONString = function () {
return s.array(this);
};
Array.prototype.contains = function(testValue) {
for (var t = 0; t < this.length; t++)
{
if (this[t] == testValue) return true;
}
return false;
};
})();
String.prototype.parseJSON = function () {
try {
return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + this + ')');
} catch (e) {
return false;
}
};
// a global month names array
var gsMonthNames = new Array(
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
);
// a global day names array
var gsDayNames = new Array(
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
);
// the date format prototype
function DateFormat(f)
{
if (!this.valueOf())
return ' ';
//var d = this;
function zf(val, places)
{
var result = "00" + val.toString();
return result.substr(result.length - places, places);
}
var result = new String(f);
result = result.replace("yyyy", this.getFullYear());
result = result.replace("mmmm", gsMonthNames[this.getMonth()]);
result = result.replace("mmm", gsMonthNames[this.getMonth()].substr(0, 3));
result = result.replace("mm", zf((this.getMonth() + 1),2));
result = result.replace("dddd", gsDayNames[this.getDay()]);
result = result.replace("ddd", gsDayNames[this.getDay()].substr(0, 3));
result = result.replace("dd", zf(this.getDate(),2));
result = result.replace("hh", zf(((h = this.getHours() % 12) ? h : 12),2));
result = result.replace("h", ((h = this.getHours() % 12) ? h : 12));
result = result.replace("nn", zf(this.getMinutes(),2));
result = result.replace("sss", zf(this.getMilliseconds(),3));
result = result.replace("ss", zf(this.getSeconds(),2));
result = result.replace("a/p", this.getHours() < 12 ? 'a' : 'p');
result = result.replace("A/P", this.getHours() < 12 ? 'A' : 'P');
return result;
/*
return f.replace(/(yyyy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,
function($1)
{
switch ($1.toLowerCase())
{
case 'yyyy': return d.getFullYear();
case 'mmmm': return gsMonthNames[d.getMonth()];
case 'mmm': return gsMonthNames[d.getMonth()].substr(0, 3);
case 'mm': return (d.getMonth() + 1).zf(2);
case 'dddd': return gsDayNames[d.getDay()];
case 'ddd': return gsDayNames[d.getDay()].substr(0, 3);
case 'dd': return d.getDate().zf(2);
case 'hh': return ((h = d.getHours() % 12) ? h : 12).zf(2);
case 'nn': return d.getMinutes().zf(2);
case 'ss': return d.getSeconds().zf(2);
case 'a/p': return d.getHours() < 12 ? 'a' : 'p';
}
}
);
*/
};
/**
* Function that returns a number rounded to a specified place.
*
* @param {Object} number Base number to round
* @param {Object} radian Position to round to (+2 = two places after the decimal, -2 = hundreds place)
*/
Math.roundTo = function (number, radian)
{
var tempNumber = number;
if (radian > 0)
{
tempNumber = number * Math.pow(10, radian);
}
else
{
tempNumber = number / Math.pow(10, -radian);
}
tempNumber = Math.pow(10, -radian) * Math.round(tempNumber);
return tempNumber;
};