diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..9da27ca6 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,19 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": ["eslint:recommended", "prettier"], + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "rules": { + "no-irregular-whitespace": [ + "error", + { + "skipComments": true + } + ] + } +} diff --git a/.gitattributes b/.gitattributes index 412eeda7..49e33503 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Auto detect text files and perform LF normalization -* text=auto +* text=auto eol=lf # Custom for Visual Studio *.cs diff=csharp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..cf928349 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,13 @@ +name: build +on: [push] +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '14' + - run: npm ci + - run: npm run build + - run: npm test diff --git a/.gitignore b/.gitignore index 3844ee89..311bcc99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +docs/dist +dist .DS_Store node_modules *.grunt @@ -7,7 +9,6 @@ obj protos *.temp *.nupkg -*.yml #ignore thumbnails created by windows Thumbs.db #Ignore files build by Visual Studio diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 1da5e27a..00000000 --- a/.jshintrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "browser": true, - "curly": true, - "evil": true, - "globals": { - "console": true, - "define": true, "exports": true, "require": true, "module": true, - "describe": true, "xdescribe": true, "it": true, "xit": true, "expect": true, "runs": true, "waits": true, "waitsFor": true, "itConditionally": true, - "easyXDM": true, - "EventEmitter2": true, - "F2": true, - "jQuery": true, - "$": true - }, - "latedef": true, - "noarg": true, - "quotmark": "single", - "shadow": false, - "sub": true, - "undef": true, - "unused": "vars" -} \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..f9085fe3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +dist +docs \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..e166c065 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{ singleQuote: true, tabWidth: 2, trailingComma: none, useTabs: true } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 76f9372f..00000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: node_js -node_js: - - "6" -notifications: - slack: openf2:A3LmWCHuXdw8SYyWfAGyaWbK -before_script: - - npm install grunt-cli -script: - - grunt travis diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f2f10188..66e41c49 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,6 @@ # Contributing to F2 -F2 is currently maintained by [Markit On Demand](http://www.markit.com/Product/Markit-On-Demand) and governed by an [Advisory Board](http://www.openf2.org/#advisory-board) (shown below). - -![image](http://www.openf2.org/img/advisory-board.png) +F2 is currently maintained by [IHS Markit Digital](https://www.markitdigital.com/). Join the team and help contribute to F2 on GitHub. The following are guidelines for contributing; please familiarize yourself before sending pull requests. @@ -14,11 +12,11 @@ First, a couple of ground rules. 1. Make sure you have a [GitHub account](https://github.com/signup/free). 2. [Submit a ticket for your issue](https://github.com/OpenF2/F2/issues), assuming one does not already exist. **(Search first!)** - * Clearly describe the issue including steps to reproduce when it is a bug. - * Include the F2 version number. + - Clearly describe the issue including steps to reproduce when it is a bug. + - Include the F2 version number. 3. [Fork the F2 repository](https://github.com/OpenF2/F2/fork). -## New to GitHub? +## New to GitHub? GitHub has terrific [Guides](http://guides.github.com/) to help developers through various aspects of contributing to open source projects. @@ -26,9 +24,9 @@ GitHub has terrific [Guides](http://guides.github.com/) to help developers throu ### Understanding the "wip" branch -The latest F2 changes can be found in the `*-wip` branch. This branch's name uses the upcoming version number followed by `-wip` which stands for "work-in-progress", for example `1.3.1-wip` as shown below. There *should* only be one `-wip` branch at any given time. +The latest F2 changes can be found in the `*-wip` branch. This branch's name uses the upcoming version number followed by `-wip` which stands for "work-in-progress", for example `1.3.1-wip` as shown below. There _should_ only be one `-wip` branch at any given time. -Do not work directly in `master`! +Do not work directly in `master`! ![Branches](http://docs.openf2.org/img/branches.png) @@ -36,22 +34,21 @@ Do not work directly in `master`! Once you've forked the F2 repository: -1. Create a new branch in your fork from the next version `*-wip` branch. Do not work directly in `master`! - * `$> git checkout -b 'your_branch_name' *-wip` -3. Read the F2 [coding standards](https://github.com/OpenF2/F2/wiki/Coding-Standards). -4. Add and document unit test(s) for your changes. **At least one unit test is required** for new or changed functionality. -5. Re-run all the Jasmine tests to confirm your changes didn't break anything. `$> grunt test` and/or `$> grunt test-live` -6. Perform browser testing in [supported browsers](https://github.com/OpenF2/F2/wiki/Browser-Compatibility). +1. Create a new branch in your fork from the next version `*-wip` branch. Do not work directly in `master`! + - `$> git checkout -b 'your_branch_name' *-wip` +2. Read the F2 [coding standards](https://github.com/OpenF2/F2/wiki/Coding-Standards). +3. Add and document unit test(s) for your changes. **At least one unit test is required** for new or changed functionality. +4. Re-run all the Jasmine tests to confirm your changes didn't break anything. `$> npm test` and/or `$> npm run test-live` +5. Perform browser testing in [supported browsers](https://github.com/OpenF2/F2/wiki/Browser-Compatibility). ### Committing Changes -* You should only commit files you have changed. **Do not commit compiled or generated F2 files, except:** - * If you've modified any file in the `/sdk/src/` directory, you must commit `/sdk/f2.min.js` for the [Travis unit tests](https://travis-ci.org/OpenF2/F2). -* After you've staged your changes, add a detailed commit message. -* Push committed changes to your fork's branch. -* [Submit a pull request](https://help.github.com/articles/using-pull-requests) for `F2\*-wip` **not** `F2\master`. -* Add a message or additional detail for your changes in the pull request comments. -* Wait for your change(s) to be reviewed. +- You should only commit files you have changed. **Do not commit compiled or generated F2 files** +- After you've staged your changes, add a detailed commit message. +- Push committed changes to your fork's branch. +- [Submit a pull request](https://help.github.com/articles/using-pull-requests) for `F2\*-wip` **not** `F2\master`. +- Add a message or additional detail for your changes in the pull request comments. +- Wait for your change(s) to be reviewed. ## Coding Standards @@ -63,11 +60,10 @@ Read our [coding standards](https://github.com/OpenF2/F2/wiki/Coding-Standards). ## Keep in Touch -If you have any questions while writing code to contribute to F2, post a message on the [Google Group](https://groups.google.com/forum/#!forum/OpenF2), find us on Twitter [@OpenF2](https://twitter.com/OpenF2) or by email at [info@openf2.org](mailto:info@openf2.org). You can also follow [our blog](http://blog.openf2.org) for more in-depth F2 updates. +If you have any questions while writing code to contribute to F2, post a question on [GitHub Issues](https://github.com/OpenF2/F2/issues/new) or by email at [info@openf2.org](mailto:info@openf2.org). ## Resources -* [F2 Google Group](https://groups.google.com/forum/#!forum/OpenF2) -* [F2 Coding Standards](https://github.com/OpenF2/F2/wiki/Coding-Standards) -* [GitHub Documentation: Using Pull Requests](https://help.github.com/articles/using-pull-requests) -* [GitHub Documentation](https://help.github.com/) +- [F2 Coding Standards](https://github.com/OpenF2/F2/wiki/Coding-Standards) +- [GitHub Documentation: Using Pull Requests](https://help.github.com/articles/using-pull-requests) +- [GitHub Documentation](https://help.github.com/) diff --git a/F2-examples.zip b/F2-examples.zip new file mode 100644 index 00000000..6cb1bde8 Binary files /dev/null and b/F2-examples.zip differ diff --git a/F2.latest.js b/F2.latest.js deleted file mode 100644 index 7ad92377..00000000 --- a/F2.latest.js +++ /dev/null @@ -1,60 +0,0 @@ -/*! f2 - v1.4.5 - 03-02-2018 - See below for copyright and license */ - -!function(exports){if(!exports.F2||exports.F2_TESTING_MODE){(function(){function a(b,d){function f(a){if(f[a]!==q)return f[a];var b;if("bug-string-char-index"==a)b="a"!="a"[0];else if("json"==a)b=f("json-stringify")&&f("json-parse");else{var c,e='{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';if("json-stringify"==a){var i=d.stringify,k="function"==typeof i&&t;if(k){(c=function(){return 1}).toJSON=c;try{k="0"===i(0)&&"0"===i(new g)&&'""'==i(new h)&&i(s)===q&&i(q)===q&&i()===q&&"1"===i(c)&&"[1]"==i([c])&&"[null]"==i([q])&&"null"==i(null)&&"[null,null,null]"==i([q,s,null])&&i({a:[c,!0,!1,null,"\x00\b\n\f\r "]})==e&&"1"===i(null,c)&&"[\n 1,\n 2\n]"==i([1,2],null,1)&&'"-271821-04-20T00:00:00.000Z"'==i(new j(-864e13))&&'"+275760-09-13T00:00:00.000Z"'==i(new j(864e13))&&'"-000001-01-01T00:00:00.000Z"'==i(new j(-621987552e5))&&'"1969-12-31T23:59:59.999Z"'==i(new j(-1))}catch(l){k=!1}}b=k}if("json-parse"==a){var m=d.parse;if("function"==typeof m)try{if(0===m("0")&&!m(!1)){c=m(e);var n=5==c.a.length&&1===c.a[0];if(n){try{n=!m('" "')}catch(l){}if(n)try{n=1!==m("01")}catch(l){}if(n)try{n=1!==m("1.")}catch(l){}}}}catch(l){n=!1}b=n}}return f[a]=!!b}b||(b=e.Object()),d||(d=e.Object());var g=b.Number||e.Number,h=b.String||e.String,i=b.Object||e.Object,j=b.Date||e.Date,k=b.SyntaxError||e.SyntaxError,l=b.TypeError||e.TypeError,m=b.Math||e.Math,n=b.JSON||e.JSON;"object"==typeof n&&n&&(d.stringify=n.stringify,d.parse=n.parse);var o,p,q,r=i.prototype,s=r.toString,t=new j(-0xc782b5b800cec);try{t=-109252==t.getUTCFullYear()&&0===t.getUTCMonth()&&1===t.getUTCDate()&&10==t.getUTCHours()&&37==t.getUTCMinutes()&&6==t.getUTCSeconds()&&708==t.getUTCMilliseconds()}catch(u){}if(!f("json")){var v="[object Function]",w="[object Date]",x="[object Number]",y="[object String]",z="[object Array]",A="[object Boolean]",B=f("bug-string-char-index");if(!t)var C=m.floor,D=[0,31,59,90,120,151,181,212,243,273,304,334],E=function(a,b){return D[b]+365*(a-1970)+C((a-1969+(b=+(b>1)))/4)-C((a-1901+b)/100)+C((a-1601+b)/400)};if((o=r.hasOwnProperty)||(o=function(a){var b,c={};return(c.__proto__=null,c.__proto__={toString:1},c).toString!=s?o=function(a){var b=this.__proto__,c=a in(this.__proto__=null,this);return this.__proto__=b,c}:(b=c.constructor,o=function(a){var c=(this.constructor||b).prototype;return a in this&&!(a in c&&this[a]===c[a])}),c=null,o.call(this,a)}),p=function(a,b){var d,e,f,g=0;(d=function(){this.valueOf=0}).prototype.valueOf=0,e=new d;for(f in e)o.call(e,f)&&g++;return d=e=null,g?p=2==g?function(a,b){var c,d={},e=s.call(a)==v;for(c in a)e&&"prototype"==c||o.call(d,c)||!(d[c]=1)||!o.call(a,c)||b(c)}:function(a,b){var c,d,e=s.call(a)==v;for(c in a)e&&"prototype"==c||!o.call(a,c)||(d="constructor"===c)||b(c);(d||o.call(a,c="constructor"))&&b(c)}:(e=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"],p=function(a,b){var d,f,g=s.call(a)==v,h=!g&&"function"!=typeof a.constructor&&c[typeof a.hasOwnProperty]&&a.hasOwnProperty||o;for(d in a)g&&"prototype"==d||!h.call(a,d)||b(d);for(f=e.length;d=e[--f];h.call(a,d)&&b(d));}),p(a,b)},!f("json-stringify")){var F={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"},G="000000",H=function(a,b){return(G+(b||0)).slice(-a)},I="\\u00",J=function(a){for(var b='"',c=0,d=a.length,e=!B||d>10,f=e&&(B?a.split(""):a);d>c;c++){var g=a.charCodeAt(c);switch(g){case 8:case 9:case 10:case 12:case 13:case 34:case 92:b+=F[g];break;default:if(32>g){b+=I+H(2,g.toString(16));break}b+=e?f[c]:a.charAt(c)}}return b+'"'},K=function(a,b,c,d,e,f,g){var h,i,j,k,m,n,r,t,u,v,B,D,F,G,I,L;try{h=b[a]}catch(M){}if("object"==typeof h&&h)if(i=s.call(h),i!=w||o.call(h,"toJSON"))"function"==typeof h.toJSON&&(i!=x&&i!=y&&i!=z||o.call(h,"toJSON"))&&(h=h.toJSON(a));else if(h>-1/0&&1/0>h){if(E){for(m=C(h/864e5),j=C(m/365.2425)+1970-1;E(j+1,0)<=m;j++);for(k=C((m-E(j,0))/30.42);E(j,k+1)<=m;k++);m=1+m-E(j,k),n=(h%864e5+864e5)%864e5,r=C(n/36e5)%24,t=C(n/6e4)%60,u=C(n/1e3)%60,v=n%1e3}else j=h.getUTCFullYear(),k=h.getUTCMonth(),m=h.getUTCDate(),r=h.getUTCHours(),t=h.getUTCMinutes(),u=h.getUTCSeconds(),v=h.getUTCMilliseconds();h=(0>=j||j>=1e4?(0>j?"-":"+")+H(6,0>j?-j:j):H(4,j))+"-"+H(2,k+1)+"-"+H(2,m)+"T"+H(2,r)+":"+H(2,t)+":"+H(2,u)+"."+H(3,v)+"Z"}else h=null;if(c&&(h=c.call(b,a,h)),null===h)return"null";if(i=s.call(h),i==A)return""+h;if(i==x)return h>-1/0&&1/0>h?""+h:"null";if(i==y)return J(""+h);if("object"==typeof h){for(G=g.length;G--;)if(g[G]===h)throw l();if(g.push(h),B=[],I=f,f+=e,i==z){for(F=0,G=h.length;G>F;F++)D=K(F,h,c,d,e,f,g),B.push(D===q?"null":D);L=B.length?e?"[\n"+f+B.join(",\n"+f)+"\n"+I+"]":"["+B.join(",")+"]":"[]"}else p(d||h,function(a){var b=K(a,h,c,d,e,f,g);b!==q&&B.push(J(a)+":"+(e?" ":"")+b)}),L=B.length?e?"{\n"+f+B.join(",\n"+f)+"\n"+I+"}":"{"+B.join(",")+"}":"{}";return g.pop(),L}};d.stringify=function(a,b,d){var e,f,g,h;if(c[typeof b]&&b)if((h=s.call(b))==v)f=b;else if(h==z){g={};for(var i,j=0,k=b.length;k>j;i=b[j++],h=s.call(i),(h==y||h==x)&&(g[i]=1));}if(d)if((h=s.call(d))==x){if((d-=d%1)>0)for(e="",d>10&&(d=10);e.lengthL;)switch(e=f.charCodeAt(L)){case 9:case 10:case 13:case 32:L++;break;case 123:case 125:case 91:case 93:case 58:case 44:return a=B?f.charAt(L):f[L],L++,a;case 34:for(a="@",L++;g>L;)if(e=f.charCodeAt(L),32>e)P();else if(92==e)switch(e=f.charCodeAt(++L)){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:a+=O[e],L++;break;case 117:for(b=++L,c=L+4;c>L;L++)e=f.charCodeAt(L),e>=48&&57>=e||e>=97&&102>=e||e>=65&&70>=e||P();a+=N("0x"+f.slice(b,L));break;default:P()}else{if(34==e)break;for(e=f.charCodeAt(L),b=L;e>=32&&92!=e&&34!=e;)e=f.charCodeAt(++L);a+=f.slice(b,L)}if(34==f.charCodeAt(L))return L++,a;P();default:if(b=L,45==e&&(d=!0,e=f.charCodeAt(++L)),e>=48&&57>=e){for(48==e&&(e=f.charCodeAt(L+1),e>=48&&57>=e)&&P(),d=!1;g>L&&(e=f.charCodeAt(L),e>=48&&57>=e);L++);if(46==f.charCodeAt(L)){for(c=++L;g>c&&(e=f.charCodeAt(c),e>=48&&57>=e);c++);c==L&&P(),L=c}if(e=f.charCodeAt(L),101==e||69==e){for(e=f.charCodeAt(++L),(43==e||45==e)&&L++,c=L;g>c&&(e=f.charCodeAt(c),e>=48&&57>=e);c++);c==L&&P(),L=c}return+f.slice(b,L)}if(d&&P(),"true"==f.slice(L,L+4))return L+=4,!0;if("false"==f.slice(L,L+5))return L+=5,!1;if("null"==f.slice(L,L+4))return L+=4,null;P()}return"$"},R=function(a){var b,c;if("$"==a&&P(),"string"==typeof a){if("@"==(B?a.charAt(0):a[0]))return a.slice(1);if("["==a){for(b=[];a=Q(),"]"!=a;c||(c=!0))c&&(","==a?(a=Q(),"]"==a&&P()):P()),","==a&&P(),b.push(R(a));return b}if("{"==a){for(b={};a=Q(),"}"!=a;c||(c=!0))c&&(","==a?(a=Q(),"}"==a&&P()):P()),(","==a||"string"!=typeof a||"@"!=(B?a.charAt(0):a[0])||":"!=Q())&&P(),b[a.slice(1)]=R(Q());return b}P()}return a},S=function(a,b,c){var d=T(a,b,c);d===q?delete a[b]:a[b]=d},T=function(a,b,c){var d,e=a[b];if("object"==typeof e&&e)if(s.call(e)==z)for(d=e.length;d--;)S(e,d,c);else p(e,function(a){S(e,a,c)});return c.call(a,b,e)};d.parse=function(a,b){var c,d;return L=0,M=""+a,c=R(Q()),"$"!=Q()&&P(),L=M=null,b&&s.call(b)==v?T((d={},d[""]=c,d),"",b):c}}}return d.runInContext=a,d}var b="function"==typeof define&&define.amd,c={"function":!0,object:!0},d=c[typeof exports]&&exports&&!exports.nodeType&&exports,e=c[typeof window]&&window||this,f=d&&c[typeof module]&&module&&!module.nodeType&&"object"==typeof global&&global;if(!f||f.global!==f&&f.window!==f&&f.self!==f||(e=f),d&&!b)a(e,d);else{var g=e.JSON,h=e.JSON3,i=!1,j=a(e,e.JSON3={noConflict:function(){return i||(i=!0,e.JSON=g,e.JSON3=h,g=h=null),j}});e.JSON={parse:j.parse,stringify:j.stringify}}b&&define(function(){return j})}).call(this),/*! - * jQuery JavaScript Library v1.11.2 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2014-12-17T15:27Z - */ -function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){function c(a){var b=a.length,c=ea.type(a);return"function"===c||ea.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}function d(a,b,c){if(ea.isFunction(b))return ea.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return ea.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(ma.test(b))return ea.filter(b,a,c);b=ea.filter(b,a)}return ea.grep(a,function(a){return ea.inArray(a,b)>=0!==c})}function e(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}function f(a){var b=ua[a]={};return ea.each(a.match(ta)||[],function(a,c){b[c]=!0}),b}function g(){oa.addEventListener?(oa.removeEventListener("DOMContentLoaded",h,!1),a.removeEventListener("load",h,!1)):(oa.detachEvent("onreadystatechange",h),a.detachEvent("onload",h))}function h(){(oa.addEventListener||"load"===event.type||"complete"===oa.readyState)&&(g(),ea.ready())}function i(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(za,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:ya.test(c)?ea.parseJSON(c):c}catch(e){}ea.data(a,b,c)}else c=void 0}return c}function j(a){var b;for(b in a)if(("data"!==b||!ea.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function k(a,b,c,d){if(ea.acceptData(a)){var e,f,g=ea.expando,h=a.nodeType,i=h?ea.cache:a,j=h?a[g]:a[g]&&g;if(j&&i[j]&&(d||i[j].data)||void 0!==c||"string"!=typeof b)return j||(j=h?a[g]=W.pop()||ea.guid++:g),i[j]||(i[j]=h?{}:{toJSON:ea.noop}),("object"==typeof b||"function"==typeof b)&&(d?i[j]=ea.extend(i[j],b):i[j].data=ea.extend(i[j].data,b)),f=i[j],d||(f.data||(f.data={}),f=f.data),void 0!==c&&(f[ea.camelCase(b)]=c),"string"==typeof b?(e=f[b],null==e&&(e=f[ea.camelCase(b)])):e=f,e}}function l(a,b,c){if(ea.acceptData(a)){var d,e,f=a.nodeType,g=f?ea.cache:a,h=f?a[ea.expando]:ea.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){ea.isArray(b)?b=b.concat(ea.map(b,ea.camelCase)):b in d?b=[b]:(b=ea.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;for(;e--;)delete d[b[e]];if(c?!j(d):!ea.isEmptyObject(d))return}(c||(delete g[h].data,j(g[h])))&&(f?ea.cleanData([a],!0):ca.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}function m(){return!0}function n(){return!1}function o(){try{return oa.activeElement}catch(a){}}function p(a){var b=Ka.split("|"),c=a.createDocumentFragment();if(c.createElement)for(;b.length;)c.createElement(b.pop());return c}function q(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==xa?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==xa?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||ea.nodeName(d,b)?f.push(d):ea.merge(f,q(d,b));return void 0===b||b&&ea.nodeName(a,b)?ea.merge([a],f):f}function r(a){Ea.test(a.type)&&(a.defaultChecked=a.checked)}function s(a,b){return ea.nodeName(a,"table")&&ea.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function t(a){return a.type=(null!==ea.find.attr(a,"type"))+"/"+a.type,a}function u(a){var b=Va.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function v(a,b){for(var c,d=0;null!=(c=a[d]);d++)ea._data(c,"globalEval",!b||ea._data(b[d],"globalEval"))}function w(a,b){if(1===b.nodeType&&ea.hasData(a)){var c,d,e,f=ea._data(a),g=ea._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)ea.event.add(b,c,h[c][d])}g.data&&(g.data=ea.extend({},g.data))}}function x(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!ca.noCloneEvent&&b[ea.expando]){e=ea._data(b);for(d in e.events)ea.removeEvent(b,d,e.handle);b.removeAttribute(ea.expando)}"script"===c&&b.text!==a.text?(t(b).text=a.text,u(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),ca.html5Clone&&a.innerHTML&&!ea.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Ea.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}function y(b,c){var d,e=ea(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:ea.css(e[0],"display");return e.detach(),f}function z(a){var b=oa,c=_a[a];return c||(c=y(a,b),"none"!==c&&c||($a=($a||ea(" - -

In getting to this point, you’ve only scratched the surface of F2 containers and apps. Continue reading and understanding the F2 spec to build exactly the financial solutions that our customers want.

-

Good news! In the project repo on GitHub, you will find a basic container along with a number of sample apps which demonstrate functionality far beyond the basic app above. Once you clone or download the project repository, open the sample container by pointing your browser at:

-

http://localhost/F2/examples/

-

These examples are also available in a separate archive if you don’t want to download the entire repository.

-

Download F2 Examples

- -

It is assumed you will be developing F2 apps locally and have a localhost setup. The URLs mentioned in this specification also assume you have configured your F2 apps to run at http://localhost/F2/. The examples provided as part of the project repository demonstrate apps written in different languages (PHP, JavaScript, C#). While it is not a requirement you have a web server configured on your computer, it will certainly allow you to more deeply explore the sample apps.

-

To better understand F2 and the role of apps, you need to understand the role of the container. If you haven’t already, read more about containers in the Framework.

-

To get started working with or developing containers, browse to the documentation for developing the container.

-

Ready to start coding?

-

Developing F2 Apps F2.js SDK Reference

- -
-

Design considerations are an important first step when creating a new app. Content can range from news to research to multimedia, and content should be presented using Progressive Enhancement, Mobile First and Responsive Design methodologies. That is to say multimedia content, for example, should be shown plugin-free (using HTML5 video or audio elements) for capable browsers and fallback to Flash-based players for browsers that do not yet support HTML5 related technologies. (VideoJS is good example of open-source JavaScript and CSS “that makes it easier to work with and build on HTML5 video, today.”)

-

If App Developers embed URLs back to their own websites or to third party sites, URLs must be opened in a new window as to not interrupt the experience of someone using the container. If authentication is required on an App Developer’s site, this can be accomplished with pass-through authentication using encrypted URLs as discussed in Single Sign On.

-

In order to ensure that apps built using F2 are successful, they must be accessible. As such, F2 made choices for which open-source libraries and frameworks would be leveraged to reduce the level of effort across F2 adopters.

-

Read more about those choices in the Framework.

-

Ultimately, the responsibility of app design falls on either the Container or App Developer. In many cases, Container Developers will provide App Developers will visual designs, style guides or other assets required to ensure apps have the form and function for a given container. Container Developers may also provide CSS for App Developers to adhere to—which should be easy since F2 enforces a consistent HTML structure across all containers and apps.

-
-

Let’s take a close look at how to build an F2 app. We’ll explain how to get an F2 AppID, what the AppManifest is all about, what output format your app needs to support, how the contents of the AppContent.html property work, and the two hooks for adding form and function to your app: scripts and styles.

-

Before opening your editor, read the configuration assumptions.

-

To develop an F2 app, you need a unique identifier called an AppID. This AppID will be unique to your app across the entire open financial framework ecosystem. The format of the AppID looks like this: com_companyName_appName, where the companyName “namespace” is your company name and appName is the name of your app.

-

As an example, your AppID could look like this:

-

com_acmecorp_watchlist

-

If you built more than one app while working at Acme Corporation, you could create more AppIDs. All of these are valid:

- -

To guarantee uniqueness, we have provided an AppID generation service that allows you to customize your AppID.

-

Get Your F2 AppID Now »

-

Once you have your AppID, start by setting up your project. You will need at least one file: the App Manifest. Create a new file called manifest.js. Also, chances are you’ll want custom styling and functionality, so go ahead and create appclass.js (for your app logic) and app.css for your CSS. Your project folder should look like this:

-

-

Helper Download the F2 examples or read about setting up a basic container and app in Getting Started.

-

For an app to be considered F2-capable, it must first have this basic structure—called the App Manifest—represented in JSON:

-
{
-    "inlineScripts":[],     
-    "scripts":[],     
-    "styles":[],     
-    "apps":[{
-            "data":{},
-            "html":"",
-            "status":""
-    }]
-}
-
-

The App Manifest can be generated by the server-side code of your choice or be written-by-hand in your favorite text editor. In the GitHub repository, there are apps written in JavaScript, PHP, and C# to serve as examples to get you started.

-

When it’s complete (using the examples further below), the App Manifest looks like this:

-
F2_jsonpCallback_com_companyname_appname({
-    "inlineScripts":["(function(){ var foo = bar; doSomething(); })()"],
-    "scripts":[
-        "http://www.domain.com/js/appclass.js"
-    ],     
-    "styles":[
-        "http://www.domain.com/css/app.css"
-    ],     
-    "apps":[{
-            "data":{ 
-                foo: "bar",
-                value: 12345
-            },
-            "html":"<div class=\"sunrise\">Hello world.</div>",
-            "status":"good"
-    }]
-})
-
-

Let’s break the App Manifest object down and look at each property (in reverse order to keep it fun).

-

Note The AppID created in the Developer Center and specified in the AppManifest will get automatically lowercased by F2 when integrated on a container.

-

The apps property is an array of AppContent objects. Each AppContent object contains three properties:

-
    -
  1. html
  2. -
  3. data
  4. -
  5. status
  6. -
-

The html property contains the view of your app represented in (optionally encoded) HTML. While you can modify the way your app appears or functions within the container, the html property is what the container will show when it registers your app and displays its contents for the first time.

-

Example:

-
"html": "<div class=\"sunrise\">Hello world.</div>"
-
-

The optionally encoded version of the html example above is:

-
"html": "%3Cdiv%20class%3D%22sunrise%22%3EHello%20world.%3C%2Fdiv%3E"
-
-

The data property exists to support the placement of arbitrary data needing to be passed along with the app. This field is optional.

-

Example:

-
"data": { 
-    foo: "bar",
-    value: 12345
-}
-
-

The status property allows app developers to communicate a server-side arbitrary status code to itself or to the container. This field is optional.

-

Example:

-
"status": "good"
-
-

The styles property is an array of URLs. The styles array refers to any CSS files needed by the app so it will be displayed properly on the container. The externally-referenced CSS files should be fully-qualified, including a protocol.

-

Example:

-
"styles": [
-    "http://www.domain.com/css/app.css"
-]
-
-

In the case when multiple stylesheetes are needed, simply add to the array as shown in this example:

-
"styles": [
-    "http://www.domain.com/css/app.css",
-    "http://www.domain.com/css/app-responsive.css"
-]
-
-

Read more about CSS and namespacing inside your app.

-

Note URLs referenced in the Scripts and Styles arrays are loaded synchronously by F2.js, so be sure to order your scripts properly.

-

The scripts property is an array of URLs. The scripts array refers to any JavaScript files needed by the app so that it will function correctly on the container. The externally-referenced JS files should be fully-qualified.

-

Example:

-
"scripts": [
-    "http://www.domain.com/js/appclass.js"
-]
-
-

In the case when multiple scripts are needed, simply add to the array as shown in this example:

-
"scripts": [
-    "http://www.domain.com/js/lib.js",
-    "http://www.domain.com/js/appclass.js"
-]
-
-

Read more about JavaScript and namespacing inside your app.

-

Note URLs referenced in the Scripts and Styles arrays are loaded synchronously by F2.js, so be sure to order your scripts properly.

-

The inlineScripts property is an array of strings. The inlineScripts array can include any JavaScript code needed by the app that cannot be included in your App Class. The contents of the inlineScripts array will be evaluated as JavaScript (using eval()) when all scripts have finished loading.

-

Example:

-
"inlineScripts": [
-    "(function(){ var foo = bar; doSomething(); })()"
-]
-
-
-

About Inline Scripts

-

While the use of inlineScripts is supported by F2’s App Manifest, it is not recommended for use. There are many reasons for this, the main one is to avoid cluttering the global namespace. Developers should make every attempt to put their JavaScript code inside their App Class.

-
- -

Read more about JavaScript and namespacing inside your app.

-

Note URLs referenced in the Scripts and Styles arrays are loaded synchronously by F2.js, so be sure to order your scripts properly.

-

If we use the examples above, our AppManifest would look like this:

-
F2_jsonpCallback_com_companyname_appname({
-    "inlineScripts":["(function(){ var foo = bar; doSomething(); })()"],
-    "scripts":[
-        "http://www.domain.com/js/appclass.js"
-    ],     
-    "styles":[
-        "http://www.domain.com/css/app.css"
-    ],     
-    "apps":[{
-            "data":{ 
-                foo: "bar",
-                value: 12345
-            },
-            "html":"<div class=\"sunrise\">Hello world.</div>",
-            "status":"good"
-    }]
-})
-
-

Note You may have noticed the presence of the function name F2_jsonpCallback_com_companyname_appname on the first line of the example above. That function name is the callback and is explained in App Manifest Response.

-

OK, so you know about F2 apps and you’re ready to write your own App Manifest. To go from zero to something, download the F2 examples. Once you have your AppManifest defined (or at least stubbed out), there’s one important detail you need to know now—the App Manifest response format.

-

As part of F2, containers register apps—typically hosted on different domains—using JSONP. This means F2 App Manifest files must provide a JSONP callback function. (If you don’t know what JSONP is or how it works, we recommend reading what Remy Sharp has to say about it.)

-

For security reasons, the App Manifest JSONP callback function must be a specific, reliable, and testable format. F2 has defined that using a combination of a string and your unique F2 AppID. The JSONP callback function name looks like this:

-

F2_jsonpCallback_<AppID>

-

When applied, the final (bare bones) App Manifest file looks like this example (where com_companyname_appname is your AppID):

-
//manifest.js
-F2_jsonpCallback_com_companyname_appname({
-    "scripts":[
-        "http://www.domain.com/js/appclass.js"
-    ],     
-    "styles":[
-        "http://www.domain.com/css/app.css"
-    ],     
-    "apps":[{
-            "html":"<div class=\"sunrise\">Hello world.</div>"
-    }]
-})
-
-

Note The JSONP callback function name will not be passed from the container using a traditional querystring parameter (HTTP GET), so you must configure this correctly for your app to appear on a container. This means you have to hard-code it in your AppManifest.

-

Note The AppID created in the Developer Center will get automatically lowercased by F2 when integrated on a container.

-

While it isn’t required, it’s expected every F2 app has HTML. The only catch is that the HTML isn’t provided by the app itself but rather passed to the container via the app’s AppManifest. Here are the steps for getting your app HTML into your AppContent.html property:

-
    -
  1. Develop the web page or module or widget or component or portlet that will be your app.
  2. -
  3. Take all the contents of it—that is, the HTML—and encode it. (This step is optional.)
  4. -
  5. Put the (optionally encoded) result in the html property of your AppContent object within your App Manifest file’s App object.
  6. -
-

Wait, what? Check out this example below or browse to example apps on GitHub:

-

Step 1.

-
<div class="sunrise">Hello world.</div>
-
-

Step 2. Encoded HTML. (Optional)

-
%3Cdiv%20class%3D%22sunrise%22%3EHello%20world.%3C%2Fdiv%3E
-
-

Step 3. App Manifest file.

-
{
-    ...
-    "apps":[{
-        "html": "<div class=\"sunrise\">Hello world.</div>"
-        ...
-    }]
-}
-
-

Note You are not required to encode the app HTML, so follow steps 2 and 3 above omitting the encoding step.

-

F2 uses and recommends Bootstrap for Container and App Developers to benefit from a consistent HTML and CSS structure regardless of who developed the F2 component. This way, Container Developers can write CSS they know will style F2 apps without engaging with the app developer to ensure compatibility.

-

This also means App Developers must adhere to Bootstrap’s grid system as defined on their website.

-

An example two-column layout using Bootstrap-specifed markup:

-
<div class="row">
-  <div class="col-md-4">...</div>
-  <div class="col-md-8">...</div>
-</div>
-
-

The .col-md-4 and .col-md-8 provide two columns in the 12-column grid.

-

Note Read more about Creating a Common Look and Feel with F2.

-

Once your app is on the container, chances are you’ll want it to actually do something. As an app developer, it is entirely up to you to write your own stylesheets and javascript code to add form and function to your app. F2’s standardized App Manifest provides hooks for your CSS and scripts to get onto the container—just use the scripts and styles arrays detailed above in the App Manifest.

-

Including your own CSS in the styles array of the App Manifest opens the door to the potential of unexpected display issues. Therefore, as an app developer, you are required to properly namespace your CSS selectors and declarations. For the details on writing correctly namespaced code, read the namespacing docs.

-

It is recommended you include your app styles in a file named app.css.

-

While it isn’t required, it’s expected all F2 apps will ship with javascript. This code should be included in an appclass.js file as shown in Setting Up Your Project. The F2.Apps property is a namespace for app developers to place the javascript class that is used to initialize their app. The javascript classes should be namepaced with the F2.App.AppID. It is recommended that the code be placed in a closure to help keep the global namespace clean.

-

For more information on F2.Apps, browse over to the F2.js SDK docs.

-

To make it even easier to build F2 apps and for faster app loading by the container, the F2.js SDK provides automatic JavaScript method execution at appropriate times during F2.registerApps() (and the internal _loadApps() method). If the class has an init() function, it will be called automatically during execution of F2’s registerApps() method.

-

We recommend—and have samples below for—two different patterns for writing your appclass.js code: prototypal inheritence or the module pattern.

-

When F2’s registerApps() method is called by the container, F2 passes three arguments to your App Class: appConfig, appContent and root. The SDK documentation details the contents of each arg and these should be familiar because appConfig contains your app’s meta, appContent contains your html, data and status properties, and root is the outermost DOM element in which your app exists on the container. The root argument provides your App Class code your app’s parent (root) element for faster DOM traversal.

-

Example:

-
//appclass.js snippet
-...
-    var App_Class = function(appConfig, appContent, root) {
-...
-
-

We won’t even begin to talk about or describe this fantastic design pattern simply because Douglas Crockford has already written all about it.

-

An example of an App Class using prototypal inheritance inside a closure is below. Note the inclusion of the App_Class.prototype.init() function—which will be called automatically during app load—and the trailing parentheses, (), which are responsible for automatic function execution. Thanks to the closure, the App_Class is returned and assigned to F2.Apps["com_companyname_appname"].

-
F2.Apps["com_companyname_appname"] = (function() {
-    var App_Class = function(appConfig, appContent, root) {
-        // constructor
-    }
-
-    App_Class.prototype.init = function() {
-        // perform init actions
-    }
-
-    return App_Class;
-})();
-`
-
-

As an alternative to the prototypal inheritance pattern above, appclass.js code could be written following the module pattern shown in the example below. Note the inclusion of an init() function—which will be called automatically during app load—and the exclusion of the closure and trailing parentheses present in the example using prototypal inheritance above.

-
F2.Apps["com_companyname_appname"] = function(appConfig, appContent, root) {
-   return {
-       init:function() {
-           // perform init actions
-       }
-   };
-};
-
-

Of course, you don’t have to use either one of these patterns in your appclass.js file. What you do have to use is a function. That is to say the value assigned to F2.Apps["com_companyname_appname"] by your App Class code must be a function. Within F2’s registerApps() method, the new operator is used which produces an object and new instance of your app.

-
-
Important!
-

In the absence of a function in your appclass.js, F2 will be unable to load your app on a container.

-
- -

If you don’t want to think about any of this and would rather just start coding, download the F2 examples.

-
-

Internationalization, or “i18n“, can be configured in a Container. This “locale” information is shared with all Apps using IETF-defined standard language tags such as “en-us” or “de-de” for English United States or German Germany, respectively.

-

Important Containers providing a locale config is only a means of communicating localization information in the container. F2 does not perform translations, number formatting or other localization modifications to Containers or Apps.

-

Container Providers can change the current locale using F2.Events. There is an event constant available for changing the locale called CONTAINER_LOCALE_CHANGE.

-

App Providers can listen for locale changes.

-
var currentLocale = F2.getContainerLocale(); //en-us
-
-//listen for Container-broadcasted F2 event with new locale
-F2.Events.on(F2.Constants.Events.CONTAINER_LOCALE_CHANGE,function(data){
-    //get newly-updated locale
-    currentLocale = F2.getContainerLocale(); //en-gb
-});
-
-

There is a parameter sent to each AppManifest request during F2.registerApps called containerLocale. Apps can also call F2.getContainerLocale() to access the current locale of the container.

-

Here is an example of the two ways of getting the container locale inside an AppClass.

-
F2.Apps["com_companyname_appname"] = (function() {
-    var App_Class = function(appConfig, appContent, root) {
-        // "containerLocale" is added to the AppConfig 
-        // during F2.registerApps
-        console.log(appConfig.containerLocale);//en-us
-    }
-
-    App_Class.prototype.init = function() {
-        // get locale using helper function
-        // if locale changes, this function will
-        // always return the current locale
-        console.log(F2.getContainerLocale());//en-us
-    }
-
-    return App_Class;
-})();
-
-

Note For more detail on the containerLocale property, browse to the SDK for F2.AppConfig.

-

The F2 AppConfig has a localeSupport property (type Array) so each App can define the region and language combinations it supports. Container code could be written to inspect the localeSupport property of any apps before registering them.

-

Sample AppConfig showing the localeSupport property:

-
{
-    "appId": "com_companyName_appName",
-    "manifestUrl": "http://www.domain.com/manifest.js"
-    "name": "App Name",
-    "views": ["home", "settings", "about"],
-    "minGridSize": 4,
-    "localeSupport": ["en-us","en-gb"] //array of IETF-defined tags
-},
-
-

Note For more detail on the localeSupport property, browse to the SDK for F2.AppConfig.

-
-

F2 is a web integration framework which means apps are inherently insecure—at least those non-secure apps. Following this spec, App Developers must avoid CSS collisions and JavaScript namespace issues to provide users with the best possible experience.

-

Note Continue reading for more specifics about secure apps.

-

As discussed in Developing F2 Apps: F2 AppID, to develop an F2 app, you need a unique identifier called an AppID. This AppID will be unique to your app across the entire open financial framework ecosystem. The format of the AppID looks like this: com_companyName_appName, where the companyName “namespace” is your company name and appName is the name of your app.

-

When Container Developers register apps, F2.js draws each app as defined by the ContainerConfig. Before the app is added to the container DOM, F2 automatically wraps an outer HTML element—with the AppID used as a class—around the rendered app.

-

This example shows app HTML after it has been drawn on the container. Note the com_companyName_appName classname.

-
<div class="f2-app-container com_companyName_appName">
-    ...
-</div>
-
-

To avoid styling conflicts or other display issues related to app-provided style sheets, App Developers must namespace their CSS selectors. Fortunately, this is quite easy.

-

Every selector in app-provided style sheets must look like this:

-
.com_companyName_appName p {
-    padding:5px;
-}
-
-.com_companyName_appName .alert {
-    color:red;
-}
-
-

Note .com_companyName_appName is prefixed on both p and .alert selectors.

-

While the CSS cascade will assign more points to IDs and while prefixing F2 AppIDs on CSS selectors isn’t required, it is recommended.

-
.com_companyName_appName #notice {
-    background-color:yellow;
-}
-
-

Note App Developers should familiarize themselves with CSS namespacing rules for Container Developers. They are largely the same with a couple notable additions.

-

It is a common web development practice to use CSS resets, and it is likely both Container and App Developers will use them. Since there are many ways to normalize built-in browser stylesheets, including Normalize.css which is used by Bootstrap, Container and App Developers must namespace their CSS reset selectors.

-

Adhering to one of the OpenAjax Alliance goals, F2 also promotes the concept of an uncluttered global javascript namespace. For Container and App Developers alike, this means following this spec closely and ensuring javascript code is contained inside closures or is extended as a new namespace on F2.

-

To ensure javascript bundled with F2 apps executes in a javascript closure, follow the guidelines for the appclass.js file and one of the two patterns described (prototypal inheritance or module).

-

The F2.js SDK was designed with extensibility in mind and therefore custom logic can be added on the F2 namespace.

-

Example:

-
F2.extend('YourPluginName', (function(){
-    return {
-        doSomething: function(){
-            F2.log("Something has been done.");
-        }
-    };
-})());
-
-

For more information, read Extending F2.

-
-

Apps are capable of sharing “context” with the container and other nearby apps. All apps have context which means the app “knows” who is using it and the content it contains. It is aware of an individual’s data entitlements and user information that the container is requested to share (name, email, company, etc).

-

This means if a user wants to create a ticker-focused container so they can keep a close eye on shares of Proctor & Gamble, the container can send “symbol context” to any listening apps that are smart enough to refresh when ticker symbol PG is entered in the container’s search box.

-

While apps can have context themselves, the responsibility for managing context switching or context passing falls on the container. The container assumes the role of a traffic cop—managing which data goes where. By using JavaScript events, the container can listen for events sent by apps and likewise apps can listen for events sent by the container. To provide a layer of security, this means apps cannot communicate directly with other apps on their own; apps must communicate via an F2 container to other apps since the container controls the F2.Events API.

-

Read more in the Framework.

-

Let’s look at some code.

-

In this example, the container broadcasts, or emits, a javascript event defined in F2.Events.Constants. The F2.Events.emit() method accepts two arguments: the event name and an optional data object.

-
F2.Events.emit(
-    F2.Constants.Events.CONTAINER_SYMBOL_CHANGE, 
-    { 
-        symbol: "AAPL", 
-        name: "Apple, Inc." 
-    }
-);
-
-

To listen to the F2.Constants.Events.CONTAINER_SYMBOL_CHANGE event inside your F2 app, you can use this code to trigger an alert dialog with the symbol:

-
F2.Events.on(
-    F2.Constants.Events.CONTAINER_SYMBOL_CHANGE, 
-    function(data){
-        F2.log("The symbol was changed to " + data.symbol);
-    }
-);
-
-

The F2.Events.on() method accepts the event name and listener function as arguments. Read the SDK for more information.

-

Note For a full list of support event types, browse to the SDK for F2.Constants.Events.

-

Often times containers will want to send context to apps during app registration. This is possible through the AppConfig.context property. This property can contain any javascript object—a string, a number, an array or an object.

-
//define app config
-var _appConfigs = [
-    {
-        appId: "com_acmecorp_news",
-        description: "Acme Corp News",
-        manifestUrl: "http://www.acme.com/apps/news-manifest.js",
-        name: "Acme News App",
-        context: {
-            sessionId: myApp.sessionId,
-            someArray: [value1,value2]
-        }
-    }
-];
-
-

When F2.registerApps() is called, the appConfig is serialized and appended to the app’s manifest URL. The serialized object converts to stringified JSON:

-
{"appId":"com_acmecorp_news","description":"Acme Corp News","manifestUrl":"http://www.acme.com/apps/news-manifest.js","name":"Acme News App","context":{"sessionId":"12345", "someArray":["value1","value2"]}}
-
-

The appConfig object is sent to the server using the params querystring name as shown in the example below. This is the complete app manifest request sent by F2.registerApps() with the appConfig URL-encoded, of course:

-
http://www.acme.com/apps/news-manifest.js?params=%7B%22appId%22%3A%22com_acmecorp_news%22%2C%22description%22%3A%22Acme%20Corp%20News%22%2C%22manifestUrl%22%3A%22http%3A%2F%2Fwww.acme.com%2Fapps%2Fnews-manifest.js%22%2C%22name%22%3A%22Acme%20News%20App%22%2C%22context%22%3A%7B%22sessionId%22%3A%2212345%22%2C%20%22someArray%22%3A%5B%22value1%22%2C%22value2%22%5D%7D%7D
-
-

This demonstrates complete flexibility of passing arbitrary context values from the container to any F2 app.

-

Important To receive context from a container during app initialization, F2 App Developers are required to build object deserialization for the params value into their app code.

-

Note It is possible to override the AppManifest request and, among other things, change the default HTTP method from GET to POST. This is useful in a scenario when the serialized AppConfig exceeds the maximum URL length or when AppConfig.context contains secure information necessitating a POST. Read more about overriding the AppManifest request.

-

In this example, your app emits an event indicating a user is looking at a different stock ticker within your app. Using F2.Events.emit() in your code, your app broadcasts the new symbol. As with container-to-app context passing, the F2.Events.emit() method accepts two arguments: the event name and an optional data object.

-
F2.Events.emit(
-    F2.Constants.Events.APP_SYMBOL_CHANGE, 
-    { 
-        symbol: "MSFT", 
-        name: "Microsoft, Inc." 
-    }
-);
-
-

The container would need to listen to your app’s broadcasted F2.Constants.Events.APP_SYMBOL_CHANGE event using code like this:

-
F2.Events.on(
-    F2.Constants.Events.APP_SYMBOL_CHANGE, 
-    function(data){
-        F2.log("The symbol was changed to " + data.symbol);
-    }
-);
-
-

Note For a full list of support event types, browse to the SDK for F2.Constants.Events.

-

Apps can also pass context between apps. If there are two or more apps on a container with similar context and the ability to receive messages (yes, through event listeners, context receiving is opt-in), apps can communicate with each other. To communicate with another app, each app will have to know the event name along with the type of data being passed. Let’s take a look.

-

Within “App 1”, context is sent using F2.Events.emit():

-
F2.Events.emit(
-    "buy_stock", //custom event name
-    { 
-        symbol: "GOOG", 
-        name: "Google Inc",
-        price: 682.68,
-        isAvailableToPurchase: true,
-        orderType: "Market Order"
-    }
-);
-
-

Within “App 2”, context is received using F2.Events.on():

-
F2.Events.on(
-    "buy_stock", 
-    function(data){
-        if (data.isAvailableToPurchase){
-            F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
-        } else {
-            F2.log("This stock is not available for purchase.")
-        }
-    }
-);
-
-

The examples above demonstrate simple Context objects. In the event more complex data and/or data types are needed, F2 Context can support any JavaScript object—a string, a number, a function, an array or an object.

-

This is an example Context object demonstrating arbitrary JavaScript objects:

-
F2.Events.emit(
-    "example_event", //custom event name
-    { 
-        //number
-        price: 100,
-        //string
-        name: 'John Smith',
-        //function
-        callback: function(){
-            F2.log('Callback!');
-        },
-        //array
-        watchlist: ['AAPL','MSFT','GE'],
-        //object
-        userInfo: {
-            name: 'John Smith',
-            title: 'Managing Director',
-            groups: ['Alpha','Beta'],
-            sessionId: 1234567890
-        }
-    }
-);
-
-

If two apps want to communicate data for populating a trade ticket and execute a callback, appclass.js code might look like this:

-
F2.Events.emit(
-    "buy_stock", //custom event name
-    { 
-        symbol: "GOOG", 
-        name: "Google Inc",
-        price: 682.68,
-        isAvailableToPurchase: true,
-        orderType: "Market Order",
-        //define callback
-        callback: function(data){
-            alert('Trade ticket populated');
-        }
-    }
-);
-
-

The F2 app listening for the buy_stock event would fire the callback function.

-
F2.Events.on(
-    "buy_stock", 
-    function(data){
-        F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
-        //..populate the trade ticket...
-        //fire the callback
-        if (typeof data.callback === 'function'){
-            data.callback();
-        }
-    }
-);
-
-

Context is a term used to describe the state of an F2 container and its apps. At the same time, Context is also the information passed from Container-to-App or from App-to-App or from App-to-Container. In the examples shown above, two types of context were shown: symbol and trade ticket context. It is important to realize F2.js allows client-side messaging between third parties using a collection of arbitrary name-value pairs. This provides the utmost flexibility and affords Container Developers the option to define context within their container.

-

Said another way, while { symbol:"AAPL", name: "Apple, Inc" } can be used to communicate symbol context, developers could also use { symbol: "123456789" } to identify Apple, Inc. The latter is more likely given not all apps would programmatically understand AAPL but—given symbol lookup services—would understand 123456789 as the universal F2 identifier for Apple, Inc. It is clear Container and App Developers alike would prefer to communicate with a guaranteed-to-never-change universal ID for all instrument types across all asset classes.

-

F2 will be providing lookup web services in future releases that provide universal F2 identifiers for container and app providers. These lookup services will not just be limited to symbols. Further details will be forthcoming as the F2 specification evolves.

-
-

F2 fully supports secure apps. A secure app is one that exists inside an iframe on a container and is hosted on a different domain. The F2.js SDK provides developers with seamless handling of Context, UI and the other F2 APIs whether or not an app is secure. This means app developers do not have to code apps any differently if an app is secure.

-

An app is defined as “secure” in the AppConfig. Creating the AppConfig is something that is done when apps are registered on the Developer Center.

-

Noting the isSecure property, the AppConfig looks like this:

-
{
-    "appId": "com_f2_demo",
-    "description": "A demo F2 app.",
-    "height":250,
-    "minGridSize": 4,
-    "manifestUrl": "manifest.js",
-    "name": "F2 App",
-    "isSecure": true //secure boolean
-}
-
-

To see examples of secure apps, fork F2 on GitHub and point your browser at:

-

http://localhost/F2/examples/container/

-

The example container runs sample apps—defined in sampleApps.js—and that’s where you’ll find the isSecure flag defined in some of the AppConfig objects.

-
-

Good news! The container is responsible for loading its apps, and as long as you’ve followed F2’s standard for App Manifests and have a working—and tested—app, you’re pretty much done.

-

If you’re curious about how containers load apps, browse to the F2.js SDK registerApps() method or read Container Development.

-

When you cloned the F2 GitHub repo you also got an example F2 container for your app development and testing. Open the project repository and navigate to ~/F2/examples/container to find them or to jump-start your testing, point your browser at:

-

http://localhost/F2/examples/container/

-

If you open ~/F2/examples/container/js/sampleApps.js in your text editor, you’ll find a list of sample F2 apps broken down by programming language. Simply modify this file to your liking and add your app anywhere in the appropriate array (JavaScript, PHP or C#). The configuration is comprised of F2.AppConfig properties, and the following are the minimum required properties.

-
{
-    appId: "com_companyName_appName",
-    manifestUrl: "http://www.domain.com/manifest.js"
-}
-
-

For full details on these F2.AppConfig properties and all the others, browse the F2.js SDK documentation.

-
-

There are some utility methods provided within F2.js in the UI namespace. These helpers are for controlling layout, showing (or hiding) loading spinners, modals, managing views within your app, and more.

-

While there are numerous utility methods in F2.UI, we will focus on a couple important ones here such as updateHeight() and showMask(). The F2.UI methods are passed as an instance to each F2 app’s App Class on the appConfig argument. The instance of F2.UI gets added to the appConfig object at runtime, and is available in appclass.js as appConfig.ui.

-

Example:

-
//appclass.js snippet
-var App_Class = function (appConfig, appContent, root) {
-    this.appConfig = appConfig;
-    this.appContent = appContent;
-    this.ui = appConfig.ui;    //F2.UI instance
-    this.$root = $(root);
-}
-
-

As the layout inside your app changes, your app should update or refresh its height on the container. This is particularly important for those secure apps inside iframes. To handle this, F2.js provides a updateHeight() method you should call anytime a DOM element is added or removed from within an app.

-

Assuming the example above is used, the this.ui property holds the instance of appConfig.ui.

-
//appclass.js snippet
-//user deletes row
-$(".row").remove();
-
-//call updateHeight method
-this.ui.updateHeight();
-
-

Apps can show loading spinners—or “masks”—when they are being loaded by a container or afterwards when making data requests. Container Developers configure the UI.Mask as discussed in the SDK F2.ContainerConfig.UI.Mask docs, therefore it is simple for app developers to call showMask().

-

To show a loading spinner when making an ajax request within an app:

-
//appclass.js snippet
-//show loading
-this.ui.showMask(this.root,true);
-
-//app makes data request
-$.ajax({
-    url: "../data.json"
-}).done(function(jqxhr){
-    F2.log(jqxhr);
-    //hide loading
-    this.ui.hideMask(this.root);
-});
-
-

The showMask() method takes two arguments: a DOM element where to show the mask and a boolean indicating whether or not to show a spinning graphic.

-

If you do not want to show a spinning graphic, simply pass false to the showMask() method. A mask without a spinner is useful in the case when you want to “lock” the view from user interaction.

-
//appclass.js snippet
-//show mask, no spinner
-this.ui.showMask(this.root,false);
-
-

For full details, read about F2.UI in the SDK.

-

To update the title of an app in the app’s chrome (as defined by the container in F2.ContainerConfig.appRender), very simply pass a string to the setTitle() method.

-
//appclass.js snippet
-this.ui.setTitle("Chart for MSFT");
-
-

F2.js provides two methods in F2.UI for modal dialogs. F2 uses and recommends Bootstrap for many reasons, and taking advantage of Bootstrap’s modals was an easy choice.

-

For full details on F2.UI.Modals and the two types of modals (alert and confirm), read the SDK docs.

-

Usage is simple:

-
//appclass.js snippet
-this.ui.Modals.alert("A message to display in a modal.");
-
-

You can optionally provide a callback to be fired when the user closes the modal.

-
//appclass.js snippet
-this.ui.Modals.alert("A message to display in a modal.", function(){
-    F2.log("Modal closed!");
-});
-
-

Additionally, there is a confirm modal.

-
//appclass.js snippet
-this.ui.Modals.confirm(
-    "A message to display in a confirmation modal.", 
-    function(){
-        F2.log("OK clicked");
-    },
-    function(){
-        F2.log("Cancel clicked");
-    }
-);
-
-

Adding and managing views within an F2 app is considered an advanced topic. If your app only needs a single view, you don’t have to worry about reading this part of the F2 spec.

-

F2 apps can have one or more views. Every app will have at least one “home” view, while others will include views for settings, help or about. Inside the F2.js SDK, we’ve included support for views and the list can be extended by the container provider.

-

Note If the container doesn’t support all the views you need inside your app, you will need to coordinate those additions with the container provider.

-

Once you’ve determined the views you’d like to include in your app, the view should be specified by applying the F2.Constants.Css.APPVIEW classname to the containing DOM Element. A data- attribute should be added to the element as well which defines what view type is represented. Bootstrap’s hide class should be applied to views that are hidden on startup.

-

To setup a single view in your app, use this HTML on your app’s outermost element noting the use of the f2-app-view classname and the data-f2-view attribute.

-
<div class='f2-app-view' data-f2-view='home'>
-    ...
-</div>
-
-

To setup multiple views in your app, write HTML like this noting the use the f2-app-view and hide classnames as well as the data-f2-view attributes.

-
<div class='f2-app-view' data-f2-view='home'>
-    ...
-</div>
-<div class='f2-app-view hide' data-f2-view='about'>
-    ...
-</div>
-
-

For details on F2.Constants.Css.APPVIEW, browse to the SDK docs.

-

The F2.UI namespace provides an API for developers to manage F2 app View state.

-

To programmatically change a View in javascript:

-
appConfig.ui.Views.change(F2.Constants.Views.HOME);
-
-

Note When appConfig.ui.Views.change() is called, the hide classname is automatically added or removed by F2.js depending on the visibility of the view. Read more in the SDK docs.

-

In F2 app HTML, you can use a combination of CSS classnames and data- attributes to provide UI elements making it easy for users to navigate between Views.

-

For example, an app has two views: “home” and “about”. On the “home” View, a button allows the user to navigate to the “about” view. In the presence of the classname f2-app-view-trigger and the data-f2-view data attribute, F2.js automatically adds a javascript event to the button.

-
<div class="f2-app-view" data-f2-view="home">
-    <!--use 'data-f2-view' to switch to the "about" View-->
-    <button class="btn btn-default f2-app-view-trigger" data-f2-view="about">Show About View</button>
-</div>
-
-

To get back to the “home” View from the “about” View:

-
<div class="f2-app-view" data-f2-view="about">
-    ...
-    <button class="btn btn-default f2-app-view-trigger" data-f2-view="home">&laquo; Back Home</button>
-    ...
-</div>
-
-

You shouldn’t be surprised to know F2.js contains event triggers for handling app View changes. To listen for View changes inside F2 app javascript code:

-
appConfig.ui.Views.change(function(view){
-    F2.log("View changed to ", view);
-});
-
-

For details on F2.UI.Views, browse to the SDK docs and for details on F2.Constants.Views, head over to the F2.Constants docs.

-
-

User or content entitlements are the responsibility of the App Developer. Many apps will need to be decoupled from the content that they need. This could include apps like research aggregation, news filtering, streaming market data, etc. Similarly to how companies build their own websites today with their own authentication and access (or content) entitlements, F2 apps are no different.

-

Further details around app entitlements will be forthcoming as the F2 specification evolves.

-
-

Single sign-on (SSO) is a shared responsibility between the Container and App Developer. In some cases, containers will want all of its apps to be authenticated seamlessly for users;that will be negotiated between Container and App Developers. For the purposes of this documentation, it is assumed Container Developers will build and host their container access authentication.

-

Once a user is authenticated on the container, how is the user then authenticated with all of the apps? Encrypted URLs.*

-

Note The Container Developer is free to utilize any app authentication method they deem fit. Container Developers and app developers will need to work together to finalize the authentication details.

-

Implementing SSO using encrypted URLs is a simple and straight-forward authentication mechanism for securing cross-domain multi-provider apps. To guarantee security between the Container and App Developer, secure API contracts must be negotiated. This includes, but is not limited to, the choice of cryptographic algorithm (such as AES) and the exchange of public keys.

-

When the container provider calls F2.registerApps(), custom logic should be added to append encrypted user credentials—on a need-to-know basis—to each app requiring authentication.

-

Read more in Developing F2 Containers.

-

Authentication is a critical part of any container-app relationship. There are a plethora of SSO implementations and there are many considerations for both Container and App Developers alike.

-

Further details around container and app single sign-on will be forthcoming as the F2 specification evolves.

-
- - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/dist/container-development.html b/docs/dist/container-development.html deleted file mode 100644 index 6cd2b46e..00000000 --- a/docs/dist/container-development.html +++ /dev/null @@ -1,1017 +0,0 @@ - - - - Container Development - F2: Open Financial Framework - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
-

Container Development

-

-The container is the foundation of any F2-enabled solution. By leveraging the F2.js SDK, Container Providers offer a consistent and reliable mechanism for all App Developers to load their apps on that container regardless of where it is hosted, who developed it, or what back-end stack it uses. You can read more about the framework, download the project on GitHub or get started below. -

- -
-

To help you get started building an F2 container, review the documentation and examples below. To jump start your F2 container or app development, download the F2 example container and apps.

-

Download F2 Examples

- -

To begin, you do not need to build (or compile) F2 as described in the readme on GitHub. Simply download F2.js and Bootstrap, and ensure you’re properly configured for continuing with the documentation.

-

Download F2.js Download Bootstrap

- -

Setup a basic container HTML template (or add F2.js to an existing website):

-
<!DOCTYPE html>
-    <head>
-        <title>F2 Container</title>
-        <link rel="stylesheet" href="/path/to/your/bootstrap.css">
-    </head>
-    <body>
-        <script src="/path/to/your/F2.js"></script>
-    </body>
-</html>
-
-

Note In developing a more advanced container, the HTML document’s body element would contain additional markup and allow for specific positioning or placement of apps. Additionally, more advanced containers could introduce features and functionality to their apps in the form of authentication APIs, streaming data feeds, federated search, etc. All containers must follow the F2 design guidelines.

-
var _appConfig = {
-    appId: 'com_openf2_examples_javascript_helloworld',
-    manifestUrl: 'http://docs.openf2.org/demos/apps/JavaScript/HelloWorld/manifest.js'
-};
-
-$(function(){
-    F2.init();
-    F2.registerApps(_appConfig);
-});
-
-

Note For more information about the AppConfig, read up on them in App Integration.

-

Now with a basic container and a basic app, combine these two for a working example. Press Result in this jsfiddle.

- - -

In getting to this point, you’ve only scratched the surface of F2 containers and apps. Continue reading and understanding the F2 spec to build exactly the financial solutions that our customers want.

-

Good news! In the project repo on GitHub, you will find a basic container along with a number of sample apps which demonstrate functionality far beyond the basic app above. Once you clone or download the project repository, open the sample container by pointing your browser at:

-

http://localhost/F2/examples/

-

These examples are also available in a separate archive if you don’t want to download the entire repository.

-

Download F2 Examples

- -

Full details on App Integration approaches are below. For an even simpler App integration than this basic example above, see auto-loading Apps.

-

It is assumed you will be developing an F2 container locally and have a localhost setup. The URLs mentioned in this specification also assume you have configured your F2 container to run at http://localhost/F2/. The examples provided as part of the project repository demonstrate apps written in different languages (PHP, JavaScript, C#). While it is not a requirement you have a web server configured on your computer, it will certainly allow you to more deeply explore the sample apps.

-

To better understand F2 and the role of containers, you need to understand the role of apps. If you haven’t already, read more about apps in the Framework.

-

To get started working with or developing apps, browse to the documentation for developing apps.

-

Developing F2 Containers F2.js SDK Reference

- -
-

Design considerations are an important first step when creating a new container. Content can range from news to research to multimedia, and content should be presented using Progressive Enhancement, Mobile First and Responsive Design methodologies. That is to say multimedia content, for example, should be shown plugin-free (using HTML5 video or audio elements) for capable browsers and fallback to Flash-based players for browsers that do not yet support HTML5 related technologies. (VideoJS is good example of open-source JavaScript and CSS “that makes it easier to work with and build on HTML5 video, today.”)

-

If App Developers embed URLs back to their own websites or to third party sites, URLs must be opened in a new window as to not interrupt the experience of someone using the container. If authentication is required on an App Developer’s site, this can be accomplished with pass-through authentication using encrypted URLs as discussed in Single Sign On.

-

In order to ensure that containers built using F2 are successful, they must be accessible. As such, F2 made choices for which open-source libraries and frameworks would be leveraged to reduce the level of effort across F2 adopters.

-

Read more about those choices in the Framework.

-

Ultimately, the responsibility of app design falls on either the Container or App Developer or both. In many cases, Container Developers will provide App Developers will visual designs, style guides or other assets required to ensure apps have the form and function for a given container. Container Developers may also provide CSS for App Developers to adhere to—which should be easy since F2 enforces a consistent HTML structure across all containers and apps. In other cases, Container and App Developers may never know each other and it’s important everyone strictly adheres to the guidelines set forth in this documentation.

-
-

A container is a browser-based web application which brings F2 apps together onto a seamless user interface. It can also provide data and user context to its apps in the form of request-response web services or streaming data feeds.

-

For a webpage to be considered an F2 container, it must first include the F2.js JavaScript SDK. This is as simple as downloading the F2 project from GitHub and adding a script tag to the page.

-
<script src="/path/to/your/f2.js"></script>
-
-

You will find a basic container in the project repo on GitHub along with a number of sample apps. Once the script tag has been added, it is up to the Container Developer to configure and customize the container. The first step is getting a ContainerID.

-

To develop a production F2 container, you need a unique identifier called a ContainerID. This ContainerID will be unique to your container across the entire open financial framework ecosystem. The format of the ContainerID looks like this: com_container_companyName_containerName, where the companyName “namespace” is your company name and containerName is the name of your container.

-

As an example, your ContainerID could look like this:

-

com_container_acmecorp_watchlist

-

If you built more than one container while working at Acme Corporation, you could create more ContainerIDs. All of these are valid:

-
    -
  • com_container_acmecorp_activetrader
  • -
  • com_container_acmecorp_retail
  • -
  • com_container_acmecorp_mobilestreamer
  • -
-

To guarantee uniqueness, we will provide a ContainerID generation service that allows customization of your ContainerID in the Developer Center.

-

Once you have your ContainerID, start by setting up your container project. You will need at least one configuration in addition to an HTML page: the app configs. (In the GitHub repository, an example is found in /examples/container/js/sampleApps.js.) This doesn’t need to be a static javascript file like sampleApps.js but the structure and format of the app configs is important.

-

The F2.js JavaScript SDK provides an API for providers to configure their containers. Every container must be setup using ContainerConfig and the methods available, however if the F2 defaults are acceptable, the ContainerConfig is not required.

-

To initialize a container using F2 defaults, call this function:

-
F2.init();
-
-

To initialize a container with a ContainerConfig, use:

-
F2.init({
-    UI: {},
-    xhr: function(){},
-    supportedViews: []
-});
-
-

Review all of the ContainerConfig properties in the reference documentation.

-

To see a more detailed example of F2.init(), look at the sample container javascript in the F2 repo on GitHub.

-

To enable debug mode in a container, use the following property in F2.init(). Setting debugMode: true adds additional logging, resource cache busting, etc.

-
F2.init({
-   debugMode: true 
-});
-
-

Note For obvious reasons, this property should only be used in a development environment.

-

The appRender(), beforeAppRender(), and afterAppRender() methods were deprecated in F2 version 1.2 in favor of F2.AppHandlers. Upgrading to F2 1.2 will not break existing containers using any of these methods as they are still present in the SDK.

-

For more information, see AppHandlers for App Layout.

-

To configure internationalization, or “i18n“, in an application the region and language can be set on the ContainerConfig. This “locale” information is shared with all Apps using IETF-defined standard language tags.

-

Configuration of current region and language using the locale:

-
F2.init({
-    locale: 'en-us'
-});
-
-

Important Providing a locale config is only a means of communicating localization information in the container. F2 does not perform translations, number formatting or other localization modifications to Containers or Apps.

-

Container Providers can change the current locale using F2.Events. There is an event constant available for changing the locale called CONTAINER_LOCALE_CHANGE.

-

Here is an example of triggering the locale change event:

-
var currentLocale = F2.getContainerLocale(); //en-us
-
-//emit F2 event with new locale
-F2.Events.emit(F2.Constants.Events.CONTAINER_LOCALE_CHANGE,{
-    locale: 'en-gb'
-});
-
-//get newly-updated locale
-currentLocale = F2.getContainerLocale(); //en-gb
-
-

There is a parameter sent to each AppManifest request during F2.registerApps called containerLocale. Apps can also call F2.getContainerLocale() to access the current locale of the container.

-

Here is an example of the two ways of getting the container locale inside an AppClass.

-
F2.Apps["com_companyname_appname"] = (function() {
-    var App_Class = function(appConfig, appContent, root) {
-        // "containerLocale" is added to the AppConfig 
-        // during F2.registerApps
-        console.log(appConfig.containerLocale);//en-us
-    }
-
-    App_Class.prototype.init = function() {
-        // get locale using helper function
-        // if locale changes, this function will
-        // always return the current locale
-        console.log(F2.getContainerLocale());//en-us
-    }
-
-    return App_Class;
-})();
-
-

Note For more detail on the containerLocale property, browse to the SDK for F2.AppConfig.

-

The F2 AppConfig has a localeSupport property (type Array) so each App can define the region and language combinations it supports. Container code could be written to inspect the localeSupport property of any apps before registering them.

-

Sample AppConfig showing the localeSupport property:

-
{
-    "appId": "com_companyName_appName",
-    "manifestUrl": "http://www.domain.com/manifest.js"
-    "name": "App Name",
-    "views": ["home", "settings", "about"],
-    "minGridSize": 4,
-    "localeSupport": ["en-us","en-gb"] //array of IETF-defined tags
-},
-
-

Note For more detail on the localeSupport property, browse to the SDK for F2.AppConfig.

-

Container Developers have the opportunity to customize some user interface (UI) elements which propagate to the App Developers’ toolkit in F2.js. One of those is F2.UI.Mask. The Mask object contains configuration defaults for the F2.UI.showMask() and F2.UI.hideMask() methods.

-

An example of setting the mask in F2.init():

-
F2.init({
-    UI:{
-        Mask:{
-            loadingIcon:'./img/spinner.gif',
-            backgroundColor: '#fff',
-            opacity: 0.5
-        }
-    }
-});
-
-

Included in the F2.UI.Mask configuration object are the following properties: backgroundColor, loadingIcon, opacity, useClasses, and zIndex. Each of these F2.UI.Mask properties is detailed in the F2.js SDK docs.

-

For more information on F2.UI, browse to the F2.js SDK docs.

-

Occasionally Container Developers need more granular control over the AppManifest request mechanism in F2.js. The manifest request process—intentionally obscured from developers through the F2.registerApps() API—is handled by a simple ajax call to an HTTP endpoint. (F2 relies on jQuery.ajax() for this.) In version 1.4.5 of F2, the AppManifest request can be overridden in the Container Config.

-

Note The AppManifest endpoint is configured in the manifestUrl property within each AppConfig.

-

The following example demonstrates how the xhr property of the ContainerConfig is used to override F2.js.

-
F2.init({
-    xhr: function(url, appConfigs, success, error, complete) {
-        $.ajax({
-            url: url,
-            type: 'POST',
-            data: {
-                params: F2.stringify(appConfigs, F2.appConfigReplacer)
-            },
-            jsonp: false, // do not put 'callback=' in the query string
-            jsonpCallback: F2.Constants.JSONP_CALLBACK + appConfigs[0].appId, // Unique function name
-            dataType: 'json',
-            success: function(appManifest) {
-                // custom success logic
-                success(appManifest); // fire success callback
-            },
-            error: function() {
-                // custom error logic
-                error(); // fire error callback
-            },
-            complete: function() {
-                // custom complete logic
-                complete(); // fire complete callback
-            }
-        });
-    }
-});
-
-

The F2.ContainerConfig.xhr property has two additional customizable properties available: dataType and type.

-

The dataType property allows the container to override the request data type (JSON or JSONP) that is used for the request. Using JSON as a dataType is only available for F2 apps running on the same domain as the container.

-
F2.init({
-    xhr: {
-        dataType: function(url) {
-            return F2.isLocalRequest(url) ? 'json' : 'jsonp';
-        }
-    }
-});
-
-

The type property allows the container to override the request method that is used (similar to the type parameter to jQuery.ajax()). Since HTTP POST is not supported on JSONP requests, using POST as a type is only available for F2 apps using JSON and are therefore running on the same base domain as the container.

-
F2.init({
-    xhr: {
-        type: function(url) {
-            return F2.isLocalRequest(url) ? 'POST' : 'GET';
-        }
-    }
-});
-
-

For more information on F2.ContainerConfig.xhr, browse to the F2.js SDK docs.

-

Occasionally Container Developers need more granular control over the request mechanism in F2.js for AppManifest-defined dependencies. The current dependency request process is handled by the straightforward createElement('script') and createStyleSheet() statements for scripts and styles, respectively. In version 1.4.5 of F2, the app dependency request can be overridden in the ContainerConfig.

-

As defined in the AppManifest, each F2 App can have script file dependencies. These are defined as URLs in the AppManifest.scripts property (type array). The script loader can be replaced with any script loading mechanism such as those found in RequireJS, jQuery or HeadJS.

-

To override the script loader, assign a function to loadScripts in F2.init as shown below. The function is passed scripts (array) and callback (function) which needs to be called when all scripts have been loaded.

-
F2.init({
-    loadScripts: function(scripts,callback){
-        //perform script loading
-        callback();
-    }
-});
-
-

The following example demonstrates using HeadJS to load script dependencies:

-
F2.init({
-    loadScripts: function(scripts,callback){
-        head.load(scripts, function(){
-            callback();
-        });
-    }
-});
-
-

Important The callback function must be executed on completion of the script loading so F2 can continue registering apps.

-

As defined in the AppManifest, each F2 App can have stylesheet file dependencies. These are defined as URLs in the AppManifest.styles property. The stylesheet loader can be replaced with any stylesheet loading mechanism such as those found in HeadJS or LazyLoad.

-

To override the stylesheet loader, assign a function to loadStyles in F2.init as shown below. The function is passed styles (array) and callback (function) which needs to be called when all stylesheets have been loaded.

-
F2.init({
-    loadStyles: function(styles,callback){
-        //perform stylesheet loading
-        callback();
-    }
-});
-
-

The following example demonstrates using HeadJS to load stylesheet dependencies:

-
F2.init({
-    loadStyles: function(styles,callback){
-        head.load(styles, function(){
-            callback();
-        });
-    }
-});
-
-

Important The callback function must be executed on completion of the stylesheet loading so F2 can continue registering apps.

-

As defined in the AppManifest, each F2 App can have inline script dependencies. These are defined as strings in the AppManifest.inlineScripts property (type array). The inline script evaluator can be replaced with any script evaluator, however, it is expected Container Developers will not require an alternative to the eval currently in use.

-

To override the inline script evaluator, assign a function to loadInlineScripts in F2.init as shown below. The function is passed inlines (array) and callback (function) which needs to be called when all inline scripts have been evaluated.

-
F2.init({
-    loadInlineScripts: function(inlines,callback){
-        //perform inline script evaluation
-        callback();
-    }
-});
-
-

Important The callback function must be executed on completion of the script loading so F2 can continue registering apps.

-

Note This Container Config option was added not because it is expected Container Developers will need or use it but rather to prevent unnecessary scripting in the script override config option.

-

In the event any scripts defined in an AppManifest fail to load—such as HTTP 404 or simply timeout after the configurable 7 seconds—F2 Events are triggered. The two events are: RESOURCE_FAILED_TO_LOAD and the APP_SCRIPT_LOAD_FAILED AppHandler. Both events are passed the appId and src of the failed script.

-
F2.Events.on('RESOURCE_FAILED_TO_LOAD', function(data){
-    F2.log('Script failed to load: ' data.src); 
-    //Ouputs 'Script failed to load: http://cdn.com/script.js'
-});
-
-

When all of the scripts defined in an AppManifest have been loaded, the APP_SCRIPTS_LOADED event is triggered. This event receives the appId and array of scripts just loaded. This event is fired for every App registered.

-
F2.Events.on('APP_SCRIPTS_LOADED', function(data){
-    F2.log('All scripts for ' +data.appId+ ' have been loaded.');
-    //Ouputs 'All scripts for com_test_app have been loaded.'
-});
-
-

F2 Container Developers should define which app views their container supports. This is set in the supportedViews property of the ContainerConfig using F2.Constants.Views.

-
F2.init({
-    supportedViews: [F2.Constants.Views.HOME, F2.Constants.Views.SETTINGS, F2.Constants.Views.REMOVE]
-});
-
-

Note Every F2 app has a home view (whether defined by the App Developer or not). This means if no views are provided by the App Developer, a home view is automatically added to appConfig.views during the app registration process inside F2.

-

For information about how to configure secure apps (i.e., load 3rd party apps in an isolated iframe) on a container, read about Secure Apps.

-

If you’re looking for sample container HTML template code, jump to the Get Started section.

-
-

There are two ways of integrating apps on a container: requesting apps on-demand (via HTTP) or by linking pre-loaded apps. Requesting apps on-demand when the container loads is the traditional way of integrating apps with F2. Incorporating apps which have been pre-fetched or are otherwise already on the container when it loads is an alternative method. The following sections describe both of these methods in detail.

-

The process of loading apps on a container occurs by using a method called F2.registerApps(). The Container Developer must call this method—which accepts two arguments: one required, one optional— after F2.init() is called. If this method isn’t called, no apps can be loaded on the container.

-

The two arguments provided to registerApps() are an array of AppConfig objects and, optionally, an array of AppManifest objects. As F2.js parses each AppConfig, the apps are validated, hydrated with some additional properties, and saved in browser memory on the container. Regardless of where the container’s AppConfig object is defined (hard-coded or via API), integrating apps is a simple process.

-

Before continuing, let’s discuss the AppConfig. The container-provided app configurations are represented simply as an array of AppConfig objects. These could be configured statically or fetched from an F2 Registry API. AppConfig objects contain app meta data—including the manifestUrl—provided by the App Developer when an app is registered in the Developer Center.

-

An example AppConfig object from an individual app:

-
{
-    appId: "com_companyName_appName",
-    manifestUrl: "http://www.domain.com/manifest.js",
-    name: "App name",
-    context: {
-        data: [1,2,3,4,5]
-    }
-}
-
-

An example array of AppConfig objects for a collection of apps:

-
[
-    {
-        appId: "com_companyName_appName",
-        manifestUrl: "http://www.domain.com/manifest.js",
-        name: "App name",
-        context: {
-            data: [1,2,3,4,5]
-        }
-    },
-    {
-        appId: "com_companyName_appName2",
-        manifestUrl: "http://www.domain.com/manifest2.js",
-        name: "App2 name",
-        context: {
-            name: 'value'
-        }
-    },
-    {
-        appId: "com_companyName_appName3",
-        manifestUrl: "http://www.domain.com/manifest3.js",
-        name: "App3 name",
-        context: {
-            status: 'ok'
-        }
-    },
-];
-
-

When the Container (or, more simply, the web page) loads F2 apps via F2.registerApps, a series of F2.AppHandler events are fired. Their order of execution is detailed in the SDK docs. An important part of this order of execution—inside step #4 under ‘App Rendering’—is how each app’s dependencies are loaded and added to the page. As detailed in the AppManifest docs, the scripts and styles arrays can include any dependencies which add style or functionality to an app.

-

During the F2 app load life cycle, the following events happen in order:

-
    -
  1. F2.registerApps called, each AppConfig iterated over
  2. -
  3. Every AppConfig receives an instanceId property (with a value of a UUID)
  4. -
  5. Every AppConfig is validated (appId and manifestUrl properties must exist)
  6. -
  7. If the AppConfig contains a root property, F2 switches to preloading mode
  8. -
  9. If the AppConfig contains the enableBatchRequests:true property, F2 switches to batching mode
  10. -
  11. Finally, the internal _loadApps function is called which:
      -
    1. Iterates over each URL in the styles array, creates a new <link rel="stylesheet"> tag and inserts it into the <head>.
    2. -
    3. Iterates over each app in the apps array, stores off any data to pass to the appclass later, and inserts any HTML into the app’s root.
    4. -
    5. Iterates over each URL in the scripts array, creates a new <script> tag and attaches it to the <body>. The scripts are requested and added in serial to ensure they execute in order.
    6. -
    7. Iterates over each string in the inlineScripts array, and evaluates the script—only when all of the scripts in the previous step have been loaded.
    8. -
    9. When this process is complete and all dependencies have been loaded, a new app instance is created and the appclass is initialized.
    10. -
    -
  12. -
-

Important Since version 1.4.0, regardless of how many times a particular app is loaded, each of its scripts and styles dependencies is requested and inserted into the page only once.

-

Since version 1.4.0, App Placeholders provide a way to greatly simplify F2 App integration. This newer declarative style allows Container Developers to add F2.js and minimal HTML (with data attributes) to a web page, F2 will then automatically find and register the App associated to the HTML.

-

By using one of the available attributes (f2-autoload), F2 auto-registers this “Hello World” App and inserts it into this “placeholder” DOM element.

-
<div id="f2-autoload" data-f2-appid="com_openf2_examples_nodejs_helloworld" data-f2-manifesturl="http://www.openf2.org/F2/apps"></div>
-
-

The following HTML elements are automatically parsed by F2.js and will trigger auto-loading (provided requirements below are met):

-
    -
  • CSS classname: .f2-autoload
  • -
  • Data attribute: [data-f2-autoload]
  • -
  • ID attribute: #f2-autoload
  • -
-

Both an appId and manifestUrl are required for F2.js to successfully register an App. Use data-f2-appid and data-f2-manifesturl as shown in this example:

-
<div id="f2-autoload" data-f2-appid="com_openf2_examples_nodejs_helloworld" data-f2-manifesturl="http://www.openf2.org/F2/apps"></div>
-
-

F2 Context can be provided for auto-loaded Apps. Use the data-f2-context data attribute and assign stringified JSON as the value.

-
data-f2-context="{&quot;hello&quot;:&quot;world&quot;}"
-
-

Implemented:

-
<div id="f2-autoload" data-f2-appid="com_openf2_examples_nodejs_helloworld" data-f2-manifesturl="http://www.openf2.org/F2/apps" data-f2-context="{&quot;hello&quot;:&quot;world&quot;}"></div>
-
-

Batch requesting of Apps as well as secure Apps are supported in the auto-loading mode.

-
    -
  • To enable an App as secure, use the data-f2-issecure data attribute.
  • -
  • To enable batch requests, use the data-f2-enablebatchrequests data attribute.
  • -
-

Note More AppConfig properties could be added as data attributes for auto-loading in future versions. See #187.

-

Note The ContainerConfig cannot be customized when auto-loading apps. See #186.

-

Requesting apps on-demand when the container loads is the traditional way of integrating apps with F2. For the purposes of this example, we will use an example news app from OpenF2.org.

-

Let’s look at some container code.

-

First, we define the AppConfig in a hard-coded _appConfig variable. This example demonstrates only a single app; if there were multiple apps, _appConfig would be an array of objects versus an object literal. Secondly, when the document is ready, F2.init() is called and subsequently F2.registerApps() with the single argument.

- - -

This javascript code will insert the example news app into the container’s <body>. Press Result in the jsfiddle above to try this demo.

-

Note If more granular control is needed for app placement, use F2.AppHandlers functionality. Read about that in AppHandlers for App Layout.

-

As an alternative to static app configuration shown above, the _appConfig variable could be assigned the result of an API call to the F2 Registry. The Registry API response is designed to match the structure of the AppConfig for passing the JSON straight through to F2 in your code. Whether your app configuration JSON comes from the F2 Registry or your own database is irrelevant; the process is identically the same as shown in this example.

- - -

About this jsfiddle To simulate an ajax request, this example uses jsfiddle’s echo feature. Simply replace the getAppConfigs function with your own ajax request and ignore the echoData variable.

-

F2 supports batch requesting of multiple apps hosted on the same domain. The default app registration process sends a single outbound HTTP request for each app registered with F2. For example, when registering five apps, five HTTP requests would be made for each app’s AppManifest. Implementing the same five apps using a batch request would result in only a single HTTP request thus greatly speeding up page performance.

-

Implementing F2 container code for apps to be requested in a batch is as simple as setting the AppConfig.enableBatchRequests property to true. The only additional requirement is that the apps to-be-batched must have the same AppConfig.manifestUrl value. That is, the batched apps must be on the same domain.

- - -

Open your browser developer tools to see the single HTTP request to http://www.openf2.org/Examples/Apps. You could modify this jsFiddle and set one of the AppConfig enableBatchRequests to false. Then re-run the code to see two HTTP requests sent in your developer tools.

-
-

Important

- The params querystring value for both batch-requested and non-batch-requested apps is a serialized collection of AppConfigs. In a scenario when many apps are batch-requested it would be possible to quickly reach the maximum HTTP GET character limit. In IE that limit is 2048 characters, it is longer in more modern browsers. To work around this issue, F2 recommends either configuring HTTP POST if the container and apps are on the same domain or by implementing CORS. -
- -

Note For more information about the AppConfig, read up on them at the top of App Integration.

-

Incorporating apps which have been pre-loaded or are otherwise already on the container when it loads is an alternative method to integrating F2 apps. This method is useful when the container is being constructed on the server-side (at run-time or on a schedule) and F2 functionality is desired. To use pre-loaded apps, the Container Developer is required to make a request to each app’s AppManifest and its dependencies before the page is rendered.

-

For the following example, let’s assume you have a web page composed on the server and all of its HTML is delivered to the browser in one payload. This page also has at least one widget (or component) you’d like to register with F2.js.

-

To use pre-loaded apps, a web page with a placeholder element for the apps is required. This simple (and empty) web page features a div#news_app.col-md-12 which serves as that placeholder or “root” element.

-
<!DOCTYPE html>
-    <head>
-        <title>F2 Container</title>
-        <link rel="stylesheet" href="/path/to/your/bootstrap.css">
-    </head>
-    <body>
-        <div class="container">
-            <div class="row">
-                <div class="col-md-12" id="news_app">
-                    <!--app goes here-->
-                </div>
-            </div>
-        </div>
-        <script src="/path/to/your/F2.js"></script>
-    </body>
-</html>
-
-

Next, make a server-side request to the news app’s AppManifest—the URL is found in manifestUrl—and capture the resulting JSON. Each AppManifest contains scripts, style sheets and HTML (more about the AppManifest). The market news app’s AppManifest looks like this:

-
{
-   "apps":[{
-         "data":{},
-         "html": "<div data-module-name=\"MarketNewsApp\">...</div>",
-    }],
-   "scripts":[
-      "http://www.openf2.org/js/main.js"
-   ],
-   "styles":[
-      "http://www.openf2.org/css/site.css"
-   ]
-}
-
-

Note Parts of this AppManifest were intentionally removed for legibility, including the required JSONP function name (F2_jsonpCallback_com_openf2_examples_csharp_marketnews). The full AppManifest is available on OpenF2.org.

-
-
Performance Tip
- Container Developers can use the AppConfig and pre-loaded AppManifest (from step 2 above) in conjunction with F2.registerApps() to speed up the loading of F2 containers. For more information, browse to Combining AppConfig and AppManifest. -
- -

You’re almost there. Next, embed the news app’s html, scripts and styles. The F2 app is inserted into .row > .col-md-12 following Bootstrap’s scaffolding guidelines. The styles were appended to the head and the scripts were appended to the body (in this case just one URL for each).

-
<!DOCTYPE html>
-    <head>
-        <title>F2 Container</title>
-        <link rel="stylesheet" href="/path/to/your/bootstrap.css">
-        <link rel="stylesheet" href="http://www.openf2.org/css/site.css">
-    </head>
-    <body>
-        <div class="container">
-            <div class="row">
-                <div class="col-md-12" id="news_app">
-                    <div data-module-name="MarketNewsApp" id="news_app">...</div>
-                </div>
-            </div>
-        </div>
-        <script src="/path/to/your/F2.js"></script>
-        <script src="http://www.openf2.org/js/main.js"></script>
-    </body>
-</html>
-
-

The example news app is now part of the web page and everything should be functioning properly. The final step is to register the app with F2.

-

To use pre-loaded apps, an additional property is required on the AppConfig object. It is called root and can be either a CSS selector string or a DOM element. Regardless of type, F2 will parse the value of root and it must return an existing in-page DOM element. Furthermore, the value of root must represent a unique DOM element as each app needs its own containing, or root, element.

-
var _appConfig = {
-    appId: 'com_openf2_examples_csharp_marketnews',
-    description: 'Example News',
-    manifestUrl: 'http://www.openf2.org/Examples/Apps',
-    name: 'Example News',
-    root: document.getElementById('news_app')
-};
-
-

Both of these are valid values for the root property.

-

Using JavaScript:

-
{
-    root: document.getElementById('news_app')
-}
-
-

Using a CSS selector string:

-
{
-    root: '#news_app'
-}
-
-

F2.js uses jQuery internally to parse the value of the root property and, in turn, jQuery relies on the Sizzle javascript selector library. If a CSS selector string is assigned to root, it must be a valid CSS 3 selector supported by Sizzle. Refer to the Sizzle documentation for more details.

-

Since you started with the AppConfig and now have the AppManifest from step 2 along with an HTML page containing the embedded app, all that remains is a simple call to F2. Registering pre-loaded apps with F2.js means passing the ammended AppConfig as shown in the example below.

-
var _appConfig = {
-    appId: 'com_openf2_examples_csharp_marketnews',
-    description: 'Example News',
-    manifestUrl: 'http://www.openf2.org/Examples/Apps',
-    name: 'Example News',
-    root: document.getElementById('news_app')
-};
-
-$(function(){
-    F2.init();
-    F2.registerApps(_appConfig);
-});
-
-

The web page and pre-loaded news app is a fully F2-enabled container. Rejoice!

-

Container Developers can use the AppConfig and pre-loaded AppManifest (from step 2 above) in conjunction with F2.registerApps() to speed up the loading of F2 containers. The F2.registerApps() API supports two arguments: appConfigs and appManifests. The former is an array of F2.AppConfig objects and the latter is an array of F2.AppManifest objects. The appManifests array must be the same length as the appConfigs array that is used as the first argument. This can be useful if apps are loaded on the server-side and passed down to the client.

-

In the following example, the AppManifest was pre-loaded and stored in the _appManifest variable.

-
var _appConfig = {
-    appId: 'com_openf2_examples_csharp_marketnews',
-    description: 'Example News',
-    manifestUrl: 'http://www.openf2.org/Examples/Apps',
-    name: 'Example News',
-    root: document.getElementById('news_app')
-};
-
-var _appManifest = {
-   "apps":[{
-         "data":{},
-         "html": "<div data-module-name=\"MarketNewsApp\">...</div>",
-    }],
-   "scripts":[
-      "http://www.openf2.org/js/main.js"
-   ],
-   "styles":[
-      "http://www.openf2.org/css/site.css"
-   ]
-};
-
-$(function(){
-    F2.init();
-    F2.registerApps(_appConfig,_appManifest);
-});
-
-

If a manifest is passed with the AppConfig, then the AppClass will receive an index from the manifest’s apps property in place of AppContent. If no manifest is supplied, the AppClass will receive the following hardcoded AppContent:

-
{
-    preloaded: true,
-    status: 'SUCCESS'
-}
-

Important The F2.registerApps() API supports both an array of objects and object literals for each argument. Internally, F2.js converts the value of each argument into an array using concatenation ([].concat()). If arrays of objects are used (when there are more than one app on the container), the _appConfig and _appManifest arrays must be of equal length, and the object at each index must be a parallel reference. This means the AppConfig and AppManifest for the sample news app used above must be in _appConfig[0] and _appManifest[0].

-
-

New functionality called F2.AppHandlers was added in F2 1.2, and the conversation about this collection of features occurred in #38 on GitHub. The new AppHandlers functionality provides Container Developers a higher level of control over configuring app rendering and interaction.

-

-The addition of F2.AppHandlers replaces the previous ContainerConfig properties beforeAppRender, appRender, and afterAppRender. These methods were deprecated—but not removed—in version 1.2. They will be permanently removed in a future version of F2. -

- -

-Since F2 version 1.2, AppHandlers is the preferred method for Container Developers to manage app layout. -

- -

The AppHandlers functionality provides an event-based system for Container Developers’ web applications. The addition of a collection of constants in F2.Constants.AppHandlers shows the primitive set of event types (or hooks) available to developers, including hooks such as appCreateRoot, appRenderAfter, appDestroyAfter and more. (Review the complete F2.Constants.AppHandlers collection in the F2.js SDK documentation.)

-

Using AppHandlers is as simple as attaching an event handler function to be executed at the appropriate time as determined by the order of operations in F2. To do this there are three functions available on F2.AppHandlers: getToken, on, and off. We’ll review the token concept first as a token is the required first argument in on and off.

-

A new feature has been added to F2 as part of AppHandlers: the event token. The token is designed to be used only by Container Developers to ensure the AppHandlers listeners are only called by their applications, and aren’t accessible to App Developers’ code. Container Developers should create a variable for this token in their JavaScript and encapsulate it inside a closure as shown in the example below.

-
(function(){
-    var token = F2.AppHandlers.getToken(); 
-    console.log(token);
-    //outputs a GUID like 'ce2e7aae-04fa-96a3-edd7-be67e99937b4'
-});
-
-

Important The getToken() function can only be called one-time. It self-destructs to protect the token for Container Developers and therefore Container Developers must call F2.AppHandlers.getToken() and store its return value before any F2 apps are registered with the container.

-

In the unlikely event a Container Developer wishes to append all apps to the <body> element, no configuration is required. Simply add this code to the container:

-
F2.init();
-F2.registerApps(appConfig);
-
-

Appending apps to the <body> is the default app rendering behavior of F2.

-

F2 AppHandlers provide event handlers for customized app layout using F2.AppHandlers.on() and F2.AppHandlers.off(). The use of on and off require both a token and an event type as arguments. The event types, defined as constants in F2.Constants.AppHandlers, are:

-
    -
  • appManifestRequestFail
  • -
  • appCreateRoot
  • -
  • appDestroy
  • -
  • appDestroyAfter
  • -
  • appDestroyBefore
  • -
  • appRender
  • -
  • appRenderAfter
  • -
  • appRenderBefore
  • -
-

Review the complete F2.Constants.AppHandlers collection and their purpose in the F2.js SDK documentation. The order of operations is detailed in F2.AppHandlers.

-

There are many uses for AppHandlers in Container Developers’ applications and they are detailed—including plenty of examples—in the F2.js SDK documentation. Before jumping to that section of the docs, let’s look at one of the more common uses for AppHandlers: targeting the placement of an app into a specific DOM element.

-

In the following example, the app will be appended to the #my_sidebar DOM element on the container.

-
var _token = F2.AppHandlers.getToken(),
-    _appConfig = {
-        appId: 'com_example_app',
-        manifestUrl: '/manifest.js'
-    };
-
-F2.init();
-F2.AppHandlers.on(_token, 'appRender', document.getElementById('my_sidebar'));
-F2.registerApps(_appConfig);
-
-

F2 will insert html from the AppManifest inside the specified DOM element. The resulting HTML will look like this after registerApps is called. Take note F2.js adds three class names to the app’s outermost element (f2-app, f2-app-container, and com_example_app for the appId).

-
<div id="my_sidebar">
-    <!--HTML defined in AppManifest inserted here-->
-    <div class="f2-app f2-app-container com_example_app">
-        <div class="f2-app-view" data-f2-view="home">
-            <p>Hello World!</p>
-        </div>
-    </div>
-</div>
-
-

Note The original html in this example app manifest is available here.

-

The jsfiddle below demonstrates a Hello World example using the appRender event type and a DOM element as the third argument in on.

- - -

Here is a slightly more complicated example of the appRender event coupled with appCreateRoot to place two apps in two separate DOM elements.

- - -

There are numerous examples shown on the Properties tab of F2.Constants.AppHandlers. These demonstrate more advanced use of F2.AppHandlers and aim to provide Container Developers demonstrable low-level control over the life cycle of app rendering.

-
-

F2 is a web integration framework which means apps are inherently insecure—at least those non-secure apps. Following this spec, App Developers must avoid CSS collisions and JavaScript namespace issues to provide users with the best possible experience.

-

Note Continue reading for more specifics about secure apps.

-

As discussed in Developing F2 Containers: F2 ContainerID, to develop an F2 container, you need a unique identifier called an ContainerID. This ContainerID will be unique to your container across the entire open financial framework ecosystem. The format of the ContainerID looks like this: com_container_companyName_containerName, where the companyName “namespace” is your company name and containerName is the name of your container.

-

To avoid styling conflicts or other display issues related to injecting app-provided style sheets into your container when F2.registerApps() is called, App Developers must namespace their CSS selectors. While there are strict rules for App Developers, the same is true for Container Developers. This is especially true when nesting multiple F2 apps inside an existing container where that container already has a CSS framework in place. (This is often called the “mutliple container” issue, and a conversation about existing problems and enhancements to F2.js is being discussed in #37 and #38.)

-

In the event there are multiple containers, every CSS selector in container-provided style sheets must be properly namespaced. The CSS files bundled with the example containers in the F2 project on GitHub demonstrate this concept, and we have included a readme for how to use a LESS compiler to automate the namespacing of Bootstrap’s CSS.

-

In this simple example, container-provided CSS should be namespaced as shown below.

-
.com_container_companyName_containerName p {
-    padding:5px;
-}
-
-.com_container_companyName_containerName .alert {
-    color:red;
-}
-
-

Note .com_container_companyName_containerName is prefixed on both p and .alert selectors.

-

While the CSS cascade will assign more points to IDs and while prefixing F2 ContainerIDs on CSS selectors isn’t required, it is recommended.

-
.com_container_companyName_containerName #notice {
-    background-color:yellow;
-}
-
-

It is a common web development practice to use CSS resets, and it is likely both Container and App Developers will use them. Since there are many ways to normalize built-in browser stylesheets, including Normalize.css which is used by Bootstrap, Container and App Developers must namespace their CSS reset selectors.

-

Adhering to one of the OpenAjax Alliance goals, F2 also promotes the concept of an uncluttered global javascript namespace. For Container and App Developers alike, this means following this spec closely and ensuring javascript code is contained inside closures or is extended as a new namespace on F2.

-

The F2.js SDK was designed with extensibility in mind and therefore custom logic can be added on the F2 namespace.

-

Example:

-
F2.extend('YourPluginName', (function(){
-    return {
-        doSomething: function(){
-            F2.log("Something has been done.");
-        }
-    };
-})());
-
-

For more information, read Extending F2.

-
-

Apps are capable of sharing “context” with the container and other nearby apps. All apps have context which means the app “knows” who is using it and the content it contains. It is aware of an individual’s data entitlements and user information that the container is requested to share (name, email, company, etc).

-

This means if a user wants to create a ticker-focused container so they can keep a close eye on shares of Proctor & Gamble, the container can send “symbol context” to any listening apps that are smart enough to refresh when ticker symbol PG is entered in the container’s search box.

-

While apps can have context themselves, the responsibility for managing context switching or context passing falls on the container. The container assumes the role of a traffic cop—managing which data goes where. By using JavaScript events, the container can listen for events sent by apps and likewise apps can listen for events sent by the container. To provide a layer of security, this means apps cannot communicate directly with other apps on their own; apps must communicate via an F2 container to other apps since the container controls the F2.Events API.

-

Read more in the Framework.

-

Each container will be responsible for hosting the F2.js JavaScript SDK. The F2 SDK not only provides the consistent mechanism app developers have come to expect for loading their apps on the container, but also contains an event API for handling context.

-

Important It is important to note that while apps can have context themselves, the responsibility for managing context switching or context passing falls on the container. The container assumes the role of a traffic cop—managing which data goes where. By using JavaScript events, the container can listen for events sent by apps and likewise apps can listen for events sent by the container. This means apps cannot communicate directly with other apps on their own; apps communicate via the container to other apps since the container controls the F2.Events API.

-

Let’s look at some code.

-

In this example, the container broadcasts, or emits, a javascript event defined in F2.Events.Constants. The F2.Events.emit() method accepts two arguments: the event name and an optional data object.

-
F2.Events.emit(
-    F2.Constants.Events.CONTAINER_SYMBOL_CHANGE, 
-    { 
-        symbol: "AAPL", 
-        name: "Apple, Inc." 
-    }
-);
-
-

To listen to the F2.Constants.Events.CONTAINER_SYMBOL_CHANGE event inside your F2 app, you can use this code to trigger an alert dialog with the symbol:

-
F2.Events.on(
-    F2.Constants.Events.CONTAINER_SYMBOL_CHANGE, 
-    function(data){
-        F2.log("The symbol was changed to " + data.symbol);
-    }
-);
-
-

The F2.Events.on() method accepts the event name and listener function as arguments. Read the SDK for more information.

-

Note For a full list of support event types, browse to the SDK for F2.Constants.Events.

-

Often times containers will want to send context to apps during app registration. This is possible through the AppConfig.context property. This property can contain any javascript object—a string, a number, an array or an object.

-
//define app config
-var _appConfigs = [
-    {
-        appId: "com_acmecorp_news",
-        description: "Acme Corp News",
-        manifestUrl: "http://www.acme.com/apps/news-manifest.js",
-        name: "Acme News App",
-        context: {
-            sessionId: myApp.sessionId,
-            someArray: [value1,value2]
-        }
-    }
-];
-
-

When F2.registerApps() is called, the appConfig is serialized and posted to the app’s manifest URL. The serialized object converts to stringified JSON:

-
{"appId":"com_acmecorp_news","description":"Acme Corp News","manifestUrl":"http://www.acme.com/apps/news-manifest.js","name":"Acme News App","context":{"sessionId":"12345", "someArray":["value1","value2"]}}
-
-

The appConfig object is sent to the server using the params querystring name as shown in the example below. This is the complete app manifest request sent by F2.registerApps() with the appConfig URL-encoded, of course:

-
http://www.acme.com/apps/news-manifest.js?params=%7B%22appId%22%3A%22com_acmecorp_news%22%2C%22description%22%3A%22Acme%20Corp%20News%22%2C%22manifestUrl%22%3A%22http%3A%2F%2Fwww.acme.com%2Fapps%2Fnews-manifest.js%22%2C%22name%22%3A%22Acme%20News%20App%22%2C%22context%22%3A%7B%22sessionId%22%3A%2212345%22%2C%20%22someArray%22%3A%5B%22value1%22%2C%22value2%22%5D%7D%7D
-
-

This demonstrates complete flexibility of passing arbitrary context values from the container to any F2 app.

-

In this example, your app emits an event indicating a user is looking at a different stock ticker within your app. Using F2.Events.emit() in your code, your app broadcasts the new symbol. As with container-to-app context passing, the F2.Events.emit() method accepts two arguments: the event name and an optional data object.

-
F2.Events.emit(
-    F2.Constants.Events.APP_SYMBOL_CHANGE, 
-    { 
-        symbol: "MSFT", 
-        name: "Microsoft, Inc." 
-    }
-);
-
-

The container would need to listen to your app’s broadcasted F2.Constants.Events.APP_SYMBOL_CHANGE event using code like this:

-
F2.Events.on(
-    F2.Constants.Events.APP_SYMBOL_CHANGE, 
-    function(data){
-        F2.log("The symbol was changed to " + data.symbol);
-    }
-);
-
-

Note For a full list of support event types, browse to the SDK for F2.Constants.Events.

-

Apps can also pass context between apps. If there are two or more apps on a container with similar context and the ability to receive messages (yes, through event listeners, context receiving is opt-in), apps can communicate with each other. To communicate with another app, each app will have to know the event name along with the type of data being passed. Let’s take a look.

-

Within “App 1”, context is sent using F2.Events.emit():

-
F2.Events.emit(
-    "buy_stock", //custom event name
-    { 
-        symbol: "GOOG", 
-        name: "Google Inc",
-        price: 682.68,
-        isAvailableToPurchase: true,
-        orderType: "Market Order"
-    }
-);
-
-

Within “App 2”, context is received using F2.Events.on():

-
F2.Events.on(
-    "buy_stock", 
-    function(data){
-        if (data.isAvailableToPurchase){
-            F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
-        } else {
-            F2.log("This stock is not available for purchase.")
-        }
-    }
-);
-
-

The examples above demonstrate simple Context objects. In the event more complex data and/or data types are needed, F2 Context can support any JavaScript object—a string, a number, a function, an array or an object.

-

This is an example Context object demonstrating arbitrary JavaScript objects:

-
F2.Events.emit(
-    "example_event", //custom event name
-    { 
-        //number
-        price: 100,
-        //string
-        name: 'John Smith',
-        //function
-        callback: function(){
-            F2.log('Callback!');
-        },
-        //array
-        watchlist: ['AAPL','MSFT','GE'],
-        //object
-        userInfo: {
-            name: 'John Smith',
-            title: 'Managing Director',
-            groups: ['Alpha','Beta'],
-            sessionId: 1234567890
-        }
-    }
-);
-
-

If two apps want to communicate data for populating a trade ticket and execute a callback, appclass.js code might look like this:

-
F2.Events.emit(
-    "buy_stock", //custom event name
-    { 
-        symbol: "GOOG", 
-        name: "Google Inc",
-        price: 682.68,
-        isAvailableToPurchase: true,
-        orderType: "Market Order",
-        //define callback
-        callback: function(data){
-            alert('Trade ticket populated');
-        }
-    }
-);
-
-

The F2 app listening for the buy_stock event would fire the callback function.

-
F2.Events.on(
-    "buy_stock", 
-    function(data){
-        F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
-        //..populate the trade ticket...
-        //fire the callback
-        if (typeof data.callback === 'function'){
-            data.callback();
-        }
-    }
-);
-
-

Context is a term used to describe the state of an F2 container and its apps. At the same time, context is also the information passed from Container-to-App or from App-to-App or from App-to-Container. In the examples shown above, two types of context were shown: symbol and trade ticket context. It is important to realize F2.js allows client-side messaging between third parties using a collection of arbitrary name-value pairs. This provides the utmost flexibility and affords container providers the option to define context within their container.

-

Said another way, while { symbol:"AAPL", name: "Apple, Inc" } can be used to communicate symbol context, developers could also use { symbol: "123456789" } to identify Apple, Inc. The latter is more likely given not all apps would programmatically understand AAPL but—given symbol lookup services—would understand 123456789 as the universal F2 identifier for Apple, Inc. It is clear Container and App Developers alike would prefer to communicate with a guaranteed-to-never-change universal ID for all instrument types across all asset classes. Further details will be forthcoming as the F2 specification evolves.

-
-

Security is a fundamental requirement of any F2 container and many F2 apps. With that in mind, the integration of secure apps on a container requires more attention and effort. The process of app integration remains largely the same for integrating secure apps with one significant addition: a second container.

-

To support a secured container environment, one of the choices made when writing this specification was the inclusion of an open-source cross-domain in-browser secure messaging library. For this, F2 relies on easyXDM. EasyXDM helps front-end developers safely work around the Same Origin Policy using browser-supported techniques without compromising the user experience. For all browsers, the easyXDM transport stack offers bi-directionality, reliability, queueing and sender-verification.

-

The process of configuring an F2 container to be secure is identical to that of an unsecure container. As such, every container must be setup using ContainerConfig and the methods available.

-

In the secure container’s $(document).ready(), add the F2.init():

-
$(document).ready(function(){
-    F2.init({
-        //define ContainerConfig properties
-        appRender: function(appConfig, html){ ... },
-        beforeAppRender: function(appConfig, html){ ... },
-        afterAppRender: function(appConfig){ ... }
-    });
-});
-
-

For secure containers, an additional property must be set on the ContainerConfig within F2.init(). Assuiming the container is hosted at https://www.domain.com/container, the following config would be appropriate:

-
$(document).ready(function(){
-    F2.init({
-        //define ContainerConfig properties
-        appRender: function(appConfig, html){ ... },
-        beforeAppRender: function(appConfig, html){ ... },
-        afterAppRender: function(appConfig){ ... },
-        secureAppPagePath: "https://secure.domain.com/container" //define secure page path
-    });
-});
-
-

This secureAppPagePath property allows the container to specify which page is used when loading secure apps. To guarantee security, the page must reside on a different domain than the parent container.

-

Important Therefore Container Developers need two containers: one non-secure (parent), one secure (child). The parent container can follow the basic template style and must call F2.init() and F2.registerApps() appropriately. Per the above, it must also define the secureAppPagePath property in its ContainerConfig. To see a working container, browse to the examples in the project repo on GitHub.

-

Since it will be loaded in an iframe and like its parent, the secure child container must also include a copy of the F2.js SDK. Additionally, it must also call F2.init() with a unique ContainerConfig.

-
F2.init({
-    appRender:function(appConfig, html) {
-        return [
-            '<div class="col-md-4">',
-                html,
-            '</div>'
-        ].join('');
-    },
-    afterAppRender:function(appConfig, html) { ... },
-
-    //now set this property to true to tell F2 this is the secure child frame.
-    isSecureAppPage:true
-});
-
-

When the parent container calls registerApps(), F2 looks at each AppConfig for the isSecure bool. If the property is set to true, F2 inserts the secure app inside an iframe and instantiates the easyXDM transport stack. To see a working secure container, browse to the examples in the project repo on GitHub.

-
-

The F2.js JavaScript SDK provides utility methods for Container Developers. These are available within the F2 namespace and complete details are in the Reference documentation.

-
-

There are some utility methods provided within F2.js in the UI namespace. These helpers are for controlling layout, showing (or hiding) loading spinners, modals, managing views within apps, and more. To see which UI helpers are available to App Developers, read about F2.UI for apps.

-

For Container Developers, the use of F2’s UI is more than likely limited to customizing the design aesthetic (CSS) and configuring the UI properties.

-

For complete details on F2.UI, browse to the SDK docs.

-
-

User or content entitlements are the responsibility of the App developer. Many apps will need to be decoupled from the content that they need. This could include apps like research aggregation, news filtering, streaming market data, etc. Similarly to how companies build their own websites today with their own authentication and access (or content) entitlements, F2 apps are no different.

-

Further details around app entitlements will be forthcoming as the F2 specification evolves.

-
-

Single sign-on (SSO) will be a shared responsibility between the Container and App Developer. In some cases, containers will want all its apps to be authenticated seamlessly for users, and that will have to be negotiated between Container and App Developers. For the purposes of this documentation, it is assumed Container Developers will build and host authentication for access to their container(s).

-

Once a user is authenticated on the container, how is the user then authenticated with all of the apps? Encrypted URLs.*

-

Note The Container Developer is free to utilize any app authentication method they deem fit. Container Developers and App Developers will need to work together to finalize the authentication details.

-

Implementing SSO using encrypted URLs is a simple and straight-forward authentication mechanism for securing cross-domain multi-provider apps. To guarantee security between the Container and App Developers, secure API contracts must be negotiated. This includes, but is not limited to, the choice of cryptographic algorithm (such as AES) and the exchange of public keys.

-

When the Container Developer calls F2.registerApps(), custom logic should be added to append encrypted user credentials—on a need-to-know basis—to each app requiring authentication.

-

Authentication is a critical part of any container-app relationship. There are a plethora of SSO implementations and there are many considerations for both Container and App Developers alike.

-

Further details around container and app single sign-on will be forthcoming as the F2 specification evolves.

-
- -
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/docs/dist/extending-f2.html b/docs/dist/extending-f2.html deleted file mode 100644 index 31f64549..00000000 --- a/docs/dist/extending-f2.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - Extending F2 - F2: Open Financial Framework - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
-

Extending F2

-

At its core, F2 is an open framework. To create a truly open and flexible foundation with F2.js, F2 can be extended with custom plugins. Extending F2 with plugins provides direct access to F2.js SDK methods and can save your teams a lot of time.

- -
-

Now that you’re comfortable with F2 and all the individual components of the framework, you are ready to extend F2 and add your own custom logic in the form of an F2 plugin.

-

There is a separate repository on GitHub dedicated to F2 plugin development. If you write a plugin you’d like to contribute back to the community, commit it to F2Plugins.

-

Download F2 Plugins View on GitHub

-
-

Plugins are encapsulated in JavaScript closures as demonstrated below. There are three arguments which can be passed into F2.extend(): namespace, object, and overwrite. For full details, read the F2.js SDK documentation.

-
F2.extend('YourPluginName', (function(){
-    return {
-        doSomething: function(){
-            F2.log("Something has been done.");
-        }
-    };
-})());
-
-

To call your custom method shown above:

-
...
-F2.YourPluginName.doSomething();
-...
-
-

This method call writes Something has been done. to the Console.

-
-

The purpose of developing a plugin is to encapsulate clever logic in a single javascript function to save time and effort performing repetitive tasks. Here are some best practices to keep in mind:

-
    -
  • Always use F2.extend() and wrap your plugin in a closure.
  • -
  • Follow the module pattern as shown in the example above or the f2-storage.js example on GitHub.
  • -
  • Adhere to F2’s guidelines when it comes to namespacing.
  • -
  • When passing options or data to the plugin, use data objects instead of n arguments. Cleanliness is key.
  • -
  • Don’t overuse or clutter the F2 namespace with more custom plugins than you need.
  • -
-
-

Have a question? Ask it on the F2 Google Group.

-

OpenF2@googlegroups.com

-
- -
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/docs/dist/f2js-sdk.html b/docs/dist/f2js-sdk.html deleted file mode 100644 index 2eee8e60..00000000 --- a/docs/dist/f2js-sdk.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - F2.js SDK - F2: Open Financial Framework - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
-

F2.js SDK

-

F2 enables you to efficiently create fully-integrated, multi-vendor, multi-asset class and multi-channel apps and deploy them in as many app ecosystems as you want.

- -

Developers who adhere to the F2 standard will make it possible for multiple apps, developed independently by different organizations or individuals, to function together creating a seamless and integrated experience.

-
-

F2 is an open framework and to get Container and App Developers started, there is a JavaScript SDK—called F2.js—in addition to example apps as part of an open-source project maintained on GitHub.

-
-

Anyone is free to download F2.js from the F2 project repository on GitHub. Once downloaded, F2.js can be added to any web page using a script tag:

-
<script src="//cdnjs.cloudflare.com/ajax/libs/F2/1.4.5/f2.min.js"></script>
-
-

The latest version of F2.js is 1.4.5.

-

Download F2.js 1.4.5 View on GitHub

- -

Packages are variants of F2.js. They are ideally used when, for example, a container already has jQuery or sandboxed apps aren’t needed. In circumstances where not all F2 features are required, Container Providers can use smaller, faster, lighter-weight versions of F2.js. Choose one below:

- -

These are all available on cdnjs.

-

For more information on the libraries used by F2, see Third Party Libraries below.

-
-

The latest version of F2.js will always be in the root of the project, and the version number can be found embedded in the code. The version number is also available on the command line by using:

-

$> grunt version

-

In accordance with industry standards, F2 is currently maintained, in as far as reasonably possible, under the Semantic Versioning guidelines.

-

Releases will be numbered with the following format:

-

<major>.<minor>.<patch>

-

For more information on SemVer, please visit SemVer.org.

-
-

It is our goal to make upgrading to the latest version of F2 a minor effort for development teams. The details from each release of F2, minor and major, are tracked in the changelog. As of version 1.2, no breaking changes have been introduced and therefore upgrading should be as simple as downloading the latest copy of F2.js and updating your website.

-

Developers can quick-link to the latest copy of F2.js:

-

//cdnjs.cloudflare.com/ajax/libs/F2/1.4.5/f2.min.js

-

A download (zip) of the current version (1.4.5) of F2 is always available along with tags of previous releases.

-

There is a page on the wiki tracking deprecated features in F2. Starting with version 1.2, three ContainerConfig properties have been retired. As F2 features and/or F2.js APIs are deprecated, we will attempt to give reasonable advance notice via any or all of the F2 communication channels. In addition, we will strive to ensure that backward compatibility will be maintained for at least one major version of F2. For example, if Feature X is deprecated in version 1.3, we will attempt to maintain backward compatibility until the next major release (version 2.0). F2 documentation will be updated accordingly to reflect any changes, and the conversation behind deprecated features will be publicly available on GitHub.

-

F2 uses third party libraries inside F2.js (see Framework: Choices). These open-source libraries are all on their own release schedules. We cannot guarantee that we will always stay abreast and in tune with such latest releases, but in an effort to improve the F2 framework, we will attempt to update F2.js so that it uses the latest, most stable and most secure version of the third party software. These updates to F2 will be made through the normal release process on GitHub and comments will be open.

-

Have a question? Ask it on the F2 Google Group (or send an email to OpenF2@googlegroups.com) or start a discussion using Issues on GitHub.

-

To track bugs, enhancements or other issues, F2 is using Issues on GitHub.

-
-

F2 is licensed under the Apache License version 2.0. Details are available in the project readme.

- -
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/docs/dist/img/ajax-loader.gif b/docs/dist/img/ajax-loader.gif deleted file mode 100644 index d764e72e..00000000 Binary files a/docs/dist/img/ajax-loader.gif and /dev/null differ diff --git a/docs/dist/index.html b/docs/dist/index.html deleted file mode 100644 index 6690ae39..00000000 --- a/docs/dist/index.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - Getting Started with F2 - F2: Open Financial Framework - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
-

Getting Started with F2

-

The goal of F2 is to define a development standard for the financial services industry that offers a cost saving, risk-reducing method for building innovative, multi-provider solutions.

- -

Below you’ll find links to the various sections of the F2 development standard as well as F2.js API reference documentation.

-
-
-
-
-

-

F2 Container

-

For Container Providers

- -
-
-

-

F2 Apps

-

For App Providers

- -
-
-

-

API Reference

-

For Container and App Developers

- -
-
-
- -
-

The latest version of F2 is 1.4.5 which was released on 2 March 2018.

-

F2 v1.0 was originally open sourced in October 2012. A detailed changelog and roadmap are available on GitHub.

- - -

Download version 1.4.5

-
-

There are a few different types of examples available below.

-
- -
-

Examples

- Visit openF2.org/examples for a live demo of production-grade Apps in a basic Container. -
-
- -
- -
-

Download

- A variety of example Containers and Apps to download and run on your localhost. Most are “plain” javascript, others are written in .NET, PHP and Node.js. The examples source code is also on GitHub. -
-
- -
- -
-

jsFiddle

- Review a collection of fiddles on jsfiddle.net/user/openF2js. -
-
- -
- -
-

Codepen

- Review a collection of pens on codepen.io/openF2. -
-
- -
- -
-

iOS Demo App

- An iOS app demonstrating F2 App integration using UIWebViews, a javascript bridge for F2 Context, and a native symbol search control. -
-
- -
-

Have a question? Find a bug? Need help?

-
- -
-

Guides

- Coming soon… -
-
- -
- -
-

GitHub Issues

- Browse and submit to Issues on GitHub for bug reports, enhancement requests, etc. -
-
- -
- -
-

Slack

- Join the F2 Slack for real-time project updates. Get an invite.

- -
-
- -
- -
-

OpenF2 Google Group

- Use the F2 mailing list on Google Groups for support. -
-
- -
- -
-

Email

- You can always email info@openF2.org with questions. -
-
- -
-

The F2 development standard will continuously evolve to bring the community the best features, services and apps. F2’s promise is to do this by building on the existing spec, not by changing it. The specification aims high to solve many problems and suit many needs. As the standard evolves and new requirements come to light, the functionality in F2 will expand accordingly.

-

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this spec are to be interpreted as described in RFC 2119. For readability, these words often do not appear in all uppercase letters.

-
-

Join our team and help contribute to F2 on GitHub. Begin by reading our contribution guidelines, and then start by forking the repo, sending pull requests, or submitting issues.

-

Thank you to the growing list of contributors!

- -
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/docs/dist/js/docs-amd.js b/docs/dist/js/docs-amd.js deleted file mode 100644 index 797424fa..00000000 --- a/docs/dist/js/docs-amd.js +++ /dev/null @@ -1,106 +0,0 @@ -define(['jquery','F2','reqPath','staticPrefix','highlightjs'],function($,F2,reqPath,staticPrefix,hljs){ - - /** - * This code is only for the F2 documentation site. Don't use it anywhere else, you really shouldn't. - * (c) Markit On Demand 2014 - */ - - //F2 docs - var F2Docs = function(){ } - - //shortcut - F2Docs.fn = F2Docs.prototype; - - /** - * Init - */ - F2Docs.fn.initialize = function() { - - this.buildLeftRailToc(); - // this.buildBookmarks(); - - //affix left nav - $('#toc > ul.nav').affix({ - offset: { - top: 214 - } - }); - - //add source & feedback links - $('#feedbackLink').attr('href', $('#feedbackLink').attr('href') + '+' + location.pathname.split('/').pop() ); - $('#viewSourceLink').attr('href', $('#viewSourceLink').attr('href') + location.pathname.split('/').pop().replace('.html','.md') ); - } - - /** - * Add bookmark links to each

- */ - F2Docs.fn.buildBookmarks = function(){ - var $docsContainer = $('#docs'), - $headers = $('section', $docsContainer).not('.level1,.level2'), - link = ""; - - $headers.each($.proxy(function(idx,item){ - var $h = $(item).children().first(), - //name = $h.text(), - anchor = $(item).prop("id"), - $link = $(link.supplant({id: anchor})); - //animate click - $link.on('click',$.proxy(function(e){ - this._animateAnchor(e,false); - },this)); - $h.append(' ').append($link); - },this)); - } - - /** - * Build left rail TOC - */ - F2Docs.fn.buildLeftRailToc = function(){ - - var $docsContainer = $('#docs'), - file = location.pathname.split('/').pop(), - $sections = $('section.level2', $docsContainer), - $listContainer = $('ul.nav-stacked','#toc'); - - //build table of contents based on sections within generated markdown file - if (!$sections.length) return; - - //loop over all sections, build nav based on

's inside the - $sections.each($.proxy(function(idx,item){ - - var $item = $(item), - sectionTitle = $item.children().first().text(), - sectionId = $item.prop("id"), - isActive = (sectionId == String(location.hash.replace("#",""))) ? " class='active'" : "", - $li, - // $level3Sections = $item.children('section.level3'); - - //nav (level2) - $li = $(""+sectionTitle+""); - - // //sub nav (level3) - // if ($level3Sections.length){ - // var $childUl = $('