Rally App SDK: Is there a way to have variable columns for table? - rally

Using the Rally App SDK, is there a way to create a table with a variable number of columns? For example, for a selected release, the columns are the iterations within that release date range, and the rows are each project.
I have all of the data I want to display, but not sure how to create the table.

Here's an example app that dynamically builds a table config with Iteration Names as columns and then adds some dummy data to it. Not too exciting, but it illustrates the idea.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!-- Copyright (c) 2002-2011 Rally Software Development Corp. All rights reserved. -->
<html>
<head>
<title>Iterations as Table Columns</title>
<meta name="Name" content="App: Iterations as Table Columns"/>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.29/sdk.js"></script>
<script type="text/javascript">
function iterationsAsTableColumns(rallyDataSource)
{
var wait = null;
var table = null;
var tableHolder = null;
// private method the builds the table of Iteration columns and your info
function showResults(results)
{
if (wait) {
wait.hide();
wait = null;
}
if (table) {
table.destroy();
}
var myIterations = results.iterations;
if (myIterations.length === 0) {
tableHolder.innerHTML = "No iterations were found";
return;
}
var columnKeys = new Array();
var columnHeaders = new Array();
var columnWidths = new Array();
var columnWidthValue = '80px';
var keyName;
// Dynamically build column config arrays for table config
for (i=0; i<myIterations.length;i++){
keyName = "Column"+i;
columnKeys.push(keyName);
columnHeaders.push("'" + myIterations[i].Name + "'");
columnWidths.push("'" + columnWidthValue + "'");
}
var config = { 'columnKeys' : columnKeys,
'columnHeaders' : columnHeaders,
'columnWidths' : columnWidths
};
table = new rally.sdk.ui.Table(config);
var cellValue;
var propertyAttributeStatement;
var rowData = new Array();
for (i=0;i<10;i++){
// create Object for row data
rowItem = new Object();
for (j=0; j<columnKeys.length;j++){
cellValue = "Cell[" + i + "][" + j + "] = Your Data Here";
propertyAttributeStatement = "rowItem." + columnKeys[j] + " = '"+cellValue+"';";
eval(propertyAttributeStatement);
}
rowData.push(rowItem);
}
table.addRows(rowData);
table.display(tableHolder);
}
//private method to query for iterations that get listed as columns
function runMainQuery(sender, eventArgs) {
var queryCriteria = '(Project.Name = "Avalanche Hazard Mapping"")';
var queryConfig =
{
key : "iterations",
type : "Iteration",
fetch : "FormattedID,Name,Project,StartDate,EndDate,CreationDate",
order : "CreationDate desc",
};
tableHolder.innerHTML = "";
wait = new rally.sdk.ui.basic.Wait({});
wait.display(tableHolder);
rallyDataSource.findAll(queryConfig, showResults);
}
//private method to start building controls on page
function initPage() {
buttonSpan = document.getElementById('buttonSpan');
tableHolder = document.getElementById('table');
var buttonConfig = {
text: "Show Table",
value: "myValue"
};
var showTableButton = new rally.sdk.ui.basic.Button(buttonConfig);
showTableButton.display(buttonSpan, runMainQuery);
}
// only public method
this.display = function() {
rally.sdk.ui.AppHeader.showPageTools(true);
initPage();
};
}
</script>
<script type="text/javascript">
rally.addOnLoad(function() {
var rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var iterationsAsTableColumnsExample = new iterationsAsTableColumns(rallyDataSource);
iterationsAsTableColumnsExample.display();
});
</script>
</head>
<body>
<div>
<span id="buttonSpan"></span>
</div>
<div style="height: 15px;"> </div>
<div id="table"></div>
</body>
</html>

Related

MSE WebM video with no audio

I've written a MSE video player and it's loading WebMs. These are loading well, however I have a problem with video files with no audio tracks.
I've tried changing the codec depending on if there is audio
mediaSource.addSourceBuffer(`video/webm; ${videoHasAudio(asset) ? 'codecs="vp9,vorbis"' : 'codecs="vp9"'}`)`
And I thought this was working but now isn't. How do I run silent WebMs in MSE?
I have added sample MSE project here:
https://github.com/thowfeeq178/MediaSourceExtention
checkout the example in the github
overview:
we need to add one for video and one for audio like below:
// BBB : https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd
var baseUrl = "https://dash.akamaized.net/akamai/bbb_30fps/";
var initUrl = baseUrl + "bbb_30fps_480x270_600k/bbb_30fps_480x270_600k_0.m4v";
var initAudioUrl = baseUrl + "bbb_a64k/bbb_a64k_0.m4a";
var templateUrl =
baseUrl + "bbb_30fps_480x270_600k/bbb_30fps_480x270_600k_$Number$.m4v";
var templateUrlForAudio = baseUrl + "bbb_a64k/bbb_a64k_$Number$.m4a";
var sourceBuffer;
var audioSourceBuffer;
var index = 0;
var audioIndex = 0;
var numberOfChunks = 159;
var video = document.querySelector("video");
var ms = new MediaSource();
function onPageLoad() {
console.log("page loaded ..");
if (!window.MediaSource) {
console.error("No Media Source API available");
return;
}
// making source controlled by JS using MS
video.src = window.URL.createObjectURL(ms);
ms.addEventListener("sourceopen", onMediaSourceOpen);
}
function onMediaSourceOpen() {
// create source buffer
sourceBuffer = ms.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
audioSourceBuffer = ms.addSourceBuffer('audio/mp4; codecs="mp4a.40.5"');
// when ever one segment is loaded go for next
sourceBuffer.addEventListener("updateend", nextSegment);
audioSourceBuffer.addEventListener("updateend", nextAudioSegment);
// fire init segemnts
GET(initUrl, appendToBuffer);
GET(initAudioUrl, appendToAudioBuffer);
// play
video.play();
}
// get next segment based on index and append, once everything loaded unlisten to the event
function nextSegment() {
var url = templateUrl.replace("$Number$", index);
GET(url, appendToBuffer);
index++;
if (index > numberOfChunks) {
sourceBuffer.removeEventListener("updateend", nextSegment);
}
}
// get next audio segment based on index and append, once everything loaded unlisten to the event
function nextAudioSegment() {
var audioUrl = templateUrlForAudio.replace("$Number$", audioIndex);
GET(audioUrl, appendToAudioBuffer);
audioIndex++;
if (index > numberOfChunks) {
audioSourceBuffer.removeEventListener("updateend", nextAudioSegment);
}
}
// add to existing source
function appendToBuffer(videoChunk) {
if (videoChunk) {
sourceBuffer.appendBuffer(new Uint8Array(videoChunk));
}
}
function appendToAudioBuffer(audioChunk) {
if (audioChunk) {
audioSourceBuffer.appendBuffer(new Uint8Array(audioChunk));
}
}
// just network thing
function GET(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.onload = function(e) {
if (xhr.status != 200) {
console.warn("Unexpected status code " + xhr.status + " for " + url);
return false;
}
callback(xhr.response);
};
xhr.send();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>MSE Demo</title>
</head>
<body onload="onPageLoad()">
<h1>MSE Demo</h1>
<div>
<video muted controls width="80%"></video>
</div>
</body>
</html>

Can you pretty print IHtmlContent?

If I have a IHtmlContent can I pretty print it?
Example:
var html = new HtmlString("<article><h2>Hello!</h2></article>");
I want it pretty printed with line breaks and indention into:
<article>
<h2>Hello!</h2>
</article>
I do not want:
<article><h2>Hello!</h2></article>
You could try to JavaScript to add the line breaks and indention into, then, use <pre> tag to render the html content. Please check the following sample:
Index.cshtml:
#{
var html ="<article><h2>Hello!</h2></article>";
}
<div id="printdiv">
#Html.Raw(html)
</div>
<div id="output">
</div>
<input type='button' id='btn' value='Print' onclick='printDiv();'>
#section Scripts{
<script>
function printDiv() {
var divToPrint = document.getElementById('printdiv');
//display the pretty html content in the web page.
document.getElementById("output").innerHTML = "<pre>" + process(divToPrint.innerHTML).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</pre>";
//create a new window to print the div content.
var newWin = window.open('', 'Print-Window');
newWin.document.open();
newWin.document.write('<html><body onload="window.print()"><pre>' + process(divToPrint.innerHTML).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + '</pre></body></html>');
newWin.document.close();
setTimeout(function () { newWin.close(); }, 10);
}
function process(str) {
var div = document.createElement('div');
div.innerHTML = str.trim();
return format(div, 0).innerHTML;
}
function format(node, level) {
var indentBefore = new Array(level++ + 1).join(' '),
indentAfter = new Array(level - 1).join(' '),
textNode;
for (var i = 0; i < node.children.length; i++) {
textNode = document.createTextNode('\n' + indentBefore);
node.insertBefore(textNode, node.children[i]);
format(node.children[i], level);
if (node.lastElementChild == node.children[i]) {
textNode = document.createTextNode('\n' + indentAfter);
node.appendChild(textNode);
}
}
return node;
}
</script>
}
The result like this:
You can parse it XML with XDocument.Parse then use XmlWriter with its settings set to Indent to true. Worked for me on my HTML too.
var html = new HtmlString("<article><h2>Hello!</h2></article>");
using var writer = new StringWriter();
html.WriteTo(writer, HtmlEncoder.Default);
var htmlString = writer.ToString();
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Encoding = Encoding.UTF8,
Indent = true,
};
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb, settings))
{
XDocument.Parse(htmlString).Save(writer);
}
Console.WriteLine(sb.ToString());

How to create dropdown list with TestSet names in Rally sdk

I'm trying to create dropdown list with names of TestSets. I need that for filtering purpose.
I have tried with below code:
function dropdownChanged(dropdown, eventArgs) {
var selectedItem = eventArgs.item;
var selectedValue = eventArgs.value;
}
function onLoad() {
var rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var config = {
type : "testset",
attribute : "name"
};
var attributeDropdown = new rally.sdk.ui.AttributeDropdown(config, rallyDataSource);
attributeDropdown.display("aDiv", dropdownChanged);
}
rally.addOnLoad(onLoad);
Can anyone help me with that?
You may use Object Dropdown instead of Attribute Dropdown. In this code test set selection from the attribute dropdown results in a table populated with test cases of the selected test set.
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.32/sdk.js"></script>
<script type="text/javascript">
var table = null;
function showTable(results) {
var t = " ";
var tableConfig = {
columnKeys : ['Name','FormattedID','TestCases'],
columnHeaders : ['Name','FormattedID','TestCases'],
columnWidths : ['200px','200px', '400px']
};
table = new rally.sdk.ui.Table(tableConfig);
for (var i=0; i < results.ts.length; i++) {
if (results.ts[i].TestCases){
console.log(results.ts[i].TestCases.length);
for(var j = 0; j < results.ts[i].TestCases.length; j++){
// console.log(results.ts[i].TestCases.length);
// console.log(results.ts[i].TestCases[j].FormattedID);
t += " ";
t += results.ts[i].TestCases[j].FormattedID;
}
results.ts[i].TestCases=t;
}
table.addRows(results.ts);
table.display(document.getElementById('tableDiv'));
}
}
function dropdownChanged(dropdown, eventArgs) {
if(table) {
table.destroy();
}
document.getElementById('tableDiv').innerHTML = "";
var queryConfig = {
type : 'testset',
key : 'ts',
fetch: 'Name,FormattedID,TestCases',
query: '(Name = "' + eventArgs.item.Name + '")'
};
rallyDataSource.findAll(queryConfig, showTable);
}
function onLoad() {
rallyDataSource = new rally.sdk.data.RallyDataSource('111', //USE YOUR OIDs
'222',
'false',
'false');
var config = {
type : "testset",
attribute: "Name",
query : '(ScheduleState = "Defined")'
};
var objectDropdown = new rally.sdk.ui.ObjectDropdown(config, rallyDataSource);
objectDropdown.display("aDiv", dropdownChanged);
}
rally.addOnLoad(onLoad);
</script>
</head>
<body>
<div id="aDiv"></div>
<div id="tableDiv"></div>
</body>
</html>

Multiple Bing Map Pushpins from SQL not showing in Firefox & Chrome but do in IE

I'm displaying a Bing Map (v7) in my Webmatrix2 website with a series of pushpins & infoboxes drawn from a SQL Express database using a JSON enquiry.
While the maps appears in all 3 browsers I'm testing (IE, FF & Chrome) the pushpins are sometimes not showing in FF & Chrome, particularly if I refresh with Cntrl+F5
This is my first JSON and Bing Maps app so expect there's a few mistakes.
Any suggestions on how to improve the code and get display consistency?
#{
Layout = "~/_MapLayout.cshtml";
}
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<link rel="StyleSheet" href="infoboxStyles.css" type="text/css">
<script type="text/javascript">
var map = null;
var pinLayer, pinInfobox;
var mouseover;
var pushpinFrameHTML = '<div class="infobox"><a class="infobox_close" href="javascript:closeInfobox()"><img src="/Images/close2.jpg" /></a><div class="infobox_content">{content}</div></div><div class="infobox_pointer"><img src="images/pointer_shadow.png"></div>';
var pinLayer = new Microsoft.Maps.EntityCollection();
var infoboxLayer = new Microsoft.Maps.EntityCollection();
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('map'), {
credentials: "my-key",
zoom: 4,
center: new Microsoft.Maps.Location(-25, 135),
mapTypeId: Microsoft.Maps.MapTypeId.road
});
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
AddData();
}
$(function AddData() {
$.getJSON('/ListSchools', function (data) {
var schools = data;
$.each(schools, function (index, school) {
for (var i = 0; i < schools.length; i++) {
var pinLocation = new Microsoft.Maps.Location(school.SchoolLat, school.SchoolLon);
var NewPin = new Microsoft.Maps.Pushpin(pinLocation);
NewPin.title = school.SchoolName;
NewPin.description = "-- Learn More --";
pinLayer.push(NewPin); //add pushpin to pinLayer
Microsoft.Maps.Events.addHandler(NewPin, 'mouseover', displayInfobox);
}
});
infoboxLayer.push(pinInfobox);
map.entities.push(pinLayer);
map.entities.push(infoboxLayer);
});
})
function displayInfobox(e) {
if (e.targetType == "pushpin") {
var pin = e.target;
var html = "<span class='infobox_title'>" + pin.title + "</span><br/>" + pin.description;
pinInfobox.setOptions({
visible: true,
offset: new Microsoft.Maps.Point(-33, 20),
htmlContent: pushpinFrameHTML.replace('{content}', html)
});
//set location of infobox
pinInfobox.setLocation(pin.getLocation());
}
}
function closeInfobox() {
pinInfobox.setOptions({ visible: false });
}
function getCurrentLocation() {
var geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);
geoLocationProvider.getCurrentPosition();
}
</script>
<body onload="getMap();">
<div id="map" style="position:relative; width:800px; height:600px;"></div>
<div>
<input type="button" value="Find Nearest Schools" onclick="getCurrentLocation();" />
</div>
</body>
The JSON file is simply
#{
var db = Database.Open("StarterSite");
var sql = #"SELECT * FROM Schools WHERE SchoolLon != ' ' AND SchoolLon != 'null' ";
var data = db.Query(sql);
Json.Write(data, Response.Output);
}
Add your pinLayer, infobox, and infoboxLayer before calling the AddData function and see if that makes a difference. Also verify that school.SchoolLat and school.SchoolLon are numbers and not a string version of a number. If they are a string, then use parseFloat to turn them into a number. Other than that everything looks fine.

google maps api v2 map.removeOverlay() marker array issue

To start off with, I would like to say that I have been looking on the internet for a really long time and have been unable to find the answer, hence my question here.
My latest school project is to create an admin page for adding articles to a database, the articles are connected to a point on a google map. The requirement for adding the point on the map is that the user is able to click the map once and the marker is produced, if the map is clicked a second time the first marker is moved to the second location. (this is what I am struggling with.)
The problem is, as the code is now, I get the error that markersArray is undefined. If I place the var markersArray = new Array; underneath the eventListener then I get an error that there is something wrong the main.js (googles file) and markersArray[0] is undefined in the second if.
By the way, I have to use google maps API v2, even though it is old.
<script type="text/javascript">
//<![CDATA[
var map;
var markers = new Array;
function load() {
if (GBrowserIsCompatible()) {
this.counter = 0;
this.map = new GMap2(document.getElementById("map"));
this.map.addControl(new GSmallMapControl());
this.map.addControl(new GMapTypeControl());
this.map.setCenter(new GLatLng(57.668911, 15.203247), 7);
GDownloadUrl("genxml.php", function(data) {
var xml = GXml.parse(data);
var Articles = xml.documentElement.getElementsByTagName("article");
for (var i = 0; i < Articles.length; i++) {
var id = Articles[i].getAttribute("id");
var title = Articles[i].getAttribute("title");
var text = Articles[i].getAttribute("text");
var searchWord = Articles[i].getAttribute("searchWord");
var point = new GLatLng(parseFloat(Articles[i].getAttribute("lat")),
parseFloat(Articles[i].getAttribute("lng")));
var article = createMarker(point, id, title, text);
this.map.addOverlay(article);
}
});
}
var myEventListener = GEvent.bind(this.map,"click", this, function(overlay, latlng) {
if (this.counter == 0) {
if (latlng) {
var marker = new GMarker(latlng);
latlng1 = latlng;
this.map.addOverlay(marker);
this.counter++;
markers.push(marker); //This is where I get the error that markersArray is undefined.
}
}
else if (this.counter == 1) {
if (latlng){
alert (markers[0]);
this.map.removeOverlay(markers[0]);
var markers = [];
this.map.addOverlay(marker);
this.counter++;
}
}
});
}
function createMarker(point, id, title, text) {
var article = new GMarker(point);
var html = "<b>" + title + "</b> <br/>"
GEvent.addListener(article, 'click', function() {
window.location = "article.php?id=" + id;
});
return article;
}
I solved the problem. I'm not exactly sure why it worked but this is what it looks like now:
var markersArray = [];
function load() {
if (GBrowserIsCompatible()) {
this.counter = 0;
this.map = new GMap2(document.getElementById("map"));
this.map.addControl(new GSmallMapControl());
this.map.addControl(new GMapTypeControl());
this.map.setCenter(new GLatLng(57.668911, 15.203247), 7);
GDownloadUrl("genxml.php", function(data) {
var xml = GXml.parse(data);
var Articles = xml.documentElement.getElementsByTagName("article");
for (var i = 0; i < Articles.length; i++) {
var id = Articles[i].getAttribute("id");
var title = Articles[i].getAttribute("title");
var text = Articles[i].getAttribute("text");
var searchWord = Articles[i].getAttribute("searchWord");
var type = Articles[i].getAttribute("type");
var point = new GLatLng(parseFloat(Articles[i].getAttribute("lat")),
parseFloat(Articles[i].getAttribute("lng")));
var article = createMarker(point, id, title, text);
this.map.addOverlay(article);
}
});
}
var myEventListener = GEvent.bind(this.map,"click", this, function(overlay, latlng) {
var marker = new GMarker(latlng);
if (this.counter == 0) {
if (latlng) {
latlng1 = latlng;
this.map.addOverlay(marker);
markersArray.push(marker);
this.counter++;
}
}
else if (this.counter == 1) {
if (latlng){
this.map.removeOverlay(markersArray[0]);
this.map.addOverlay(marker);
this.counter++;
}
}
});
}
function createMarker(point, id, title, text) {
var article = new GMarker(point);
var html = "<b>" + title + "</b> <br/>"
GEvent.addListener(article, 'click', function() {
window.location = "article.php?id=" + id;
});
return article;
}