diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..5a324a8e --- /dev/null +++ b/.eslintrc @@ -0,0 +1,44 @@ +{ + "env": { + "browser": true, + "amd": true, + "jasmine": true + }, + "globals": { + "module": true, + "runs": true, + "itConditionally": true, + // Examples + "F2_jsonpCallback_com_openf2_examples_javascript_cds": true + }, + "rules": { + "dot-notation": false, + "new-cap": false, + "no-eval": false, + "no-comma-dangle": true, + "no-cond-assign": true, + "no-console": false, + "quotes": [1, "single"], + "strict": false, + "no-underscore-dangle": false, + "valid-jsdoc": [2, { + "requireReturn": false + }], + // Stylistic + "block-scoped-var": true, + "no-else-return": true, + "no-eq-null": true, + "func-style": [2, "declaration"], + "spaced-line-comment": ["always"], + "space-in-parens": ["never"], + "space-in-brackets": ["never"], + "space-before-blocks": "always", + "space-after-keywords": "always", + "space-after-function-name": "never", + "operator-assignment": [2, "always"], + // TODO: reverse when issues are fixed + "consistent-return": false, + "no-use-before-define": false, + "no-unused-vars": false + } +} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 1da5e27a..00000000 --- a/.jshintrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "browser": true, - "curly": true, - "evil": true, - "globals": { - "console": true, - "define": true, "exports": true, "require": true, "module": true, - "describe": true, "xdescribe": true, "it": true, "xit": true, "expect": true, "runs": true, "waits": true, "waitsFor": true, "itConditionally": true, - "easyXDM": true, - "EventEmitter2": true, - "F2": true, - "jQuery": true, - "$": true - }, - "latedef": true, - "noarg": true, - "quotmark": "single", - "shadow": false, - "sub": true, - "undef": true, - "unused": "vars" -} \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index f5667641..e1df560e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,441 +1,493 @@ module.exports = function(grunt) { - var exec = require('child_process').exec, - handlebars = require('handlebars'), - moment = require('moment'), - pkg = grunt.file.readJSON('package.json'), - semver = require('semver'), - path = require('path'); + var exec = require('child_process').exec; + var handlebars = require('handlebars'); + var moment = require('moment'); + var pkg = grunt.file.readJSON('package.json'); + var semver = require('semver'); + var path = require('path'); - // TODO: Remove Handlebars dependency and use the built-in grunt templating - // Handlebars helpers - handlebars.registerHelper('if', function(conditional, options) { - if (options.hash.desired === options.hash.test) { - return options.fn(this); - } - }); + // TODO: Remove Handlebars dependency and use the built-in grunt templating + handlebars.registerHelper('if', function(conditional, options) { + if (options.hash.desired === options.hash.test) { + return options.fn(this); + } + }); - // Project config - grunt.initConfig({ - pkg: pkg, - clean: { - 'github-pages': { - options: { force: true }, - src: ['../gh-pages/src'] - }, - 'F2-examples': { - options: { force: true }, - src: ['./F2-examples.zip'] - } - }, - copy: { - 'github-pages': { - files: [ - { - expand: true, - cwd: 'docs/', - src: ['**'], - dest: '../gh-pages' - }, - { - expand: true, - cwd: 'dist/', - src: ['f2.latest.js'], - rename: function(dest, src){ - return '../gh-pages/js/f2.min.js';//See #35 - } - } - ] - }, - 'F2-examples': { - files: [ - { - expand: true, - cwd: './', - src: ['F2-examples.zip'], - dest: '../gh-pages' - } - ] - } - }, - compress: { - main: { - options: { - archive: 'F2-examples.zip', - pretty: true - }, - files: [ - { - expand: true, - cwd: 'examples/', - src: ['**'], - dest: 'examples/' - }, - { - expand: true, - cwd: 'dist/', - src: ['f2.debug.js'], - dest: 'dist/' - }, - { - expand: true, - src: ['tests/require.min.js'], - dest: 'dist/' - } - ] - } - }, - concat: { - options: { - process: { data: pkg }, - separator: '\n', - stripBanners: false - }, - dist: { - src: [ - 'src/lib/template/header.js.tmpl', - 'src/vendor/jquery.js', - 'src/vendor/jquery.noconflict.js', - 'src/vendor/bootstrap-modal.js', - 'src/vendor/eventemitter2.js', - 'src/vendor/easyXDM/easyXDM.js', - '<%= jshint.files %>', - 'src/lib/template/footer.js.tmpl' - ], - dest: 'dist/f2.debug.js' - }, - 'no-third-party': { - src: [ - 'src/lib/template/header.js.tmpl', - '<%= jshint.files %>', - 'src/lib/template/footer.js.tmpl' - ], - dest: 'dist/f2.no-third-party.js' - }, - 'no-jquery-or-bootstrap': { - src: [ - 'src/lib/template/header.js.tmpl', - 'src/vendor/eventemitter2.js', - 'src/vendor/easyXDM/easyXDM.js', - '<%= jshint.files %>', - 'src/lib/template/footer.js.tmpl' - ], - dest: 'dist/packages/f2.no-jquery-or-bootstrap.js' - }, - 'no-bootstrap': { - src: [ - 'src/lib/template/header.js.tmpl', - 'src/vendor/jquery.js', - 'src/vendor/jquery.noconflict.js', - 'src/vendor/eventemitter2.js', - 'src/vendor/easyXDM/easyXDM.js', - '<%= jshint.files %>', - 'src/lib/template/footer.js.tmpl' - ], - dest: 'dist/packages/f2.no-bootstrap.js' - }, - 'no-easyXDM': { - src: [ - 'src/lib/template/header.js.tmpl', - 'src/vendor/jquery.js', - 'src/vendor/bootstrap-modal.js', - 'src/vendor/jquery.noconflict.js', - 'src/vendor/eventemitter2.js', - '<%= jshint.files %>', - 'src/lib/template/footer.js.tmpl' - ], - dest: 'dist/packages/f2.no-easyXDM.js' - }, - 'basic': { //reminiscent of F2 1.0, no secure apps and Container Provide must have jQuery & Bootstrap on page before F2. - src: [ - 'src/lib/template/header.js.tmpl', - 'src/vendor/eventemitter2.js', - '<%= jshint.files %>', - 'src/lib/template/footer.js.tmpl' - ], - dest: 'dist/packages/f2.basic.js' - }, - }, - /** - * Need to downgrade forever-monitor to v1.1 because of: - * https://github.com/blai/grunt-express/issues/12 - * cd node_modules/grunt-express; npm uninstall forever-monitor; npm install forever-monitor@1.1; - */ - express: { - server: { - options: { - bases: './', - port: 8080, - server: (require('path')).resolve('./tests/server') - } - } - }, - jasmine: { - 'non-amd': { - options: { - host: 'http://localhost:8080/tests/', - outfile: 'index.html' - } - }, - 'amd': { - options: { - host: 'http://localhost:8080/tests/', - outfile: 'index-amd.html' - } - } - }, - jshint: { - options: { - jshintrc: '.jshintrc' - }, - files: [ - 'src/lib/F2.js', - 'src/lib/app_handlers.js', - 'src/lib/classes.js', - 'src/lib/constants.js', - 'src/lib/events.js', - 'src/lib/rpc.js', - 'src/lib/ui.js', - 'src/lib/container.js' - ] - }, - uglify: { - options: { - preserveComments: 'some', - banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("mm-dd-yyyy") %> - See below for copyright and license */\n' - }, - dist: { - files: {'dist/f2.min.js': ['dist/f2.debug.js']}, - options: { - report: 'gzip' - } - }, - sourcemap: { - files: '<%= uglify.dist.files %>', - options: { - sourceMap: function(fileName) { - return fileName.replace(/\.js$/, '.js.map'); - }, - sourceMapPrefix: 1, - sourceMappingURL: function(path) { - return path.replace(grunt.config('sourcemap.options.prefix'), '').replace(/\.js$/, '.js.map'); - } - } - }, - 'package-no-jquery-or-bootstrap': { - files: { 'dist/packages/f2.no-jquery-or-bootstrap.min.js' : ['dist/packages/f2.no-jquery-or-bootstrap.js'] }, - options: { report: 'gzip' } - }, - 'package-no-bootstrap': { - files: { 'dist/packages/f2.no-bootstrap.min.js' : ['dist/packages/f2.no-bootstrap.js'] }, - options: { report: 'gzip' } - }, - 'package-no-easyXDM': { - files: { 'dist/packages/f2.no-easyXDM.min.js' : ['dist/packages/f2.no-easyXDM.js'] }, - options: { report: 'gzip' } - }, - 'package-basic': { - files: { 'dist/packages/f2.basic.min.js' : ['dist/packages/f2.basic.js'] }, - options: { report: 'gzip' } - } - }, - sourcemap: { - options: { - src: 'dist/f2.min.js', - prefix: './dist/' - } - }, - watch: { - docs: { - files: ['docs/src/**/*.*', 'package.json', 'docs/bin/gen-docs.js'], - tasks: ['docs'], - options: { - spawn: false, - } - }, - scripts: { - files: ['./src/lib/**/*.js'], - tasks: ['js'], - options: { - spawn: false, - } - } - }, - http: { - getDocsLayout: { - options: { - url: 'http://www.openf2.org/api/layout/docs', - json: true, - strictSSL: false, - callback: function(err, res, response){ - var log = grunt.log.write('Retrieved doc layout...') - grunt.config.set('docs-layout',response); - log.ok(); - log = grunt.log.write('Saving templates as HTML...'); - //save as HTML for gen-docs step - grunt.file.write('./docs/src/template/head.html', response.head); - grunt.file.write('./docs/src/template/nav.html', response.nav); - grunt.file.write('./docs/src/template/footer.html', response.footer); - log.ok(); - } - } - } - } - }); + grunt.initConfig({ + browserify: { + options: { + alias: [] + }, + dist: { + dest: 'dist/f2.debug.js', + standalone: 'F2', + src: ['src/lib/index.js'] + }, + noVendor: { + dest: 'dist/f2.no-third-party.js', + src: ['src/lib/index.js'], + options: { + exclude: ['jquery', 'eventemitter2', 'bootstrap-modal', 'easyxdm'] + } + }, + noJqueryBootstrap: { + dest: 'dist/packages/f2.no-jquery-or-bootstrap.js', + src: ['src/lib/index.js'], + options: { + exclude: ['jquery', 'bootstrap-modal'] + } + }, + noBootstrap: { + dest: 'dist/packages/f2.no-bootstrap.js', + src: ['src/lib/index.js'], + options: { + exclude: ['bootstrap-modal'] + } + }, + noEasyxdm: { + dest: 'dist/packages/f2.no-easyXDM.js', + src: ['src/lib/index.js'], + options: { + exclude: ['easyxdm'] + } + }, + basic: { + dest: 'dist/packages/f2.basic.js', + src: ['src/lib/index.js'], + options: { + exclude: ['easyxdm', 'jquery', 'bootstrap-modal'] + } + } + }, + clean: { + 'github-pages': { + options: { + force: true + }, + src: ['../gh-pages/src'] + }, + 'F2-examples': { + options: { + force: true + }, + src: ['./F2-examples.zip'] + } + }, + compress: { + main: { + options: { + archive: 'F2-examples.zip', + pretty: true + }, + files: [{ + expand: true, + cwd: 'examples/', + src: ['**'], + dest: 'examples/' + }, { + expand: true, + cwd: 'dist/', + src: ['f2.debug.js'], + dest: 'dist/' + }, { + expand: true, + src: ['tests/require.min.js'], + dest: 'dist/' + }] + } + }, + concat: { + options: { + process: { + data: pkg + }, + separator: '\n', + stripBanners: false + }, + dist: { + src: [ + 'src/lib/template/header.js.tmpl', + 'dist/f2.debug.js', + 'src/lib/template/footer.js.tmpl' + ], + dest: 'dist/f2.debug.js' + }, + 'no-third-party': { + src: [ + 'src/lib/template/header.js.tmpl', + 'dist/f2.no-third-party.js', + 'src/lib/template/footer.js.tmpl' + ], + dest: 'dist/f2.no-third-party.js' + }, + 'no-jquery-or-bootstrap': { + src: [ + 'src/lib/template/header.js.tmpl', + 'dist/packages/f2.no-jquery-or-bootstrap.js', + 'src/lib/template/footer.js.tmpl' + ], + dest: 'dist/packages/f2.no-jquery-or-bootstrap.js' + }, + 'no-bootstrap': { + src: [ + 'src/lib/template/header.js.tmpl', + 'dist/packages/f2.no-bootstrap.js', + 'src/lib/template/footer.js.tmpl' + ], + dest: 'dist/packages/f2.no-bootstrap.js' + }, + 'no-easyXDM': { + src: [ + 'src/lib/template/header.js.tmpl', + 'dist/packages/f2.no-easyXDM.js', + 'src/lib/template/footer.js.tmpl' + ], + dest: 'dist/packages/f2.no-easyXDM.js' + }, + // Reminiscent of F2 1.0, no secure apps and Container Provide must have jQuery & Bootstrap on page before F2. + 'basic': { + src: [ + 'src/lib/template/header.js.tmpl', + 'dist/packages/f2.basic.js', + 'src/lib/template/footer.js.tmpl' + ], + dest: 'dist/packages/f2.basic.js' + } + }, + copy: { + 'github-pages': { + files: [{ + expand: true, + cwd: 'docs/', + src: ['**'], + dest: '../gh-pages' + }, { + expand: true, + cwd: 'dist/', + src: ['f2.latest.js'], + rename: function(dest, src) { + return '../gh-pages/js/f2.min.js'; //See #35 + } + }] + }, + 'F2-examples': { + files: [{ + expand: true, + cwd: './', + src: ['F2-examples.zip'], + dest: '../gh-pages' + }] + } + }, + eslint: { + options: { + config: '.eslintrc' + }, + target: [ + './src/lib/*.js', + './examples/apps/JavaScript/CDS/**/*.js' + ] + }, + /** + Need to downgrade forever-monitor to v1.1 because of: + https://github.com/blai/grunt-express/issues/12 + cd node_modules/grunt-express; npm uninstall forever-monitor; npm install forever-monitor@1.1; + */ + express: { + server: { + options: { + bases: './', + port: 8080, + server: (require('path')).resolve('./tests/server') + } + } + }, + http: { + getDocsLayout: { + options: { + url: 'http://www.openf2.org/api/layout/docs', + json: true, + strictSSL: false, + callback: function(err, res, response) { + var log = grunt.log.write('Retrieved doc layout...') + grunt.config.set('docs-layout', response); + log.ok(); + log = grunt.log.write('Saving templates as HTML...'); + // Save as HTML for gen-docs step + grunt.file.write('./docs/src/template/head.html', response.head); + grunt.file.write('./docs/src/template/nav.html', response.nav); + grunt.file.write('./docs/src/template/footer.html', response.footer); + log.ok(); + } + } + } + }, + jasmine: { + 'non-amd': { + options: { + host: 'http://localhost:8080/tests/', + outfile: 'index.html' + } + }, + 'amd': { + options: { + host: 'http://localhost:8080/tests/', + outfile: 'index-amd.html' + } + } + }, + pkg: pkg, + sourcemap: { + options: { + src: 'dist/f2.min.js', + prefix: './dist/' + } + }, + uglify: { + options: { + preserveComments: 'some', + banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("mm-dd-yyyy") %> - See below for copyright and license */\n' + }, + dist: { + files: { + 'dist/f2.min.js': ['dist/f2.debug.js'] + }, + options: { + report: 'gzip' + } + }, + sourcemap: { + files: '<%= uglify.dist.files %>', + options: { + sourceMap: function(fileName) { + return fileName.replace(/\.js$/, '.js.map'); + }, + sourceMapPrefix: 1, + sourceMappingURL: function(path) { + return path.replace(grunt.config('sourcemap.options.prefix'), '').replace(/\.js$/, '.js.map'); + } + } + }, + 'package-no-jquery-or-bootstrap': { + files: { + 'dist/packages/f2.no-jquery-or-bootstrap.min.js': ['dist/packages/f2.no-jquery-or-bootstrap.js'] + }, + options: { + report: 'gzip' + } + }, + 'package-no-bootstrap': { + files: { + 'dist/packages/f2.no-bootstrap.min.js': ['dist/packages/f2.no-bootstrap.js'] + }, + options: { + report: 'gzip' + } + }, + 'package-no-easyXDM': { + files: { + 'dist/packages/f2.no-easyXDM.min.js': ['dist/packages/f2.no-easyXDM.js'] + }, + options: { + report: 'gzip' + } + }, + 'package-basic': { + files: { + 'dist/packages/f2.basic.min.js': ['dist/packages/f2.basic.js'] + }, + options: { + report: 'gzip' + } + } + }, + watch: { + docs: { + files: ['docs/src/**/*.*', 'package.json', 'docs/bin/gen-docs.js'], + tasks: ['docs'], + options: { + spawn: false + } + }, + scripts: { + files: ['./src/lib/**/*.js'], + tasks: ['js'], + options: { + spawn: false + } + }, + lint: { + files: [ + './src/lib/**/*.js', + './examples/apps/JavaScript/**/*.js' + ], + tasks: ['lint'], + options: { + spawn: false + } + } + } + }); - // Register tasks - grunt.registerTask('fix-sourcemap', 'Fixes the source map file', function() { - var uglifyOptions = grunt.config('uglify.sourcemap.options'); - var options = grunt.config('sourcemap.options'); - var dest = uglifyOptions.sourceMap(options.src); - var rawMap = grunt.file.read(dest); + // Load plugins + grunt.loadNpmTasks('grunt-browserify'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-compress'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-jasmine'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-eslint'); + grunt.loadNpmTasks('grunt-express'); + grunt.loadNpmTasks('grunt-http'); - rawMap = rawMap.replace(options.prefix, ''); - grunt.file.write(dest, rawMap); - }); + // Register tasks + grunt.registerTask('default', ['test', 'js', 'docs', 'zip']); + grunt.registerTask('docs', ['http', 'generate-docs', 'yuidoc']); + grunt.registerTask('fix-sourcemap', 'Fixes the source map file', taskFixSourcemaps); + grunt.registerTask('generate-docs', 'Generate docs', taskGenerateDocs); + grunt.registerTask('github-pages', ['copy:github-pages', 'clean:github-pages']); + grunt.registerTask('js', ['lint', 'browserify', 'concat:dist', 'concat:no-third-party', 'uglify:dist', 'sourcemap']); + grunt.registerTask('lint', ['eslint']); + grunt.registerTask('nuget', 'Builds the NuGet package for distribution on NuGet.org', taskNuget); + grunt.registerTask('packages', [ + 'concat:no-jquery-or-bootstrap', + 'concat:no-bootstrap', + 'concat:no-easyXDM', + 'concat:basic', + 'uglify:package-no-jquery-or-bootstrap', + 'uglify:package-no-bootstrap', + 'uglify:package-no-easyXDM', + 'uglify:package-basic' + ]); + grunt.registerTask('release', 'Prepares the code for release (merge into master)', taskRelease); + grunt.registerTask('sourcemap', ['uglify:sourcemap', 'fix-sourcemap']); + grunt.registerTask('test', ['express', 'jasmine']); + grunt.registerTask('test-live', ['express', 'express-keepalive']); + grunt.registerTask('travis', ['test']); + grunt.registerTask('version', 'Displays version information for F2', taskVersion); + grunt.registerTask('yuidoc', 'Builds the reference docs with YUIDocJS', taskYuiDoc); + grunt.registerTask('zip', ['compress', 'copy:F2-examples', 'clean:F2-examples']); - grunt.registerTask('generate-docs', 'Generate docs', function() { - var done = this.async(), - log = grunt.log.write('Generating docs...'); + function taskFixSourcemaps() { + var uglifyOptions = grunt.config('uglify.sourcemap.options'); + var options = grunt.config('sourcemap.options'); + var dest = uglifyOptions.sourceMap(options.src); + var rawMap = grunt.file.read(dest); - exec('node ' + path.join(__dirname, 'docs/bin/gen-docs'), function(err, stdout, stderr) { - if (err) { - grunt.log.error(err.message); - grunt.fail.fatal('Docs generation aborted.'); - return; - } - grunt.log.write(stdout); - log.ok(); - done(); - }); - }); + rawMap = rawMap.replace(options.prefix, ''); + grunt.file.write(dest, rawMap); + } - grunt.registerTask('yuidoc', 'Builds the reference docs with YUIDocJS', function() { + function taskGenerateDocs() { + var done = this.async(); + var log = grunt.log.write('Generating docs...'); - var builder, - docOptions = { - quiet: true, - norecurse: true, - paths: ['./src/lib'], - outdir: './docs/dist/sdk/', - themedir: './docs/src/sdk-template', - helpers: ['./docs/src/sdk-template/helpers/helpers.js'] - }, - done = this.async(), - json, - log = grunt.log.write('Generating reference docs...'), - Y = require('yuidocjs'); + exec('node ' + path.join(__dirname, 'docs/bin/gen-docs'), function(err, stdout, stderr) { + if (err) { + grunt.log.error(err.message); + grunt.fail.fatal('Docs generation aborted.'); + return; + } + grunt.log.write(stdout); + log.ok(); + done(); + }); + } - json = (new Y.YUIDoc(docOptions)).run(); - // massage in some meta information from F2.json - json.project = { - docsAssets: '../', - version: pkg.version, - releaseDateFormatted: pkg._releaseDateFormatted - }; - docOptions = Y.Project.mix(json, docOptions); + function taskNuget() { + var done = this.async(); + var log = grunt.log.write('Creating NuSpec file...'); + var nuspec = grunt.file.read('./dist/f2.nuspec.tmpl'); - // ensures that the class has members and isn't just an empty namespace - // used in sidebar.handlebars - Y.Handlebars.registerHelper('hasClassMembers', function() { - for (var i = 0, len = json.classitems.length; i < len; i++) { - //console.log(json.classitems[i].class, this.name); - if (json.classitems[i].class === this.name) { - return ''; - } - } - return 'hidden'; - }); + nuspec = grunt.template.process(nuspec, { data: pkg }); + grunt.file.write('./dist/f2.nuspec', nuspec); + log.ok(); - builder = new Y.DocBuilder(docOptions, json); - builder.compile(function() { - log.ok(); - done(); - }); - }); + log = grunt.log.write('Creating NuGet package...'); + grunt.util.spawn({ + cmd: 'nuget', + args: ['pack', 'f2.nuspec'], + opts: { + cwd: './dist' + } + }, function(error, result, code) { + if (error) { + grunt.fail.fatal(error); + } else { + grunt.file.delete('./dist/f2.nuspec'); + log.ok(); + done(); + } + }); + } - grunt.registerTask('nuget', 'Builds the NuGet package for distribution on NuGet.org', function() { - var done = this.async(), - log = grunt.log.write('Creating NuSpec file...'), - nuspec = grunt.file.read('./dist/f2.nuspec.tmpl'); + function taskRelease(releaseType) { + if (!/^major|minor|patch$/i.test(releaseType) && !semver.valid(releaseType)) { + grunt.log.error('"' + releaseType + '" is not a valid release type (major, minor, or patch) or SemVer version'); + return; + } - nuspec = grunt.template.process(nuspec, { data: pkg }); - grunt.file.write('./dist/f2.nuspec', nuspec); - log.ok(); + pkg.version = semver.valid(releaseType) ? releaseType : String(semver.inc(pkg.version, releaseType)).replace(/\-\w+$/, ''); + pkg._releaseDate = new Date().toJSON(); + pkg._releaseDateFormatted = moment(pkg._releaseDate).format('D MMMM YYYY'); - log = grunt.log.write('Creating NuGet package...'); - grunt.util.spawn( - { - cmd: 'nuget', - args: ['pack', 'f2.nuspec'], - opts: { - cwd: './dist' - } - }, - function(error, result, code){ - if (error){ - grunt.fail.fatal(error); - } else { - grunt.file.delete('./dist/f2.nuspec'); - log.ok(); - done(); - } - } - ); - }); + grunt.file.write('./package.json', JSON.stringify(pkg, null, '\t')); + grunt.config.set('pkg', pkg); - grunt.registerTask('release', 'Prepares the code for release (merge into master)', function(releaseType) { - if (!/^major|minor|patch$/i.test(releaseType) && !semver.valid(releaseType)) { - grunt.log.error('"' + releaseType + '" is not a valid release type (major, minor, or patch) or SemVer version'); - return; - } + grunt.task.run('version'); + } - pkg.version = semver.valid(releaseType) ? releaseType : String(semver.inc(pkg.version, releaseType)).replace(/\-\w+$/, ''); - pkg._releaseDate = new Date().toJSON(); - pkg._releaseDateFormatted = moment(pkg._releaseDate).format('D MMMM YYYY'); + function taskVersion() { + grunt.log.writeln(grunt.template.process( + 'This copy of F2 is at version <%= version %> with a release date of <%= _releaseDateFormatted %>', + { data: pkg } + )); + } - grunt.file.write('./package.json', JSON.stringify(pkg, null, '\t')); - grunt.config.set('pkg', pkg); + function taskYuiDoc() { + var builder; + var docOptions = { + quiet: true, + norecurse: true, + paths: ['./src/lib'], + outdir: './docs/dist/sdk/', + themedir: './docs/src/sdk-template', + helpers: ['./docs/src/sdk-template/helpers/helpers.js'] + }; + var done = this.async(); + var log = grunt.log.write('Generating reference docs...'); + var Y = require('yuidocjs'); - grunt.task.run('version'); - }); + var json = (new Y.YUIDoc(docOptions)).run(); + // Massage in some meta information from F2.json + json.project = { + docsAssets: '../', + version: pkg.version, + releaseDateFormatted: pkg._releaseDateFormatted + }; + docOptions = Y.Project.mix(json, docOptions); - grunt.registerTask('version', 'Displays version information for F2', function() { - grunt.log.writeln(grunt.template.process( - 'This copy of F2 is at version <%= version %> with a release date of <%= _releaseDateFormatted %>', - { data: pkg } - )); - }); + // Ensures that the class has members and isn't just an empty namespace + // Used in sidebar.handlebars + Y.Handlebars.registerHelper('hasClassMembers', function() { + for (var i = 0, len = json.classitems.length; i < len; i++) { + if (json.classitems[i].class === this.name) { + return ''; + } + } - // Load plugins - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-compress'); - grunt.loadNpmTasks('grunt-contrib-jasmine'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-express'); - grunt.loadNpmTasks('grunt-http'); + return 'hidden'; + }); + + builder = new Y.DocBuilder(docOptions, json); + builder.compile(function() { + log.ok(); + done(); + }); + } - grunt.registerTask('docs', ['http','generate-docs', 'yuidoc']); - grunt.registerTask('github-pages', ['copy:github-pages', 'clean:github-pages']); - grunt.registerTask('zip', ['compress', 'copy:F2-examples', 'clean:F2-examples']); - grunt.registerTask('js', ['concat:dist', 'concat:no-third-party', 'uglify:dist', 'sourcemap']); - grunt.registerTask('sourcemap', ['uglify:sourcemap', 'fix-sourcemap']); - grunt.registerTask('packages', [ - 'concat:no-jquery-or-bootstrap', - 'concat:no-bootstrap', - 'concat:no-easyXDM', - 'concat:basic', - 'uglify:package-no-jquery-or-bootstrap', - 'uglify:package-no-bootstrap', - 'uglify:package-no-easyXDM', - 'uglify:package-basic' - ]); - grunt.registerTask('test', ['jshint', 'express', 'jasmine']); - grunt.registerTask('test-live', ['jshint', 'express', 'express-keepalive']); - grunt.registerTask('travis', ['test']); - grunt.registerTask('default', ['test', 'js', 'docs', 'zip']); }; diff --git a/dist/f2.debug.js b/dist/f2.debug.js index 4bfdd728..4dc7df62 100644 --- a/dist/f2.debug.js +++ b/dist/f2.debug.js @@ -1,5 +1,5 @@ /*! - * F2 v1.4.0 12-29-2014 + * F2 v1.4.0 01-21-2015 * Copyright (c) 2014 Markit On Demand, Inc. http://www.openf2.org * * "F2" is licensed under the Apache License, Version 2.0 (the "License"); @@ -28,17668 +28,17576 @@ */ ;(function(exports) { - if (exports.F2 && !exports.F2_TESTING_MODE) { - return; - } - -/*! - * jQuery JavaScript Library v1.11.1 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2014-05-01T17:42Z - */ - -(function( global, factory ) { - - if ( typeof module === "object" && typeof module.exports === "object" ) { - // For CommonJS and CommonJS-like environments where a proper window is present, - // execute the factory and get jQuery - // For environments that do not inherently posses a window with a document - // (such as Node.js), expose a jQuery-making factory as module.exports - // This accentuates the need for the creation of a real window - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + if (exports.F2 && !exports.F2_TESTING_MODE) { + return; + } -// Can't do this because several apps including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -// Support: Firefox 18+ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 9 && minor > 0; + return true; +} -var hasOwn = class2type.hasOwnProperty; +/* + * Cross Browser implementation for adding and removing event listeners. + */ +var on, un; +if (isHostMethod(window, "addEventListener")) { + on = function(target, type, listener){ + target.addEventListener(type, listener, false); + }; + un = function(target, type, listener){ + target.removeEventListener(type, listener, false); + }; +} +else if (isHostMethod(window, "attachEvent")) { + on = function(object, sEvent, fpNotify){ + object.attachEvent("on" + sEvent, fpNotify); + }; + un = function(object, sEvent, fpNotify){ + object.detachEvent("on" + sEvent, fpNotify); + }; +} +else { + throw new Error("Browser not supported"); +} -var support = {}; +/* + * Cross Browser implementation of DOMContentLoaded. + */ +var domIsReady = false, domReadyQueue = [], readyState; +if ("readyState" in document) { + // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and + // 'interactive' (HTML5 specs, recent WebKit builds) states. + // https://bugs.webkit.org/show_bug.cgi?id=45119 + readyState = document.readyState; + domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive")); +} +else { + // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately + // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not. + // We only need a body to add elements to, so the existence of document.body is enough for us. + domIsReady = !!document.body; +} +function dom_onReady(){ + if (domIsReady) { + return; + } + domIsReady = true; + for (var i = 0; i < domReadyQueue.length; i++) { + domReadyQueue[i](); + } + domReadyQueue.length = 0; +} -var - version = "1.11.1", +if (!domIsReady) { + if (isHostMethod(window, "addEventListener")) { + on(document, "DOMContentLoaded", dom_onReady); + } + else { + on(document, "readystatechange", function(){ + if (document.readyState == "complete") { + dom_onReady(); + } + }); + if (document.documentElement.doScroll && window === top) { + var doScrollCheck = function(){ + if (domIsReady) { + return; + } + // http://javascript.nwbox.com/IEContentLoaded/ + try { + document.documentElement.doScroll("left"); + } + catch (e) { + setTimeout(doScrollCheck, 1); + return; + } + dom_onReady(); + }; + doScrollCheck(); + } + } + + // A fallback to window.onload, that will always work + on(window, "load", dom_onReady); +} +/** + * This will add a function to the queue of functions to be run once the DOM reaches a ready state. + * If functions are added after this event then they will be executed immediately. + * @param {function} fn The function to add + * @param {Object} scope An optional scope for the function to be called with. + */ +function whenReady(fn, scope){ + if (domIsReady) { + fn.call(scope); + return; + } + domReadyQueue.push(function(){ + fn.call(scope); + }); +} - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, +/** + * Returns an instance of easyXDM from the parent window with + * respect to the namespace. + * + * @return An instance of easyXDM (in the parent window) + */ +function getParentObject(){ + var obj = parent; + if (namespace !== "") { + for (var i = 0, ii = namespace.split("."); i < ii.length; i++) { + obj = obj[ii[i]]; + } + } + return obj.easyXDM; +} - // Support: Android<4.1, IE<9 - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, +/** + * Removes easyXDM variable from the global scope. It also returns control + * of the easyXDM variable to whatever code used it before. + * + * @param {String} ns A string representation of an object that will hold + * an instance of easyXDM. + * @return An instance of easyXDM + */ +function noConflict(ns){ + + window.easyXDM = _easyXDM; + namespace = ns; + if (namespace) { + IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_"; + } + return easyXDM; +} - toArray: function() { - return slice.call( this ); - }, +/* + * Methods for working with URLs + */ +/** + * Get the domain name from a url. + * @param {String} url The url to extract the domain from. + * @return The domain part of the url. + * @type {String} + */ +function getDomainName(url){ + return url.match(reURI)[3]; +} - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num != null ? +/** + * Get the port for a given URL, or "" if none + * @param {String} url The url to extract the port from. + * @return The port part of the url. + * @type {String} + */ +function getPort(url){ + return url.match(reURI)[4] || ""; +} - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : +/** + * Returns a string containing the schema, domain and if present the port + * @param {String} url The url to extract the location from + * @return {String} The location part of the url + */ +function getLocation(url){ + var m = url.toLowerCase().match(reURI); + var proto = m[2], domain = m[3], port = m[4] || ""; + if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) { + port = ""; + } + return proto + "//" + domain + port; +} - // Return all the elements in a clean array - slice.call( this ); - }, +/** + * Resolves a relative url into an absolute one. + * @param {String} url The path to resolve. + * @return {String} The resolved url. + */ +function resolveUrl(url){ + + // replace all // except the one in proto with / + url = url.replace(reDoubleSlash, "$1/"); + + // If the url is a valid url we do nothing + if (!url.match(/^(http||https):\/\//)) { + // If this is a relative path + var path = (url.substring(0, 1) === "/") ? "" : location.pathname; + if (path.substring(path.length - 1) !== "/") { + path = path.substring(0, path.lastIndexOf("/") + 1); + } + + url = location.protocol + "//" + location.host + path + url; + } + + // reduce all 'xyz/../' to just '' + while (reParent.test(url)) { + url = url.replace(reParent, ""); + } + + return url; +} - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { +/** + * Appends the parameters to the given url.
+ * The base url can contain existing query parameters. + * @param {String} url The base url. + * @param {Object} parameters The parameters to add. + * @return {String} A new valid url with the parameters appended. + */ +function appendQueryParameters(url, parameters){ + + var hash = "", indexOf = url.indexOf("#"); + if (indexOf !== -1) { + hash = url.substring(indexOf); + url = url.substring(0, indexOf); + } + var q = []; + for (var key in parameters) { + if (parameters.hasOwnProperty(key)) { + q.push(key + "=" + encodeURIComponent(parameters[key])); + } + } + return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash; +} - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; +// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash +var query = (function(input){ + input = input.substring(1).split("&"); + var data = {}, pair, i = input.length; + while (i--) { + pair = input[i].split("="); + data[pair[0]] = decodeURIComponent(pair[1]); + } + return data; +}(/xdm_e=/.test(location.search) ? location.search : location.hash)); - // Return the newly-formed element set - return ret; - }, +/* + * Helper methods + */ +/** + * Helper for checking if a variable/property is undefined + * @param {Object} v The variable to test + * @return {Boolean} True if the passed variable is undefined + */ +function undef(v){ + return typeof v === "undefined"; +} - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, +/** + * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works. + * @return {JSON} A valid JSON conforming object, or null if not found. + */ +var getJSON = function(){ + var cached = {}; + var obj = { + a: [1, 2, 3] + }, json = "{\"a\":[1,2,3]}"; + + if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) { + // this is a working JSON instance + return JSON; + } + if (Object.toJSON) { + if (Object.toJSON(obj).replace((/\s/g), "") === json) { + // this is a working stringify method + cached.stringify = Object.toJSON; + } + } + + if (typeof String.prototype.evalJSON === "function") { + obj = json.evalJSON(); + if (obj.a && obj.a.length === 3 && obj.a[2] === 3) { + // this is a working parse method + cached.parse = function(str){ + return str.evalJSON(); + }; + } + } + + if (cached.stringify && cached.parse) { + // Only memoize the result if we have valid instance + getJSON = function(){ + return cached; + }; + return cached; + } + return null; +}; - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, +/** + * Applies properties from the source object to the target object.
+ * @param {Object} target The target of the properties. + * @param {Object} source The source of the properties. + * @param {Boolean} noOverwrite Set to True to only set non-existing properties. + */ +function apply(destination, source, noOverwrite){ + var member; + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + if (prop in destination) { + member = source[prop]; + if (typeof member === "object") { + apply(destination[prop], member, noOverwrite); + } + else if (!noOverwrite) { + destination[prop] = source[prop]; + } + } + else { + destination[prop] = source[prop]; + } + } + } + return destination; +} - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, +// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName]. +function testForNamePropertyBug(){ + var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input")); + input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues + HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name]; + document.body.removeChild(form); +} - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: deletedIds.sort, - splice: deletedIds.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - /* jshint eqeqeq: false */ - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - // parseFloat NaNs numeric-cast false positives (null|true|false|"") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, +/** + * Creates a frame and appends it to the DOM. + * @param config {object} This object can have the following properties + * + * @return The frames DOMElement + * @type DOMElement + */ +function createFrame(config){ + if (undef(HAS_NAME_PROPERTY_BUG)) { + testForNamePropertyBug(); + } + var frame; + // This is to work around the problems in IE6/7 with setting the name property. + // Internally this is set as 'submitName' instead when using 'iframe.name = ...' + // This is not required by easyXDM itself, but is to facilitate other use cases + if (HAS_NAME_PROPERTY_BUG) { + frame = document.createElement(" - - diff --git a/src/vendor/easyXDM/example/widget.html b/src/vendor/easyXDM/example/widget.html deleted file mode 100644 index 5093eeb9..00000000 --- a/src/vendor/easyXDM/example/widget.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - easyXDM.Widget - - - - - - - - diff --git a/src/vendor/easyXDM/example/widgets.html b/src/vendor/easyXDM/example/widgets.html deleted file mode 100644 index 17bff037..00000000 --- a/src/vendor/easyXDM/example/widgets.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - easyXDM - - - - - - - -
- Index of examples - | Readme at github - | - | easyXDM.net - | easyXDM at Google Groups -
- The examples are executing slower than the production build due to the extensive tracing. -
- If you are alerted about a popup, then this is only the trace log feature. You can ignore this. -
- -
-
-
- -
-
- -
-
-
- - - - diff --git a/src/vendor/easyXDM/example/xhr.html b/src/vendor/easyXDM/example/xhr.html deleted file mode 100644 index a6d7f5d9..00000000 --- a/src/vendor/easyXDM/example/xhr.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - easyXDM - - - - - -
- Index of examples - | Readme at github - | - | easyXDM.net - | easyXDM at Google Groups -
- The examples are executing slower than the production build due to the extensive tracing. -
- If you are alerted about a popup, then this is only the trace log feature. You can ignore this. -
- - -
-
-
-
-
- This example shows how to use easyXDM to call regular ajax/cors services (no JSONP) from remote domains. -
- -
- Data from response: -
- Data from header: -
- - - - diff --git a/src/vendor/easyXDM/json2.js b/src/vendor/easyXDM/json2.js deleted file mode 100644 index a1a3b170..00000000 --- a/src/vendor/easyXDM/json2.js +++ /dev/null @@ -1,482 +0,0 @@ -/* - http://www.JSON.org/json2.js - 2010-03-20 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. - - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ - -/*jslint evil: true, strict: false */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (!this.JSON) { - this.JSON = {}; -} - -(function () { - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function (key) { - - return isFinite(this.valueOf()) ? - this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } - - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? - '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : - '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 ? '[]' : - gap ? '[\n' + gap + - partial.join(',\n' + gap) + '\n' + - mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - k = rep[i]; - if (typeof k === 'string') { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 ? '{}' : - gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + - mind + '}' : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/. -test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). -replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). -replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' ? - walk({'': j}, '') : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); diff --git a/src/vendor/easyXDM/name.html b/src/vendor/easyXDM/name.html deleted file mode 100644 index 137ef91e..00000000 --- a/src/vendor/easyXDM/name.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - diff --git a/src/vendor/easyXDM/tests/easyTest.css b/src/vendor/easyXDM/tests/easyTest.css deleted file mode 100644 index f14ca3fc..00000000 --- a/src/vendor/easyXDM/tests/easyTest.css +++ /dev/null @@ -1,14 +0,0 @@ -.easyTest_messages { -} - -.easyTest_error { - color: red; -} - -.easyTest_success { - color: green; -} - -.easyTest_msg { - color: black; -} \ No newline at end of file diff --git a/src/vendor/easyXDM/tests/easyTest.js b/src/vendor/easyXDM/tests/easyTest.js deleted file mode 100644 index 1da48125..00000000 --- a/src/vendor/easyXDM/tests/easyTest.js +++ /dev/null @@ -1,262 +0,0 @@ -var easyTest = (function(){ - var _messages; - var _start; - var MessageType = { - Error: 1, - Success: 2, - Info: 3 - }; - - /** - * Logs the message to the body - * @param {String} msg The message to displey - * @param {MessageType} type The messagetype - */ - function _log(msg, type){ - var el = _messages.appendChild(document.createElement("div")); - el.innerHTML = msg; - _messages.scrollTop = _messages.scrollHeight; - switch (type) { - case MessageType.Error: - el.className = "easyTest_error"; - break; - case MessageType.Success: - el.className = "easyTest_success"; - break; - default: - el.className = "easyTest_msg"; - break; - } - } - - var Assert = { - // Type checks - isTypeOf: function(type, obj){ - return typeof obj === type; - }, - isInstanceOf: function(type, obj){ - return obj instanceof type; - }, - isString: function(obj){ - return this.isTypeOf("string", obj); - }, - isNumber: function(obj){ - return this.isTypeOf("number", obj); - }, - isObject: function(obj){ - return this.isTypeOf("object", obj); - }, - isBoolean: function(obj){ - return this.isTypeOf("boolean", obj); - }, - isFunction: function(obj){ - return this.isTypeOf("function", obj); - }, - // Equality - areEqual: function(a, b){ - return a == b; - }, - areNotEqual: function(a, b){ - return a != b; - }, - // Identical - areSame: function(a, b){ - return a === b; - }, - areNotSame: function(a, b){ - return a !== b; - } - - }; - - function Test(test, fn){ - var _scope, _steps = test.steps, _step, _stepIndex = 0; - var _timer, _runStep, _startedAt, _stepStartedAt; - - /** - * Clean up and tear down the test.
- * Calls back to notify that the test is complete - */ - function _endTest(){ - // Tear down the test - if (test.tearDown) { - try { - test.tearDown.call(_scope); - } - catch (ex) { - _log("Teardown '" + ex.message + "(" + ex.fileName + ", " + ex.lineNumber + ")" + "'", MessageType.Error); - } - } - for (var key in _scope) { - if (_scope.hasOwnProperty(key)) { - delete _scope[key]; - } - } - - // Call back - fn(); - } - - /** - * Used to notify the framework of the result of the test - * @param {String} name The name of the test - * @param {Boolean} result The result of the test - * @param {String} reason An optional reason why the test returned the result - */ - function _notifyResult(name, result, reason){ - var now = new Date().getTime(); - var testsetTime = now - _start.getTime(); - var testTime = now - _startedAt.getTime(); - var stepTime = now - _stepStartedAt.getTime(); - - var times = testsetTime + "ms, " + testTime + "ms, " + stepTime + "ms - "; - if (result) { - _log(times + name + " succeeded! " + (reason || ""), MessageType.Success); - } - else { - _log(times + name + " failed! " + (reason || ""), MessageType.Error); - if (test.failedMessage) { - _log(test.failedMessage, MessageType.Info); - } - } - // Go to next step - if (result) { - _stepIndex++; - window.setTimeout(function(){ - _runStep(); - }, 0); - } - else { - _endTest(); - } - } - - - /** - * Runs through the test step - */ - _runStep = function(){ - if (_stepIndex < _steps.length) { - // We still have steps to run - _step = _steps[_stepIndex]; - _stepStartedAt = new Date(); - if (_step.timeout) { - // This an asynchronous test - _timer = window.setTimeout(function(){ - _notifyResult(_step.name, false, "Failed due to timeout."); - }, _step.timeout); - try { - _step.run.call(_scope); - } - catch (ex) { - //If it fails we cancel the timeout - window.clearTimeout(_timer); - _notifyResult(_step.name, false, "'" + ex.message + "(" + ex.fileName + ", " + ex.lineNumber + ")" + "'"); - } - } - else { - // This is a synchronous test - try { - var result = _step.run.call(_scope); - _notifyResult(_step.name, result); - } - catch (ex) { - _notifyResult(_step.name, false, "'" + ex.message + "(" + ex.fileName + ", " + ex.lineNumber + ")" + "'"); - } - } - } - else { - _endTest(); - } - }; - - return { - /** - * Runs the test. - * Will first try to execute the setup method before continuing the steps - */ - run: function(){ - var excuse; - if (test.runIf) { - excuse = test.runIf(); - } - if (excuse) { - _log("Skipping test ' " + test.name + "'. " + excuse); - fn(); - } - else { - _log("Running test '" + test.name + "'"); - _scope = { - Assert: Assert, - log: _log, - notifyResult: function(result){ - window.clearTimeout(_timer); - _notifyResult(_step.name, result); - } - }; - if (test.setUp) { - // Setup the test - try { - test.setUp.call(_scope); - _log("Setup succeeded", MessageType.Success); - } - catch (ex) { - _log("Setup failed", MessageType.Error); - } - } - _startedAt = new Date(); - _runStep(); - } - } - }; - } - - return { - /** - * Runs through all the tests - * @param {Array} tests The tests to run - */ - test: function(testset){ - var tests = [], testConfig, i = testset.length, test; - - // Prepare the messaging facilities - if (!_messages) { - _messages = document.createElement("div"); - _messages.className = "easyTest_messages"; - (document.getElementById("messages") || document.body).appendChild(_messages); - } - else { - _messages.innerHTML = ""; - } - - // Convert the testset - while (i--) { - testConfig = testset[i]; - if (!testConfig.steps) { - // Convert a single step test to a proper test - testConfig = { - steps: testConfig - }; - } - - tests.push(new Test(testConfig, function(){ - // Get the next test to run - test = tests.pop(); - if (test) { - // This is needed to avoid a strange bug in Opera, - window.setTimeout(function(){ - test.run(); - }, 0); - } - else { - // No more tests to run - _log("Test run complete", MessageType.Info); - } - })); - } - // Start the first test - _start = new Date(); - tests.pop().run(); - } - }; -}()); diff --git a/src/vendor/easyXDM/tests/easyXDM.debug.js b/src/vendor/easyXDM/tests/easyXDM.debug.js deleted file mode 100644 index 2ee6f377..00000000 --- a/src/vendor/easyXDM/tests/easyXDM.debug.js +++ /dev/null @@ -1,2856 +0,0 @@ -(function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) { -/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/ -/*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */ -// -// easyXDM -// http://easyxdm.net/ -// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -var global = this; -var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded -var emptyFn = Function.prototype; -var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4) -var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression -var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol -var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global) -var easyXDM = {}; -var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite -var IFRAME_PREFIX = "easyXDM_"; -var HAS_NAME_PROPERTY_BUG; -var useHash = false; // whether to use the hash over the query -var flashVersion; // will be set if using flash -var HAS_FLASH_THROTTLED_BUG; -var _trace = emptyFn; - - -// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting -function isHostMethod(object, property){ - var t = typeof object[property]; - return t == 'function' || - (!!(t == 'object' && object[property])) || - t == 'unknown'; -} - -function isHostObject(object, property){ - return !!(typeof(object[property]) == 'object' && object[property]); -} - -// end - -// http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/ -function isArray(o){ - return Object.prototype.toString.call(o) === '[object Array]'; -} - -// end -function hasFlash(){ - var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash"; - - if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") { - // adapted from the swfobject code - var description = navigator.plugins[name].description; - if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) { - flashVersion = description.match(/\d+/g); - } - } - if (!flashVersion) { - var flash; - try { - flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1); - flash = null; - } - catch (notSupportedException) { - } - } - if (!flashVersion) { - return false; - } - var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10); - HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0; - return true; -} - -/* - * Cross Browser implementation for adding and removing event listeners. - */ -var on, un; -if (isHostMethod(window, "addEventListener")) { - on = function(target, type, listener){ - _trace("adding listener " + type); - target.addEventListener(type, listener, false); - }; - un = function(target, type, listener){ - _trace("removing listener " + type); - target.removeEventListener(type, listener, false); - }; -} -else if (isHostMethod(window, "attachEvent")) { - on = function(object, sEvent, fpNotify){ - _trace("adding listener " + sEvent); - object.attachEvent("on" + sEvent, fpNotify); - }; - un = function(object, sEvent, fpNotify){ - _trace("removing listener " + sEvent); - object.detachEvent("on" + sEvent, fpNotify); - }; -} -else { - throw new Error("Browser not supported"); -} - -/* - * Cross Browser implementation of DOMContentLoaded. - */ -var domIsReady = false, domReadyQueue = [], readyState; -if ("readyState" in document) { - // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and - // 'interactive' (HTML5 specs, recent WebKit builds) states. - // https://bugs.webkit.org/show_bug.cgi?id=45119 - readyState = document.readyState; - domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive")); -} -else { - // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately - // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not. - // We only need a body to add elements to, so the existence of document.body is enough for us. - domIsReady = !!document.body; -} - -function dom_onReady(){ - if (domIsReady) { - return; - } - domIsReady = true; - _trace("firing dom_onReady"); - for (var i = 0; i < domReadyQueue.length; i++) { - domReadyQueue[i](); - } - domReadyQueue.length = 0; -} - - -if (!domIsReady) { - if (isHostMethod(window, "addEventListener")) { - on(document, "DOMContentLoaded", dom_onReady); - } - else { - on(document, "readystatechange", function(){ - if (document.readyState == "complete") { - dom_onReady(); - } - }); - if (document.documentElement.doScroll && window === top) { - var doScrollCheck = function(){ - if (domIsReady) { - return; - } - // http://javascript.nwbox.com/IEContentLoaded/ - try { - document.documentElement.doScroll("left"); - } - catch (e) { - setTimeout(doScrollCheck, 1); - return; - } - dom_onReady(); - }; - doScrollCheck(); - } - } - - // A fallback to window.onload, that will always work - on(window, "load", dom_onReady); -} -/** - * This will add a function to the queue of functions to be run once the DOM reaches a ready state. - * If functions are added after this event then they will be executed immediately. - * @param {function} fn The function to add - * @param {Object} scope An optional scope for the function to be called with. - */ -function whenReady(fn, scope){ - if (domIsReady) { - fn.call(scope); - return; - } - domReadyQueue.push(function(){ - fn.call(scope); - }); -} - -/** - * Returns an instance of easyXDM from the parent window with - * respect to the namespace. - * - * @return An instance of easyXDM (in the parent window) - */ -function getParentObject(){ - var obj = parent; - if (namespace !== "") { - for (var i = 0, ii = namespace.split("."); i < ii.length; i++) { - if (!obj) { - throw new Error(ii.slice(0, i + 1).join('.') + ' is not an object'); - } - obj = obj[ii[i]]; - } - } - if (!obj || !obj.easyXDM) { - throw new Error('Could not find easyXDM in parent.' + namespace); - } - return obj.easyXDM; -} - -/** - * Removes easyXDM variable from the global scope. It also returns control - * of the easyXDM variable to whatever code used it before. - * - * @param {String} ns A string representation of an object that will hold - * an instance of easyXDM. - * @return An instance of easyXDM - */ -function noConflict(ns){ - if (typeof ns != "string" || !ns) { - throw new Error('namespace must be a non-empty string'); - } - _trace("Settings namespace to '" + ns + "'"); - - window.easyXDM = _easyXDM; - namespace = ns; - if (namespace) { - IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_"; - } - return easyXDM; -} - -/* - * Methods for working with URLs - */ -/** - * Get the domain name from a url. - * @param {String} url The url to extract the domain from. - * @return The domain part of the url. - * @type {String} - */ -function getDomainName(url){ - if (!url) { - throw new Error("url is undefined or empty"); - } - return url.match(reURI)[3]; -} - -/** - * Get the port for a given URL, or "" if none - * @param {String} url The url to extract the port from. - * @return The port part of the url. - * @type {String} - */ -function getPort(url){ - if (!url) { - throw new Error("url is undefined or empty"); - } - return url.match(reURI)[4] || ""; -} - -/** - * Returns a string containing the schema, domain and if present the port - * @param {String} url The url to extract the location from - * @return {String} The location part of the url - */ -function getLocation(url){ - if (!url) { - throw new Error("url is undefined or empty"); - } - if (/^file/.test(url)) { - throw new Error("The file:// protocol is not supported"); - } - var m = url.toLowerCase().match(reURI); - var proto = m[2], domain = m[3], port = m[4] || ""; - if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) { - port = ""; - } - return proto + "//" + domain + port; -} - -/** - * Resolves a relative url into an absolute one. - * @param {String} url The path to resolve. - * @return {String} The resolved url. - */ -function resolveUrl(url){ - if (!url) { - throw new Error("url is undefined or empty"); - } - - // replace all // except the one in proto with / - url = url.replace(reDoubleSlash, "$1/"); - - // If the url is a valid url we do nothing - if (!url.match(/^(http||https):\/\//)) { - // If this is a relative path - var path = (url.substring(0, 1) === "/") ? "" : location.pathname; - if (path.substring(path.length - 1) !== "/") { - path = path.substring(0, path.lastIndexOf("/") + 1); - } - - url = location.protocol + "//" + location.host + path + url; - } - - // reduce all 'xyz/../' to just '' - while (reParent.test(url)) { - url = url.replace(reParent, ""); - } - - _trace("resolved url '" + url + "'"); - return url; -} - -/** - * Appends the parameters to the given url.
- * The base url can contain existing query parameters. - * @param {String} url The base url. - * @param {Object} parameters The parameters to add. - * @return {String} A new valid url with the parameters appended. - */ -function appendQueryParameters(url, parameters){ - if (!parameters) { - throw new Error("parameters is undefined or null"); - } - - var hash = "", indexOf = url.indexOf("#"); - if (indexOf !== -1) { - hash = url.substring(indexOf); - url = url.substring(0, indexOf); - } - var q = []; - for (var key in parameters) { - if (parameters.hasOwnProperty(key)) { - q.push(key + "=" + encodeURIComponent(parameters[key])); - } - } - return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash; -} - - -// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash -var query = (function(input){ - input = input.substring(1).split("&"); - var data = {}, pair, i = input.length; - while (i--) { - pair = input[i].split("="); - data[pair[0]] = decodeURIComponent(pair[1]); - } - return data; -}(/xdm_e=/.test(location.search) ? location.search : location.hash)); - -/* - * Helper methods - */ -/** - * Helper for checking if a variable/property is undefined - * @param {Object} v The variable to test - * @return {Boolean} True if the passed variable is undefined - */ -function undef(v){ - return typeof v === "undefined"; -} - -/** - * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works. - * @return {JSON} A valid JSON conforming object, or null if not found. - */ -var getJSON = function(){ - var cached = {}; - var obj = { - a: [1, 2, 3] - }, json = "{\"a\":[1,2,3]}"; - - if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) { - // this is a working JSON instance - return JSON; - } - if (Object.toJSON) { - if (Object.toJSON(obj).replace((/\s/g), "") === json) { - // this is a working stringify method - cached.stringify = Object.toJSON; - } - } - - if (typeof String.prototype.evalJSON === "function") { - obj = json.evalJSON(); - if (obj.a && obj.a.length === 3 && obj.a[2] === 3) { - // this is a working parse method - cached.parse = function(str){ - return str.evalJSON(); - }; - } - } - - if (cached.stringify && cached.parse) { - // Only memoize the result if we have valid instance - getJSON = function(){ - return cached; - }; - return cached; - } - return null; -}; - -/** - * Applies properties from the source object to the target object.
- * @param {Object} target The target of the properties. - * @param {Object} source The source of the properties. - * @param {Boolean} noOverwrite Set to True to only set non-existing properties. - */ -function apply(destination, source, noOverwrite){ - var member; - for (var prop in source) { - if (source.hasOwnProperty(prop)) { - if (prop in destination) { - member = source[prop]; - if (typeof member === "object") { - apply(destination[prop], member, noOverwrite); - } - else if (!noOverwrite) { - destination[prop] = source[prop]; - } - } - else { - destination[prop] = source[prop]; - } - } - } - return destination; -} - -// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName]. -function testForNamePropertyBug(){ - var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input")); - input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues - HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name]; - document.body.removeChild(form); - _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG); -} - -/** - * Creates a frame and appends it to the DOM. - * @param config {object} This object can have the following properties - * - * @return The frames DOMElement - * @type DOMElement - */ -function createFrame(config){ - _trace("creating frame: " + config.props.src); - if (undef(HAS_NAME_PROPERTY_BUG)) { - testForNamePropertyBug(); - } - var frame; - // This is to work around the problems in IE6/7 with setting the name property. - // Internally this is set as 'submitName' instead when using 'iframe.name = ...' - // This is not required by easyXDM itself, but is to facilitate other use cases - if (HAS_NAME_PROPERTY_BUG) { - frame = document.createElement("