how to display a rally "custom board" dashboard in confluence wiki - javascript
I have been digging in the this site and others for several days and the answer to my problem still escapes me.
I have read all of these pages:
http://pastebin.com/cbagkw8h
but none of them exactly answers this question:
I am trying to get a Rally Dashboard (custom board) to appear in HTML/Javascript in a confluence wiki. I have gotten a simple Standard Report working using a read-only account and AppSDK1.32 with loginKey by embedding the following HTML/Javascript into the Confluence wiki page:
{html}
<meta name="Name" content="App Example: Rally Application" />
<meta name="Version" content="2011.04" />
<meta name="Vendor" content="Rally Software" />
<script type="text/javascript"
src="https://rally1.rallydev.com/apps/1.32/sdk.js?loginKey=loginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkey">
</script>
<script type="text/javascript">
function onLoad() {
var rallyDataSource = new rally.sdk.data.RallyDataSource(
'__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
rally.sdk.ui.AppHeader.destroy();
var reportConfig = {report: rally.sdk.ui.StandardReport.IterationBurndown,
width : 400, height: 300};
var report = new rally.sdk.ui.StandardReport(reportConfig);
report.display("reportDiv");
}
rally.addOnLoad(onLoad);
</script>
<div id="reportDiv" style="width: 400px; margin-left:20px"></div>
<br/>
{html}
I am trying to expand this success to an entire dashboard with App SDK2.x using the new apiKey - by using the following code:
{html}
<meta name="Name" content="App Example: Rally Application" />
<meta name="Version" content="2015.04" />
<meta name="Vendor" content="eBay Enterprise" />
<script type="text/javascript"
src="https://loginapirally1.rallydev.com/apps/1.32/sdk.js?loginKey=loginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkey">
</script>
<script type="text/javascript">
function onLoad() {
rally.sdk.ui.AppHeader.destroy();
document.getElementById("iframeA").width = screen.width - 60 ;
document.getElementById("iframeA").height = (screen.width - 60 ) * 3;
}
rally.addOnLoad(onLoad);
</script>
<iframe id="iframeA" src="https://loginapirally1.rallydev.com/#/111111111d/custom/222222222?expandApp=333333333&apiKey=_apikeyapikeyapikeyapikeyapikeyapikeyapikey" width="1024" height="1024">
</iframe>
<br/>
{html}
I am noticing a few things:
1) it almost works - I get the dashboard/report title but not the cards
2) the apiKey seems to have no affect at all - I still get prompted for a login and password (which I could stand if I could see the cards).
3) it doesn't seem to matter if I put the apiKey before or after the hash symbol
Citation A suggested using the "full screen" dashboard/report but didn't cover the apiKey.
Citaton B says that the AppSDK2 uses the apiKey as of Apr 14 2014 but doesn't say how to use it exactly with AppSDK2.
I have gotten the apiKey to work with the Ruby API but it is unclear how to access the dashboard/reports from there.
Citation C says that the AppSDK1 is based on the Javascript dojo framework and the AppSDK2 is based on the Javascript Sencha's ExtJS but avoids giving any kind of rosetta stone from one to the other.
The only other options I can think of is to 1) copy the entire HTML page-source from the "Custom Board" and then start debugging the Javascript with ExtJS (but I cannot find an example of where to put the apiKey for ExtJS) or 2) bypass all of the APIs and use Ruby Watir-Webdriver (which uses
Selenium) and VNCServer to clip an image of the "Custom Board" page and show THAT in confluence.
Citations: http://pastebin.com/YMUEPjSF
The issue seems to be specific to the canned Custom Board that cannot be loaded externally. It should work if you write a js source code to build a similar Board and compile that into a deployment html. That is similar to option (1) you mentioned in the end of your post if I understand it correctly.
Here is my test where I compared Custom Board and Custom HTML side by side.
Below is a screenshot from Rally. This custom dashboard has Custom Board on the left and Custom HTML on the right. The Custom HTML is using a code example of filterable board from AppSDK2 documentation.
Next I use this code:
<html>
<head>
<title>Custom Grid</title>
<meta name="Name" content="App: Custom Dashboard"/>
<meta name="Version" content="2011.08.31"/>
<meta name="Vendor" content="Rally Labs, NickM"/>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.32/sdk.js?loginKey=c33e83...."></script>
<script type="text/javascript">
rally.addOnLoad(function() {
var iframe = document.createElement("iframe");
iframe.src = "https://loginapirally1.rallydev.com/#/14018981229/custom/34207853894"
iframe.width = 2000;
iframe.height = 1000;
document.getElementById("storyboard").appendChild(iframe);
});
</script>
</head>
<body>
<div id="storyboard"></div>
</body>
</html>
Here is the dashboard loaded externally on localhost:3000. The left column of the dashboard where Custom Board is expected to load is empty, but the right column with a custom html code of a board loads successfully:
It looks like the canned Custom Board cannot be loaded externally but a custom html code written in AppSDK2 can be displayed externally.
A couple of observations:
There is really no upgrade path from AppSDK1 to AppSDK2. The underlying frameworks and the class structures are very different and the code cannot be simply refactored. There is no translation from one to the other.
LoginKey is intended to work with AppSDK1. Both are legacy. Both predate AppSDK2 and ApiKey. To use ApiKey with custom html apps written with AppSDK2 see "Use API Key with AppSDK2" article.
AppSDK2 does not support LoginKey usage for authentication. The reason it seems to work in this example is that we load the entire page. Loading the entire page using iframe's src property is possible with LoginKey. In this example there is no reason to use ApiKey and LoginKey together. You are right that ApiKey makes no difference in this use case.
The way LoginKey works is that it "tricks" the browser into thinking that there is this different server, loginapirally1.rallydev.com. If you look in Network tab of your browser and see that request comes from there it means that LoginKey is working. ApiKey works differently. There is no equivalent to loginapirally1 server with ApiKey.
If you are being prompted to supply login credentials when using LoginKey it means that LoginKey is not working. See "LoginKey Troublshooting" article.
Embedding custom AppSDK2 apps in 3rd party portals (running custom apps externally) is possible with ApiKey, and the supported scenario described in this guide is similar to the option (1) you mentioned in the end of your post. Loading entire Rally page or entire Rallynavigation is not a supported use case even though it is possible with LoginKey.
Related
python selenium webdriver not showing all html
I am developing a web scraper in python. This is my code: from selenium.webdriver.chrome.options import Options from selenium import webdriver from bs4 import BeautifulSoup chrome_options = Options() chrome_options.add_argument("--headless") driver = webdriver.Chrome(options=chrome_options) driver.get("https://www.hapag-lloyd.com/en/home.html") source = driver.page_source soup = BeautifulSoup(source, 'html.parser') print(soup) but the html returned is different from what I saw on the browser(please check the last few lines): <html><head> <meta content="no-cache" http-equiv="Pragma"/> <meta content="-1" http-equiv="Expires"/> <meta content="no-cache" http-equiv="CacheControl"/> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> <link href="data:;base64,iVBORw0KGgo=" rel="shortcut icon"/> <script> (function(){ window["bobcmn"] = "111110101010102000000022000000052000000002a4b927ad200000096300000000300000000300000006/TSPD/300000008TSPD_101300000005https3000000b0081ecde62cab2000d65f90c7efd5185e314a8800e00a5aad11b1a439eb174c6c3f64d45284e14d9508dcf0830d0a2800346a2db5907272d4309ad725a7dc856ab98589c10724bd284477ca152744f4ac2102b44d72e2a1e9200000000200000000"; window.aIv=!!window.aIv;try{(function(){(function(){})();var sZ=78;try{var IZ,lZ,OZ=s(868)?0:1,zZ=s(999)?0:1,ss=s(445)?0:1,Ss=s(601)?0:1;for(var is=(s(421),0);is<lZ;++is)OZ+=s(211)?2:1,zZ+=s(768)?1:2,ss+=(s(54),2),Ss+=s(289)?2:3;IZ=OZ+zZ+ss+Ss;window.zz===IZ&&(window.zz=++IZ)}catch(Ls){window.zz=IZ}var Os=!0;function _(Z){var S=arguments.length,I=[],O=1;while(O<S)I[O-1]=arguments[O++]-Z;return String.fromCharCode.apply(String,I)} function SS(Z){var S=30;!Z||document[J(S,148,135,145,135,128,135,138,135,146,151,113,146,127,146,131)]&&document[_(S,148,135,145,135,128,135,138,135,146,151,113,146,127,146,131)]!==l(68616527636,S)||(Os=!1);return Os}function l(Z,S){Z+=S;return Z.toString(36)}function J(Z){var S=arguments.length,I=[];for(var O=1;O<S;++O)I.push(arguments[O]-Z);return String.fromCharCode.apply(String,I)}function _S(){}SS(window[_S[_(sZ,188,175,187,179)]]===_S);SS(typeof ie9rgb4!==l(1242178186121,sZ)); SS(RegExp("\x3c")[l(1372127,sZ)](function(){return"\x3c"})&!RegExp(l(42811,sZ))[l(1372127,sZ)](function(){return"'x3'+'d';"})); var IS=window[J(sZ,175,194,194,175,177,182,147,196,179,188,194)]||RegExp(J(sZ,187,189,176,183,202,175,188,178,192,189,183,178),l(-60,sZ))[l(1372127,sZ)](window["\x6e\x61vi\x67a\x74\x6f\x72"]["\x75\x73e\x72A\x67\x65\x6et"]),jS=+new Date+(s(267)?375283:6E5),JS,Z_,s_,S_=window[_(sZ,193,179,194,162,183,187,179,189,195,194)],__=IS?s(890)?18994:3E4:s(725)?3775:6E3; document[J(sZ,175,178,178,147,196,179,188,194,154,183,193,194,179,188,179,192)]&&document[J(sZ,175,178,178,147,196,179,188,194,154,183,193,194,179,188,179,192)](J(sZ,196,183,193,183,176,183,186,183,194,199,177,182,175,188,181,179),function(Z){var S=88;document[J(S,206,193,203,193,186,193,196,193,204,209,171,204,185,204,189)]&&(document[_(S,206,193,203,193,186,193,196,193,204,209,171,204,185,204,189)]===_(S,192,193,188,188,189,198)&&Z[J(S,193,203,172,202,205,203,204,189,188)]?s_=!0:document[J(S,206, 193,203,193,186,193,196,193,204,209,171,204,185,204,189)]===l(68616527578,S)&&(JS=+new Date,s_=!1,i_()))});function i_(){if(!document[_(47,160,164,148,161,168,130,148,155,148,146,163,158,161)])return!0;var Z=+new Date;if(Z>jS&&(s(988)?840535:6E5)>Z-JS)return SS(!1);var S=SS(Z_&&!s_&&JS+__<Z);JS=Z;Z_||(Z_=!0,S_(function(){Z_=!1},s(891)?0:1));return S}i_();var I_=[s(915)?10661718:17795081,s(30)?27611931586:2147483647,s(748)?1636390818:1558153217]; function L_(Z){var S=43;Z=typeof Z===l(1743045633,S)?Z:Z[_(S,159,154,126,159,157,148,153,146)](s(837)?37:36);var I=window[Z];if(!I[_(S,159,154,126,159,157,148,153,146)])return;var O=""+I;window[Z]=function(Z,S){Z_=!1;return I(Z,S)};window[Z][J(S,159,154,126,159,157,148,153,146)]=function(){return O}}for(var O_=(s(493),0);O_<I_[l(1294399127,sZ)];++O_)L_(I_[O_]);SS(!1!==window[_(sZ,175,151,196)]);window.LZ={zs:"084e4452c4017800c5def6fe02b0086dc53ff9519b1bcb514d1f4dd874776393bcfec37f99ebfc4795da47aec5f492a8a4131f92a5e26fecd10807e6bd8ba79b77bb1692ddac2154a98808ca5559f35a278cf21dd71a1e61c4579303187e42dc179ae0846f6078a996bb6f824e2238fc7b431f54a421fcf7145bd4fcc3d9b982"}; function Zi(Z){var S=+new Date,I;!document[_(63,176,180,164,177,184,146,164,171,164,162,179,174,177,128,171,171)]||S>jS&&(s(968)?421041:6E5)>S-JS?I=SS(!1):(I=SS(Z_&&!s_&&JS+__<S),JS=S,Z_||(Z_=!0,S_(function(){Z_=!1},s(688)?0:1)));return!(arguments[Z]^I)}function s(Z){return 265>Z} (function(){var Z=/(\A([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}\Z)|(\A(([0-9a-f]{1,4}:){1,7}|:):\Z)|(\A:(:[0-9a-f]{1,4}){1,7}\Z)/ig,S=document.getElementsByTagName("head")[0],I=[];S&&(S=S.innerHTML.slice(0,1E3));while(S=Z.exec(""))I.push(S)})();})();}catch(x){}finally{ie9rgb4=void(0);};function ie9rgb4(a,b){return a>>b>>0}; })(); </script> <script src="/TSPD/081ecde62cab200082f75af3905bec19af31f4aaf7bd4079c3ac5a62a6fb4096cfcec166097ddde7?type=7" type="text/javascript"></script> <noscript>Please enable JavaScript to view the page content.<br/>Your support ID is: 17324345507588527622.</noscript> </head><body> <form action="" enctype="multipart/form-data" method="post"><input name="_pd" type="hidden" value=""/></form></body></html> It reports "Please enable JavaScript to view the page content.Your support ID is: 17324345507588527622.". I checked a few queries launched by other people. This problem should have been solved by the use of chrome. And I also tried to get html with the requests-html. But the programming just keep running and do not return a thing.
It's a limitation of the page_source method. See this answer: https://stackoverflow.com/a/64897405/1387701 and See the source code: Description copied from interface: WebDriver Get the source of the last loaded page. If the page has been modified after loading (for example, by Javascript) there is no guarantee that the returned text is that of the modified page. Please consult the documentation of the particular driver being used to determine whether the returned text reflects the current state of the page or the text last sent by the web server. The page source returned is a representation of the underlying DOM: do not expect it to be formatted or escaped in the same way as the response sent from the web server. Think of it as an artist's impression.
Tweak CRM Sitemap to have different URL navigations for different environments
We want to have different Sitemap subarea Url, so that the Sitemap can be independent of environments & worryfree when we refresh the environments from higher region to lower. Even deployments can be error free & can avoid manual step in post deployment activity. Dev: <SubArea Id="nav_hub" ResourceId="Hub_SubArea_Title" DescriptionResourceId="Hub_SubArea_Description" ToolTipResourseId="Hub_SubArea_ToolTip" Icon="/_imgs/Hub_32.png" Url="http://mydevhub.com/home.aspx" AvailableOffline="false" /> UAT: <SubArea Id="nav_hub" ResourceId="Hub_SubArea_Title" DescriptionResourceId="Hub_SubArea_Description" ToolTipResourseId="Hub_SubArea_ToolTip" Icon="/_imgs/Hub_32.png" Url="http://myuathub.com/home.aspx" AvailableOffline="false" /> Any idea to do that?
I ended up doing this workaround as we cannot pass dynamic variable url to Sitemap. 1.Created a Sub-Area with url to custom HTML web resource as below: $webresource:pub/Scripts/External/navigation.html 2.Just used the below content to open a new window based on org url: <html><head> <script src="../../../ClientGlobalContext.js.aspx" type="text/javascript"></script> <script language="javascript"> var crmUrl = parent.Xrm.Page.context.getClientUrl(); if (crmUrl.indexOf('devinstance.crm.dynamics.com') > 0) parent.window.open('http://mydevhub.com/home.aspx'); if (crmUrl.indexOf('uatinstance.crm.dynamics.com') > 0) parent.window.open('http://myuathub.com/home.aspx'); </script> </head><body> </body></html>
In case anyone else lands here (and since I can't comment yet) the answer provided is deprecated. The newer way of achieving this is var globalContext = Xrm.Utility.getGlobalContext(); globalContext.getClientUrl(); (Source)
Can you use JavaScript inside an email, which is sent using Python? [duplicate]
This question already has answers here: Is JavaScript supported in an email message? (11 answers) Closed 5 years ago. Can you use JavaScript inside an email, which is sent using Python? My aim is to send a working clock inside an email. I am trying to use Python to do so. I am using IDLE and the Python libraries stmplib, email and html2text to send emails. My code looks like the code shown below. I omitted some details (style and script) as they are unimportant. me = "my.email#gmail.com" you = "my.email#gmail.com" msg = MIMEMultipart('alternative') msg['Subject'] = "Clock" msg['From'] = me msg['To'] = you html = """\ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Clock</title> <style></style> </head> <body> <div class="clock"> <p class="clockhour">HH</p> <p class="clocksym1">:</p> <p class="clockminute">MM</p> <p class="clocksym2">:</p> <p class="clocksecond">SS</p> </div> <script type="text/javascript"></script> </body> </html> """ text = html2text(html) part1 = MIMEText(text, 'plain') part2 = MIMEText(html, 'html') msg.attach(part1) msg.attach(part2) s = SMTP('smtp.gmail.com:587') s.ehlo() s.starttls() s.login("my.email#gmail.com", "my password") s.sendmail(me, you, msg.as_string()) s.quit() The full version of the HTML in this code gives me a properly functioning clock, but if I attempt sending it to myself using Gmail I receive a different result. Viewing the HTML: In Gmail: This shows, that parts of the CSS load, but others like the font or the font size don't. It also shows that the JavaScript does not load. (Normally viewing the HTML code in a browser gives a functioning clock, while in an email doesn't.) Is there a way to send an email with this clock?
Short Answer: No. You can't use JavaScript for email template. Tricky way: You can work on relevant file and get the parsed value in your template file using server side language. Example: clock.js // code for js template.php // echo the value // The value is rendered in html and works in email template too. But this case is not suitable for you as you're trying to implement countdown clock. This is suitable only for static value. However, linking to external page content will help you to show the timer. For your case, You may try using http://motionmailapp.com/ Hope, this helps!
javascript is unsupported in email html, but at least you can place a link to the page with clock countdown.
AngularJS - simple tutorial wont work
I started out with Angular and came across this code that should work, but it doesn't. Angular is downloaded and added via the script tag and it is correct, others tutorials worked before. I have tried everything but just doesnt seem to find out what's the problem. Started learning from the book AngularJS from O'Reilly. <html ng-app="nameApp"> <head> <title>Angular Training</title> </head> <body ng-controller="NameCtrl"> <ul> <li ng-repeat="name in names"> {{ name }} remove </li> </ul> <form ng-submit="addName()"> <input type="text" ng-model="enteredName"> <input type="submit" value="add"> </form> <script src='unzipped___AngularJS-1.3.12\angular-1.3.12\angular.min.js'></script> <script> var nameApp = angular.module('nameApp', []); nameApp.controller('NameCtrl', function ($scope){ $scope.names = ['Larry','Curly', 'Moe']; $scope.addName = function(){ $scope.names.push($scope.enteredName); $scope.enteredName = ''; }; $scope.removeName = function(name){ var i = $scope.names.indexOf(name); $scope.names.splice(i, 1); }; }); </script> </body> </html> https://jsfiddle.net/eqk5adc1/3/
https://jsfiddle.net/5qv2e2jm/ Try adding this <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
Based on comments, it sounds like you are likely running into security issues. Modern browsers can typically prevent loading external js files from the local file system for security reasons. This is dependent on the browser you use. For more information, this security concept is called the same-origin policy. "this is a Javascript frameworks so in my opinion a server could be omitted..." This is not necessarily true because of the aforementioned security concept. If you are using Firefox you can disable this security feature (though I would recommend only temporarily) using the following steps: Navigate to about:config In the search bar type security.fileuri.strict_origin_policy Set this property to false. These steps should allow local js files to be loaded in Firefox. In the end, it may be easier to simply setup a server or use a cheap cloud server (google, amazon, c9.io, etc.). Another option might be just using jsfiddle like you did above.
Options to store data on desktop, using webpage
Goal: To sum it up, I'm trying to replace an excel spreadsheet. I'm creating an application that will run in IE9, but does not connect to the internet or an intranet (I know, I know. Just bear with me. If you're curious read more below). It needs to use CRUD (create, read, update, and delete) methods on a set of data that changes daily. The dataset must persist even when the browser is closed. Question: What options are available, using javascript and html, for storing data on the local computer the web page is accessed on? I'm doing this at work, so there will be no server-side to this. I also will not be able to install any software on the computer, although I can download javascript plugins. The webpage will be loaded from a file on the computer, using Win 7 and IE9. Background: This deserves an explanation. I use an excel spreadsheet to track a set of data that changes daily. I'm learning HTML and javascript, and I can create a much better (and easier to use) solution as a webpage. I can create the UI / UX, but I'm having a difficult time figuring out how to store the data on the local computer. Any good suggestions? Attempts: Unfortunately, it seems localStorage is not an option. I'm attempting to use jStorage, but I've been running into problems there, also. A similar set of problems has been encountered using simpleStorage. Thank you for considering, please let me know if any more info is needed, or if I need to clarify something. Addendum: Localstorage, and other forms of HTML5 storage, do not work. Officially it does, unofficially it is very buggy. See blog post here, and SO answer here. Either way, with the following simple code: HTML: <!DOCTYPE html> <html> <head> <title>Backlog Tracker</title> <script src="jquery-2.1.1.min.js"></script> <script src="backlog_localstorage.js"></script> </head> <body> </body> </html> and javascript (ref as "backlog_localstorage.js" above): $(document).ready(function(){ $("body").append("<button>Try It</button>"); $("button").click(function(){ localStorage.setItem("key1", "Hello"); console.log(localStorage.getItem("key1")); }); }); ... I get the following error: "SCRIPT5007: Unable to get value of the property 'setItem': object is null or undefined" on the line localStorage.setItem("key1", "Hello");
HTA (which is really just an html file with one extra tag and a different file extension) is one possible solution for windows users: Important: Save as demo.hta to run on windows as an app <!DOCTYPE html> <html> <!-- some parts lifted from http://msdn.microsoft.com/en-us/library/ms536496(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/ms536473(v=vs.85).aspx --> <head> <title>State Saving Demo</title> <hta:application id="App" application="yes" applicationname="demo" icon="calc.exe" border="thin" caption="yes" sysmenu="yes" showintaskbar="yes" singleinstance="yes" sysmenu="no" maximizeButton="yes" minimizeButton="yes" navigable="no" scroll="yes" contextmenu="no" selection="no" windowstate="normal" > <!-- Use Internet Explorer 10 Standards mode (to use JSON, CSS3, etc...) --> <meta http-equiv="x-ua-compatible" content="IE=10"> </head> <body onload=loadMe() > <h1 id=h1>Command-line args: </h1> <h3>Persisted Text</h3> <textarea rows=20 cols=100 id=mydata onchange=saveMe() > You can change me and i won't forget! </textarea> <script> document.title+=" - Today is " + Date(); // task/title bar demo h1.innerHTML+= JSON.stringify( App.commandLine ); // optional invocation info here (much like a real app) // app-specific custom code: FILENAME="state.txt"; function saveMe(){save(FILENAME, mydata.value); } function loadMe(){mydata.value=load(FILENAME) || mydata.value;} // generic utils: function load(filename) { //IE FSO file Loader var file, text="", fso= new ActiveXObject('Scripting.FileSystemObject'); try{ file = fso.OpenTextFile(filename, 1, false); text = file.readAll(); file.Close(); }catch(y){} return text; } function save(filename, sData){ //IE FSO file Saver var file, fso = new ActiveXObject('Scripting.FileSystemObject'); file = fso.CreateTextFile(filename, 2, false); file.write(sData); file.Close(); return file; } </script> </body> </html> I recently re-discovered HTAs, and they are not half bad. I don't think I would want to distribute and maintain them, but HTA's are an easy way to make simple desktop app using HTML, CSS, and JS. Its nice not to have to build anything to "recompile" the app after changes are made. saves a few steps compared to node-webkit, packaged apps, air, cordova, etc, but HTA's have a major downside: they only work on windows afaik...
Looks to me like you can use LocalStorage, the big question is how are you trying to store it? You can easily store an object/array into LocalStorage, and that object/array can be your data, then JS can output this into a table. If you're looking to store actual files then you're looking at something more like an ActiveX plugin. http://caniuse.com/#search=localstorage Alternatively if you have internet access through a desktop or a phone you can put this on Google Drive. This would be far easier than reinventing the wheel.