├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── dist ├── xapiwrapper.min.js └── xapiwrapper.min.js.map ├── doc ├── index.html └── static │ ├── bootstrap.min.css │ ├── domtastic.min.js │ ├── prism.css │ └── prism.js ├── examples ├── example.html ├── libs │ └── ace-editor │ │ ├── ace.js │ │ ├── mode-json.js │ │ ├── theme-twilight.js │ │ └── worker-json.js ├── stmtBank.js └── useWrapper.html ├── lib ├── cryptojs_v3.1.2.js └── utf8-text-encoding.js ├── package-lock.json ├── package.json ├── src ├── activitytypes.js ├── verbs.js ├── xapi-launch.js ├── xapi-util.js ├── xapistatement.js └── xapiwrapper.js └── test ├── README.md ├── libs ├── blanket_mocha.min.js ├── expect │ └── 0.3.1 │ │ └── index.js ├── jquery │ └── 2.1.4 │ │ └── jquery.min.js ├── mocha-blanket-adapter.js ├── mocha │ └── 2.2.5 │ │ ├── mocha.css │ │ └── mocha.js ├── require.js └── should.min.js ├── my.mock.wrapper.js ├── testAttachments.html ├── testState.html ├── testUtil.html └── tests ├── test.attachments.js ├── test.state.js └── test.util.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | node_modules 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | 'pkg': grunt.file.readJSON('package.json'), 6 | 'bump': { 7 | options: { 8 | updateConfigs: ['pkg'], 9 | commitFiles: ['-a'] 10 | } 11 | }, 12 | 'uglify': { 13 | options: { 14 | banner: '/*! <%= pkg.name %> v <%= pkg.version %> | Built on <%= grunt.template.today("yyyy-mm-dd HH:MM:sso") %> */\n', 15 | sourceMap: true 16 | }, 17 | 'build': { 18 | files: { 19 | "dist/xapiwrapper.min.js": [ 20 | "lib/cryptojs_v3.1.2.js", 21 | "lib/utf8-text-encoding.js", 22 | "src/activitytypes.js", 23 | "src/verbs.js", 24 | "src/xapiwrapper.js", 25 | "src/xapistatement.js", 26 | "src/xapi-util.js", 27 | "src/xapi-launch.js" 28 | ] 29 | } 30 | } 31 | }, 32 | 'exec': { 33 | docs: 'node ./node_modules/doxstrap/bin/doxstrap.js --title "xAPIWrapper <%= pkg.version %> Reference" --layout "bs-sidebar.html" --no-sort --output doc' 34 | } 35 | }); 36 | 37 | // Load the plugins. 38 | grunt.loadNpmTasks('grunt-bump'); 39 | grunt.loadNpmTasks('grunt-contrib-uglify'); 40 | grunt.loadNpmTasks('grunt-exec'); 41 | 42 | // Default task(s). 43 | grunt.registerTask('default', ['uglify']);//,'exec']); 44 | 45 | // Build only 46 | grunt.registerTask('build', ['uglify']); 47 | 48 | // Docs only 49 | grunt.registerTask('docs', ['exec']); 50 | 51 | // those with adl repo access can use this to publish a tag and release 52 | // $> grunt release:minor 53 | grunt.registerTask('release', 'Build the release of xapiwrapper', function(n) { 54 | var vertype = n; 55 | if (vertype == null) vertype = 'minor'; 56 | grunt.task.run('bump-only:' + vertype, 'default', 'bump-commit'); 57 | }); 58 | 59 | }; 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /doc/static/domtastic.min.js: -------------------------------------------------------------------------------- 1 | !function(t){var e=function(){return t()["default"]};if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.$=e()}}(function(){return function t(e,n,r){function i(s,u){if(!n[s]){if(!e[s]){var a="function"==typeof require&&require;if(!u&&a)return a(s,!0);if(o)return o(s,!0);throw new Error("Cannot find module '"+s+"'")}var c=n[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return i(n?n:t)},c,c.exports,t,e,n,r)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;si;i++)e.push(r[i]);return e}function s(t){return l||(u.prototype=n.fn,u.prototype.constructor=u,l=!0),new u(t)}function u(t){for(var e=0,n=t.length;n>e;)this[e]=t[e++];this.length=n}var a=t("./util"),c=a.global,f=a.makeIterable,l=([].slice,!1),d=/^\s*<(\w+|!)[^>]*>/,h=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,p=/^[\.#]?[\w-]*$/,v=function(){var t="undefined"!=typeof Element?Element.prototype:c,e=t.matches||t.matchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.msMatchesSelector||t.oMatchesSelector;return function(t,n){return e.call(t,n)}}();e.exports={$:n,find:r,matches:v,__esModule:!0}},{"./util":18}],16:[function(t,e){"use strict";function n(t){var e=[];return f(this,function(n){n.children&&f(n.children,function(n){(!t||t&&h(n,t))&&e.push(n)})}),d(e)}function r(t){for(var e=this[0];e.nodeType!==e.DOCUMENT_NODE;e=e.parentNode)if(h(e,t))return d(e);return d()}function i(){var t=[];return f(this,function(e){t.push.apply(t,l(e.childNodes))}),d(t)}function o(t){return a.call(this,t,t+1)}function s(t){return this[t]}function u(t){var e=[];return f(this,function(n){(!t||t&&h(n.parentNode,t))&&e.push(n.parentNode)}),d(e)}function a(){return d([].slice.apply(this,arguments))}var c=t("./util"),f=c.each,l=c.toArray,c=t("./selector"),d=c.$,h=c.matches;e.exports={children:n,contents:i,closest:r,eq:o,get:s,parent:u,slice:a,__esModule:!0}},{"./selector":15,"./util":18}],17:[function(t,e){"use strict";function n(t){return"function"==typeof t}var r=Array.isArray;e.exports={isFunction:n,isArray:r,__esModule:!0}},{}],18:[function(t,e){"use strict";function n(t,e,n){var r=t.length;if(void 0!==r&&void 0===t.nodeType)for(var i=0;r>i;i++)e.call(n,t[i],i,t);else e.call(n,t,0,t);return t}function r(t){for(var e=[],n=1;n code[class*="language-"], 56 | pre[class*="language-"] { 57 | background: #f5f2f0; 58 | } 59 | 60 | /* Inline code */ 61 | :not(pre) > code[class*="language-"] { 62 | padding: .1em; 63 | border-radius: .3em; 64 | } 65 | 66 | .token.comment, 67 | .token.prolog, 68 | .token.doctype, 69 | .token.cdata { 70 | color: slategray; 71 | } 72 | 73 | .token.punctuation { 74 | color: #999; 75 | } 76 | 77 | .namespace { 78 | opacity: .7; 79 | } 80 | 81 | .token.property, 82 | .token.tag, 83 | .token.boolean, 84 | .token.number, 85 | .token.constant, 86 | .token.symbol { 87 | color: #905; 88 | } 89 | 90 | .token.selector, 91 | .token.attr-name, 92 | .token.string, 93 | .token.builtin { 94 | color: #690; 95 | } 96 | 97 | .token.operator, 98 | .token.entity, 99 | .token.url, 100 | .language-css .token.string, 101 | .style .token.string, 102 | .token.variable { 103 | color: #a67f59; 104 | background: hsla(0,0%,100%,.5); 105 | } 106 | 107 | .token.atrule, 108 | .token.attr-value, 109 | .token.keyword { 110 | color: #07a; 111 | } 112 | 113 | 114 | .token.regex, 115 | .token.important { 116 | color: #e90; 117 | } 118 | 119 | .token.important { 120 | font-weight: bold; 121 | } 122 | 123 | .token.entity { 124 | cursor: help; 125 | } 126 | -------------------------------------------------------------------------------- /doc/static/prism.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * MIT license http://www.opensource.org/licenses/mit-license.php/ 4 | * @author Lea Verou http://lea.verou.me 5 | */(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&").replace(/e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+""};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();; 6 | Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}}, number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|(&){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g}; 7 | ; 8 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|get|set|new|with|typeof|try|throw|catch|finally|null|break|continue)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,inside:{tag:{pattern:/(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});; -------------------------------------------------------------------------------- /examples/example.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 31 | 32 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /examples/libs/ace-editor/mode-json.js: -------------------------------------------------------------------------------- 1 | define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"variable",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)'},{token:"string",regex:'"',next:"string"},{token:"constant.numeric",regex:"0[xX][0-9a-fA-F]+\\b"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:"constant.language.boolean",regex:"(?:true|false)\\b"},{token:"invalid.illegal",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"invalid.illegal",regex:"\\/\\/.*$"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:"\\s+"}],string:[{token:"constant.language.escape",regex:/\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/},{token:"string",regex:'[^"\\\\]+'},{token:"string",regex:'"',next:"start"},{token:"string",regex:"",next:"start"}]}};r.inherits(s,i),t.JsonHighlightRules=s}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f,l={},c=function(e){var t=-1;e.multiSelect&&(t=e.selection.index,l.rangeCount!=e.multiSelect.rangeCount&&(l={rangeCount:e.multiSelect.rangeCount}));if(l[t])return f=l[t];f=l[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:"",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:"",maybeInsertedLineEnd:""}},h=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},p=function(){this.add("braces","insertion",function(e,t,n,r,i){var s=n.getCursorPosition(),u=r.doc.getLine(s.row);if(i=="{"){c(n);var a=n.getSelectionRange(),l=r.doc.getTextRange(a);if(l!==""&&l!=="{"&&n.getWrapBehavioursEnabled())return h(a,l,"{","}");if(p.isSaneInsertion(n,r))return/[\]\}\)]/.test(u[s.column])||n.inMultiSelectMode?(p.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}):(p.recordMaybeInsert(n,r,"{"),{text:"{",selection:[1,1]})}else if(i=="}"){c(n);var d=u.substring(s.column,s.column+1);if(d=="}"){var v=r.$findOpeningBracket("}",{column:s.column+1,row:s.row});if(v!==null&&p.isAutoInsertedClosing(s,u,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else{if(i=="\n"||i=="\r\n"){c(n);var m="";p.isMaybeInsertedClosing(s,u)&&(m=o.stringRepeat("}",f.maybeInsertedBrackets),p.clearMaybeInsertedClosing());var d=u.substring(s.column,s.column+1);if(d==="}"){var g=r.findMatchingBracket({row:s.row,column:s.column+1},"}");if(!g)return null;var y=this.$getIndent(r.getLine(g.row))}else{if(!m){p.clearMaybeInsertedClosing();return}var y=this.$getIndent(u)}var b=y+r.getTabString();return{text:"\n"+b+"\n"+y+m,selection:[1,b.length,1,b.length]}}p.clearMaybeInsertedClosing()}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;f.maybeInsertedBrackets--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"(",")");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"[","]");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){c(n);var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!==""&&u!=="'"&&u!='"'&&n.getWrapBehavioursEnabled())return h(o,u,s,s);if(!u){var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column),p=f.substring(a.column,a.column+1),d=r.getTokenAt(a.row,a.column),v=r.getTokenAt(a.row,a.column+1);if(l=="\\"&&d&&/escape/.test(d.type))return null;var m=d&&/string|escape/.test(d.type),g=!v||/string|escape/.test(v.type),y;if(p==s)y=m!==g;else{if(m&&!g)return null;if(m&&g)return null;var b=r.$mode.tokenRe;b.lastIndex=0;var w=b.test(l);b.lastIndex=0;var E=b.test(l);if(w||E)return null;if(p&&!/[\s;,.})\]\\]/.test(p))return null;y=!0}return{text:y?s+s:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==s)return i.end.column++,i}})};p.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},p.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},p.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,f.autoInsertedLineEnd[0])||(f.autoInsertedBrackets=0),f.autoInsertedRow=r.row,f.autoInsertedLineEnd=n+i.substr(r.column),f.autoInsertedBrackets++},p.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(f.maybeInsertedBrackets=0),f.maybeInsertedRow=r.row,f.maybeInsertedLineStart=i.substr(0,r.column)+n,f.maybeInsertedLineEnd=i.substr(r.column),f.maybeInsertedBrackets++},p.isAutoInsertedClosing=function(e,t,n){return f.autoInsertedBrackets>0&&e.row===f.autoInsertedRow&&n===f.autoInsertedLineEnd[0]&&t.substr(e.column)===f.autoInsertedLineEnd},p.isMaybeInsertedClosing=function(e,t){return f.maybeInsertedBrackets>0&&e.row===f.maybeInsertedRow&&t.substr(e.column)===f.maybeInsertedLineEnd&&t.substr(0,e.column)==f.maybeInsertedLineStart},p.popAutoInsertedClosing=function(){f.autoInsertedLineEnd=f.autoInsertedLineEnd.substr(1),f.autoInsertedBrackets--},p.clearMaybeInsertedClosing=function(){f&&(f.maybeInsertedBrackets=0,f.maybeInsertedRow=-1)},r.inherits(p,i),t.CstyleBehaviour=p}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/json",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/json_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle","ace/worker/worker_client"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./json_highlight_rules").JsonHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./behaviour/cstyle").CstyleBehaviour,a=e("./folding/cstyle").FoldMode,f=e("../worker/worker_client").WorkerClient,l=function(){this.HighlightRules=s,this.$outdent=new o,this.$behaviour=new u,this.foldingRules=new a};r.inherits(l,i),function(){this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new f(["ace"],"ace/mode/json_worker","JsonWorker");return t.attachToDocument(e.getDocument()),t.on("annotate",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t},this.$id="ace/mode/json"}.call(l.prototype),t.Mode=l}) -------------------------------------------------------------------------------- /examples/libs/ace-editor/theme-twilight.js: -------------------------------------------------------------------------------- 1 | define("ace/theme/twilight",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!0,t.cssClass="ace-twilight",t.cssText=".ace-twilight .ace_gutter {background: #232323;color: #E2E2E2}.ace-twilight .ace_print-margin {width: 1px;background: #232323}.ace-twilight {background-color: #141414;color: #F8F8F8}.ace-twilight .ace_cursor {color: #A7A7A7}.ace-twilight .ace_marker-layer .ace_selection {background: rgba(221, 240, 255, 0.20)}.ace-twilight.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #141414;}.ace-twilight .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-twilight .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(255, 255, 255, 0.25)}.ace-twilight .ace_marker-layer .ace_active-line {background: rgba(255, 255, 255, 0.031)}.ace-twilight .ace_gutter-active-line {background-color: rgba(255, 255, 255, 0.031)}.ace-twilight .ace_marker-layer .ace_selected-word {border: 1px solid rgba(221, 240, 255, 0.20)}.ace-twilight .ace_invisible {color: rgba(255, 255, 255, 0.25)}.ace-twilight .ace_keyword,.ace-twilight .ace_meta {color: #CDA869}.ace-twilight .ace_constant,.ace-twilight .ace_constant.ace_character,.ace-twilight .ace_constant.ace_character.ace_escape,.ace-twilight .ace_constant.ace_other,.ace-twilight .ace_heading,.ace-twilight .ace_markup.ace_heading,.ace-twilight .ace_support.ace_constant {color: #CF6A4C}.ace-twilight .ace_invalid.ace_illegal {color: #F8F8F8;background-color: rgba(86, 45, 86, 0.75)}.ace-twilight .ace_invalid.ace_deprecated {text-decoration: underline;font-style: italic;color: #D2A8A1}.ace-twilight .ace_support {color: #9B859D}.ace-twilight .ace_fold {background-color: #AC885B;border-color: #F8F8F8}.ace-twilight .ace_support.ace_function {color: #DAD085}.ace-twilight .ace_list,.ace-twilight .ace_markup.ace_list,.ace-twilight .ace_storage {color: #F9EE98}.ace-twilight .ace_entity.ace_name.ace_function,.ace-twilight .ace_meta.ace_tag,.ace-twilight .ace_variable {color: #AC885B}.ace-twilight .ace_string {color: #8F9D6A}.ace-twilight .ace_string.ace_regexp {color: #E9C062}.ace-twilight .ace_comment {font-style: italic;color: #5F5A60}.ace-twilight .ace_variable {color: #7587A6}.ace-twilight .ace_xml-pe {color: #494949}.ace-twilight .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWMQERFpYLC1tf0PAAgOAnPnhxyiAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) -------------------------------------------------------------------------------- /examples/libs/ace-editor/worker-json.js: -------------------------------------------------------------------------------- 1 | "no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console,e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?tthis.end.column?1:0:ethis.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.rowt)var r={row:t+1,column:0};else if(this.start.row=0&&t.row=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;othis.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e0,r=t=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){!e instanceof o&&(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n="0"&&i<="9")t+=i,a();if(i==="."){t+=".";while(a()&&i>="0"&&i<="9")t+=i}if(i==="e"||i==="E"){t+=i,a();if(i==="-"||i==="+")t+=i,a();while(i>="0"&&i<="9")t+=i,a()}e=+t;if(!isNaN(e))return e;u("Bad number")},l=function(){var e,t,n="",r;if(i==='"')while(a()){if(i==='"')return a(),n;if(i==="\\"){a();if(i==="u"){r=0;for(t=0;t<4;t+=1){e=parseInt(a(),16);if(!isFinite(e))break;r=r*16+e}n+=String.fromCharCode(r)}else{if(typeof s[i]!="string")break;n+=s[i]}}else n+=i}u("Bad string")},c=function(){while(i&&i<=" ")a()},h=function(){switch(i){case"t":return a("t"),a("r"),a("u"),a("e"),!0;case"f":return a("f"),a("a"),a("l"),a("s"),a("e"),!1;case"n":return a("n"),a("u"),a("l"),a("l"),null}u("Unexpected '"+i+"'")},p,d=function(){var e=[];if(i==="["){a("["),c();if(i==="]")return a("]"),e;while(i){e.push(p()),c();if(i==="]")return a("]"),e;a(","),c()}}u("Bad array")},v=function(){var e,t={};if(i==="{"){a("{"),c();if(i==="}")return a("}"),t;while(i){e=l(),c(),a(":"),Object.hasOwnProperty.call(t,e)&&u('Duplicate key "'+e+'"'),t[e]=p(),c();if(i==="}")return a("}"),t;a(","),c()}}u("Bad object")};return p=function(){c();switch(i){case"{":return v();case"[":return d();case'"':return l();case"-":return f();default:return i>="0"&&i<="9"?f():h()}},function(e,t){var n;return o=e,r=0,i=" ",n=p(),c(),i&&u("Syntax error"),typeof t=="function"?function s(e,n){var r,i,o=e[n];if(o&&typeof o=="object")for(r in o)Object.hasOwnProperty.call(o,r)&&(i=s(o,r),i!==undefined?o[r]=i:delete o[r]);return t.call(e,n,o)}({"":n},""):n}}),define("ace/mode/json_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/json/json_parse"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../worker/mirror").Mirror,s=e("./json/json_parse"),o=t.JsonWorker=function(e){i.call(this,e),this.setTimeout(200)};r.inherits(o,i),function(){this.onUpdate=function(){var e=this.doc.getValue(),t=[];try{e&&s(e)}catch(n){var r=this.doc.indexToPosition(n.at-1);t.push({row:r.row,column:r.column,text:n.message,type:"error"})}this.sender.emit("annotate",t)}}.call(o.prototype)}),define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+ta)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 38 | 39 | 44 | 45 | 46 | 54 |
55 |

xAPI Test Page

56 |

endpoint:

57 |
58 |
59 |
60 |
61 |

Custom Statement

62 |
63 |
64 |
Actor
65 |
66 | 70 |
71 |
72 | 76 |
77 |
78 |
79 |
Object
80 |
81 | 85 |
86 |
87 | 91 |
92 |
93 | 97 |
98 |
99 |
100 |
Result
101 |
102 | Score
103 | 107 | 111 | 115 | 119 |
120 |
121 | 125 |
126 |
127 | 131 |
132 |
133 | 137 |
138 |
139 | 143 |
144 |
145 | 149 |
150 |
151 |
152 |
Context
153 |
154 | 158 |
159 |
160 | ctx acts
161 | 165 | 169 | 173 | 177 |
178 |
179 | 183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 | 191 |
192 |
193 |
194 |
195 | 196 |

197 |                 
198 | 199 | 200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 | 209 | 227 | 228 | 238 | 239 | 345 | 346 | 425 | 426 | 427 | -------------------------------------------------------------------------------- /lib/utf8-text-encoding.js: -------------------------------------------------------------------------------- 1 | (function(root) { 2 | 3 | // NOTES: 4 | // Provides utf8 only implementation of TextEncoder and TextDecoder for IE10+ 5 | // https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder 6 | // https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder 7 | 8 | // It is a modified version of https://gist.github.com/Yaffle/5458286 for IE10+ and Uint8Array compatibility 9 | // https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder#Methods 10 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array 11 | 12 | if (typeof root.TextEncoder === 'undefined') { 13 | 14 | // Normalise String.prototype.codePointAt for IE10+ 15 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt 16 | function StringToCodePointAt(string, position) { 17 | if (String.prototype.codePointAt) return string.codePointAt(position); 18 | string = String(string); 19 | var size = string.length; 20 | // `ToInteger` 21 | var index = position ? Number(position) : 0; 22 | if (index != index) { // better `isNaN` 23 | index = 0; 24 | } 25 | // Account for out-of-bounds indices: 26 | if (index < 0 || index >= size) { 27 | return undefined; 28 | } 29 | // Get the first code unit 30 | var first = string.charCodeAt(index); 31 | var second; 32 | if ( // check if it’s the start of a surrogate pair 33 | first >= 0xD800 && first <= 0xDBFF && // high surrogate 34 | size > index + 1 // there is a next code unit 35 | ) { 36 | second = string.charCodeAt(index + 1); 37 | if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate 38 | // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae 39 | return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; 40 | } 41 | } 42 | return first; 43 | }; 44 | 45 | function TextEncoder(encoding) { 46 | if (!encoding) encoding = 'utf8'; 47 | switch (encoding) { 48 | case 'utf-8': 49 | case 'utf8': 50 | break; 51 | default: 52 | throw 'TextEncoder only supports utf8'; 53 | } 54 | } 55 | TextEncoder.prototype.encode = function (string) { 56 | var octets = new Uint8Array(string.length * 3); 57 | var pos = -1; 58 | var length = string.length; 59 | var i = 0; 60 | while (i < length) { 61 | var codePoint = StringToCodePointAt(string, i); 62 | var c = 0; 63 | var bits = 0; 64 | if (codePoint <= 0x0000007F) { 65 | c = 0; 66 | bits = 0x00; 67 | } else if (codePoint <= 0x000007FF) { 68 | c = 6; 69 | bits = 0xC0; 70 | } else if (codePoint <= 0x0000FFFF) { 71 | c = 12; 72 | bits = 0xE0; 73 | } else if (codePoint <= 0x001FFFFF) { 74 | c = 18; 75 | bits = 0xF0; 76 | } 77 | octets[pos += 1] = (bits | (codePoint >> c)); 78 | c -= 6; 79 | while (c >= 0) { 80 | octets[pos += 1] = (0x80 | ((codePoint >> c) & 0x3F)); 81 | c -= 6; 82 | } 83 | i += codePoint >= 0x10000 ? 2 : 1; 84 | } 85 | return octets.subarray(0, pos+1); 86 | }; 87 | 88 | root.TextEncoder = TextEncoder; 89 | 90 | } 91 | 92 | if (typeof root.TextDecoder === 'undefined') { 93 | 94 | // Normalise String.fromCodePointAt for IE10+ 95 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint 96 | function StringFromCodePoint(_) { 97 | if (String.fromCodePoint) return String.fromCodePoint(_); 98 | var codeUnits = [], codeLen = 0, result = ''; 99 | for (var index=0, len = arguments.length; index !== len; ++index) { 100 | var codePoint = +arguments[index]; 101 | // correctly handles all cases including `NaN`, `-Infinity`, `+Infinity` 102 | // The surrounding `!(...)` is required to correctly handle `NaN` cases 103 | // The (codePoint>>>0) === codePoint clause handles decimals and negatives 104 | if (!(codePoint < 0x10FFFF && (codePoint>>>0) === codePoint)) 105 | throw RangeError('Invalid code point: ' + codePoint); 106 | if (codePoint <= 0xFFFF) { // BMP code point 107 | codeLen = codeUnits.push(codePoint); 108 | } else { // Astral code point; split in surrogate halves 109 | // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae 110 | codePoint -= 0x10000; 111 | codeLen = codeUnits.push( 112 | (codePoint >> 10) + 0xD800, // highSurrogate 113 | (codePoint % 0x400) + 0xDC00 // lowSurrogate 114 | ); 115 | } 116 | if (codeLen >= 0x3fff) { 117 | result += String.fromCharCode.apply(null, codeUnits); 118 | codeUnits.length = 0; 119 | } 120 | } 121 | return result + String.fromCharCode.apply(null, codeUnits); 122 | }; 123 | 124 | function TextDecoder(encoding) { 125 | if (!encoding) encoding = 'utf8'; 126 | switch (encoding) { 127 | case 'utf-8': 128 | case 'utf8': 129 | break; 130 | default: 131 | throw 'TextDecoder only supports utf8'; 132 | } 133 | } 134 | TextDecoder.prototype.decode = function (octets) { 135 | var string = ''; 136 | var i = 0; 137 | while (i < octets.length) { 138 | var octet = octets[i]; 139 | var bytesNeeded = 0; 140 | var codePoint = 0; 141 | if (octet <= 0x7F) { 142 | bytesNeeded = 0; 143 | codePoint = octet & 0xFF; 144 | } else if (octet <= 0xDF) { 145 | bytesNeeded = 1; 146 | codePoint = octet & 0x1F; 147 | } else if (octet <= 0xEF) { 148 | bytesNeeded = 2; 149 | codePoint = octet & 0x0F; 150 | } else if (octet <= 0xF4) { 151 | bytesNeeded = 3; 152 | codePoint = octet & 0x07; 153 | } 154 | if (octets.length - i - bytesNeeded > 0) { 155 | var k = 0; 156 | while (k < bytesNeeded) { 157 | octet = octets[i + k + 1]; 158 | codePoint = (codePoint << 6) | (octet & 0x3F); 159 | k += 1; 160 | } 161 | } else { 162 | codePoint = 0xFFFD; 163 | bytesNeeded = octets.length - i; 164 | } 165 | string += StringFromCodePoint(codePoint); 166 | i += bytesNeeded + 1; 167 | } 168 | return string 169 | }; 170 | 171 | root.TextDecoder = TextDecoder; 172 | 173 | } 174 | 175 | })(this); 176 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xAPIWrapper", 3 | "description": "An easier way to build, send, and retrieve xAPI statements", 4 | "version": "1.11.0", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/adlnet/xAPIWrapper.git" 8 | }, 9 | "devDependencies": { 10 | "doxstrap": "~0.0.8", 11 | "grunt": "^1.0.4", 12 | "grunt-bump": "0.8.0", 13 | "grunt-contrib-uglify": "~4.0.1", 14 | "grunt-exec": "~0.4.6" 15 | }, 16 | "dependencies": { 17 | "mocha": "^5.2.0", 18 | "should": "^13.2.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/activitytypes.js: -------------------------------------------------------------------------------- 1 | (function(ADL){ 2 | ADL.activityTypes = { 3 | "assessment": "http://adlnet.gov/expapi/activities/assessment", 4 | "attempt": "http://adlnet.gov/expapi/activities/attempt", 5 | "course": "http://adlnet.gov/expapi/activities/course", 6 | "file": "http://adlnet.gov/expapi/activities/file", 7 | "cmiInteraction": "http://adlnet.gov/expapi/activities/cmi.interaction", 8 | "interaction": "http://adlnet.gov/expapi/activities/interaction", 9 | "lesson": "http://adlnet.gov/expapi/activities/lesson", 10 | "link": "http://adlnet.gov/expapi/activities/link", 11 | "media": "http://adlnet.gov/expapi/activities/media", 12 | "meeting": "http://adlnet.gov/expapi/activities/meeting", 13 | "module": "http://adlnet.gov/expapi/activities/module", 14 | "objective": "http://adlnet.gov/expapi/activities/objective", 15 | "performance": "http://adlnet.gov/expapi/activities/performance", 16 | "profile": "http://adlnet.gov/expapi/activities/profile", 17 | "question": "http://adlnet.gov/expapi/activities/question", 18 | "simulation": "http://adlnet.gov/expapi/activities/simulation" 19 | }; 20 | }(window.ADL = window.ADL || {})); 21 | -------------------------------------------------------------------------------- /src/verbs.js: -------------------------------------------------------------------------------- 1 | (function(ADL){ 2 | ADL.verbs = { 3 | "abandoned" : { 4 | "id" : "https://w3id.org/xapi/adl/verbs/abandoned", 5 | "display" : {"en-US" : "abandoned"} 6 | }, 7 | "answered" : { 8 | "id" : "http://adlnet.gov/expapi/verbs/answered", 9 | "display" : {"de-DE" : "beantwortete", 10 | "en-US" : "answered", 11 | "fr-FR" : "a répondu", 12 | "es-ES" : "contestó", 13 | "ar-AR" : "أجاب"} 14 | }, 15 | "asked" : { 16 | "id" : "http://adlnet.gov/expapi/verbs/asked", 17 | "display" : {"de-DE" : "fragte", 18 | "en-US" : "asked", 19 | "fr-FR" : "a demandé", 20 | "es-ES" : "preguntó", 21 | "ar-AR" : "طلب"} 22 | }, 23 | "attempted" : { 24 | "id" : "http://adlnet.gov/expapi/verbs/attempted", 25 | "display" : {"de-DE" : "versuchte", 26 | "en-US" : "attempted", 27 | "fr-FR" : "a essayé", 28 | "es-ES" : "intentó", 29 | "ar-AR" : "حاول"} 30 | }, 31 | "attended" : { 32 | "id" : "http://adlnet.gov/expapi/verbs/attended", 33 | "display" : {"de-DE" : "nahm teil an", 34 | "en-US" : "attended", 35 | "fr-FR" : "a suivi", 36 | "es-ES" : "asistió", 37 | "ar-AR" : "حضر"} 38 | }, 39 | "commented" : { 40 | "id" : "http://adlnet.gov/expapi/verbs/commented", 41 | "display" : {"de-DE" : "kommentierte", 42 | "en-US" : "commented", 43 | "fr-FR" : "a commenté", 44 | "es-ES" : "comentó", 45 | "ar-AR" : "علق"} 46 | }, 47 | "completed" : { 48 | "id" : "http://adlnet.gov/expapi/verbs/completed", 49 | "display" : {"de-DE" : "beendete", 50 | "en-US" : "completed", 51 | "fr-FR" : "a terminé", 52 | "es-ES" : "completó", 53 | "ar-AR" : "أكمل"} 54 | }, 55 | "exited" : { 56 | "id" : "http://adlnet.gov/expapi/verbs/exited", 57 | "display" : {"de-DE" : "verließ", 58 | "en-US" : "exited", 59 | "fr-FR" : "a quitté", 60 | "es-ES" : "salió", 61 | "ar-AR" : "خرج"} 62 | }, 63 | "experienced" : { 64 | "id" : "http://adlnet.gov/expapi/verbs/experienced", 65 | "display" : {"de-DE" : "erlebte", 66 | "en-US" : "experienced", 67 | "fr-FR" : "a éprouvé", 68 | "es-ES" : "experimentó", 69 | "ar-AR" : "شاهد"} 70 | }, 71 | "failed" : { 72 | "id" : "http://adlnet.gov/expapi/verbs/failed", 73 | "display" : {"de-DE" : "verfehlte", 74 | "en-US" : "failed", 75 | "fr-FR" : "a échoué", 76 | "es-ES" : "fracasó", 77 | "ar-AR" : "فشل"} 78 | }, 79 | "imported" : { 80 | "id" : "http://adlnet.gov/expapi/verbs/imported", 81 | "display" : {"de-DE" : "importierte", 82 | "en-US" : "imported", 83 | "fr-FR" : "a importé", 84 | "es-ES" : "importó", 85 | "ar-AR" : "مستورد"} 86 | }, 87 | "initialized" : { 88 | "id" : "http://adlnet.gov/expapi/verbs/initialized", 89 | "display" : {"de-DE" : "initialisierte", 90 | "en-US" : "initialized", 91 | "fr-FR" : "a initialisé", 92 | "es-ES" : "inicializó", 93 | "ar-AR" : "بدأ"} 94 | }, 95 | "interacted" : { 96 | "id" : "http://adlnet.gov/expapi/verbs/interacted", 97 | "display" : {"de-DE" : "interagierte", 98 | "en-US" : "interacted", 99 | "fr-FR" : "a interagi", 100 | "es-ES" : "interactuó", 101 | "ar-AR" : "تفاعل"} 102 | }, 103 | "launched" : { 104 | "id" : "http://adlnet.gov/expapi/verbs/launched", 105 | "display" : {"de-DE" : "startete", 106 | "en-US" : "launched", 107 | "fr-FR" : "a lancé", 108 | "es-ES" : "lanzó", 109 | "ar-AR" : "أطلق"} 110 | }, 111 | "mastered" : { 112 | "id" : "http://adlnet.gov/expapi/verbs/mastered", 113 | "display" : {"de-DE" : "meisterte", 114 | "en-US" : "mastered", 115 | "fr-FR" : "a maîtrisé", 116 | "es-ES" : "dominó", 117 | "ar-AR" : "أتقن"} 118 | }, 119 | "passed" : { 120 | "id" : "http://adlnet.gov/expapi/verbs/passed", 121 | "display" : {"de-DE" : "bestand", 122 | "en-US" : "passed", 123 | "fr-FR" : "a réussi", 124 | "es-ES" : "aprobó", 125 | "ar-AR" : "نجح"} 126 | }, 127 | "preferred" : { 128 | "id" : "http://adlnet.gov/expapi/verbs/preferred", 129 | "display" : {"de-DE" : "bevorzugte", 130 | "en-US" : "preferred", 131 | "fr-FR" : "a préféré", 132 | "es-ES" : "prefirió", 133 | "ar-AR" : "فضل"} 134 | }, 135 | "progressed" : { 136 | "id" : "http://adlnet.gov/expapi/verbs/progressed", 137 | "display" : {"de-DE" : "machte Fortschritt mit", 138 | "en-US" : "progressed", 139 | "fr-FR" : "a progressé", 140 | "es-ES" : "progresó", 141 | "ar-AR" : "تقدم"} 142 | }, 143 | "registered" : { 144 | "id" : "http://adlnet.gov/expapi/verbs/registered", 145 | "display" : {"de-DE" : "registrierte", 146 | "en-US" : "registered", 147 | "fr-FR" : "a enregistré", 148 | "es-ES" : "registró", 149 | "ar-AR" : "سجل"} 150 | }, 151 | "responded" : { 152 | "id" : "http://adlnet.gov/expapi/verbs/responded", 153 | "display" : {"de-DE" : "reagierte", 154 | "en-US" : "responded", 155 | "fr-FR" : "a répondu", 156 | "es-ES" : "respondió", 157 | "ar-AR" : "استجاب"} 158 | }, 159 | "resumed" : { 160 | "id" : "http://adlnet.gov/expapi/verbs/resumed", 161 | "display" : {"de-DE" : "setzte fort", 162 | "en-US" : "resumed", 163 | "fr-FR" : "a repris", 164 | "es-ES" : "continuó", 165 | "ar-AR" : "استأنف"} 166 | }, 167 | "satisfied" : { 168 | "id" : "https://w3id.org/xapi/adl/verbs/satisfied", 169 | "display" : {"de-DE" : "befriedigt", 170 | "en-US" : "satisfied", 171 | "fr-FR" : "satisfaite", 172 | "es-ES" : "satisfecho", 173 | "ar-AR" : "راض"} 174 | }, 175 | "scored" : { 176 | "id" : "http://adlnet.gov/expapi/verbs/scored", 177 | "display" : {"de-DE" : "erreichte", 178 | "en-US" : "scored", 179 | "fr-FR" : "a marqué", 180 | "es-ES" : "anotó", 181 | "ar-AR" : "سحل النقاط"} 182 | }, 183 | "shared" : { 184 | "id" : "http://adlnet.gov/expapi/verbs/shared", 185 | "display" : {"de-DE" : "teilte", 186 | "en-US" : "shared", 187 | "fr-FR" : "a partagé", 188 | "es-ES" : "compartió", 189 | "ar-AR" : "شارك"} 190 | }, 191 | "suspended" : { 192 | "id" : "http://adlnet.gov/expapi/verbs/suspended", 193 | "display" : {"de-DE" : "pausierte", 194 | "en-US" : "suspended", 195 | "fr-FR" : "a suspendu", 196 | "es-ES" : "aplazó", 197 | "ar-AR" : "علق"} 198 | }, 199 | "terminated" : { 200 | "id" : "http://adlnet.gov/expapi/verbs/terminated", 201 | "display" : {"de-DE" : "beendete", 202 | "en-US" : "terminated", 203 | "fr-FR" : "a terminé", 204 | "es-ES" : "terminó", 205 | "ar-AR" : "أنهى"} 206 | }, 207 | "voided" : { 208 | "id" : "http://adlnet.gov/expapi/verbs/voided", 209 | "display" : {"de-DE" : "entwertete", 210 | "en-US" : "voided", 211 | "fr-FR" : "a annulé", 212 | "es-ES" : "anuló", 213 | "ar-AR" : "فرغ"} 214 | }, 215 | "waived" : { 216 | "id" : "https://w3id.org/xapi/adl/verbs/waived", 217 | "display" : {"de-DE" : "verzichtet", 218 | "en-US" : "waived", 219 | "fr-FR" : "renoncé", 220 | "es-ES" : "renunciado", 221 | "ar-AR" : "تخلى"} 222 | } 223 | }; 224 | }(window.ADL = window.ADL || {})); 225 | -------------------------------------------------------------------------------- /src/xapi-launch.js: -------------------------------------------------------------------------------- 1 | (function(obj){ 2 | var ADL = obj; 3 | function getQueryVariable(variable) 4 | { 5 | var query = window.location.search.substring(1); 6 | var vars = query.split('&'); 7 | for (var i = 0; i < vars.length; i++) 8 | { 9 | var pair = vars[i].split('='); 10 | if (decodeURIComponent(pair[0]) == variable) 11 | { 12 | return decodeURIComponent(pair[1]); 13 | } 14 | } 15 | // console.log('Query variable %s not found', variable); 16 | } 17 | 18 | function cb_wrap(cb) 19 | { 20 | return function() 21 | { 22 | var args = arguments; 23 | window.setTimeout(function() 24 | { 25 | var callerArgs = []; 26 | for (var i = 0; i < args.length; i++) 27 | { 28 | callerArgs.push(args[i]); 29 | } 30 | cb.apply(window, callerArgs); 31 | }, 0) 32 | } 33 | } 34 | //The library will append the necessary launch info to each new A that is linked to the page. 35 | //NOTE: This cannot work if you programmatically change the window location. If you do, you must 36 | //execute the logic in setupCourseLinks to send the initialization data to the new location (if 37 | //you wish that new location to track as part of this session) 38 | function observeForNewLinks() 39 | { 40 | // select the target node 41 | var target = document.body; 42 | // create an observer instance 43 | var observer = new MutationObserver(function(mutations) 44 | { 45 | mutations.forEach(function(mutation) 46 | { 47 | for (var i in mutation.addedNodes) 48 | { 49 | if (mutation.addedNodes.hasOwnProperty(i)) 50 | { 51 | if (mutation.addedNodes[i].constructor == HTMLAnchorElement) { 52 | var node = mutation.addedNodes[i]; 53 | setupCourseLinks([node]); 54 | } 55 | } 56 | 57 | } 58 | }); 59 | }); 60 | // configuration of the observer: 61 | var config = { 62 | attributes: true, 63 | childList: true, 64 | subtree: true 65 | }; 66 | // pass in the target node, as well as the observer options 67 | observer.observe(target, config); 68 | // later, you can stop observing 69 | /// observer.disconnect(); 70 | } 71 | //This library will init all links in the DOM that include the attribute "courseLink = true" 72 | //with the information necessary for the document at that link to track as part of this session. 73 | function setupCourseLinks(_nodes) 74 | { 75 | var launchToken = getQueryVariable("xAPILaunchKey"); 76 | var launchEndpoint = getQueryVariable("xAPILaunchService"); 77 | var encrypted = getQueryVariable("encrypted"); 78 | var query = "xAPILaunchKey=" + launchToken + "&xAPILaunchService=" + launchEndpoint; 79 | if (encrypted) 80 | { 81 | query += "&encrypted=true"; 82 | } 83 | for(var i = 0; i < _nodes.length; i++) 84 | { 85 | var link = _nodes[i]; 86 | var href = link.href; 87 | var courseLink = link.attributes.getNamedItem('courselink') 88 | if (courseLink && courseLink.value == "true") 89 | { 90 | if (href.indexOf("?") > -1) 91 | { 92 | href = href + "&" + query; 93 | } 94 | else 95 | href = href + "?" + query; 96 | link.href = href; 97 | } 98 | }; 99 | } 100 | 101 | function xAPILaunch(cb, terminate_on_unload, strict_callbacks) 102 | { 103 | cb = cb_wrap(cb); 104 | try 105 | { 106 | var launchToken = getQueryVariable("xAPILaunchKey"); 107 | var launchEndpoint = getQueryVariable("xAPILaunchService"); 108 | var encrypted = getQueryVariable("encrypted"); 109 | if (encrypted) 110 | { 111 | //here, we'd have to implement decryption for the data. This makes little sense in a client side only course 112 | } 113 | 114 | xAPILaunch.terminate = function(message) 115 | { 116 | var launch = new URL(launchEndpoint); 117 | launch.pathname += "launch/" + launchToken + "/terminate"; 118 | var xhr2 = new XMLHttpRequest(); 119 | xhr2.withCredentials = true; 120 | xhr2.crossDomain = true; 121 | 122 | xhr2.open('POST', launch.toString(), false); 123 | xhr2.setRequestHeader("Content-type" , "application/json"); 124 | xhr2.send(JSON.stringify({"code":0,"description": message ||"User closed content"})); 125 | 126 | } 127 | 128 | if (!launchToken || !launchEndpoint) 129 | return cb("invalid launch parameters"); 130 | var launch = new URL(launchEndpoint); 131 | launch.pathname += "launch/" + launchToken; 132 | var xhr = new XMLHttpRequest(); 133 | xhr.withCredentials = true; 134 | xhr.crossDomain = true; 135 | xhr.onerror = function(err) 136 | { 137 | //exit the try catch so inner execptions in the callback don't trigger this catch 138 | window.setTimeout(function() 139 | { 140 | return cb(err); 141 | }) 142 | } 143 | xhr.onload = function(e) 144 | { 145 | if (xhr.status !== 200) 146 | { 147 | return xhr.onerror(xhr.responseText); 148 | } 149 | var body = JSON.parse(xhr.responseText); 150 | var launchData = body; 151 | 152 | var conf = {}; 153 | conf['endpoint'] = launchData.endpoint; 154 | conf["actor"] = launchData.actor; 155 | conf.withCredentials = true; 156 | conf.strictCallbacks = strict_callbacks || false; 157 | 158 | window.onunload = function() 159 | { 160 | if (!terminate_on_unload) 161 | return; 162 | xAPILaunch.terminate("User closed content") 163 | } 164 | var wrapper = new ADL.XAPIWrapper.constructor(); 165 | wrapper.changeConfig(conf); 166 | //Links that include "courseLink='true'" 167 | setupCourseLinks(document.body.querySelectorAll('a')); 168 | //Also, if links are added dynamically, we will do the same logic for those links. 169 | observeForNewLinks(); 170 | return cb(null, body, wrapper); 171 | } 172 | xhr.open('POST', launch.toString(), true); 173 | xhr.send(); 174 | } 175 | catch (e) 176 | { 177 | cb(e); 178 | } 179 | }; 180 | ADL.launch = xAPILaunch; 181 | })(window.ADL = window.ADL || {}); 182 | -------------------------------------------------------------------------------- /src/xapi-util.js: -------------------------------------------------------------------------------- 1 | (function (obj) { 2 | var ADL = obj; 3 | var onBrowser = false; 4 | if (typeof window !== 'undefined') { 5 | ADL = window.ADL = obj.ADL || {}; 6 | onBrowser = true; 7 | } 8 | 9 | var getObjDefName = function (o) { 10 | if (o.definition && o.definition.name) { 11 | return ADL.xapiutil.getLangVal(o.definition.name); 12 | } 13 | return undefined; 14 | }; 15 | 16 | var getSubStatementDisplay = function (o) { 17 | if(o.objectType !== "SubStatement") return; 18 | if(o.object.objectType === "SubStatement") return; 19 | if(o.id || o.stored || o.version || o.authority) return; 20 | var disp = ADL.xapiutil.getActorId(o.actor) + ":" + ADL.xapiutil.getVerbDisplay(o.verb) + ":" + ADL.xapiutil.getObjectId(o.object); 21 | return disp; 22 | }; 23 | 24 | 25 | ADL.xapiutil = {}; 26 | 27 | ADL.xapiutil.getLang = function () { 28 | var lang; 29 | if (typeof navigator !== 'undefined') 30 | lang = navigator.language || navigator.browserLanguage || 31 | navigator.systemLanguage || navigator.userLanguage; 32 | else if (typeof process !== 'undefined' && typeof process.env !== 'undefined' && typeof process.env.LANG !== 'undefined') { 33 | var str = process.env.LANG; 34 | lang = str.slice(0, str.indexOf('.')); 35 | lang = lang.replace(/_/, '-') 36 | } 37 | return lang || "en-US"; 38 | }; 39 | 40 | ADL.xapiutil.getLangVal = function (langprop) { 41 | 42 | if (!langprop) return; 43 | 44 | var options = Object.keys(langprop); 45 | // test that langprop is a dict (obj) 46 | // skips if not a dict(obj) and returns 47 | if (options.length == 0) return undefined; 48 | 49 | var lang = ADL.xapiutil.getLang(), 50 | ret, 51 | dispGotten = false; 52 | 53 | do { //test and retest 54 | if (langprop[lang]) 55 | { 56 | ret = langprop[lang]; 57 | dispGotten = true; 58 | } 59 | else if (lang.indexOf('-')) 60 | { 61 | lang = lang.substring(0, lang.lastIndexOf('-')); 62 | } 63 | } while (!dispGotten && lang !==""); 64 | 65 | return ret; 66 | }; 67 | 68 | ADL.xapiutil.getMoreStatements = function (iterations, callback, searchParams) { 69 | if (!onBrowser) throw new Error("Node not supported."); 70 | 71 | var stmts = []; 72 | 73 | ADL.XAPIWrapper.getStatements(searchParams, null, function getMore(r) { 74 | if (! (r && r.response) ) return; 75 | var res = JSON.parse(r.response); 76 | if (! res.statements) return; 77 | stmts = stmts.concat(res.statements); 78 | 79 | if (iterations-- <= 0) { 80 | callback(stmts); 81 | } 82 | else { 83 | if (res.more && res.more !== "") 84 | { 85 | ADL.XAPIWrapper.getStatements(searchParams, res.more, getMore); 86 | } 87 | else if (res.more === "") 88 | { 89 | callback(stmts); 90 | } 91 | } 92 | }); 93 | }; 94 | 95 | ADL.xapiutil.getActorId = function (a) { 96 | return a.mbox || a.openid || a.mbox_sha1sum || a.account; 97 | }; 98 | 99 | ADL.xapiutil.getActorIdString = function (a) { 100 | var id = a.mbox || a.openid || a.mbox_sha1sum; 101 | if (! id) { 102 | if (a.account) id = a.account.homePage + ":" + a.account.name; 103 | else if (a.member) id = "Anon Group " + a.member; 104 | else id = 'unknown'; 105 | } 106 | return id; 107 | }; 108 | 109 | ADL.xapiutil.getActorDisplay = function (a) { 110 | return a.name || ADL.xapiutil.getActorIdString(a); 111 | }; 112 | 113 | ADL.xapiutil.getVerbDisplay = function (v) { 114 | if (!v) return; 115 | if (v.display) { 116 | return ADL.xapiutil.getLangVal(v.display) || v.id; 117 | } 118 | return v.id; 119 | }; 120 | 121 | ADL.xapiutil.getObjectType = function (o) { 122 | return o.objectType || ((o.id) ? "Activity" : "Agent"); 123 | }; 124 | 125 | ADL.xapiutil.getObjectId = function (o) { 126 | if (o.id) return o.id; 127 | var type = ADL.xapiutil.getObjectType(o); 128 | if (type === "Agent" || type === "Group") return ADL.xapiutil.getActorId(o); 129 | return undefined; 130 | }; 131 | 132 | ADL.xapiutil.getObjectIdString = function (o) { 133 | if (!o) return 'unknown' 134 | if (o.id) return o.id; 135 | var type = ADL.xapiutil.getObjectType(o); 136 | if (type === "Agent" || type === "Group") return ADL.xapiutil.getActorIdString(o); 137 | else if (type == "SubStatement") { 138 | return getSubStatementDisplay(o); 139 | } 140 | return 'unknown'; 141 | }; 142 | 143 | ADL.xapiutil.getObjectDisplay = function (o) { 144 | if (!o) return "unknown" 145 | var disp = getObjDefName(o) || o.name || o.id; 146 | if (! disp) { 147 | var type = ADL.xapiutil.getObjectType(o); 148 | if (type === "Agent" || type == "Group") disp = ADL.xapiutil.getActorDisplay(o); 149 | else if (type == "SubStatement") { 150 | disp = getSubStatementDisplay(o); 151 | } 152 | } 153 | 154 | return disp; 155 | }; 156 | 157 | })(this); 158 | -------------------------------------------------------------------------------- /src/xapistatement.js: -------------------------------------------------------------------------------- 1 | (function(ADL){ 2 | 3 | function _getobj(obj, path){ 4 | var parts = path.split('.'); 5 | 6 | var part = parts[0]; 7 | path = parts.slice(1).join('.'); 8 | 9 | if( !obj[part] ){ 10 | if( /\[\]$/.test(part) ){ 11 | part = part.slice(0,-2); 12 | if (!Array.isArray(obj[part])) { 13 | obj[part] = []; 14 | } 15 | } 16 | else 17 | obj[part] = {}; 18 | } 19 | 20 | if( !path ) 21 | return obj[part]; 22 | else 23 | return _getobj(obj[part], path); 24 | } 25 | 26 | /******************************************************************************* 27 | * XAPIStatement - a convenience class to wrap statement objects 28 | * 29 | * This sub-API is supposed to make it easier to author valid xAPI statements 30 | * by adding constructors and encouraging best practices. All objects in this 31 | * API are fully JSON-compatible, so anything expecting an xAPI statement can 32 | * take an improved statement and vice versa. 33 | * 34 | * A working knowledge of what exactly the LRS expects is still expected, 35 | * but it's easier to map an 'I did this' statement to xAPI now. 36 | * 37 | * Tech note: All constructors also double as shallow clone functions. E.g. 38 | * 39 | * var activity1 = new Activity('A walk in the park'); 40 | * var activity2 = new Activity(activity1); 41 | * var activity3 = new Activity(stmt_from_lrs.object); 42 | * 43 | *******************************************************************************/ 44 | 45 | /* 46 | * A convenient JSON-compatible xAPI statement wrapper 47 | * All args are optional, but the statement may not be complete or valid 48 | * Can also pass an Agent IFI, Verb ID, and an Activity ID in lieu of these args 49 | * @param {string} [actor] The Agent or Group committing the action described by the statement 50 | * @param {string} [verb] The Verb for the action described by the statement 51 | * @param {string} [object] The receiver of the action. An Agent, Group, Activity, SubStatement, or StatementRef 52 | * @example 53 | * var stmt = new ADL.XAPIStatement( 54 | * 'mailto:steve.vergenz.ctr@adlnet.gov', 55 | * 'http://adlnet.gov/expapi/verbs/launched', 56 | * 'http://vwf.adlnet.gov/xapi/virtual_world_sandbox' 57 | * ); 58 | * >> { 59 | * "actor": { 60 | * "objectType": "Agent", 61 | * "mbox": "mailto:steve.vergenz.ctr@adlnet.gov" }, 62 | * "verb": { 63 | * "id": "http://adlnet.gov/expapi/verbs/launched" }, 64 | * "object": { 65 | * "objectType": "Activity", 66 | * "id": "http://vwf.adlnet.gov/xapi/virtual_world_sandbox" }, 67 | * "result": { 68 | * "An optional property that represents a measured outcome related to the Statement in which it is included."}} 69 | */ 70 | var XAPIStatement = function(actor, verb, object, result) 71 | { 72 | 73 | // initialize 74 | 75 | // if first arg is an xapi statement, parse 76 | if( actor && actor.actor && actor.verb && actor.object ){ 77 | var stmt = actor; 78 | for(var i in stmt){ 79 | if(i != 'actor' && i != 'verb' && i != 'object') 80 | this[i] = stmt[i]; 81 | } 82 | actor = stmt.actor; 83 | verb = stmt.verb; 84 | object = stmt.object; 85 | } 86 | 87 | if(actor){ 88 | if( actor instanceof Agent ) 89 | this.actor = actor; 90 | else if(actor.objectType === 'Agent' || !actor.objectType) 91 | this.actor = new Agent(actor); 92 | else if(actor.objectType === 'Group') 93 | this.actor = new Group(actor); 94 | } 95 | else this.actor = null; 96 | 97 | if(verb){ 98 | if( verb instanceof Verb ) 99 | this.verb = verb; 100 | else 101 | this.verb = new Verb(verb); 102 | } 103 | else this.verb = null; 104 | 105 | // decide what kind of object was passed 106 | if(object) 107 | { 108 | if( object.objectType === 'Activity' || !object.objectType ){ 109 | if( object instanceof Activity ) 110 | this.object = object; 111 | else 112 | this.object = new Activity(object); 113 | } 114 | else if( object.objectType === 'Agent' ){ 115 | if( object instanceof Agent ) 116 | this.object = object; 117 | else 118 | this.object = new Agent(object); 119 | } 120 | else if( object.objectType === 'Group' ){ 121 | if( object instanceof Group ) 122 | this.object = object; 123 | else 124 | this.object = new Group(object); 125 | } 126 | else if( object.objectType === 'StatementRef' ){ 127 | if( object instanceof StatementRef ) 128 | this.object = object; 129 | else 130 | this.object = new StatementRef(object); 131 | } 132 | else if( object.objectType === 'SubStatement' ){ 133 | if( object instanceof SubStatement ) 134 | this.object = object; 135 | else 136 | this.object = new SubStatement(object); 137 | } 138 | else this.object = null; 139 | } 140 | else this.object = null; 141 | 142 | // add support for result object 143 | if(result) 144 | { 145 | this.result = result; 146 | } 147 | 148 | this.generateId = function(){ 149 | this.id = ADL.ruuid(); 150 | }; 151 | }; 152 | 153 | XAPIStatement.prototype.toString = function(){ 154 | return this.actor.toString() + " " + this.verb.toString() + " " + this.object.toString() + " " + this.result.toString(); 155 | }; 156 | 157 | XAPIStatement.prototype.isValid = function(){ 158 | return this.actor && this.actor.isValid() 159 | && this.verb && this.verb.isValid() 160 | && this.object && this.object.isValid() 161 | && this.result && this.result.isValid(); 162 | }; 163 | 164 | XAPIStatement.prototype.generateRegistration = function(){ 165 | _getobj(this,'context').registration = ADL.ruuid(); 166 | }; 167 | 168 | XAPIStatement.prototype.addParentActivity = function(activity){ 169 | _getobj(this,'context.contextActivities.parent[]').push(new Activity(activity)); 170 | }; 171 | 172 | XAPIStatement.prototype.addGroupingActivity = function(activity){ 173 | _getobj(this,'context.contextActivities.grouping[]').push(new Activity(activity)); 174 | }; 175 | 176 | XAPIStatement.prototype.addOtherContextActivity = function(activity){ 177 | _getobj(this,'context.contextActivities.other[]').push(new Activity(activity)); 178 | }; 179 | 180 | 181 | /* 182 | * Provides an easy constructor for xAPI agent objects 183 | * @param {string} identifier One of the Inverse Functional Identifiers specified in the spec. 184 | * That is, an email, a hashed email, an OpenID, or an account object. 185 | * See (https://github.com/adlnet/xAPI-Spec/blob/master/xAPI.md#inversefunctional) 186 | * @param {string} [name] The natural-language name of the agent 187 | */ 188 | var Agent = function(identifier, name) 189 | { 190 | this.objectType = 'Agent'; 191 | this.name = name; 192 | 193 | // figure out what type of identifier was given 194 | if( identifier && (identifier.mbox || identifier.mbox_sha1sum || identifier.openid || identifier.account) ){ 195 | for(var i in identifier){ 196 | this[i] = identifier[i]; 197 | } 198 | } 199 | else if( /^mailto:/.test(identifier) ){ 200 | this.mbox = identifier; 201 | } 202 | else if( /^[0-9a-f]{40}$/i.test(identifier) ){ 203 | this.mbox_sha1sum = identifier; 204 | } 205 | else if( /^http[s]?:/.test(identifier) ){ 206 | this.openid = identifier; 207 | } 208 | else if( identifier && identifier.homePage && identifier.name ){ 209 | this.account = identifier; 210 | } 211 | }; 212 | Agent.prototype.toString = function(){ 213 | return this.name || this.mbox || this.openid || this.mbox_sha1sum || this.account.name; 214 | }; 215 | Agent.prototype.isValid = function() 216 | { 217 | return this.mbox || this.mbox_sha1sum || this.openid 218 | || (this.account.homePage && this.account.name) 219 | || (this.objectType === 'Group' && this.member); 220 | }; 221 | 222 | 223 | /* 224 | * A type of agent, can contain multiple agents 225 | * @param {string} [identifier] (optional if `members` specified) See Agent. 226 | * @param {string} [members] An array of Agents describing the membership of the group 227 | * @param {string} [name] The natural-language name of the agent 228 | */ 229 | var Group = function(identifier, members, name) 230 | { 231 | Agent.call(this, identifier, name); 232 | this.member = members; 233 | this.objectType = 'Group'; 234 | }; 235 | Group.prototype = new Agent; 236 | 237 | 238 | /* 239 | * Really only provides a convenient language map 240 | * @param {string} id The IRI of the action taken 241 | * @param {string} [description] An English-language description, or a Language Map 242 | */ 243 | var Verb = function(id, description) 244 | { 245 | // if passed a verb object then copy and return 246 | if( id && id.id ){ 247 | for(var i in id){ 248 | this[i] = id[i]; 249 | } 250 | return; 251 | } 252 | 253 | // save id and build language map 254 | this.id = id; 255 | if(description) 256 | { 257 | if( typeof(description) === 'string' || description instanceof String ){ 258 | this.display = {'en-US': description}; 259 | } 260 | else { 261 | this.display = description; 262 | } 263 | } 264 | }; 265 | Verb.prototype.toString = function(){ 266 | if(this.display && (this.display['en-US'] || this.display['en'])) 267 | return this.display['en-US'] || this.display['en']; 268 | else 269 | return this.id; 270 | }; 271 | Verb.prototype.isValid = function(){ 272 | return this.id; 273 | }; 274 | 275 | 276 | /* 277 | * Describes an object that an agent interacts with 278 | * @param {string} id The unique activity IRI 279 | * @param {string} name An English-language identifier for the activity, or a Language Map 280 | * @param {string} description An English-language description of the activity, or a Language Map 281 | */ 282 | var Activity = function(id, name, description) 283 | { 284 | // if first arg is activity, copy everything over 285 | if(id && id.id){ 286 | var act = id; 287 | for(var i in act){ 288 | this[i] = act[i]; 289 | } 290 | return; 291 | } 292 | 293 | this.objectType = 'Activity'; 294 | this.id = id; 295 | if( name || description ) 296 | { 297 | this.definition = {}; 298 | 299 | if( typeof(name) === 'string' || name instanceof String ) 300 | this.definition.name = {'en-US': name}; 301 | else if(name) 302 | this.definition.name = name; 303 | 304 | if( typeof(description) === 'string' || description instanceof String ) 305 | this.definition.description = {'en-US': description}; 306 | else if(description) 307 | this.definition.description = description; 308 | } 309 | }; 310 | Activity.prototype.toString = function(){ 311 | if(this.definition && this.definition.name && (this.definition.name['en-US'] || this.definition.name['en'])) 312 | return this.definition.name['en-US'] || this.definition.name['en']; 313 | else 314 | return this.id; 315 | }; 316 | Activity.prototype.isValid = function(){ 317 | return this.id && (!this.objectType || this.objectType === 'Activity'); 318 | }; 319 | 320 | /* 321 | * An object that refers to a separate statement 322 | * @param {string} id The UUID of another xAPI statement 323 | */ 324 | var StatementRef = function(id){ 325 | if(id && id.id){ 326 | for(var i in id){ 327 | this[i] = id[i]; 328 | } 329 | } 330 | else { 331 | this.objectType = 'StatementRef'; 332 | this.id = id; 333 | } 334 | }; 335 | StatementRef.prototype.toString = function(){ 336 | return 'statement('+this.id+')'; 337 | }; 338 | StatementRef.prototype.isValid = function(){ 339 | return this.id && this.objectType && this.objectType === 'StatementRef'; 340 | }; 341 | 342 | /* 343 | * A self-contained statement as the object of another statement 344 | * See XAPIStatement for constructor details 345 | * @param {string} actor The Agent or Group committing the action described by the statement 346 | * @param {string} verb The Verb for the action described by the statement 347 | * @param {string} object The receiver of the action. An Agent, Group, Activity, or StatementRef 348 | */ 349 | var SubStatement = function(actor, verb, object){ 350 | XAPIStatement.call(this,actor,verb,object); 351 | this.objectType = 'SubStatement'; 352 | 353 | delete this.id; 354 | delete this.stored; 355 | delete this.version; 356 | delete this.authority; 357 | }; 358 | SubStatement.prototype = new XAPIStatement; 359 | SubStatement.prototype.toString = function(){ 360 | return '"' + SubStatement.prototype.prototype.toString.call(this) + '"'; 361 | }; 362 | 363 | XAPIStatement.Agent = Agent; 364 | XAPIStatement.Group = Group; 365 | XAPIStatement.Verb = Verb; 366 | XAPIStatement.Activity = Activity; 367 | XAPIStatement.StatementRef = StatementRef; 368 | XAPIStatement.SubStatement = SubStatement; 369 | ADL.XAPIStatement = XAPIStatement; 370 | 371 | }(window.ADL = window.ADL || {})); 372 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Testing xAPI-Util 2 | 3 | Tests the functionality of /src/xapi-util.js. The test can be run in both a browser or in node. 4 | 5 | For both/either: 6 | 7 | * Clone the repository to your machine 8 | ``` 9 | .../workspace 10 | $ git clone https://github.com/adlnet/xAPIWrapper.git 11 | ``` 12 | 13 | ## Browser 14 | 15 | From a browser: 16 | 17 | * Use the terminal to start a server in the xAPIWrapper folder 18 | ``` 19 | .../xAPIWrapper 20 | $ http-server 21 | Starting up http-server, serving ./ 22 | Available on: 23 | http:172.16.0.111:8080 24 | http:127.0.0.1:8080 25 | Hit CTRL-C to stop the server 26 | 27 | ``` 28 | * With the browser navigate to /test/testUtil.html 29 | `http://localhost:8080/test/testUtil.html` 30 | * The tests will automatically run displaying the results: passes, failures, duration, percentage. Below the test results, code coverage results are displayed. 31 | 32 | ## Node 33 | 34 | * In the terminal navigate to the xAPIWrapper folder 35 | * Use the commands 36 | ``` 37 | .../xAPIWrapper 38 | $npm install should 39 | ...and... 40 | $ mocha test/tests/test.util.js 41 | 42 | ``` 43 | * The tests will run displaying the information in the terminal including results: passing, failing, milliseconds to complete, and a stack trace of any failing tests. 44 | -------------------------------------------------------------------------------- /test/libs/mocha-blanket-adapter.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | if(!mocha) { 4 | throw new Exception("mocha library does not exist in global namespace!"); 5 | } 6 | 7 | 8 | /* 9 | * Mocha Events: 10 | * 11 | * - `start` execution started 12 | * - `end` execution complete 13 | * - `suite` (suite) test suite execution started 14 | * - `suite end` (suite) all tests (and sub-suites) have finished 15 | * - `test` (test) test execution started 16 | * - `test end` (test) test completed 17 | * - `hook` (hook) hook execution started 18 | * - `hook end` (hook) hook complete 19 | * - `pass` (test) test passed 20 | * - `fail` (test, err) test failed 21 | * 22 | */ 23 | 24 | var OriginalReporter = mocha._reporter; 25 | 26 | var BlanketReporter = function(runner) { 27 | runner.on('start', function() { 28 | blanket.setupCoverage(); 29 | }); 30 | 31 | runner.on('end', function() { 32 | blanket.onTestsDone(); 33 | }); 34 | 35 | runner.on('suite', function() { 36 | blanket.onModuleStart(); 37 | }); 38 | 39 | runner.on('test', function() { 40 | blanket.onTestStart(); 41 | }); 42 | 43 | runner.on('test end', function(test) { 44 | blanket.onTestDone(test.parent.tests.length, test.state === 'passed'); 45 | }); 46 | 47 | runner.on('hook', function(){ 48 | blanket.onTestStart(); 49 | }); 50 | 51 | runner.on('hook end', function(){ 52 | blanket.onTestsDone(); 53 | }); 54 | 55 | // NOTE: this is an instance of BlanketReporter 56 | new OriginalReporter(runner); 57 | }; 58 | 59 | BlanketReporter.prototype = OriginalReporter.prototype; 60 | 61 | mocha.reporter(BlanketReporter); 62 | 63 | var oldRun = mocha.run, 64 | oldCallback = null; 65 | 66 | mocha.run = function (finishCallback) { 67 | oldCallback = finishCallback; 68 | console.log("waiting for blanket..."); 69 | }; 70 | blanket.beforeStartTestRunner({ 71 | callback: function(){ 72 | if (!blanket.options("existingRequireJS")){ 73 | oldRun(oldCallback); 74 | } 75 | mocha.run = oldRun; 76 | } 77 | }); 78 | })(); 79 | -------------------------------------------------------------------------------- /test/libs/mocha/2.2.5/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, 13 | #mocha li { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | #mocha ul { 19 | list-style: none; 20 | } 21 | 22 | #mocha h1, 23 | #mocha h2 { 24 | margin: 0; 25 | } 26 | 27 | #mocha h1 { 28 | margin-top: 15px; 29 | font-size: 1em; 30 | font-weight: 200; 31 | } 32 | 33 | #mocha h1 a { 34 | text-decoration: none; 35 | color: inherit; 36 | } 37 | 38 | #mocha h1 a:hover { 39 | text-decoration: underline; 40 | } 41 | 42 | #mocha .suite .suite h1 { 43 | margin-top: 0; 44 | font-size: .8em; 45 | } 46 | 47 | #mocha .hidden { 48 | display: none; 49 | } 50 | 51 | #mocha h2 { 52 | font-size: 12px; 53 | font-weight: normal; 54 | cursor: pointer; 55 | } 56 | 57 | #mocha .suite { 58 | margin-left: 15px; 59 | } 60 | 61 | #mocha .test { 62 | margin-left: 15px; 63 | overflow: hidden; 64 | } 65 | 66 | #mocha .test.pending:hover h2::after { 67 | content: '(pending)'; 68 | font-family: arial, sans-serif; 69 | } 70 | 71 | #mocha .test.pass.medium .duration { 72 | background: #c09853; 73 | } 74 | 75 | #mocha .test.pass.slow .duration { 76 | background: #b94a48; 77 | } 78 | 79 | #mocha .test.pass::before { 80 | content: '✓'; 81 | font-size: 12px; 82 | display: block; 83 | float: left; 84 | margin-right: 5px; 85 | color: #00d6b2; 86 | } 87 | 88 | #mocha .test.pass .duration { 89 | font-size: 9px; 90 | margin-left: 5px; 91 | padding: 2px 5px; 92 | color: #fff; 93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 96 | -webkit-border-radius: 5px; 97 | -moz-border-radius: 5px; 98 | -ms-border-radius: 5px; 99 | -o-border-radius: 5px; 100 | border-radius: 5px; 101 | } 102 | 103 | #mocha .test.pass.fast .duration { 104 | display: none; 105 | } 106 | 107 | #mocha .test.pending { 108 | color: #0b97c4; 109 | } 110 | 111 | #mocha .test.pending::before { 112 | content: '◦'; 113 | color: #0b97c4; 114 | } 115 | 116 | #mocha .test.fail { 117 | color: #c00; 118 | } 119 | 120 | #mocha .test.fail pre { 121 | color: black; 122 | } 123 | 124 | #mocha .test.fail::before { 125 | content: '✖'; 126 | font-size: 12px; 127 | display: block; 128 | float: left; 129 | margin-right: 5px; 130 | color: #c00; 131 | } 132 | 133 | #mocha .test pre.error { 134 | color: #c00; 135 | max-height: 300px; 136 | overflow: auto; 137 | } 138 | 139 | /** 140 | * (1): approximate for browsers not supporting calc 141 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) 142 | * ^^ seriously 143 | */ 144 | #mocha .test pre { 145 | display: block; 146 | float: left; 147 | clear: left; 148 | font: 12px/1.5 monaco, monospace; 149 | margin: 5px; 150 | padding: 15px; 151 | border: 1px solid #eee; 152 | max-width: 85%; /*(1)*/ 153 | max-width: calc(100% - 42px); /*(2)*/ 154 | word-wrap: break-word; 155 | border-bottom-color: #ddd; 156 | -webkit-border-radius: 3px; 157 | -webkit-box-shadow: 0 1px 3px #eee; 158 | -moz-border-radius: 3px; 159 | -moz-box-shadow: 0 1px 3px #eee; 160 | border-radius: 3px; 161 | } 162 | 163 | #mocha .test h2 { 164 | position: relative; 165 | } 166 | 167 | #mocha .test a.replay { 168 | position: absolute; 169 | top: 3px; 170 | right: 0; 171 | text-decoration: none; 172 | vertical-align: middle; 173 | display: block; 174 | width: 15px; 175 | height: 15px; 176 | line-height: 15px; 177 | text-align: center; 178 | background: #eee; 179 | font-size: 15px; 180 | -moz-border-radius: 15px; 181 | border-radius: 15px; 182 | -webkit-transition: opacity 200ms; 183 | -moz-transition: opacity 200ms; 184 | transition: opacity 200ms; 185 | opacity: 0.3; 186 | color: #888; 187 | } 188 | 189 | #mocha .test:hover a.replay { 190 | opacity: 1; 191 | } 192 | 193 | #mocha-report.pass .test.fail { 194 | display: none; 195 | } 196 | 197 | #mocha-report.fail .test.pass { 198 | display: none; 199 | } 200 | 201 | #mocha-report.pending .test.pass, 202 | #mocha-report.pending .test.fail { 203 | display: none; 204 | } 205 | #mocha-report.pending .test.pass.pending { 206 | display: block; 207 | } 208 | 209 | #mocha-error { 210 | color: #c00; 211 | font-size: 1.5em; 212 | font-weight: 100; 213 | letter-spacing: 1px; 214 | } 215 | 216 | #mocha-stats { 217 | position: fixed; 218 | top: 15px; 219 | right: 10px; 220 | font-size: 12px; 221 | margin: 0; 222 | color: #888; 223 | z-index: 1; 224 | } 225 | 226 | #mocha-stats .progress { 227 | float: right; 228 | padding-top: 0; 229 | } 230 | 231 | #mocha-stats em { 232 | color: black; 233 | } 234 | 235 | #mocha-stats a { 236 | text-decoration: none; 237 | color: inherit; 238 | } 239 | 240 | #mocha-stats a:hover { 241 | border-bottom: 1px solid #eee; 242 | } 243 | 244 | #mocha-stats li { 245 | display: inline-block; 246 | margin: 0 5px; 247 | list-style: none; 248 | padding-top: 11px; 249 | } 250 | 251 | #mocha-stats canvas { 252 | width: 40px; 253 | height: 40px; 254 | } 255 | 256 | #mocha code .comment { color: #ddd; } 257 | #mocha code .init { color: #2f6fad; } 258 | #mocha code .string { color: #5890ad; } 259 | #mocha code .keyword { color: #8a6343; } 260 | #mocha code .number { color: #2f6fad; } 261 | 262 | @media screen and (max-device-width: 480px) { 263 | #mocha { 264 | margin: 60px 0px; 265 | } 266 | 267 | #mocha #stats { 268 | position: absolute; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /test/libs/require.js: -------------------------------------------------------------------------------- 1 | /* 2 | RequireJS 2.1.20 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved. 3 | Available via the MIT or new BSD license. 4 | see: http://github.com/jrburke/requirejs for details 5 | */ 6 | var requirejs,require,define; 7 | (function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||e.onError!==ca)try{f=h.execCb(c,l,b,f)}catch(d){a=d}else f=h.execCb(c,l,b,f);this.map.isDefine&& 19 | void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(q[c]=f,e.onResourceLoad))e.onResourceLoad(h,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete= 20 | !0)}}else t(h.defQueueMap,c)||this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=i(a.prefix);this.depMaps.push(d);s(d,"defined",u(this,function(f){var l,d;d=n(aa,this.map.id);var g=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,p=h.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(g=f.normalize(g,function(a){return c(a,P,!0)})||""),f=i(a.prefix+"!"+g,this.map.parentMap),s(f,"defined",u(this,function(a){this.init([],function(){return a}, 21 | null,{enabled:!0,ignore:!0})})),d=n(m,f.id)){this.depMaps.push(f);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=h.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];A(m,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,g=i(d),P=M;c&&(f=c);P&& 22 | (M=!1);r(g);t(k.config,b)&&(k.config[d]=k.config[b]);try{e.exec(f)}catch(m){return w(B("fromtexteval","fromText eval for "+b+" failed: "+m,m,[b]))}P&&(M=!0);this.depMaps.push(g);h.completeLoad(d);p([d],l)}),f.load(a.name,p,l,k))}));h.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=i(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c= 23 | n(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;s(a,"defined",u(this,function(a){this.undefed||(this.defineDep(b,a),this.check())}));this.errback?s(a,"error",u(this,this.errback)):this.events.error&&s(a,"error",u(this,function(a){this.emit("error",a)}))}c=a.id;f=m[c];!t(L,c)&&(f&&!f.enabled)&&h.enable(a,this)}));A(this.pluginMaps,u(this,function(a){var b=n(m,a.id);b&&!b.enabled&&h.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]= 24 | []);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};h={config:k,contextName:b,registry:m,defined:q,urlFetched:S,defQueue:C,defQueueMap:{},Module:Z,makeModuleMap:i,nextTick:e.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.shim,c={paths:!0,bundles:!0,config:!0,map:!0};A(a,function(a,b){c[b]?(k[b]||(k[b]={}),U(k[b],a,!0,!0)):k[b]=a});a.bundles&&A(a.bundles,function(a,b){v(a, 25 | function(a){a!==b&&(aa[a]=b)})});a.shim&&(A(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=h.makeShimExports(a);b[c]=a}),k.shim=b);a.packages&&v(a.packages,function(a){var b,a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(k.paths[b]=a.location);k.pkgs[b]=a.name+"/"+(a.main||"main").replace(ha,"").replace(Q,"")});A(m,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=i(b,null,!0))});if(a.deps||a.callback)h.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b; 26 | a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,j){function g(c,d,p){var k,n;j.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=!0);if("string"===typeof c){if(G(d))return w(B("requireargs","Invalid require call"),p);if(a&&t(L,c))return L[c](m[a.id]);if(e.get)return e.get(h,c,a,g);k=i(c,a,!1,!0);k=k.id;return!t(q,k)?w(B("notloaded",'Module name "'+k+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):q[k]}J();h.nextTick(function(){J(); 27 | n=r(i(null,a));n.skipMap=j.skipMap;n.init(c,d,p,{enabled:!0});D()});return g}j=j||{};U(g,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),j=b.split("/")[0];if(-1!==e&&(!("."===j||".."===j)||1g.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1));g.src=d;J=g;D?y.insertBefore(g,D):y.appendChild(g);J=null;return g}if(ea)try{importScripts(d),b.completeLoad(c)}catch(i){b.onError(B("importscripts", 35 | "importScripts failed for "+c+" at "+d,i,[c]))}};z&&!s.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return r=I,s.baseUrl||(E=r.split("/"),r=E.pop(),O=E.length?E.join("/")+"/":"./",s.baseUrl=O),r=r.replace(Q,""),e.jsExtRegExp.test(r)&&(r=I),s.deps=s.deps?s.deps.concat(r):[r],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ja,"").replace(ka, 36 | function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b||(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}g?(g.defQueue.push([b,c,d]),g.defQueueMap[b]=!0):R.push([b,c,d])};define.amd={jQuery:!0};e.exec=function(b){return eval(b)};e(s)}})(this); 37 | -------------------------------------------------------------------------------- /test/testAttachments.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Tests 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/testState.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Tests 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/testUtil.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Tests 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 35 | 36 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/tests/test.attachments.js: -------------------------------------------------------------------------------- 1 | describe('testing xAPI attachments', function () { 2 | 3 | var onBrowser, should; 4 | 5 | before(function () { 6 | 7 | onBrowser = typeof window !== 'undefined' ? true : false; 8 | if (!onBrowser) { 9 | should = require('should'); 10 | } 11 | 12 | }); 13 | 14 | it('should be able to send a simple string attachment', function (done) { 15 | 16 | var conf = { 17 | "endpoint" : "https://lrs.adlnet.gov/xapi/", 18 | "user" : "tom", 19 | "password" : "1234", 20 | }; 21 | ADL.XAPIWrapper.changeConfig(conf); 22 | 23 | var statement = {"actor":{"mbox":"mailto:tom@tom.com"}, "verb":{"id":"http://verb.com/do1"}, "object":{"id":"http://from.tom/act1", "objectType":"Activity", "definition":{"name":{"en-US": "soccer", "fr": "football", "de": "foossball"}}}}; 24 | 25 | 26 | var attachmentMetadata = { 27 | "usageType": "http://adlnet.gov/expapi/attachments/asdf", 28 | "display": 29 | { 30 | "en-US": "asdfasdf" 31 | }, 32 | "description": 33 | { 34 | "en-US": "asdfasdfasd" 35 | }, 36 | "contentType": "application/octet-stream" 37 | } 38 | var attachment = { 39 | value: "this is a simple string attachment", 40 | type:attachmentMetadata 41 | } 42 | 43 | ADL.XAPIWrapper.sendStatement(statement, function (xhr) { 44 | xhr.should.be.type('object'); 45 | xhr.status.should.eql(200); 46 | done(); 47 | }, [attachment]); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /test/tests/test.state.js: -------------------------------------------------------------------------------- 1 | describe('testing xAPI attachments', function () { 2 | 3 | var onBrowser, should; 4 | before(function () { 5 | 6 | onBrowser = typeof window !== 'undefined' ? true : false; 7 | if (!onBrowser) { 8 | should = require('should'); 9 | } 10 | }); 11 | 12 | it('should be able to send and retrieve an activity state', function (done) { 13 | 14 | var conf = { 15 | "endpoint": "https://lrs.adlnet.gov/xapi/", 16 | "user": "tom", 17 | "password": "1234", 18 | }; 19 | ADL.XAPIWrapper.changeConfig(conf); 20 | 21 | var activityId = "http://adlnet.gov/expapi/activities/question" 22 | var activityState = "some-state"; 23 | 24 | var agent = {"mbox":"mailto:tom@example.com"}; 25 | var stateval = {"info":"the state info"}; 26 | 27 | ADL.XAPIWrapper.sendState(activityId, agent, activityState, null, stateval, null, null, function(xhr, body){ 28 | 29 | xhr.should.be.type('object'); 30 | xhr.status.should.eql(204); 31 | 32 | ADL.XAPIWrapper.getState(activityId, agent, activityState, null, null, function(xhr, body){ 33 | 34 | xhr.should.be.type('object'); 35 | xhr.status.should.eql(200); 36 | body.info.should.eql(stateval.info); 37 | done(); 38 | } 39 | ); 40 | } 41 | ); 42 | }); 43 | }); -------------------------------------------------------------------------------- /test/tests/test.util.js: -------------------------------------------------------------------------------- 1 | after(function () { 2 | //nothing in here 3 | }); 4 | 5 | describe('testing xAPI utilities', function () { 6 | 7 | var util, s1, s2, s3, s4, s5, s6, onBrowser, should, stmts; 8 | 9 | before(function () { 10 | 11 | onBrowser = false; 12 | if (typeof window !== 'undefined') { 13 | util = ADL.xapiutil; 14 | onBrowser = true; 15 | stmts = ADL.stmts; 16 | } 17 | else { 18 | util = require('../../src/xapi-util').xapiutil; 19 | should = require('should'); 20 | stmts = require('../../examples/stmtBank.js').stmts; 21 | } 22 | 23 | s1 = {"actor":{"mbox":"mailto:tom@tom.com", "openid":"openid", "mbox_sha1sum":"mbox_sha1sum", "account":"wrapperTesting"}, "verb":{"id":"http://verb.com/do1"}, "object":{"id":"http://from.tom/act1", "objectType":"StatementRef", "definition":{"name":{"en-US": "soccer", "fr": "football", "de": "foossball"}}}}; 24 | 25 | s2 = {"actor":{"openid":"openid", "mbox_sha1sum":"mbox_sha1sum", "account":"wrapperTesting", "name":"joe"}, "verb":{"id":"http://verb.com/do2", "display": {"fr": "recommander", "de": "empfehlen", "es": "recomendar", "en": "recommend"}}, "object":{"objectType":"Agent", "mbox":"mailto:joe@mail.com"}}; 26 | 27 | s3 = {"actor":{"mbox_sha1sum":"randomstringthatmakesnosensembox_sha1sum", "account":"wrapperTesting"}, "verb":{"id":"http://verb.com/do3"}, "object":{"objectType":"Group", 'notid':"http://from.tom/act3", "member":["joe"], "name":"obiwan", "mbox_sha1sum":"randomstringthatmakesnosensembox_sha1sum"}}; 28 | 29 | s4 = {"actor":{ "account":{"homePage":'http://adlnet.gov/test', "name":"wrapperTesting"}}, "verb":{ "id":"http://verb.com/do4", "display":{ "en-US":"initialized" }}, "object":{ "notid":"http://from.tom/act4", "objectType":"SubStatement", "actor":{ "mbox_sha1sum":"randomstringthatmakesnosensembox_sha1sum", "account":"wrapperTesting"}, "verb":{ "id":"http://verb.com/do3"}, "object":{ "objectType":"Group", "notid":"http://from.tom/act3", "member":["joe"], "mbox_sha1sum":"randomstringthatmakesnosensembox_sha1sum"}}}; 30 | 31 | s5 = {"actor":{"member":["joe"], "objectType": "Group"}, "verb":{"id":"http://verb.com/do5"}, "object":{"id":"http://from.tom/act5"}}; 32 | 33 | s6 = {"actor":{"some":"thing else"}, "verb":{"id":"http://verb.com/do6", "display":{"fr": "établi", "de": "etabliert"}}, "object":{"some":'thing else'}}; 34 | }); 35 | 36 | 37 | describe('test getLang', function () { 38 | //tests relies on environment settings being 'en-US' 39 | //failing this test does not necessarily mean that the code is bad, change "en-US" to match your proper environment setting 40 | it('should get the language from the browser or node', function () { 41 | (util.getLang()).should.eql("en-US"); 42 | }); 43 | }); 44 | 45 | describe('test getLangVal', function () { 46 | it('should get an object definition name', function () { 47 | (util.getLangVal(s1.object.definition.name)).should.eql("soccer"); 48 | }); 49 | it('should get a verb display', function () { 50 | (util.getLangVal(s4.verb.display)).should.eql("initialized"); 51 | }); 52 | it('should get the en if the en-US is not available', function () { 53 | (util.getLangVal(s2.verb.display)).should.eql("recommend"); 54 | }); 55 | it('should return the first display option if language code does not match any of the keys', function () { 56 | ("undefined").should.eql(typeof util.getLangVal(s6.verb.display)); 57 | }); 58 | it('should throw out junk', function () { 59 | ("undefined").should.eql(typeof util.getLangVal(s5.actor)); 60 | ("undefined").should.eql(typeof util.getLangVal(s5.verb)); 61 | ("undefined").should.eql(typeof util.getLangVal(s5.object)); 62 | ("undefined").should.eql(typeof util.getLangVal(s5)); 63 | }); 64 | it('should quit if we pass in nothing to it', function () { 65 | ("undefined").should.eql(typeof util.getLangVal()); 66 | }); 67 | it('should get the proper display if given a proper dictionary even a couple levels deep', function () { 68 | (util.getLangVal(stmts['Object-Sub-Statement-with-StatementRef'].object.verb.display)).should.eql(stmts['Object-Sub-Statement-with-StatementRef'].object.verb.display.en); 69 | }); 70 | }); 71 | 72 | describe('test getMoreStatements', function () { 73 | if (typeof window !== 'undefined') 74 | { 75 | it('should test getMoreStatements in the browser', function () { 76 | (util.getMoreStatements(3, function (stmts) { 77 | stmts.length.should.eql(16); 78 | Array.isArray(stmts).should.eql(true); 79 | stmts.should.be.type('object'); 80 | util.getLang().should.eql("en-US"); 81 | util.getActorId(stmts[0].actor).should.eql(ADL.stmts["Base-Statement"].actor.mbox); 82 | util.getVerbDisplay(stmts[7].verb).should.eql(ADL.stmts["Verb-User-Defined"].verb.display['en-US']); 83 | util.getObjectType(stmts[10].object).should.eql(ADL.stmts["Object-Agent"].object.objectType); 84 | })) 85 | }); 86 | it('should handle only a single request with no additional calls', function () { 87 | (util.getMoreStatements(0, function (stmts) { 88 | stmts.length.should.eql(4); 89 | Array.isArray(stmts).should.eql(true); 90 | util.getActorIdString(stmts[0].actor).should.eql(ADL.stmts['Base-Statement'].actor.mbox); 91 | util.getVerbDisplay(stmts[3].verb).should.eql(ADL.stmts["Actor-Anon-Group"].verb.display['en-US']); 92 | util.getObjectIdString(stmts[2].object).should.eql(ADL.stmts["Actor-Id-Group"].object.id); 93 | })); 94 | }); 95 | it('should handle only a single additional call', function () { 96 | (util.getMoreStatements(1, function (stmts) { 97 | stmts.length.should.eql(8); 98 | Array.isArray(stmts).should.eql(true); 99 | util.getActorIdString(stmts[0].actor).should.eql(ADL.stmts['Base-Statement'].actor.mbox); 100 | util.getVerbDisplay(stmts[7].verb).should.eql(ADL.stmts["Verb-User-Defined"].verb.display['en-US']); 101 | util.getObjectIdString(stmts[4].object).should.eql(ADL.stmts["Actor-Mbox"].object.id); 102 | })); 103 | }); 104 | it('should handle a request which overreaches the available statements', function () { 105 | (util.getMoreStatements(100, function (stmts) { 106 | stmts.length.should.eql(Object.keys(ADL.stmts).length); 107 | Array.isArray(stmts).should.eql(true); 108 | util.getActorIdString(stmts[0].actor).should.eql(ADL.stmts['Base-Statement'].actor.mbox); 109 | util.getVerbDisplay(stmts[15].verb).should.eql(ADL.stmts["Result"].verb.display['en-US']); 110 | util.getObjectType(stmts[12].object).should.eql(ADL.stmts["Object-StatementRef"].object.objectType); 111 | })); 112 | }); 113 | } 114 | }); 115 | 116 | describe('test getActorId', function () { 117 | it('should get the mailbox of the actor', function () { 118 | (util.getActorId(s1.actor)).should.eql(s1.actor.mbox); 119 | }); 120 | it('should get the openid of the actor', function () { 121 | (util.getActorId(s2.actor)).should.eql(s2.actor.openid); 122 | }); 123 | it('should get the mailbox sha1sum of the actor', function () { 124 | (util.getActorId(s3.actor)).should.eql(s3.actor.mbox_sha1sum); 125 | }); 126 | it('should get the account of the actor', function () { 127 | (util.getActorId(s4.actor)).should.eql(s4.actor.account); 128 | }); 129 | it('should get the account of an identified group', function () { 130 | (util.getActorId(stmts["Actor-Id-Group"].actor)).should.eql(stmts["Actor-Id-Group"].actor.account); 131 | }); 132 | it('should be undefined for an anonymous group', function () { 133 | ("undefined").should.eql(typeof util.getActorId(stmts["Actor-Anon-Group"].actor)); 134 | ("undefined").should.eql(typeof util.getActorId(s5.actor)); 135 | }); 136 | }); 137 | 138 | describe('test getActorIdString', function () { 139 | it('should return the mailbox of the actor', function () { 140 | (util.getActorIdString(s1.actor)).should.be.String(); 141 | (util.getActorIdString(s1.actor)).should.eql(s1.actor.mbox); 142 | }); 143 | it('should return the openid', function () { 144 | (util.getActorIdString(s2.actor)).should.eql(s2.actor.openid); 145 | }); 146 | it('should return the sha1sum of the mailbox', function () { 147 | (util.getActorIdString(s3.actor)).should.eql(s3.actor.mbox_sha1sum); 148 | }); 149 | it('should return a String of the account', function () { 150 | (util.getActorIdString(s4.actor)).should.be.String(); 151 | (util.getActorIdString(s4.actor)).should.eql(s4.actor.account.homePage + ":" + s4.actor.account.name); 152 | }); 153 | it('should return a String of the member', function () { 154 | (util.getActorIdString(s5.actor)).should.be.String(); 155 | (util.getActorIdString(s5.actor)).should.eql("Anon Group " + s5.actor.member); 156 | }); 157 | it ('should return unknown if nothing is present', function () { 158 | (util.getActorIdString(s6.actor)).should.eql("unknown"); 159 | }); 160 | }); 161 | 162 | describe('test getActorDisplay', function () { 163 | it('should get the actor name', function () { 164 | (util.getActorDisplay(s2.actor)).should.eql(s2.actor.name); 165 | }); 166 | it('should get the actor id string', function () { 167 | (util.getActorDisplay(s1.actor).should.eql(s1.actor.mbox)) 168 | }); 169 | }); 170 | 171 | describe('test getVerbDisplay', function () { 172 | it('should return undefined with no verb', function () { 173 | ("undefined").should.equal(typeof util.getVerbDisplay()); 174 | }); 175 | it('should get the verb in the proper language', function () { 176 | (util.getVerbDisplay(s4.verb)).should.eql(s4.verb.display['en-US']); 177 | }); 178 | it('should get the verb id', function () { 179 | (util.getVerbDisplay(s1.verb).should.eql(s1.verb.id)) 180 | }) 181 | }); 182 | 183 | describe('test getObjectType', function () { 184 | it('should get the objectType when available', function () { 185 | (util.getObjectType(s1.object)).should.eql(s1.object.objectType); 186 | }); 187 | it('should assume "Activity" if object id available', function () { 188 | (util.getObjectType(s5.object).should.eql('Activity')); 189 | }); 190 | it('should assume "Agent" if neither id nor objectType available', function () { 191 | (util.getObjectType(s6.object).should.eql('Agent')); 192 | }); 193 | }); 194 | 195 | describe('test getObjectId', function () { 196 | it('should get the id', function () { 197 | (util.getObjectId(s1.object)).should.eql(s1.object.id); 198 | }); 199 | it('should get the actor id, if no id and objectType is Agent', function () { 200 | (util.getObjectId(s2.object)).should.eql(s2.object.mbox); 201 | }); 202 | it('should get the actor id, if no id and objectType is Group', function () { 203 | (util.getObjectId(s3.object)).should.eql(util.getActorId(s3.object)); 204 | }); 205 | it('should get the actor id, if Statement Ref', function () { 206 | (util.getObjectId(stmts["Object-StatementRef"].object)).should.eql(stmts["Object-StatementRef"].object.id); 207 | }); 208 | it('should get the actor id, if Sub-Statement', function () { 209 | ("undefined").should.eql(typeof util.getObjectId(stmts["Object-Sub-Statement"].object)); 210 | }); 211 | it('should return undefined, if malformed', function () { 212 | ('undefined').should.eql(typeof util.getObjectId(s6.object)); 213 | }); 214 | }); 215 | 216 | describe('test getObjectIdString', function () { 217 | it('should get the id', function () { 218 | (util.getActorIdString(s1.object)).should.be.String(); 219 | (util.getObjectIdString(s1.object)).should.eql(s1.object.id); 220 | }); 221 | it('should get the Actor Id String, if no id and type is Agent or Group', function () { 222 | (util.getObjectIdString(s2.object)).should.be.String(); 223 | (util.getObjectIdString(s2.object)).should.eql(s2.object.mbox); 224 | }); 225 | it('should get the Actor-Verb-Object String, if no id and type is SubStatement', function () { 226 | (util.getObjectIdString(s4.object)).should.be.String(); 227 | (util.getObjectIdString(s4.object)).should.eql(s3.actor.mbox_sha1sum + ":" + s3.verb.id + ":" + s3.object.mbox_sha1sum); 228 | }); 229 | it('should return unknown, if those do not work', function () { 230 | ('unknown').should.eql(util.getObjectIdString(s6.object)); 231 | }); 232 | it('should return unknown, if you pass it junk', function () { 233 | ("unknown").should.eql(util.getObjectIdString(stmts)); 234 | ("unknown").should.eql(util.getObjectIdString('stmts')); 235 | ("unknown").should.eql(util.getObjectIdString()); 236 | }); 237 | }); 238 | 239 | describe('test getObjectDisplay', function () { 240 | it('should get the object definition name', function () { 241 | (util.getObjectDisplay(s1.object)).should.eql(s1.object.definition.name[util.getLang()]); 242 | }); 243 | it('or should get the object name', function () { 244 | (util.getObjectDisplay(s3.object)).should.eql(s3.object.name); 245 | }); 246 | it('or should get the object id', function () { 247 | (util.getObjectDisplay(s5.object)).should.eql(s5.object.id); 248 | }); 249 | it('or should get the object actor id', function () { 250 | (util.getObjectDisplay(s2.object)).should.eql(s2.object.mbox); 251 | }); 252 | it('or should get the Actor-Verb-Object String', function () { 253 | (util.getObjectDisplay(s4.object)).should.eql(s3.actor.mbox_sha1sum + ":" + s3.verb.id + ":" + s3.object.mbox_sha1sum); 254 | }); 255 | it('should handle junk', function () { 256 | ('unknown').should.eql(util.getObjectDisplay(s3)); 257 | ('unknown').should.eql(util.getObjectDisplay()); 258 | ('unknown').should.eql(util.getObjectDisplay('s3')); 259 | }); 260 | }); 261 | 262 | }) 263 | --------------------------------------------------------------------------------