diff --git a/Gruntfile.js b/Gruntfile.js index 9aa23612742..78f2da5358a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -19,76 +19,76 @@ var util = require('util'); var vm = require('vm'); module.exports = function(grunt) { - // Project configuration. grunt.initConfig({ - 'pkg': '', - 'meta': { - 'banner': '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + - '<%= grunt.template.today("yyyy-mm-dd") %>\n' + - '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' + - '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + - ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */' + pkg: '', + meta: { + banner: + '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + + '<%= grunt.template.today("yyyy-mm-dd") %>\n' + + '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' + + '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + + ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */', }, - 'target': process.env['DESTDIR'] || 'target', - 'qunit': { - 'files': ['tests/qunit/tests/*.html'] + target: process.env['DESTDIR'] || 'target', + qunit: { + files: ['tests/qunit/tests/*.html'], }, - 'lint': { - 'files': [ + lint: { + files: [ 'grunt.js', 'admin/**/*.js', 'shared/**/*.js', 'ui/**/*.js', 'node_modules/oae-*/**/*.js', - '!node_modules/oae-release-tools/**' - ] + '!node_modules/oae-release-tools/**', + ], }, - 'watch': { - 'files': '', - 'tasks': 'lint test' + watch: { + files: '', + tasks: 'lint test', }, - 'csslint': { - 'options': { - 'ids': false // ignore "Don't use IDs in CSS selectors" warning + csslint: { + options: { + ids: false, // ignore "Don't use IDs in CSS selectors" warning }, - 'files': [ + files: [ 'admin/**/*.css', 'shared/oae/**/*.css', 'ui/**/*.css', 'node_modules/oae-*/**/*.css', - '!node_modules/oae-release-tools/**' - ] + '!node_modules/oae-release-tools/**', + ], }, - 'jshint': { - 'options': { - 'node': true, - 'sub': true, - 'indent': 4, - 'trailing': true, - 'quotmark': 'single', - 'curly': true, - 'white': false, - 'strict': false, - 'esversion': 6 + jshint: { + options: { + node: true, + sub: true, + indent: 4, + trailing: true, + quotmark: 'single', + curly: true, + white: false, + strict: false, + esversion: 6, }, - 'files': [ + files: [ 'admin/**/*.js', 'shared/oae/**/*.js', 'ui/**/*.js', 'node_modules/oae-*/**/*.js', - '!node_modules/oae-release-tools/**' - ] + '!node_modules/oae-release-tools/**', + ], }, - 'clean': { - 'folder': '<%= target %>/' + clean: { + folder: '<%= target %>/', }, - 'copy': { - 'main': { - 'files': [ + copy: { + main: { + files: [ { - 'expand': true, - 'src': [ + expand: true, + src: [ '**', '!<%= target %>/**', '!tests/**', @@ -99,50 +99,52 @@ module.exports = function(grunt) { '!node_modules/optimist/**', '!node_modules/properties-parser/**', '!node_modules/readdirp/**', - '!node_modules/underscore/**' + '!node_modules/underscore/**', ], - 'dest': '<%= target %>/original' - } - ] - } + dest: '<%= target %>/original', + }, + ], + }, }, - 'requirejs': { - 'optimize': { - 'options': { - 'appDir': './', - 'baseUrl': './shared', - 'mainConfigFile': './shared/oae/api/oae.bootstrap.js', - 'dir': '<%= target %>/optimized', - 'optimize': 'uglify', - 'uglify2': { - 'output': { - 'max_line_len': 500000 - } + requirejs: { + optimize: { + options: { + appDir: './', + baseUrl: './shared', + mainConfigFile: './shared/oae/api/oae.bootstrap.js', + dir: '<%= target %>/optimized', + optimize: 'uglify', + uglify2: { + output: { + max_line_len: 500000, + }, }, - 'preserveLicenseComments': false, - 'optimizeCss': 'standard', + preserveLicenseComments: false, + optimizeCss: 'standard', // TODO: Replace this with a saner value // @see https://github.com/jrburke/r.js/pull/653 - 'cssImportIgnore': '//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,400,300,600,700&subset=latin,cyrillic-ext,latin-ext,greek-ext', - 'inlineText': true, - 'useStrict': false, - 'pragmas': {}, - 'skipPragmas': false, - 'skipModuleInsertion': false, - 'modules': [{ - 'name': 'oae.core', - 'exclude': ['jquery'] - }], - 'fileExclusionRegExp': /^(\.|<%= target %>|tests|tools|grunt|optimist|properties-parser|readdirp|underscore$|shelljs$|oae-release-tools|mkdirp|es6-promise|cssstyle|resolve|nwmatcher|strip-json-comments|glob$|har-validator|boom|cryptiles|debug|benchmark|hawk|hoek|sntp|json-schema-traverse|robots\.txt)/, - 'logLevel': 2 - } - } + cssImportIgnore: + '//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,400,300,600,700&subset=latin,cyrillic-ext,latin-ext,greek-ext', + inlineText: true, + useStrict: false, + pragmas: {}, + skipPragmas: false, + skipModuleInsertion: false, + modules: [ + { + name: 'oae.core', + exclude: ['jquery'], + }, + ], + fileExclusionRegExp: /^(\.|<%= target %>|tests|tools|grunt|optimist|properties-parser|readdirp|underscore$|shelljs$|oae-release-tools|mkdirp|es6-promise|cssstyle|resolve|nwmatcher|strip-json-comments|glob$|har-validator|boom|cryptiles|debug|benchmark|hawk|hoek|sntp|json-schema-traverse|robots\.txt)/, + logLevel: 2, + }, + }, }, - 'ver': { - 'oae': { - 'basedir': '<%= target %>/optimized', - 'phases': [ - + ver: { + oae: { + basedir: '<%= target %>/optimized', + phases: [ /*! * In the first phase, we hash the contents of all the shared bundle and culture * folders and rename the foler to contain the hash. All references to the @@ -150,14 +152,12 @@ module.exports = function(grunt) { * JS files as those are the only places we have references to them. */ { - 'folders': [ + folders: [ '<%= target %>/optimized/shared/oae/bundles/ui', '<%= target %>/optimized/shared/oae/bundles/email', - '<%= target %>/optimized/shared/vendor/js/l10n/cultures' + '<%= target %>/optimized/shared/vendor/js/l10n/cultures', ], - 'references': [ - '<%= target %>/optimized/shared/**/*.js' - ] + references: ['<%= target %>/optimized/shared/**/*.js'], }, /*! @@ -176,46 +176,42 @@ module.exports = function(grunt) { * TODO: Remove "custom" when there is a proper landing page customization strategy */ { - 'files': _hashFiles({ - 'directories': [ + files: _hashFiles({ + directories: [ '<%= target %>/optimized/admin', '<%= target %>/optimized/custom', '<%= target %>/optimized/docs', '<%= target %>/optimized/shared', - '<%= target %>/optimized/ui' + '<%= target %>/optimized/ui', ], - 'excludeExts': [ + excludeExts: [ 'css', 'html', 'ico', 'js', 'json', - 'less' + 'less', ], - 'extra': [ + extra: [ '!<%= target %>/optimized/shared/oae/bundles/email.*/**', '!<%= target %>/optimized/shared/oae/bundles/ui.*/**', - '!<%= target %>/optimized/shared/vendor/js/l10n/cultures.*/**' - ] + '!<%= target %>/optimized/shared/vendor/js/l10n/cultures.*/**', + ], }), - 'references': _replacementReferences({ - 'directories': [ + references: _replacementReferences({ + directories: [ '<%= target %>/optimized/admin', '<%= target %>/optimized/custom', '<%= target %>/optimized/docs', '<%= target %>/optimized/node_modules/oae-*', '<%= target %>/optimized/shared', - '<%= target %>/optimized/ui' + '<%= target %>/optimized/ui', ], - 'includeExts': [ - 'css', - 'html', - 'js' + includeExts: ['css', 'html', 'js'], + extra: [ + '<%= target %>/optimized/shared/oae/macros/*.html', ], - 'extra': [ - '<%= target %>/optimized/shared/oae/macros/*.html' - ] - }) + }), }, /*! @@ -223,8 +219,10 @@ module.exports = function(grunt) { * files in the shared directory. */ { - 'files': ['<%= target %>/optimized/shared/oae/macros/*.html'], - 'references': ['<%= target %>/optimized/shared/**/*.js'] + files: [ + '<%= target %>/optimized/shared/oae/macros/*.html', + ], + references: ['<%= target %>/optimized/shared/**/*.js'], }, /*! @@ -237,28 +235,25 @@ module.exports = function(grunt) { * TODO: Remove "custom" when there is a proper landing page customization strategy */ { - 'files': [ + files: [ '<%= target %>/optimized/shared/**/*.js', '<%= target %>/optimized/shared/**/*.css', - '!<%= target %>/optimized/shared/vendor/js/l10n/cultures.*/**' + '!<%= target %>/optimized/shared/vendor/js/l10n/cultures.*/**', ], - 'references': _replacementReferences({ - 'directories': [ + references: _replacementReferences({ + directories: [ '<%= target %>/optimized/admin', '<%= target %>/optimized/custom', '<%= target %>/optimized/docs', '<%= target %>/optimized/node_modules/oae-*', '<%= target %>/optimized/shared', - '<%= target %>/optimized/ui' + '<%= target %>/optimized/ui', ], - 'includeExts': [ - 'html', - 'js' + includeExts: ['html', 'js'], + extra: [ + '<%= target %>/optimized/shared/oae/macros/*.html', ], - 'extra': [ - '<%= target %>/optimized/shared/oae/macros/*.html' - ] - }) + }), }, /*! @@ -274,161 +269,259 @@ module.exports = function(grunt) { * TODO: Remove "custom" when there is a proper landing page customization strategy */ { - 'folders': [ + folders: [ '<%= target %>/optimized/admin/js', '<%= target %>/optimized/custom/js', '<%= target %>/optimized/docs/js', - '<%= target %>/optimized/ui/js' + '<%= target %>/optimized/ui/js', ], - 'files': [ + files: [ '<%= target %>/optimized/admin/**/*.css', '<%= target %>/optimized/docs/**/*.css', '<%= target %>/optimized/custom/**/*.css', - '<%= target %>/optimized/ui/**/*.css' + '<%= target %>/optimized/ui/**/*.css', ], - 'references': _replacementReferences({ - 'directories': [ + references: _replacementReferences({ + directories: [ '<%= target %>/optimized/admin', '<%= target %>/optimized/custom', '<%= target %>/optimized/docs', '<%= target %>/optimized/node_modules/oae-*', - '<%= target %>/optimized/ui' + '<%= target %>/optimized/ui', ], - 'includeExts': [ - 'html', - 'js' + includeExts: ['html', 'js'], + extra: [ + '<%= target %>/optimized/shared/oae/macros/*.html', ], - 'extra': [ - '<%= target %>/optimized/shared/oae/macros/*.html' - ] - }) - } + }), + }, ], - 'version': '<%= target %>/optimized/hashes.json' - } + version: '<%= target %>/optimized/hashes.json', + }, }, - 'replace': { - 'url': 'URL pointing to a CDN that gets set by the cdn task', - 'main': { - 'src': [ + replace: { + url: 'URL pointing to a CDN that gets set by the cdn task', + main: { + src: [ 'target/optimized/ui/*.html', 'target/optimized/ui/custom/*.html', 'target/optimized/admin/*.html', 'target/optimized/shared/oae/api/oae.bootstrap.*.js', - 'target/optimized/shared/oae/api/oae.core.*.js' + 'target/optimized/shared/oae/api/oae.core.*.js', ], - 'overwrite': true, - 'replacements': [ + overwrite: true, + replacements: [ { - 'from': /(src)="\/(.+?)"/ig, - 'to': function(matchedWord, index, fullText, regexMatches) { - return _cdnifyStaticAsset(grunt.config('replace').url, matchedWord, index, fullText, regexMatches); - } + from: /(src)="\/(.+?)"/gi, + to: function( + matchedWord, + index, + fullText, + regexMatches, + ) { + return _cdnifyStaticAsset( + grunt.config('replace').url, + matchedWord, + index, + fullText, + regexMatches, + ); + }, }, { - 'from': /(data-loadmodule)="\/(.+?)"/ig, - 'to': function(matchedWord, index, fullText, regexMatches) { - return _cdnifyStaticAsset(grunt.config('replace').url, matchedWord, index, fullText, regexMatches); - } + from: /(data-loadmodule)="\/(.+?)"/gi, + to: function( + matchedWord, + index, + fullText, + regexMatches, + ) { + return _cdnifyStaticAsset( + grunt.config('replace').url, + matchedWord, + index, + fullText, + regexMatches, + ); + }, }, { - 'from': /(data-main)="\/(.+?)"/ig, - 'to': function(matchedWord, index, fullText, regexMatches) { - return _cdnifyStaticAsset(grunt.config('replace').url, matchedWord, index, fullText, regexMatches); - } + from: /(data-main)="\/(.+?)"/gi, + to: function( + matchedWord, + index, + fullText, + regexMatches, + ) { + return _cdnifyStaticAsset( + grunt.config('replace').url, + matchedWord, + index, + fullText, + regexMatches, + ); + }, }, { - 'from': /("}'); - grunt.file.write(grunt.config('target') + '/optimized/ui/version.json', json); + var json = grunt.template.process( + '{"oae:ux-version":"<%= meta.version %>"}', + ); + grunt.file.write( + grunt.config('target') + '/optimized/ui/version.json', + json, + ); }); // Task to fill out the nginx config template @@ -490,11 +595,13 @@ module.exports = function(grunt) { var template = grunt.file.read('./nginx/nginx.conf'); grunt.config.set('nginxConf', nginxConfig); var config = grunt.template.process(template); - var outfile = grunt.config('target') + '/optimized/nginx/nginx.conf'; + var outfile = + grunt.config('target') + '/optimized/nginx/nginx.conf'; grunt.file.write(outfile, config); grunt.log.writeln('nginx.conf rendered at '.green + outfile.green); } else { - var msg = 'No ' + infile + ' found, not rendering nginx.conf template'; + var msg = + 'No ' + infile + ' found, not rendering nginx.conf template'; grunt.log.writeln(msg.yellow); } }); @@ -505,7 +612,14 @@ module.exports = function(grunt) { // as a result grunt.registerTask('touchBootstrap', function() { // Just place a comment in the file with the current timestamp - util.format('\n// Date Built: %d', Date.now()).toEnd(util.format('%s/optimized/shared/oae/api/oae.bootstrap.js', grunt.config('target'))); + util + .format('\n// Date Built: %d', Date.now()) + .toEnd( + util.format( + '%s/optimized/shared/oae/api/oae.bootstrap.js', + grunt.config('target'), + ), + ); }); // Task to hash files @@ -514,7 +628,10 @@ module.exports = function(grunt) { this.requires('touchBootstrap'); // Add a new ver task for each module that needs to be optimized - var oaeModules = grunt.file.expand({filter:'isDirectory'}, grunt.config('target') + '/optimized/node_modules/oae-*/*'); + var oaeModules = grunt.file.expand( + { filter: 'isDirectory' }, + grunt.config('target') + '/optimized/node_modules/oae-*/*', + ); oaeModules.forEach(function(module) { grunt.log.writeln(module); @@ -522,11 +639,10 @@ module.exports = function(grunt) { util.format('%s/**/*.css', module), util.format('%s/**/*.html', module), util.format('%s/**/*.js', module), - util.format('%s/**/*.json', module) + util.format('%s/**/*.json', module), ]; var phases = [ - /*! * First, hash all files that do not have references to other files. That's * basically everything except HTML, JS, CSS files. Additionally, we @@ -538,21 +654,25 @@ module.exports = function(grunt) { * deterministic name */ { - 'files': _hashFiles({ - 'directories': [module], - 'excludeExts': ['css', 'html', 'js', 'json', 'properties'] + files: _hashFiles({ + directories: [module], + excludeExts: [ + 'css', + 'html', + 'js', + 'json', + 'properties', + ], }), - 'references': moduleReferences.slice() + references: moduleReferences.slice(), }, /*! * Second, hash the bundles directories of the widgets */ { - 'folders': [ - util.format('%s/bundles', module) - ], - 'references': moduleReferences.slice() + folders: [util.format('%s/bundles', module)], + references: moduleReferences.slice(), }, /*! @@ -578,11 +698,11 @@ module.exports = function(grunt) { * See https://github.com/oaeproject/3akai-ux/issues/3551 for more information. */ { - 'files': [ + files: [ util.format('%s/**/*.css', module), - util.format('%s/**/*.js', module) + util.format('%s/**/*.js', module), ], - 'references': [util.format('%s/**/*.html', module)] + references: [util.format('%s/**/*.html', module)], }, /*! @@ -602,9 +722,9 @@ module.exports = function(grunt) { * first. */ { - 'files': [util.format('%s/**/*.html', module)], - 'references': [util.format('%s/**/*.json', module)] - } + files: [util.format('%s/**/*.html', module)], + references: [util.format('%s/**/*.json', module)], + }, ]; grunt.config.set(util.format('ver.%s.basedir', module), module); @@ -614,7 +734,6 @@ module.exports = function(grunt) { grunt.task.run('ver:oae'); grunt.task.run('updateBootstrapPaths'); - }); // Task to update the paths in oae.bootstrap to the hashed versions @@ -623,7 +742,8 @@ module.exports = function(grunt) { var basedir = grunt.config('target') + '/optimized/'; var hashedPaths = require('./' + grunt.config.get('ver.oae.version')); - var bootstrapPath = basedir + hashedPaths['/shared/oae/api/oae.bootstrap.js']; + var bootstrapPath = + basedir + hashedPaths['/shared/oae/api/oae.bootstrap.js']; var bootstrap = grunt.file.read(bootstrapPath); var regex = /("|')?paths("|')?: ?\{[^}]*\}/; var scriptPaths = 'paths = {' + bootstrap.match(regex)[0] + '}'; @@ -638,7 +758,10 @@ module.exports = function(grunt) { if (hashedPaths[path]) { hashedPath = hashedPaths[path]; // trim off prefix and .js - paths[key] = hashedPath.substring(prefix.length, hashedPath.length - 3); + paths[key] = hashedPath.substring( + prefix.length, + hashedPath.length - 3, + ); } }); bootstrap = bootstrap.replace(regex, 'paths:' + JSON.stringify(paths)); @@ -670,17 +793,25 @@ module.exports = function(grunt) { // A task that will copy the release files to a directory of your choosing grunt.registerTask('copyReleaseArtifacts', function(outputDir) { if (!outputDir) { - return grunt.log.writeln('Please provide a path where the release files should be copied to'.red); + return grunt.log.writeln( + 'Please provide a path where the release files should be copied to' + .red, + ); } var config = { - 'files': [ + files: [ { - 'expand': true, - 'src': ['./<%= grunt.config("target") %>/*', './README.md', './LICENSE', './COMMITTERS.txt'], - 'dest': outputDir - } - ] + expand: true, + src: [ + './<%= grunt.config("target") %>/*', + './README.md', + './LICENSE', + './COMMITTERS.txt', + ], + dest: outputDir, + }, + ], }; grunt.config.set('copy.release', config); grunt.task.run('copy:release'); @@ -697,7 +828,10 @@ module.exports = function(grunt) { // /tmp/release/original - contains the original UI files grunt.registerTask('release', function(outputDir) { if (!outputDir) { - return grunt.log.writeln('Please provide a path where the release files should be copied to'.red); + return grunt.log.writeln( + 'Please provide a path where the release files should be copied to' + .red, + ); } // Run the default task that will minify and hash all the UI files. @@ -709,7 +843,7 @@ module.exports = function(grunt) { }); // Lint tasks (JavaScript only for now, too many errors in css) - grunt.registerTask('lint', ['jshint' /*, 'csslint' */ ]); + grunt.registerTask('lint', ['jshint' /*, 'csslint' */]); // Wrap the QUnit task grunt.renameTask('qunit', 'contrib-qunit'); @@ -717,13 +851,18 @@ module.exports = function(grunt) { // Fall back to the `qunit-host` option host = host || grunt.option('qunit-host'); if (!host) { - return grunt.fail.fatal('Please provide a link to a running OAE instance. e.g. `grunt qunit:tenant1.oae.com` or `grunt qunit --qunit-host tenant1.oae.com`'); + return grunt.fail.fatal( + 'Please provide a link to a running OAE instance. e.g. `grunt qunit:tenant1.oae.com` or `grunt qunit --qunit-host tenant1.oae.com`', + ); } - var urls = _.map(grunt.file.expand(grunt.config.get('qunit.files')), function(file) { - return 'http://' + host + '/' + file; - }); - var config = {'options': {'urls': urls}}; + var urls = _.map( + grunt.file.expand(grunt.config.get('qunit.files')), + function(file) { + return 'http://' + host + '/' + file; + }, + ); + var config = { options: { urls: urls } }; grunt.config.set('contrib-qunit.all', config); grunt.task.run('contrib-qunit'); }); @@ -741,14 +880,26 @@ module.exports = function(grunt) { path = path || grunt.option('path'); if (!path) { - return grunt.fail.fatal('Please provide a path to a CasperJS test file. e.g. `grunt test-file --path=node_modules/oae-core/preferences/tests/preferences.js`'); + return grunt.fail.fatal( + 'Please provide a path to a CasperJS test file. e.g. `grunt test-file --path=node_modules/oae-core/preferences/tests/preferences.js`', + ); } grunt.task.run('exec:runCasperTest:' + path); }); // Default task for production build - grunt.registerTask('default', ['clean', 'copy', 'git-describe', 'requirejs', 'touchBootstrap', 'hashFiles', 'cdn', 'writeVersion', 'configNginx']); + grunt.registerTask('default', [ + 'clean', + 'copy', + 'git-describe', + 'requirejs', + 'touchBootstrap', + 'hashFiles', + 'cdn', + 'writeVersion', + 'configNginx', + ]); }; /** @@ -805,7 +956,6 @@ var _hashFiles = function(options) { return _.union(globs, options.extra); }; - /** * Prepend the CDN url for those static assets that are not delivered by either * the OAE APIs or other external hosts @@ -818,13 +968,22 @@ var _hashFiles = function(options) { * @return {String} The string that will replace `matchedWord` * @api private */ -var _cdnifyStaticAsset = function(cdn, matchedWord, index, fullText, regexMatches) { +var _cdnifyStaticAsset = function( + cdn, + matchedWord, + index, + fullText, + regexMatches, +) { // Get the name of the attribute (e.g., `src`, `data-main`, ...) var attr = regexMatches[0]; // Do not replace anything that already points to an outside source // e.g., do not cdnify src="//www.youtube" or href="https://foo.com/asset.jpg" - if (regexMatches[1].indexOf('/') === 0 || regexMatches[1].indexOf('api') === 0) { + if ( + regexMatches[1].indexOf('/') === 0 || + regexMatches[1].indexOf('api') === 0 + ) { return matchedWord; } diff --git a/admin/js/admin.js b/admin/js/admin.js index 32b715ad303..3c9fa53d8f1 100644 --- a/admin/js/admin.js +++ b/admin/js/admin.js @@ -13,8 +13,11 @@ * permissions and limitations under the License. */ -require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, oae) { - +require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function( + $, + _, + oae, +) { // Variable that will be used to keep track of the current tenant var currentContext = null; // Variable that will cache the configuration schema @@ -22,7 +25,6 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o // Variable that will cache the configuration for the current tenant var configuration = null; - ///////////////// // NAVIGATION // ///////////////// @@ -34,81 +36,85 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o // Structure that will be used to construct the left hand navigation pages var lhNavPages = null; if (oae.data.me.anon) { - lhNavPages = [{ - 'id': 'adminlogin', - 'title': oae.api.i18n.translate('__MSG__SIGN_IN__'), - 'layout': [ - { - 'width': 'col-md-12', - 'widgets': [ - { - 'name': 'adminlogin' - } - ] - } - ] - }]; + lhNavPages = [ + { + id: 'adminlogin', + title: oae.api.i18n.translate('__MSG__SIGN_IN__'), + layout: [ + { + width: 'col-md-12', + widgets: [ + { + name: 'adminlogin', + }, + ], + }, + ], + }, + ]; } else { lhNavPages = [ { - 'id': 'tenants', - 'icon': 'fa-dashboard', - 'closeNav': true, - 'title': currentContext.isGlobalAdminServer ? oae.api.i18n.translate('__MSG__TENANTS__') : oae.api.i18n.translate('__MSG__TENANT__'), - 'layout': [ + id: 'tenants', + icon: 'fa-dashboard', + closeNav: true, + title: currentContext.isGlobalAdminServer + ? oae.api.i18n.translate('__MSG__TENANTS__') + : oae.api.i18n.translate('__MSG__TENANT__'), + layout: [ { - 'width': 'col-md-12', - 'widgets': [ + width: 'col-md-12', + widgets: [ { - 'name': 'tenants', - 'settings': { - 'context': currentContext - } - } - ] - } - ] + name: 'tenants', + settings: { + context: currentContext, + }, + }, + ], + }, + ], }, { - 'id': 'configuration', - 'icon': 'fa-cogs', - 'closeNav': true, - 'title': oae.api.i18n.translate('__MSG__CONFIGURATION__'), - 'layout': [ + id: 'configuration', + icon: 'fa-cogs', + closeNav: true, + title: oae.api.i18n.translate('__MSG__CONFIGURATION__'), + layout: [ { - 'width': 'col-md-12', - 'widgets': [ + width: 'col-md-12', + widgets: [ { - 'name': 'configuration', - 'settings': { - 'configuration': configuration, - 'configurationSchema': configurationSchema, - 'context': currentContext - } - } - ] - } - ] + name: 'configuration', + settings: { + configuration: configuration, + configurationSchema: configurationSchema, + context: currentContext, + }, + }, + ], + }, + ], }, { - 'id': 'usermanagement', - 'icon': 'fa-user', - 'closeNav': true, - 'title': oae.api.i18n.translate('__MSG__USER_MANAGEMENT__'), - 'layout': [ + id: 'usermanagement', + icon: 'fa-user', + closeNav: true, + title: oae.api.i18n.translate('__MSG__USER_MANAGEMENT__'), + layout: [ { - 'width': 'col-md-12', - 'widgets': [ + width: 'col-md-12', + widgets: [ { - 'name': 'usermanagement', - 'settings': { - 'context': currentContext - } - } - ] - } - ] - } + name: 'usermanagement', + settings: { + context: currentContext, + }, + }, + ], + }, + ], + }, ]; // Only expose the maintenance functionality when the admin is looking at the global admin @@ -116,44 +122,44 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o // for individual tenants. if (currentContext.isGlobalAdminServer) { lhNavPages.push({ - 'id': 'maintenance', - 'icon': 'fa-wrench', - 'closeNav': true, - 'title': oae.api.i18n.translate('__MSG__MAINTENANCE__'), - 'layout': [ + id: 'maintenance', + icon: 'fa-wrench', + closeNav: true, + title: oae.api.i18n.translate('__MSG__MAINTENANCE__'), + layout: [ { - 'width': 'col-md-12', - 'widgets': [ + width: 'col-md-12', + widgets: [ { - 'name': 'maintenance' - } - ] - } - ] + name: 'maintenance', + }, + ], + }, + ], }); - // Only expose the skinning functionality when the admin is looking at an individual tenant. - // The global tenant does not require skinning as the values wouldn't flow through - // to the tenants appropriately if both of them have skinning values stored. + // Only expose the skinning functionality when the admin is looking at an individual tenant. + // The global tenant does not require skinning as the values wouldn't flow through + // to the tenants appropriately if both of them have skinning values stored. } else { lhNavPages.push({ - 'id': 'skinning', - 'icon': 'fa-tint', - 'closeNav': true, - 'title': oae.api.i18n.translate('__MSG__SKINNING__'), - 'layout': [ + id: 'skinning', + icon: 'fa-tint', + closeNav: true, + title: oae.api.i18n.translate('__MSG__SKINNING__'), + layout: [ { - 'width': 'col-md-12', - 'widgets': [ + width: 'col-md-12', + widgets: [ { - 'name': 'skinning', - 'settings': { - 'configuration': configuration, - 'context': currentContext - } - } - ] - } - ] + name: 'skinning', + settings: { + configuration: configuration, + context: currentContext, + }, + }, + ], + }, + ], }); } } @@ -162,18 +168,25 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o // Individual tenant on the global admininstration UI if (currentContext.isTenantOnGlobalAdminServer) { baseURL = '/tenant/' + currentContext.alias; - // Administration UI on a user tenant + // Administration UI on a user tenant } else if (!currentContext.isGlobalAdminServer) { baseURL = '/admin'; } - $(window).trigger('oae.trigger.lhnavigation', [lhNavPages, null, baseURL]); + $(window).trigger('oae.trigger.lhnavigation', [ + lhNavPages, + null, + baseURL, + ]); $(window).on('oae.ready.lhnavigation', function() { - $(window).trigger('oae.trigger.lhnavigation', [lhNavPages, null, baseURL]); + $(window).trigger('oae.trigger.lhnavigation', [ + lhNavPages, + null, + baseURL, + ]); }); }; - //////////////////// // INITIALIZATION // //////////////////// @@ -187,8 +200,8 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o var getCurrentContext = function(callback) { // Get information about the current tenant $.ajax({ - 'url': '/api/tenant', - 'success': function(data) { + url: '/api/tenant', + success: function(data) { currentContext = data; if (currentContext.isGlobalAdminServer) { @@ -196,7 +209,10 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o // case, the URL should be /tenant/ var tenantAlias = oae.api.util.url().segment(2); if (tenantAlias) { - oae.api.admin.getTenant(tenantAlias, function(err, data) { + oae.api.admin.getTenant(tenantAlias, function( + err, + data, + ) { currentContext = data; currentContext.isTenantOnGlobalAdminServer = true; callback(); @@ -207,7 +223,7 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o } else { callback(); } - } + }, }); }; @@ -219,8 +235,8 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o var loadConfiguration = function(callback) { // Get the config schema $.ajax({ - 'url': '/api/config/schema', - 'success': function(data) { + url: '/api/config/schema', + success: function(data) { configurationSchema = data; // Remove the OAE UI module from the schema to avoid it being rendered @@ -240,14 +256,14 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o // cached configs to the administrator in the administration UI, as that could // cause configuration changes not to appear immediately. $.ajax({ - 'url': url, - 'cache': false, - 'success': function(data) { + url: url, + cache: false, + success: function(data) { configuration = data; callback(); - } + }, }); - } + }, }); }; @@ -263,16 +279,16 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o $(document).on('oae.context.get', function(ev, widgetId) { if (widgetId) { $(document).trigger('oae.context.send.' + widgetId, { - 'currentContext': currentContext + currentContext: currentContext, }); } else { $(document).trigger('oae.context.send', { - 'currentContext': currentContext + currentContext: currentContext, }); } }); $(document).trigger('oae.context.send', { - 'currentContext': currentContext + currentContext: currentContext, }); }; @@ -282,7 +298,10 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o var initializeAdminUI = function() { // Redirect to the 'Access denied' page if the user is logged in // but not the tenant or global admin - if (!oae.data.me.anon && (!oae.data.me.isTenantAdmin && !oae.data.me.isGlobalAdmin)) { + if ( + !oae.data.me.anon && + (!oae.data.me.isTenantAdmin && !oae.data.me.isGlobalAdmin) + ) { return oae.api.util.redirect().accessdenied(); } @@ -303,5 +322,4 @@ require(['jquery', 'underscore', 'oae.core', 'jquery.history'], function($, _, o }; initializeAdminUI(); - }); diff --git a/docs/internal/js/internal.js b/docs/internal/js/internal.js index 85a2cd1254d..2ae90107c3c 100644 --- a/docs/internal/js/internal.js +++ b/docs/internal/js/internal.js @@ -14,7 +14,6 @@ */ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { - /** * Renders the documentation for a specific module */ @@ -32,17 +31,21 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { // Get the current requested module from the History.js // Retrieve the documentation for the current module from the server getModuleDocs(module, type, function(docs) { - oae.api.util.template().render($('#internal-module-template'), { - 'docs': docs, - 'module': module - }, $('#internal-module-container')); + oae.api.util.template().render( + $('#internal-module-template'), + { + docs: docs, + module: module, + }, + $('#internal-module-container'), + ); // Scroll to the appropriate place on the page. This will be the top of the page most of the time, unless // a direct link to a function has been clicked (e.g. http://cambridge.oae.com/docs/backend/oae-authentication/createUser) // In this case, we scroll to the function's documentation var offset = 0; var apiFunction = History.getState().data.apiFunction; - if (apiFunction){ + if (apiFunction) { var $anchor = $('a[name="' + module + '.' + apiFunction + '"]'); offset = $anchor.offset().top; } @@ -57,7 +60,13 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { * @param {String} currentModule The name of the module that is currently shown in the UI */ var renderNavigation = function(modules, currentModule) { - oae.api.util.template().render($('#internal-modules-template'), modules, $('#internal-modules-container')); + oae.api.util + .template() + .render( + $('#internal-modules-template'), + modules, + $('#internal-modules-container'), + ); }; /** @@ -73,9 +82,10 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { url: '/api/doc/' + type + '/' + module, success: function(docs) { callback(docs); - }, error: function(err) { + }, + error: function(err) { callback(null); - } + }, }); }; @@ -93,14 +103,14 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { success: function(frontendModules) { modules.frontend = frontendModules; // Get the available back-end modules - $.ajax({ + $.ajax({ url: '/api/doc/backend', success: function(backendModules) { modules.backend = backendModules; callback(modules); - } + }, }); - } + }, }); }; @@ -119,10 +129,14 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { */ var selectModule = function() { // Push the state and render the selected module - History.pushState({ - 'type': $(this).attr('data-type'), - 'module': $(this).attr('data-id') - }, $('title').text(), $('a', $(this)).attr('href')); + History.pushState( + { + type: $(this).attr('data-type'), + module: $(this).attr('data-id'), + }, + $('title').text(), + $('a', $(this)).attr('href'), + ); return false; }; @@ -131,7 +145,11 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { */ var addBinding = function() { // Module switching - $(document).on('click', '#internal-modules-container ul li', selectModule) + $(document).on( + 'click', + '#internal-modules-container ul li', + selectModule, + ); // The statechange event will be triggered every time the browser back or forward button // is pressed or state is pushed/replaced using Hisory.js. $(window).on('statechange', renderModuleDocs); @@ -166,15 +184,18 @@ require(['jquery', 'oae.core', 'jquery.history'], function($, oae) { // for the requested module. However, as the page can already have the History.js state data // when only doing a page refresh, we need to add a random number to make sure that History.js // recognizes this as a new state and triggers the `statechange` event. - History.replaceState({ - 'type': type, - 'module': moduleToLoad, - 'apiFunction': apiFunction, - '_': Math.random() - }, $('title').text(), History.getState().cleanUrl); + History.replaceState( + { + type: type, + module: moduleToLoad, + apiFunction: apiFunction, + _: Math.random(), + }, + $('title').text(), + History.getState().cleanUrl, + ); }); }; doInit(); - }); diff --git a/docs/rest/lib/backbone-min.js b/docs/rest/lib/backbone-min.js index c1c0d4fff28..59c2b2ee102 100644 --- a/docs/rest/lib/backbone-min.js +++ b/docs/rest/lib/backbone-min.js @@ -4,35 +4,825 @@ // Backbone may be freely distributed under the MIT license. // For all details and documentation: // http://backbonejs.org -(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks= -{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g= -z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent= -{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null== -b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent: -b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)}; -a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error, -h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t(); -return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending= -{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length|| -!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator); -this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c=b))this.iframe=i('' - ).bind('load', function () { + (counter += 1) + + '">', + ).bind('load', function() { var fileInputClones, - paramNames = $.isArray(options.paramName) ? - options.paramName : [options.paramName]; - iframe - .unbind('load') - .bind('load', function () { - var response; - // Wrap in a try/catch block to catch exceptions thrown - // when trying to access cross-domain iframe contents: - try { - response = iframe.contents(); - // Google Chrome and Firefox do not throw an - // exception when calling iframe.contents() on - // cross-domain requests, so we unify the response: - if (!response.length || !response[0].firstChild) { - throw new Error(); - } - } catch (e) { - response = undefined; + paramNames = $.isArray(options.paramName) + ? options.paramName + : [options.paramName]; + iframe.unbind('load').bind('load', function() { + var response; + // Wrap in a try/catch block to catch exceptions thrown + // when trying to access cross-domain iframe contents: + try { + response = iframe.contents(); + // Google Chrome and Firefox do not throw an + // exception when calling iframe.contents() on + // cross-domain requests, so we unify the response: + if ( + !response.length || + !response[0].firstChild + ) { + throw new Error(); } - // The complete callback returns the - // iframe content document as response object: - completeCallback( - 200, - 'success', - {'iframe': response} - ); - // Fix for IE endless progress bar activity bug - // (happens on form submits to iframe targets): - $('') - .appendTo(form); - form.remove(); + } catch (e) { + response = undefined; + } + // The complete callback returns the + // iframe content document as response object: + completeCallback(200, 'success', { + iframe: response, }); + // Fix for IE endless progress bar activity bug + // (happens on form submits to iframe targets): + $( + '', + ).appendTo(form); + form.remove(); + }); form .prop('target', iframe.prop('name')) .prop('action', options.url) .prop('method', options.type); if (options.formData) { - $.each(options.formData, function (index, field) { + $.each(options.formData, function(index, field) { $('') .prop('name', field.name) .val(field.value) .appendTo(form); }); } - if (options.fileInput && options.fileInput.length && - options.type === 'POST') { + if ( + options.fileInput && + options.fileInput.length && + options.type === 'POST' + ) { fileInputClones = options.fileInput.clone(); // Insert a clone for each file input field: - options.fileInput.after(function (index) { + options.fileInput.after(function(index) { return fileInputClones[index]; }); if (options.paramName) { - options.fileInput.each(function (index) { + options.fileInput.each(function(index) { $(this).prop( 'name', - paramNames[index] || options.paramName + paramNames[index] || options.paramName, ); }); } @@ -137,7 +143,7 @@ // Insert the file input fields at their original location // by replacing the clones with the originals: if (fileInputClones && fileInputClones.length) { - options.fileInput.each(function (index, input) { + options.fileInput.each(function(index, input) { var clone = $(fileInputClones[index]); $(input).prop('name', clone.prop('name')); clone.replaceWith(input); @@ -146,7 +152,7 @@ }); form.append(iframe).appendTo(document.body); }, - abort: function () { + abort: function() { if (iframe) { // javascript:false as iframe src aborts the request // and prevents warning popups on HTTPS in IE6. @@ -158,7 +164,7 @@ if (form) { form.remove(); } - } + }, }; } }); @@ -167,19 +173,18 @@ // The following adds converters from iframe to text, json, html, and script: $.ajaxSetup({ converters: { - 'iframe text': function (iframe) { + 'iframe text': function(iframe) { return iframe && $(iframe[0].body).text(); }, - 'iframe json': function (iframe) { + 'iframe json': function(iframe) { return iframe && $.parseJSON($(iframe[0].body).text()); }, - 'iframe html': function (iframe) { + 'iframe html': function(iframe) { return iframe && $(iframe[0].body).html(); }, - 'iframe script': function (iframe) { + 'iframe script': function(iframe) { return iframe && $.globalEval($(iframe[0].body).text()); - } - } + }, + }, }); - -})); +}); diff --git a/shared/vendor/js/jquery-plugins/jquery.jeditable.oae-edited.js b/shared/vendor/js/jquery-plugins/jquery.jeditable.oae-edited.js index 1e6fb9f4b3a..8d218e3cc6c 100644 --- a/shared/vendor/js/jquery-plugins/jquery.jeditable.oae-edited.js +++ b/shared/vendor/js/jquery-plugins/jquery.jeditable.oae-edited.js @@ -20,53 +20,51 @@ */ /** - * Version 1.7.1 - * - * ** means there is basic unit tests for this parameter. - * - * @name Jeditable - * @type jQuery - * @param String target (POST) URL or function to send edited content to ** - * @param Hash options additional options - * @param String options[method] method to use to send edited content (POST or PUT) ** - * @param Function options[callback] Function to run after submitting edited content ** - * @param String options[name] POST parameter name of edited content - * @param String options[id] POST parameter name of edited div id - * @param Hash options[submitdata] Extra parameters to send when submitting edited content. - * @param String options[type] text, textarea or select (or any 3rd party input type) ** - * @param Integer options[rows] number of rows if using textarea ** - * @param Integer options[cols] number of columns if using textarea ** - * @param Mixed options[height] 'auto', 'none' or height in pixels ** - * @param Mixed options[width] 'auto', 'none' or width in pixels ** - * @param String options[loadurl] URL to fetch input content before editing ** - * @param String options[loadtype] Request type for load url. Should be GET or POST. - * @param String options[loadtext] Text to display while loading external content. - * @param Mixed options[loaddata] Extra parameters to pass when fetching content before editing. - * @param Mixed options[data] Or content given as paramameter. String or function.** - * @param String options[indicator] indicator html to show when saving - * @param String options[tooltip] optional tooltip text via title attribute ** - * @param String options[event] jQuery event such as 'click' of 'dblclick' ** - * @param String options[submit] submit button value, empty means no button ** - * @param String options[cancel] cancel button value, empty means no button ** - * @param String options[cssclass] CSS class to apply to input form. 'inherit' to copy from parent. ** - * @param String options[style] Style to apply to input form 'inherit' to copy from parent. ** - * @param String options[select] true or false, when true text is highlighted ?? - * @param String options[placeholder] Placeholder text or html to insert when element is empty. ** - * @param String options[onblur] 'cancel', 'submit', 'ignore' or function ?? - * @param Number options[maxlength] The maximum character count allowed - * - * @param Function options[onsubmit] function(settings, original) { ... } called before submit - * @param Function options[onreset] function(settings, original) { ... } called before reset - * @param Function options[onerror] function(settings, original, xhr) { ... } called on error - * - * @param Hash options[ajaxoptions] jQuery Ajax options. See docs.jquery.com. - * - */ + * Version 1.7.1 + * + * ** means there is basic unit tests for this parameter. + * + * @name Jeditable + * @type jQuery + * @param String target (POST) URL or function to send edited content to ** + * @param Hash options additional options + * @param String options[method] method to use to send edited content (POST or PUT) ** + * @param Function options[callback] Function to run after submitting edited content ** + * @param String options[name] POST parameter name of edited content + * @param String options[id] POST parameter name of edited div id + * @param Hash options[submitdata] Extra parameters to send when submitting edited content. + * @param String options[type] text, textarea or select (or any 3rd party input type) ** + * @param Integer options[rows] number of rows if using textarea ** + * @param Integer options[cols] number of columns if using textarea ** + * @param Mixed options[height] 'auto', 'none' or height in pixels ** + * @param Mixed options[width] 'auto', 'none' or width in pixels ** + * @param String options[loadurl] URL to fetch input content before editing ** + * @param String options[loadtype] Request type for load url. Should be GET or POST. + * @param String options[loadtext] Text to display while loading external content. + * @param Mixed options[loaddata] Extra parameters to pass when fetching content before editing. + * @param Mixed options[data] Or content given as paramameter. String or function.** + * @param String options[indicator] indicator html to show when saving + * @param String options[tooltip] optional tooltip text via title attribute ** + * @param String options[event] jQuery event such as 'click' of 'dblclick' ** + * @param String options[submit] submit button value, empty means no button ** + * @param String options[cancel] cancel button value, empty means no button ** + * @param String options[cssclass] CSS class to apply to input form. 'inherit' to copy from parent. ** + * @param String options[style] Style to apply to input form 'inherit' to copy from parent. ** + * @param String options[select] true or false, when true text is highlighted ?? + * @param String options[placeholder] Placeholder text or html to insert when element is empty. ** + * @param String options[onblur] 'cancel', 'submit', 'ignore' or function ?? + * @param Number options[maxlength] The maximum character count allowed + * + * @param Function options[onsubmit] function(settings, original) { ... } called before submit + * @param Function options[onreset] function(settings, original) { ... } called before reset + * @param Function options[onerror] function(settings, original, xhr) { ... } called on error + * + * @param Hash options[ajaxoptions] jQuery Ajax options. See docs.jquery.com. + * + */ define(['jquery.jeditable-focus']); (function($) { - $.fn.editable = function(target, options) { - if ('disable' == target) { $(this).data('disabled.editable', true); return; @@ -83,41 +81,49 @@ define(['jquery.jeditable-focus']); return; } - var settings = $.extend({}, $.fn.editable.defaults, {target:target}, options); + var settings = $.extend( + {}, + $.fn.editable.defaults, + { target: target }, + options, + ); /* setup some functions */ - var plugin = $.editable.types[settings.type].plugin || function() { }; - var submit = $.editable.types[settings.type].submit || function() { }; - var buttons = $.editable.types[settings.type].buttons - || $.editable.types['defaults'].buttons; - var content = $.editable.types[settings.type].content - || $.editable.types['defaults'].content; - var element = $.editable.types[settings.type].element - || $.editable.types['defaults'].element; - var reset = $.editable.types[settings.type].reset - || $.editable.types['defaults'].reset; - var callback = settings.callback || function() { }; - var onedit = settings.onedit || function() { }; - var onsubmit = settings.onsubmit || function() { }; - var onreset = settings.onreset || function() { }; - var onerror = settings.onerror || reset; + var plugin = $.editable.types[settings.type].plugin || function() {}; + var submit = $.editable.types[settings.type].submit || function() {}; + var buttons = + $.editable.types[settings.type].buttons || + $.editable.types['defaults'].buttons; + var content = + $.editable.types[settings.type].content || + $.editable.types['defaults'].content; + var element = + $.editable.types[settings.type].element || + $.editable.types['defaults'].element; + var reset = + $.editable.types[settings.type].reset || + $.editable.types['defaults'].reset; + var callback = settings.callback || function() {}; + var onedit = settings.onedit || function() {}; + var onsubmit = settings.onsubmit || function() {}; + var onreset = settings.onreset || function() {}; + var onerror = settings.onerror || reset; /* show tooltip */ if (settings.tooltip) { $(this).attr('title', settings.tooltip); } - settings.autowidth = 'auto' == settings.width; + settings.autowidth = 'auto' == settings.width; settings.autoheight = 'auto' == settings.height; return this.each(function() { - /* save this to self because this changes when scope changes */ var self = this; /* inlined block elements lose their width and height after first edit */ /* save them for later use as workaround */ - var savedwidth = $(self).width(); + var savedwidth = $(self).width(); var savedheight = $(self).height(); /* save so it can be later used by $.editable('destroy') */ @@ -129,7 +135,6 @@ define(['jquery.jeditable-focus']); } $(this).bind(settings.event, function(e) { - /* abort if disabled for this element */ if (true === $(this).data('disabled.editable')) { return; @@ -142,7 +147,7 @@ define(['jquery.jeditable-focus']); /* abort if onedit hook returns false */ if (false === onedit.apply(this, [settings, self])) { - return; + return; } /* prevent default action and bubbling */ @@ -158,28 +163,35 @@ define(['jquery.jeditable-focus']); /* are workaround for http://dev.jquery.com/ticket/2190 */ if (0 == $(self).width()) { //$(self).css('visibility', 'hidden'); - settings.width = savedwidth; + settings.width = savedwidth; settings.height = savedheight; } else { if (settings.width != 'none') { - settings.width = - settings.autowidth ? $(self).width() : settings.width; + settings.width = settings.autowidth + ? $(self).width() + : settings.width; } if (settings.height != 'none') { - settings.height = - settings.autoheight ? $(self).height() : settings.height; + settings.height = settings.autoheight + ? $(self).height() + : settings.height; } } //$(this).css('visibility', ''); /* remove placeholder text, replace is here because of IE */ - if ($(this).html().toLowerCase().replace(/(;|")/g, '') == - settings.placeholder.toLowerCase().replace(/(;|")/g, '')) { - $(this).html(''); + if ( + $(this) + .html() + .toLowerCase() + .replace(/(;|")/g, '') == + settings.placeholder.toLowerCase().replace(/(;|")/g, '') + ) { + $(this).html(''); } - self.editing = true; - self.revert = $(self).text(); + self.editing = true; + self.revert = $(self).text(); $(self).html(''); /* create the form object */ @@ -213,31 +225,44 @@ define(['jquery.jeditable-focus']); if (settings.loadurl) { var t = setTimeout(function() { input.disabled = true; - content.apply(form, [settings.loadtext, settings, self]); + content.apply(form, [ + settings.loadtext, + settings, + self, + ]); }, 100); var loaddata = {}; loaddata[settings.id] = self.id; if ($.isFunction(settings.loaddata)) { - $.extend(loaddata, settings.loaddata.apply(self, [self.revert, settings])); + $.extend( + loaddata, + settings.loaddata.apply(self, [ + self.revert, + settings, + ]), + ); } else { $.extend(loaddata, settings.loaddata); } $.ajax({ - type : settings.loadtype, - url : settings.loadurl, - data : loaddata, - async : false, - success: function(result) { - window.clearTimeout(t); - input_content = result; - input.disabled = false; - } + type: settings.loadtype, + url: settings.loadurl, + data: loaddata, + async: false, + success: function(result) { + window.clearTimeout(t); + input_content = result; + input.disabled = false; + }, }); } else if (settings.data) { input_content = settings.data; if ($.isFunction(settings.data)) { - input_content = settings.data.apply(self, [self.revert, settings]); + input_content = settings.data.apply(self, [ + self.revert, + settings, + ]); } } else { input_content = self.revert; @@ -291,12 +316,11 @@ define(['jquery.jeditable-focus']); }); } else { input.blur(function(e) { - /* TODO: maybe something here */ + /* TODO: maybe something here */ }); } form.submit(function(e) { - if (t) { clearTimeout(t); } @@ -310,62 +334,79 @@ define(['jquery.jeditable-focus']); /* custom inputs call before submit hook. */ /* if it returns false abort submitting */ if (false !== submit.apply(form, [settings, self])) { + /* check if given target is function */ + if ($.isFunction(settings.target)) { + var str = settings.target.apply(self, [ + input.val(), + settings, + ]); + $(self).text(str); + self.editing = false; + callback.apply(self, [ + self.innerHTML, + settings, + ]); + /* TODO: this is not dry */ + if (!$.trim($(self).html())) { + $(self).html(settings.placeholder); + } + } else { + /* add edited content and id of edited element to POST */ + var submitdata = {}; + submitdata[settings.name] = input.val(); + submitdata[settings.id] = self.id; + /* add extra data to be POST:ed */ + if ($.isFunction(settings.submitdata)) { + $.extend( + submitdata, + settings.submitdata.apply(self, [ + self.revert, + settings, + ]), + ); + } else { + $.extend(submitdata, settings.submitdata); + } - /* check if given target is function */ - if ($.isFunction(settings.target)) { - var str = settings.target.apply(self, [input.val(), settings]); - $(self).text(str); - self.editing = false; - callback.apply(self, [self.innerHTML, settings]); - /* TODO: this is not dry */ - if (!$.trim($(self).html())) { - $(self).html(settings.placeholder); - } - } else { - /* add edited content and id of edited element to POST */ - var submitdata = {}; - submitdata[settings.name] = input.val(); - submitdata[settings.id] = self.id; - /* add extra data to be POST:ed */ - if ($.isFunction(settings.submitdata)) { - $.extend(submitdata, settings.submitdata.apply(self, [self.revert, settings])); - } else { - $.extend(submitdata, settings.submitdata); - } - - /* quick and dirty PUT support */ - if ('PUT' == settings.method) { - submitdata['_method'] = 'put'; - } - - /* show the saving indicator */ - $(self).html(settings.indicator); - - /* defaults for ajaxoptions */ - var ajaxoptions = { - type : 'POST', - data : submitdata, - dataType: 'html', - url : settings.target, - success : function(result, status) { - if (ajaxoptions.dataType == 'html') { - $(self).html(result); - } - self.editing = false; - callback.apply(self, [result, settings]); - if (!$.trim($(self).html())) { - $(self).html(settings.placeholder); - } - }, - error : function(xhr, status, error) { - onerror.apply(form, [settings, self, xhr]); - } - }; - - /* override with what is given in settings.ajaxoptions */ - $.extend(ajaxoptions, settings.ajaxoptions); - $.ajax(ajaxoptions); + /* quick and dirty PUT support */ + if ('PUT' == settings.method) { + submitdata['_method'] = 'put'; + } + /* show the saving indicator */ + $(self).html(settings.indicator); + + /* defaults for ajaxoptions */ + var ajaxoptions = { + type: 'POST', + data: submitdata, + dataType: 'html', + url: settings.target, + success: function(result, status) { + if (ajaxoptions.dataType == 'html') { + $(self).html(result); + } + self.editing = false; + callback.apply(self, [ + result, + settings, + ]); + if (!$.trim($(self).html())) { + $(self).html(settings.placeholder); + } + }, + error: function(xhr, status, error) { + onerror.apply(form, [ + settings, + self, + xhr, + ]); + }, + }; + + /* override with what is given in settings.ajaxoptions */ + $.extend(ajaxoptions, settings.ajaxoptions); + $.ajax(ajaxoptions); } } } @@ -384,7 +425,7 @@ define(['jquery.jeditable-focus']); /* before reset hook, if it returns false abort reseting */ if (false !== onreset.apply(form, [settings, self])) { $(self).text(self.revert); - self.editing = false; + self.editing = false; if (!$.trim($(self).html())) { $(self).html(settings.placeholder); } @@ -396,35 +437,33 @@ define(['jquery.jeditable-focus']); } }; }); - }; - $.editable = { types: { defaults: { - element : function(settings, original) { + element: function(settings, original) { var input = $(''); $(this).append(input); - return(input); + return input; }, - content : function(string, settings, original) { + content: function(string, settings, original) { $(':input:first', this).val(string); }, - reset : function(settings, original) { - original.reset(this); + reset: function(settings, original) { + original.reset(this); }, - buttons : function(settings, original) { + buttons: function(settings, original) { var form = this; if (settings.submit) { /* if given html string use that */ if (settings.submit.match(/>$/)) { var submit = $(settings.submit).click(function() { - if (submit.attr("type") != "submit") { + if (submit.attr('type') != 'submit') { form.submit(); } }); - /* otherwise use button with given string as text */ + /* otherwise use button with given string as text */ } else { var submit = $('