diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..d91aec1 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "lib" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8d6e66c..d69e6b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,8 @@ -build/archive -build/component -build/cdn +build/temp dist -# for npm +# npm modules node_modules -# for bower -components - -.DS_Store \ No newline at end of file +# bower components +lib/*/* \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 4771380..3b8702b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,12 +10,12 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-compress'); grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-jscs-checker'); + grunt.loadNpmTasks('grunt-shell'); + grunt.loadNpmTasks('grunt-karma'); + grunt.loadNpmTasks('grunt-bump'); grunt.loadNpmTasks('lumbar'); - - // Parse config files - var lumbarConfig = grunt.file.readJSON('lumbar.json'); - var packageConfig = grunt.file.readJSON('package.json'); - var pluginConfig = grunt.file.readJSON('fullcalendar.jquery.json'); // This will eventually get passed to grunt.initConfig() // Initialize multitasks... @@ -24,17 +24,34 @@ module.exports = function(grunt) { uglify: {}, copy: {}, compress: {}, - clean: {} + shell: {}, + clean: { + temp: 'build/temp' + } }; - // Combine certain configs for the "meta" template variable (<%= meta.whatever %>) - config.meta = _.extend({}, packageConfig, pluginConfig); + // for the "meta" template variable (<%= meta.whatever %>) + config.meta = grunt.file.readJSON('fullcalendar.jquery.json'); // The "grunt" command with no arguments - grunt.registerTask('default', 'archive'); + grunt.registerTask('default', 'dist'); + + // Builds all distributable files, for a new release possibly + grunt.registerTask('dist', [ + 'clean', + 'modules', + 'languages', + 'karma:single', + 'archiveDist', + 'cdnjsDist' + ]); // Bare minimum for debugging - grunt.registerTask('dev', 'lumbar:build'); + grunt.registerTask('dev', [ + 'shell:assume-unchanged', + 'lumbar:build', + 'languages' + ]); @@ -42,8 +59,11 @@ module.exports = function(grunt) { ----------------------------------------------------------------------------------------------------*/ grunt.registerTask('modules', 'Build the FullCalendar modules', [ + 'jscs:srcModules', + 'clean:modules', 'lumbar:build', 'concat:moduleVariables', + 'jshint:builtModules', 'uglify:modules' ]); @@ -51,7 +71,14 @@ module.exports = function(grunt) { config.lumbar = { build: { build: 'lumbar.json', - output: 'build/out' // a directory. lumbar doesn't like trailing slash + output: 'dist', // a directory. lumbar doesn't like trailing slash + background: false // lumbar complains otherwise + }, + watch: { + watch: 'lumbar.json', + output: 'dist', // a directory. lumbar doesn't like trailing slash + background: false, // lumbar complains otherwise + sourceMap: true } }; @@ -61,9 +88,9 @@ module.exports = function(grunt) { process: true // replace }, expand: true, - cwd: 'build/out/', - src: [ '*.js', '*.css', '!jquery*' ], - dest: 'build/out/' + cwd: 'dist/', + src: [ '*.js', '*.css' ], + dest: 'dist/' }; // create minified versions (*.min.js) @@ -72,11 +99,69 @@ module.exports = function(grunt) { preserveComments: 'some' // keep comments starting with /*! }, expand: true, - src: 'build/out/fullcalendar.js', // only do it for fullcalendar.js + src: 'dist/fullcalendar.js', // only do it for fullcalendar.js ext: '.min.js' - } + }; - config.clean.modules = 'build/out/*'; + config.clean.modules = [ + 'dist/*.{js,css,map}', // maps created by lumbar sourceMap + 'dist/src' // created by lumbar sourceMap + ]; + + + + /* Languages + ----------------------------------------------------------------------------------------------------*/ + + grunt.registerTask('languages', [ + 'jscs:srcLanguages', + 'jshint:srcLanguages', + 'clean:languages', + 'generateLanguages', + 'uglify:languages', + 'uglify:languagesAll' + ]); + + config.generateLanguages = { + moment: 'lib/moment/lang/', + datepicker: 'lib/jquery-ui/ui/i18n/', + fullCalendar: 'lang/', + dest: 'build/temp/lang/', + allDest: 'build/temp/lang-all.js' + }; + + config.uglify.languages = { + expand: true, + cwd: 'build/temp/lang/', + src: '*.js', + dest: 'dist/lang/' + }; + + config.uglify.languagesAll = { + src: 'build/temp/lang-all.js', + dest: 'dist/lang-all.js' + }; + + config.clean.languages = [ + 'build/temp/lang', + 'build/temp/lang-all.js', + 'dist/lang', + 'dist/lang-all.js' + ]; + + + + /* Automated Tests + ----------------------------------------------------------------------------------------------------*/ + + config.karma = { + options: { + configFile: 'build/karma.conf.js' + }, + url: {}, // visit a URL in a browser + headless: { browsers: [ 'PhantomJS' ] }, + single: { browsers: [ 'PhantomJS' ], singleRun: true, autoWatch: false } + }; @@ -84,12 +169,22 @@ module.exports = function(grunt) { ----------------------------------------------------------------------------------------------------*/ grunt.registerTask('archive', 'Create a distributable ZIP archive', [ - 'clean:modules', - 'clean:archive', 'modules', + 'languages', + 'karma:single', + 'archiveDist' + ]); + + grunt.registerTask('archiveDist', [ + 'clean:archive', 'copy:archiveModules', - 'copy:archiveDependencies', + 'copy:archiveLanguages', + 'copy:archiveLanguagesAll', + 'copy:archiveMoment', + 'copy:archiveJQuery', + 'concat:archiveJQueryUI', 'copy:archiveDemos', + 'copy:archiveDemoTheme', 'copy:archiveMisc', 'compress:archive' ]); @@ -97,27 +192,47 @@ module.exports = function(grunt) { // copy FullCalendar modules into ./fullcalendar/ directory config.copy.archiveModules = { expand: true, - cwd: 'build/out/', - src: [ '*.js', '*.css', '!jquery*' ], - dest: 'build/archive/fullcalendar/' + cwd: 'dist/', + src: [ '*.js', '*.css' ], + dest: 'build/temp/archive/' }; - // copy jQuery and jQuery UI into the ./jquery/ directory - config.copy.archiveDependencies = { + config.copy.archiveLanguages = { expand: true, - flatten: true, + cwd: 'dist/lang/', + src: '*.js', + dest: 'build/temp/archive/lang/' + }; + + config.copy.archiveLanguagesAll = { + src: 'dist/lang-all.js', + dest: 'build/temp/archive/lang-all.js' + }; + + config.copy.archiveMoment = { + src: 'lib/moment/min/moment.min.js', + dest: 'build/temp/archive/lib/moment.min.js' + }; + + config.copy.archiveJQuery = { + src: 'lib/jquery/dist/jquery.min.js', + dest: 'build/temp/archive/lib/jquery.min.js' + }; + + config.concat.archiveJQueryUI = { src: [ - // we want to retain the original filenames - lumbarConfig.modules['jquery'].scripts[0], - lumbarConfig.modules['jquery-ui'].scripts[0] + 'lib/jquery-ui/ui/minified/jquery.ui.core.min.js', + 'lib/jquery-ui/ui/minified/jquery.ui.widget.min.js', + 'lib/jquery-ui/ui/minified/jquery.ui.mouse.min.js', + 'lib/jquery-ui/ui/minified/jquery.ui.draggable.min.js', + 'lib/jquery-ui/ui/minified/jquery.ui.resizable.min.js' ], - dest: 'build/archive/jquery/' + dest: 'build/temp/archive/lib/jquery-ui.custom.min.js' }; // copy demo files into ./demos/ directory config.copy.archiveDemos = { options: { - processContentExclude: 'demos/*/**', // don't process anything more than 1 level deep (like assets) processContent: function(content) { content = content.replace(/((?:src|href)=['"])([^'"]*)(['"])/g, function(m0, m1, m2, m3) { return m1 + transformDemoPath(m2) + m3; @@ -126,23 +241,34 @@ module.exports = function(grunt) { } }, src: 'demos/**', - dest: 'build/archive/' + dest: 'build/temp/archive/' + }; + + // copy the "cupertino" jquery-ui theme into the demo directory (for demos/theme.html) + config.copy.archiveDemoTheme = { + expand: true, + cwd: 'lib/jquery-ui/themes/cupertino/', + src: [ 'jquery-ui.min.css', 'images/*' ], + dest: 'build/temp/archive/lib/cupertino/' }; // in demo HTML, rewrites paths to work in the archive function transformDemoPath(path) { - path = path.replace('/build/out/jquery.js', '/' + lumbarConfig.modules['jquery'].scripts[0]); - path = path.replace('/build/out/jquery-ui.js', '/' + lumbarConfig.modules['jquery-ui'].scripts[0]); - path = path.replace('/lib/', '/jquery/'); - path = path.replace('/build/out/', '/fullcalendar/'); + path = path.replace('../lib/moment/moment.js', '../lib/moment.min.js'); + path = path.replace('../lib/jquery/dist/jquery.js', '../lib/jquery.min.js'); + path = path.replace('../lib/jquery-ui/ui/jquery-ui.js', '../lib/jquery-ui.custom.min.js'); + path = path.replace('../lib/jquery-ui/themes/cupertino/', '../lib/cupertino/'); + path = path.replace('../dist/', '../'); path = path.replace('/fullcalendar.js', '/fullcalendar.min.js'); return path; } // copy license and changelog config.copy.archiveMisc = { - src: "*.txt", - dest: 'build/archive/' + files: { + 'build/temp/archive/license.txt': 'license.txt', + 'build/temp/archive/changelog.txt': 'changelog.md' + } }; // create the ZIP @@ -151,94 +277,126 @@ module.exports = function(grunt) { archive: 'dist/<%= meta.name %>-<%= meta.version %>.zip' }, expand: true, - cwd: 'build/archive/', + cwd: 'build/temp/archive/', src: '**', dest: '<%= meta.name %>-<%= meta.version %>/' // have a top-level directory in the ZIP file }; - config.clean.archive = 'build/archive/*'; - config.clean.dist = 'dist/*'; + config.clean.archive = [ + 'build/temp/archive', + 'dist/*.zip' + ]; - /* Bower Component (http://twitter.github.com/bower/) + /* Release Utilities ----------------------------------------------------------------------------------------------------*/ - grunt.registerTask('component', 'Build the FullCalendar component for the Bower package manager', [ - 'clean:modules', - 'clean:component', - 'modules', - 'copy:componentModules', - 'copy:componentReadme', - 'componentConfig' - ]); - - // copy FullCalendar modules into component root - config.copy.componentModules = { - expand: true, - cwd: 'build/out/', - src: [ '*.js', '*.css', '!jquery*' ], - dest: 'build/component/' + config.bump = { // changes the version number in the configs + options: { + files: [ + 'package.json', + 'bower.json', + 'fullcalendar.jquery.json' + ], + commit: false, + createTag: false, + push: false + } }; - // copy the component-specific README - config.copy.componentReadme = { - src: 'build/component-readme.md', - dest: 'build/component/readme.md' - }; - - // assemble the component's config from existing configs - grunt.registerTask('componentConfig', function() { - var config = grunt.file.readJSON('build/component.json'); - grunt.file.write( - 'build/component/component.json', - JSON.stringify( - _.extend({}, pluginConfig, config), // combine 2 configs - null, // replacer - 2 // indent - ) - ); - }); - - config.clean.component = 'build/component/*'; - - /* CDN (http://cdnjs.com/) + /* CDNJS (http://cdnjs.com/) ----------------------------------------------------------------------------------------------------*/ - grunt.registerTask('cdn', 'Build files for CDNJS\'s hosted version of FullCalendar', [ - 'clean:modules', - 'clean:cdn', + grunt.registerTask('cdnjs', 'Build files for CDNJS\'s hosted version of FullCalendar', [ 'modules', - 'copy:cdnModules', - 'cdnConfig' + 'languages', + 'karma:single', + 'cdnjsDist' ]); - config.copy.cdnModules = { + grunt.registerTask('cdnjsDist', [ + 'clean:cdnjs', + 'copy:cdnjsModules', + 'copy:cdnjsLanguages', + 'copy:cdnjsLanguagesAll', + 'cdnjsConfig' + ]); + + config.copy.cdnjsModules = { expand: true, - cwd: 'build/out/', - src: [ '*.js', '*.css', '!jquery*' ], - dest: 'build/cdn/<%= meta.version %>/' + cwd: 'dist/', + src: [ '*.js', '*.css' ], + dest: 'dist/cdnjs/<%= meta.version %>/' }; - grunt.registerTask('cdnConfig', function() { - var config = grunt.file.readJSON('build/cdn.json'); + config.copy.cdnjsLanguages = { + expand: true, + cwd: 'dist/lang/', + src: '*.js', + dest: 'dist/cdnjs/<%= meta.version %>/lang/' + }; + + config.copy.cdnjsLanguagesAll = { + src: 'dist/lang-all.js', + dest: 'dist/cdnjs/<%= meta.version %>/lang-all.js' + }; + + grunt.registerTask('cdnjsConfig', function() { + var jqueryConfig = grunt.file.readJSON('fullcalendar.jquery.json'); + var cdnjsConfig = grunt.file.readJSON('build/cdnjs.json'); grunt.file.write( - 'build/cdn/package.json', + 'dist/cdnjs/package.json', JSON.stringify( - _.extend({}, pluginConfig, config), // combine 2 configs + _.extend({}, jqueryConfig, cdnjsConfig), // combine 2 configs null, // replace 2 // indent ) ); }); - config.clean.cdn = 'build/cdn/<%= meta.version %>/*'; - // NOTE: not a complete clean. also need to manually worry about package.json and version folders + config.clean.cdnjs = 'dist/cdnjs'; + + + + /* Linting and Code Style Checking + ----------------------------------------------------------------------------------------------------*/ + + grunt.registerTask('check', 'Lint and check code style', [ + 'jscs', + 'jshint:srcModules', // so we can fix most quality errors in their original files + 'lumbar:build', + 'jshint' // will run srcModules again but oh well + ]); + + // configs located elsewhere + config.jshint = require('./build/jshint.conf'); + config.jscs = require('./build/jscs.conf'); + + + + /* dist & git hacks + ---------------------------------------------------------------------------------------------------- + // These shell commands are used to force/unforce git from thinking that files have changed. + // Used to ignore changes when dist files are overwritten, but not committed, during development. + */ + + config.shell['assume-unchanged'] = { + command: 'git update-index --assume-unchanged `git ls-files dist`' + }; + config.shell['no-assume-unchanged'] = { + command: 'git update-index --no-assume-unchanged `git ls-files dist`' + }; + config.shell['list-assume-unchanged'] = { + command: 'git ls-files -v | grep \'^h\'' + }; // finally, give grunt the config object... grunt.initConfig(config); + + grunt.loadTasks('./build/tasks/'); }; diff --git a/bower.json b/bower.json index 6f58c29..c79399f 100644 --- a/bower.json +++ b/bower.json @@ -1,39 +1,35 @@ { "name": "fullcalendar", - "version": "1.6.3", - "dependencies": { - "jquery": "~1.10.2" - }, - "optionalDependencies": { - "jquery-ui": "~1.10.3" - }, - "title": "FullCalendar", - "description": "Full-sized drag & drop event calendar with resource views", - "keywords": [ - "calendar", - "event", - "full-sized", - "Resources" - ], + "version": "2.0.2", + + "description": "Full-sized drag & drop event calendar", + "keywords": [ "calendar", "event", "full-sized" ], "homepage": "http://arshaw.com/fullcalendar/", - "demo": "", - "docs": "http://arshaw.com/fullcalendar/docs/", - "download": "", - "bugs": "https://github.com/seankenny/fullcalendar/issues", - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/seankenny/fullcalendar/blob/master/license.txt" - } - ], - "author": { - "name": "Adam Shaw, Sean Kenny", - "email": "srkenny@gmail.com", - "url": "http://seankenny.me/" + + "dependencies": { + "jquery": ">=1.7.1", + "moment": ">=2.5.0" }, - "copyright": "2013 Adam Shaw, Sean Kenny - resource view", + "devDependencies": { + "jquery-ui": "1.8.17 - 1.10.4", + "jquery-simulate-ext": "~1.3.0", + "jquery-mockjax": "~1.5.3", + "jasmine-jquery": "~2.0.3", + "jasmine-fixture": "~1.2.0", + "moment-timezone": "~0.0.6" + }, + "main": [ - "/build/component/fullcalendar.js", - "/build/component/fullcalendar.css" + "/dist/fullcalendar.js", + "/dist/fullcalendar.css" + ], + "ignore": [ + "*", + "**/.*", + "!/dist/**", + "!/bower.json", + "!/changelog.*", + "!/license.*", + "!/readme.*" ] } \ No newline at end of file diff --git a/build/cdnjs-commit.sh b/build/cdnjs-commit.sh new file mode 100755 index 0000000..ed09fb8 --- /dev/null +++ b/build/cdnjs-commit.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +cd "`dirname $0`/.." +proj_dir="$PWD" + +echo +echo "This script assumes the following:" +echo "1. You have run the release script" +echo "2. You have a clone of CDNJS's repo with remotes 'upstream' and 'origin'" +echo "3. You have initialized CDNJS's repo with 'npm install'" +echo + +# 1. make a fork of cdnjs on github +# 2. clone the fork from github (which will be the 'origin') +# 3. `git remote add upstream git@github.com:cdnjs/cdnjs.git` + +version=$(sed -n 's/^.*"version" *: *"\([^"]*\)".*$/\1/p' package.json) +cdnjs_dir="$HOME/Scratch/cdnjs" + +echo "FullCalendar version: $version" +echo "Default CDNJS directory: $cdnjs_dir" +echo + +echo "Enter the location of the CDNJS directory. To keep the default, press enter." +read cdnjs_dir_override + +if [[ "$cdnjs_dir_override" ]] +then + cdnjs_dir="$cdnjs_dir_override" +fi + +echo "Updating local copy of CDNJS..." && \ +cd "$cdnjs_dir" && \ +git pull upstream master && \ +\ +echo "Copying over our changes..." && \ +cd "$proj_dir" && \ +cp -r -f dist/cdnjs/* "$cdnjs_dir/ajax/libs/fullcalendar/" && \ +\ +echo "Running CDNJS's tests..." && \ +cd "$cdnjs_dir" && \ +npm test && \ +\ +echo "Building commit..." && \ +git add "ajax/libs/fullcalendar/" && \ +git commit -e -m "fullcalendar v$version" && \ +echo && \ +echo 'DONE. It is now up to you to run `'"cd $cdnjs_dir && git push origin master"'` and submit the PR to CDNJS.' && \ +echo \ No newline at end of file diff --git a/build/cdn.json b/build/cdnjs.json similarity index 100% rename from build/cdn.json rename to build/cdnjs.json diff --git a/build/component-readme.md b/build/component-readme.md deleted file mode 100644 index 367bfea..0000000 --- a/build/component-readme.md +++ /dev/null @@ -1,10 +0,0 @@ - -FullCalendar Component -====================== - -This repo is the official [Bower](http://twitter.github.com/bower/) component endpoint for the -[FullCalendar Project](http://arshaw.com/fullcalendar/). -It is a shim repo that has been generated by running the `grunt component` command in the -main development repo. - -[Visit the development repo](https://github.com/arshaw/fullcalendar) \ No newline at end of file diff --git a/build/component.json b/build/component.json deleted file mode 100644 index 9da237b..0000000 --- a/build/component.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "main": [ - "./fullcalendar.js", - "./fullcalendar.css" - ] -} \ No newline at end of file diff --git a/build/demo-date-update.sh b/build/demo-date-update.sh new file mode 100755 index 0000000..1ed31a4 --- /dev/null +++ b/build/demo-date-update.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +read -p "Enter new year (4 digits): " year +read -p "Enter new month (2 digits): " month +read -p "This will modify files in the demos folder, is that ok? (y/n): " yn + +if [[ $yn != "y" ]] +then + exit +fi + +find "`dirname $0`/../demos" -type f \( -name '*.html' -o -name '*.json' \) -print0 \ +| xargs -0 sed -i '' -e "s/[0-9][0-9][0-9][0-9]-[0-9][0-9]/$year-$month/g" + +echo "DONE" \ No newline at end of file diff --git a/build/jscs.conf.js b/build/jscs.conf.js new file mode 100644 index 0000000..5cdadf8 --- /dev/null +++ b/build/jscs.conf.js @@ -0,0 +1,53 @@ +module.exports = { + + options: { + requireCurlyBraces: [ 'if', 'else', 'for', 'while', 'do', 'try', 'catch' ], + requireSpacesInFunctionExpression: { beforeOpeningCurlyBrace: true }, + disallowSpacesInFunctionExpression: { beforeOpeningRoundBrace: true }, + disallowSpacesInsideParentheses: true, + requireSpacesInsideObjectBrackets: 'all', + disallowQuotedKeysInObjects: 'allButReserved', + disallowSpaceAfterObjectKeys: true, + requireCommaBeforeLineBreak: true, + requireOperatorBeforeLineBreak: [ '?', '+', '-', '/', '*', '=', '==', '===', '!=', '!==', '>', '>=', '<', '<=' ], + disallowLeftStickedOperators: [ '?' ], + requireRightStickedOperators: [ '!' ], + requireLeftStickedOperators: [ ',' ], + disallowRightStickedOperators: [ ':' ], + disallowSpaceAfterPrefixUnaryOperators: [ '++', '--', '+', '-', '~', '!' ], + disallowSpaceBeforePostfixUnaryOperators: [ '++', '--' ], + requireCamelCaseOrUpperCaseIdentifiers: true, + disallowKeywords: [ 'with' ], + disallowMultipleLineStrings: true, + requireDotNotation: true, + requireParenthesesAroundIIFE: true + }, + + srcModules: [ + 'src/**/*.js', + '!**/intro.js', + '!**/outro.js' + ], + + srcLanguages: 'lang/*.js', + + tests: { + options: { + // more restrictions. + // we eventually want these to apply to all other code too. + requireSpaceAfterKeywords: [ 'if', 'else', 'for', 'while', 'do', 'switch', 'return', 'try', 'catch' ], + requireSpacesInsideArrayBrackets: 'all', + requireKeywordsOnNewLine: [ 'else', 'catch' ], + disallowTrailingWhitespace: true, + validateQuoteMarks: '\'', + maximumLineLength: 120 + }, + src: 'tests/automated/*.js' + }, + + misc: [ + '*.js', // ex: Gruntfile.js + 'build/*.js' // ex: this file + ] + +}; \ No newline at end of file diff --git a/build/jshint.conf.js b/build/jshint.conf.js new file mode 100644 index 0000000..e6fad80 --- /dev/null +++ b/build/jshint.conf.js @@ -0,0 +1,55 @@ +module.exports = { + + options: { + browser: true, + globals: { + // `false` means read-only + define: false, + moment: false, + jQuery: false + }, + es3: true, + bitwise: true, + camelcase: true, + curly: true, + forin: true, + freeze: true, + immed: true, + noarg: true, + smarttabs: true, + trailing: true, + eqnull: true, + '-W032': true, // Unnecessary semicolon. (lumbar's ;;) + '-W008': true // A leading decimal point can be confused with a dot (ex: .5) + }, + + srcModules: [ + 'src/**/*.js', + '!**/intro.js', // exclude + '!**/outro.js' // + ], + + builtModules: { + options: { + // Built modules are ready to be checked for... + undef: true, // use of undeclared globals + unused: 'vars', // functions/variables (excluding function arguments) that are never used + latedef: 'nofunc' // variables that are referenced before their `var` statement + }, + src: [ + 'dist/*.js', + '!**/*.min.js', // exclude + '!**/lang-all.js' // + ] + }, + + srcLanguages: 'lang/*.js', + + tests: 'tests/automated/*.js', + + misc: [ + '*.js', // ex: Gruntfile.js + 'build/*.js' // ex: this file + ] + +}; \ No newline at end of file diff --git a/build/karma.conf.js b/build/karma.conf.js new file mode 100644 index 0000000..74343d2 --- /dev/null +++ b/build/karma.conf.js @@ -0,0 +1,79 @@ + +module.exports = function(config) { + config.set({ + + // base path, that will be used to resolve files and exclude + basePath: '', + + // frameworks to use + frameworks: [ 'jasmine' ], + + // list of files / patterns to load in the browser + files: [ + + // For IE8 testing. Because doesn't have forEach and other ES5 methods + // which are common in the tests. + // You must run `bower install es5-shim` first. + //'../lib/es5-shim/es5-shim.js', + + // For IE8 testing, we'll need jQuery 1.x. Before running karma, force the version: + // `bower install jquery#1` and choose 1 + // to undo: `bower update jquery` + + '../lib/moment/moment.js', + '../lib/jquery/dist/jquery.js', + '../lib/jquery-ui/ui/jquery-ui.js', + + // for jquery simulate + '../lib/jquery-simulate-ext/libs/bililiteRange.js', + '../lib/jquery-simulate-ext/libs/jquery.simulate.js', + '../lib/jquery-simulate-ext/src/jquery.simulate.ext.js', + '../lib/jquery-simulate-ext/src/jquery.simulate.drag-n-drop.js', + '../lib/jquery-simulate-ext/src/jquery.simulate.key-sequence.js', + '../lib/jquery-simulate-ext/src/jquery.simulate.key-combo.js', + '../tests/lib/jquery-simulate-hacks.js', // needs to be last + + '../lib/jquery-mockjax/jquery.mockjax.js', + '../lib/jasmine-jquery/lib/jasmine-jquery.js', + '../lib/jasmine-fixture/dist/jasmine-fixture.js', + '../tests/lib/jasmine-ext.js', + + '../dist/fullcalendar.js', + '../dist/gcal.js', + '../dist/lang-all.js', + '../dist/fullcalendar.css', + '../tests/base.css', + + // For IE8 testing. Because it can't handle running all the tests at once. + // Comment out the *.js line and run karma with each of the lines below. + //'../tests/automated/{a,b,c,d,e,f,g,h,i,j,k,l}*.js' + //'../tests/automated/{m,n}*.js' // mostly moment tests + //'../tests/automated/{o,p,q,r,s,t,u,v,w,x,y,z}*.js' + + '../tests/automated/*.js' + ], + + // list of files to exclude + exclude: [], + + // test results reporter to use + // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' + reporters: [ 'dots' ], + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + // If browser does not capture in given timeout [ms], kill it + captureTimeout: 60000 + }); +}; \ No newline at end of file diff --git a/build/release.sh b/build/release.sh new file mode 100755 index 0000000..0537983 --- /dev/null +++ b/build/release.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +cd "`dirname $0`/.." + +read -p "Enter the new version number with no 'v' (for example '1.0.1'): " version + +if [[ ! "$version" ]] +then + exit +fi + +grunt bump --setversion=$version && \ +grunt dist && \ +grunt shell:no-assume-unchanged && \ +git add -f dist/*.js dist/*.css dist/lang/*.js && \ +git commit -a -e -m "version $version" && \ +git tag -a v$version -m "version $version" + +status=$? + +# regardless of error/success, undo the temporary no-assume-unchanged +git reset +grunt shell:assume-unchanged + +if [ $status -eq 0 ] +then + echo + echo 'DONE. It is now up to you to run `'"git push origin master && git push origin v$version"'`' + echo +fi \ No newline at end of file diff --git a/build/tasks/generateLanguages.js b/build/tasks/generateLanguages.js new file mode 100644 index 0000000..5079e95 --- /dev/null +++ b/build/tasks/generateLanguages.js @@ -0,0 +1,209 @@ +var pathLib = require('path'); + +module.exports = function(grunt) { + + var config = grunt.config('generateLanguages'); + + + grunt.registerTask('generateLanguages', function() { + + var combinedJS = ''; + var languageCnt = 0; + var skippedLangCodes = []; + + grunt.file.mkdir(config.dest, 0755); + + grunt.file.expand(pathLib.join(config.moment, '*.js')).forEach(function(momentPath) { + + var langCode = momentPath.match(/([^\/]*)\.js$/)[1]; + var js = getLangJS(langCode, momentPath); + + if (js) { + + grunt.file.write( + pathLib.join(config.dest, langCode + '.js'), + wrapWithUMD(js) + ); + + combinedJS += wrapWithClosure(js) + '\n'; + + languageCnt++; + } + else { + skippedLangCodes.push(langCode); + } + + }); + + // code for resetting the language back to English + combinedJS += '\nmoment.lang("en");'; + combinedJS += '\n$.fullCalendar.lang("en");'; + combinedJS += '\nif ($.datepicker) $.datepicker.setDefaults($.datepicker.regional[""]);'; + + if (config.allDest) { + grunt.file.write(config.allDest, wrapWithUMD(combinedJS)); + } + + grunt.log.writeln(skippedLangCodes.length + ' skipped languages: ' + skippedLangCodes.join(', ')); + grunt.log.writeln(languageCnt + ' generated languages.'); + + }); + + + function getLangJS(langCode, momentPath) { + + var shortLangCode; + var momentLangJS; + var datepickerLangJS; + var fullCalendarLangJS; + + // given "fr-ca", get just "fr" + if (langCode.indexOf('-') != -1) { + shortLangCode = langCode.replace(/-.*/, ''); + } + + momentLangJS = getMomentLangJS(momentPath); + + datepickerLangJS = getDatepickerLangJS(langCode); + if (!datepickerLangJS && shortLangCode) { + datepickerLangJS = getDatepickerLangJS(shortLangCode, langCode); + } + + fullCalendarLangJS = getFullCalendarLangJS(langCode); + if (!fullCalendarLangJS && shortLangCode) { + fullCalendarLangJS = getFullCalendarLangJS(shortLangCode, langCode); + } + + // If this is an "en" language, only the Moment config is needed. + // For all other languages, all 3 configs are needed. + if (momentLangJS && (shortLangCode == 'en' || (datepickerLangJS && fullCalendarLangJS))) { + + // if there is no definition, we still need to tell FC to set the default + if (!fullCalendarLangJS) { + fullCalendarLangJS = '$.fullCalendar.lang("' + langCode + '");'; + } + + datepickerLangJS = datepickerLangJS || ''; + + return momentLangJS + '\n' + + datepickerLangJS + '\n' + + fullCalendarLangJS; + } + } + + + function wrapWithUMD(body) { + return [ + '(function(factory) {', + ' if (typeof define === "function" && define.amd) {', + ' define([ "jquery", "moment" ], factory);', + ' }', + ' else {', + ' factory(jQuery, moment);', + ' }', + '})(function($, moment) {', + '', + body, + '', + '});' + ].join('\n'); + } + + + function wrapWithClosure(body) { + return [ + '(function() {', + '', + body, + '', + '})();' + ].join('\n'); + } + + + function getMomentLangJS(path) { // file assumed to exist + + var js = grunt.file.read(path); + + js = js.replace( // remove the UMD wrap + /\(\s*function[\S\s]*?function\s*\(\s*moment\s*\)\s*\{([\S\s]*)\}\)\);?/, + function(m0, body) { + body = body.replace(/^ /mg, ''); // remove 1 level of indentation + return body; + } + ); + + js = js.replace( // replace the `return` statement so execution continues + /^(\s*)return moment\.lang\(/m, + '$1moment.lang(' + ); + + return js; + } + + + function getDatepickerLangJS(langCode, targetLangCode) { + + // convert "en-ca" to "en-CA" + var datepickerLangCode = langCode.replace(/\-(\w+)/, function(m0, m1) { + return '-' + m1.toUpperCase(); + }); + + var path = pathLib.join(config.datepicker, 'jquery.ui.datepicker-' + datepickerLangCode + '.js'); + var js; + + try { + js = grunt.file.read(path); + } + catch (ex) { + return false; + } + + js = js.replace( + /^jQuery\([\S\s]*?\{([\S\s]*)\}\);?/m, // inside the jQuery(function) wrap, + function(m0, body) { // use only the function body, modified. + + var match = body.match(/\$\.datepicker\.regional[\S\s]*?(\{[\S\s]*?\});?/); + var props = match[1]; + + // remove 1 level of tab indentation + props = props.replace(/^\t/mg, ''); + + return "$.fullCalendar.datepickerLang(" + + "'" + (targetLangCode || langCode) + "', " + // for FullCalendar + "'" + datepickerLangCode + "', " + // for datepicker + props + + ");"; + } + ); + + return js; + } + + + function getFullCalendarLangJS(langCode, targetLangCode) { + + var path = pathLib.join(config.fullCalendar, langCode + '.js'); + var js; + + try { + js = grunt.file.read(path); + } + catch (ex) { + return false; + } + + // if we originally wanted "ar-ma", but only "ar" is available, we have to adjust + // the declaration + if (targetLangCode && targetLangCode != langCode) { + js = js.replace( + /\$\.fullCalendar\.lang\(['"]([^'"]*)['"]/, + '$.fullCalendar.lang("' + targetLangCode + '"' + ); + } + + return js; + } + + +}; diff --git a/build/watch b/build/watch deleted file mode 100755 index 3a7c91f..0000000 --- a/build/watch +++ /dev/null @@ -1 +0,0 @@ -"`dirname $0`/../node_modules/lumbar/bin/lumbar" watch "$@" "`dirname $0`/out" \ No newline at end of file diff --git a/build/watch.sh b/build/watch.sh new file mode 100755 index 0000000..56eb656 --- /dev/null +++ b/build/watch.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +cd "`dirname $0`/.." + +grunt shell:assume-unchanged +grunt lumbar:watch \ No newline at end of file diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..e96f5bd --- /dev/null +++ b/changelog.md @@ -0,0 +1,602 @@ + +v2.0.2 (2014-06-24) +------------------- + +- bug with persisting addEventSource calls ([2191]) +- bug with persisting removeEvents calls with an array source ([2187]) +- bug with removeEvents method when called with 0 removes all events ([2082]) + +[2191]: https://code.google.com/p/fullcalendar/issues/detail?id=2191 +[2187]: https://code.google.com/p/fullcalendar/issues/detail?id=2187 +[2082]: https://code.google.com/p/fullcalendar/issues/detail?id=2082 + + +v2.0.1 (2014-06-15) +------------------- + +- `delta` parameters reintroduced in `eventDrop` and `eventResize` handlers ([2156]) + - **Note**: this changes the argument order for `revertFunc` +- wrongfully triggering a windowResize when resizing an agenda view event ([1116]) +- `this` values in event drag-n-drop/resize handlers consistently the DOM node ([1177]) +- `displayEventEnd` - v2 workaround to force display of an end time ([2090]) +- don't modify passed-in eventSource items ([954]) +- destroy method now removes fc-ltr class ([2033]) +- weeks of last/next month still visible when weekends are hidden ([2095]) +- fixed memory leak when destroying calendar with selectable/droppable ([2137]) +- Icelandic language ([2180]) +- Bahasa Indonesia language ([PR 172]) + +[1116]: https://code.google.com/p/fullcalendar/issues/detail?id=1116 +[1177]: https://code.google.com/p/fullcalendar/issues/detail?id=1177 +[2090]: https://code.google.com/p/fullcalendar/issues/detail?id=2090 +[954]: https://code.google.com/p/fullcalendar/issues/detail?id=954 +[2033]: https://code.google.com/p/fullcalendar/issues/detail?id=2033 +[2095]: https://code.google.com/p/fullcalendar/issues/detail?id=2095 +[2137]: https://code.google.com/p/fullcalendar/issues/detail?id=2137 +[2156]: https://code.google.com/p/fullcalendar/issues/detail?id=2156 +[2180]: https://code.google.com/p/fullcalendar/issues/detail?id=2180 +[PR 172]: https://github.com/arshaw/fullcalendar/pull/172 + + +v2.0.0 (2014-06-01) +------------------- + +Internationalization support, timezone support, and [MomentJS] integration. Extensive changes, many +of which are backwards incompatible. + +[Full list of changes][Upgrading-to-v2] | [Affected Issues][Date-Milestone] + +An automated testing framework has been set up ([Karma] + [Jasmine]) and tests have been written +which cover about half of FullCalendar's functionality. Special thanks to @incre-d, @vidbina, and +@sirrocco for the help. + +In addition, the main development repo has been repurposed to also include the built distributable +JS/CSS for the project and will serve as the new [Bower] endpoint. + +[MomentJS]: http://momentjs.com/ +[Upgrading-to-v2]: http://arshaw.com/fullcalendar/wiki/Upgrading-to-v2/ +[Date-Milestone]: https://code.google.com/p/fullcalendar/issues/list?can=1&q=milestone%3Ddate +[Karma]: http://karma-runner.github.io/ +[Jasmine]: http://jasmine.github.io/ +[Bower]: http://bower.io/ + + +v1.6.4 (2013-09-01) +------------------- + +- better algorithm for positioning timed agenda events ([1115]) +- `slotEventOverlap` option to tweak timed agenda event overlapping ([218]) +- selection bug when slot height is customized ([1035]) +- supply view argument in `loading` callback ([1018]) +- fixed week number not displaying in agenda views ([1951]) +- fixed fullCalendar not initializing with no options ([1356]) +- NPM's `package.json`, no more warnings or errors ([1762]) +- building the bower component should output `bower.json` instead of `component.json` ([PR 125]) +- use bower internally for fetching new versions of jQuery and jQuery UI + +[1115]: https://code.google.com/p/fullcalendar/issues/detail?id=1115 +[218]: https://code.google.com/p/fullcalendar/issues/detail?id=218 +[1035]: https://code.google.com/p/fullcalendar/issues/detail?id=1035 +[1018]: https://code.google.com/p/fullcalendar/issues/detail?id=1018 +[1951]: https://code.google.com/p/fullcalendar/issues/detail?id=1951 +[1356]: https://code.google.com/p/fullcalendar/issues/detail?id=1356 +[1762]: https://code.google.com/p/fullcalendar/issues/detail?id=1762 +[PR 125]: https://github.com/arshaw/fullcalendar/pull/125 + + +v1.6.3 (2013-08-10) +------------------- + +- `viewRender` callback ([PR 15]) +- `viewDestroy` callback ([PR 15]) +- `eventDestroy` callback ([PR 111]) +- `handleWindowResize` option ([PR 54]) +- `eventStartEditable`/`startEditable` options ([PR 49]) +- `eventDurationEditable`/`durationEditable` options ([PR 49]) +- specify function for `$.ajax` `data` parameter for JSON event sources ([PR 59]) +- fixed bug with agenda event dropping in wrong column ([PR 55]) +- easier event element z-index customization ([PR 58]) +- classNames on past/future days ([PR 88]) +- allow `null`/`undefined` event titles ([PR 84]) +- small optimize for agenda event rendering ([PR 56]) +- deprecated: + - `viewDisplay` + - `disableDragging` + - `disableResizing` +- bundled with latest jQuery (1.10.2) and jQuery UI (1.10.3) + +[PR 15]: https://github.com/arshaw/fullcalendar/pull/15 +[PR 111]: https://github.com/arshaw/fullcalendar/pull/111 +[PR 54]: https://github.com/arshaw/fullcalendar/pull/54 +[PR 49]: https://github.com/arshaw/fullcalendar/pull/49 +[PR 59]: https://github.com/arshaw/fullcalendar/pull/59 +[PR 55]: https://github.com/arshaw/fullcalendar/pull/55 +[PR 58]: https://github.com/arshaw/fullcalendar/pull/58 +[PR 88]: https://github.com/arshaw/fullcalendar/pull/88 +[PR 84]: https://github.com/arshaw/fullcalendar/pull/84 +[PR 56]: https://github.com/arshaw/fullcalendar/pull/56 + + +v1.6.2 (2013-07-18) +------------------- + +- `hiddenDays` option ([686]) +- bugfix: when `eventRender` returns `false`, incorrect stacking of events ([762]) +- bugfix: couldn't change `event.backgroundImage` when calling `updateEvent` (thx @stephenharris) + +[686]: https://code.google.com/p/fullcalendar/issues/detail?id=686 +[762]: https://code.google.com/p/fullcalendar/issues/detail?id=762 + + +v1.6.1 (2013-04-14) +------------------- + +- fixed event inner content overflow bug ([1783]) +- fixed table header className bug [1772] +- removed text-shadow on events (better for general use, thx @tkrotoff) + +[1783]: https://code.google.com/p/fullcalendar/issues/detail?id=1783 +[1772]: https://code.google.com/p/fullcalendar/issues/detail?id=1772 + + +v1.6.0 (2013-03-18) +------------------- + +- visual facelift, with bootstrap-inspired buttons and colors +- simplified HTML/CSS for events and buttons +- `dayRender`, for modifying a day cell ([191], thx @althaus) +- week numbers on side of calendar ([295]) + - `weekNumber` + - `weekNumberCalculation` + - `weekNumberTitle` + - `W` formatting variable +- finer snapping granularity for agenda view events ([495], thx @ms-doodle-com) +- `eventAfterAllRender` ([753], thx @pdrakeweb) +- `eventDataTransform` (thx @joeyspo) +- `data-date` attributes on cells (thx @Jae) +- expose `$.fullCalendar.dateFormatters` +- when clicking fast on buttons, prevent text selection +- bundled with latest jQuery (1.9.1) and jQuery UI (1.10.2) +- Grunt/Lumbar build system for internal development +- build for Bower package manager +- build for jQuery plugin site + +[191]: https://code.google.com/p/fullcalendar/issues/detail?id=191 +[295]: https://code.google.com/p/fullcalendar/issues/detail?id=295 +[495]: https://code.google.com/p/fullcalendar/issues/detail?id=495 +[753]: https://code.google.com/p/fullcalendar/issues/detail?id=753 + + +v1.5.4 (2012-09-05) +------------------- + +- made compatible with jQuery 1.8.* (thx @archaeron) +- bundled with jQuery 1.8.1 and jQuery UI 1.8.23 + + +v1.5.3 (2012-02-06) +------------------- + +- fixed dragging issue with jQuery UI 1.8.16 ([1168]) +- bundled with jQuery 1.7.1 and jQuery UI 1.8.17 + +[1168]: https://code.google.com/p/fullcalendar/issues/detail?id=1168 + + +v1.5.2 (2011-08-21) +------------------- + +- correctly process UTC "Z" ISO8601 date strings ([750]) + +[750]: https://code.google.com/p/fullcalendar/issues/detail?id=750 + + +v1.5.1 (2011-04-09) +------------------- + +- more flexible ISO8601 date parsing ([814]) +- more flexible parsing of UNIX timestamps ([826]) +- FullCalendar now buildable from source on a Mac ([795]) +- FullCalendar QA'd in FF4 ([883]) +- upgraded to jQuery 1.5.2 (which supports IE9) and jQuery UI 1.8.11 + +[814]: https://code.google.com/p/fullcalendar/issues/detail?id=814 +[826]: https://code.google.com/p/fullcalendar/issues/detail?id=826 +[795]: https://code.google.com/p/fullcalendar/issues/detail?id=795 +[883]: https://code.google.com/p/fullcalendar/issues/detail?id=883 + + +v1.5 (2011-03-19) +----------------- + +- slicker default styling for buttons +- reworked a lot of the calendar's HTML and accompanying CSS (solves [327] and [395]) +- more printer-friendly (fullcalendar-print.css) +- fullcalendar now inherits styles from jquery-ui themes differently. + styles for buttons are distinct from styles for calendar cells. + (solves [299]) +- can now color events through FullCalendar options and Event-Object properties ([117]) + THIS IS NOW THE PREFERRED METHOD OF COLORING EVENTS (as opposed to using className and CSS) + - FullCalendar options: + - eventColor (changes both background and border) + - eventBackgroundColor + - eventBorderColor + - eventTextColor + - Event-Object options: + - color (changes both background and border) + - backgroundColor + - borderColor + - textColor +- can now specify an event source as an *object* with a `url` property (json feed) or + an `events` property (function or array) with additional properties that will + be applied to the entire event source: + - color (changes both background and border) + - backgroudColor + - borderColor + - textColor + - className + - editable + - allDayDefault + - ignoreTimezone + - startParam (for a feed) + - endParam (for a feed) + - ANY OF THE JQUERY $.ajax OPTIONS + allows for easily changing from GET to POST and sending additional parameters ([386]) + allows for easily attaching ajax handlers such as `error` ([754]) + allows for turning caching on ([355]) +- Google Calendar feeds are now specified differently: + - specify a simple string of your feed's URL + - specify an *object* with a `url` property of your feed's URL. + you can include any of the new Event-Source options in this object. + - the old `$.fullCalendar.gcalFeed` method still works +- no more IE7 SSL popup ([504]) +- remove `cacheParam` - use json event source `cache` option instead +- latest jquery/jquery-ui + +[327]: https://code.google.com/p/fullcalendar/issues/detail?id=327 +[395]: https://code.google.com/p/fullcalendar/issues/detail?id=395 +[299]: https://code.google.com/p/fullcalendar/issues/detail?id=299 +[117]: https://code.google.com/p/fullcalendar/issues/detail?id=117 +[386]: https://code.google.com/p/fullcalendar/issues/detail?id=386 +[754]: https://code.google.com/p/fullcalendar/issues/detail?id=754 +[355]: https://code.google.com/p/fullcalendar/issues/detail?id=355 +[504]: https://code.google.com/p/fullcalendar/issues/detail?id=504 + + +v1.4.11 (2011-02-22) +-------------------- + +- fixed rerenderEvents bug ([790]) +- fixed bug with faulty dragging of events from all-day slot in agenda views +- bundled with jquery 1.5 and jquery-ui 1.8.9 + +[790]: https://code.google.com/p/fullcalendar/issues/detail?id=790 + + +v1.4.10 (2011-01-02) +-------------------- + +- fixed bug with resizing event to different week in 5-day month view ([740]) +- fixed bug with events not sticking after a removeEvents call ([757]) +- fixed bug with underlying parseTime method, and other uses of parseInt ([688]) + +[740]: https://code.google.com/p/fullcalendar/issues/detail?id=740 +[757]: https://code.google.com/p/fullcalendar/issues/detail?id=757 +[688]: https://code.google.com/p/fullcalendar/issues/detail?id=688 + + +v1.4.9 (2010-11-16) +------------------- + +- new algorithm for vertically stacking events ([111]) +- resizing an event to a different week ([306]) +- bug: some events not rendered with consecutive calls to addEventSource ([679]) + +[111]: https://code.google.com/p/fullcalendar/issues/detail?id=111 +[306]: https://code.google.com/p/fullcalendar/issues/detail?id=306 +[679]: https://code.google.com/p/fullcalendar/issues/detail?id=679 + + +v1.4.8 (2010-10-16) +------------------- + +- ignoreTimezone option (set to `false` to process UTC offsets in ISO8601 dates) +- bugfixes + - event refetching not being called under certain conditions ([417], [554]) + - event refetching being called multiple times under certain conditions ([586], [616]) + - selection cannot be triggered by right mouse button ([558]) + - agenda view left axis sized incorrectly ([465]) + - IE js error when calendar is too narrow ([517]) + - agenda view looks strange when no scrollbars ([235]) + - improved parsing of ISO8601 dates with UTC offsets +- $.fullCalendar.version +- an internal refactor of the code, for easier future development and modularity + +[417]: https://code.google.com/p/fullcalendar/issues/detail?id=417 +[554]: https://code.google.com/p/fullcalendar/issues/detail?id=554 +[586]: https://code.google.com/p/fullcalendar/issues/detail?id=586 +[616]: https://code.google.com/p/fullcalendar/issues/detail?id=616 +[558]: https://code.google.com/p/fullcalendar/issues/detail?id=558 +[465]: https://code.google.com/p/fullcalendar/issues/detail?id=465 +[517]: https://code.google.com/p/fullcalendar/issues/detail?id=517 +[235]: https://code.google.com/p/fullcalendar/issues/detail?id=235 + + +v1.4.7 (2010-07-05) +------------------- + +- "dropping" external objects onto the calendar + - droppable (boolean, to turn on/off) + - dropAccept (to filter which events the calendar will accept) + - drop (trigger) +- selectable options can now be specified with a View Option Hash +- bugfixes + - dragged & reverted events having wrong time text ([406]) + - bug rendering events that have an endtime with seconds, but no hours/minutes ([477]) + - gotoDate date overflow bug ([429]) + - wrong date reported when clicking on edge of last column in agenda views [412] +- support newlines in event titles +- select/unselect callbacks now passes native js event + +[406]: https://code.google.com/p/fullcalendar/issues/detail?id=406 +[477]: https://code.google.com/p/fullcalendar/issues/detail?id=477 +[429]: https://code.google.com/p/fullcalendar/issues/detail?id=429 +[412]: https://code.google.com/p/fullcalendar/issues/detail?id=412 + + +v1.4.6 (2010-05-31) +------------------- + +- "selecting" days or timeslots + - options: selectable, selectHelper, unselectAuto, unselectCancel + - callbacks: select, unselect + - methods: select, unselect +- when dragging an event, the highlighting reflects the duration of the event +- code compressing by Google Closure Compiler +- bundled with jQuery 1.4.2 and jQuery UI 1.8.1 + + +v1.4.5 (2010-02-21) +------------------- + +- lazyFetching option, which can force the calendar to fetch events on every view/date change +- scroll state of agenda views are preserved when switching back to view +- bugfixes + - calling methods on an uninitialized fullcalendar throws error + - IE6/7 bug where an entire view becomes invisible ([320]) + - error when rendering a hidden calendar (in jquery ui tabs for example) in IE ([340]) + - interconnected bugs related to calendar resizing and scrollbars + - when switching views or clicking prev/next, calendar would "blink" ([333]) + - liquid-width calendar's events shifted (depending on initial height of browser) ([341]) + - more robust underlying algorithm for calendar resizing + +[320]: https://code.google.com/p/fullcalendar/issues/detail?id=320 +[340]: https://code.google.com/p/fullcalendar/issues/detail?id=340 +[333]: https://code.google.com/p/fullcalendar/issues/detail?id=333 +[341]: https://code.google.com/p/fullcalendar/issues/detail?id=341 + + +v1.4.4 (2010-02-03) +------------------- + +- optimized event rendering in all views (events render in 1/10 the time) +- gotoDate() does not force the calendar to unnecessarily rerender +- render() method now correctly readjusts height + + +v1.4.3 (2009-12-22) +------------------- + +- added destroy method +- Google Calendar event pages respect currentTimezone +- caching now handled by jQuery's ajax +- protection from setting aspectRatio to zero +- bugfixes + - parseISO8601 and DST caused certain events to display day before + - button positioning problem in IE6 + - ajax event source removed after recently being added, events still displayed + - event not displayed when end is an empty string + - dynamically setting calendar height when no events have been fetched, throws error + + +v1.4.2 (2009-12-02) +------------------- + +- eventAfterRender trigger +- getDate & getView methods +- height & contentHeight options (explicitly sets the pixel height) +- minTime & maxTime options (restricts shown hours in agenda view) +- getters [for all options] and setters [for height, contentHeight, and aspectRatio ONLY! stay tuned..] +- render method now readjusts calendar's size +- bugfixes + - lightbox scripts that use iframes (like fancybox) + - day-of-week classNames were off when firstDay=1 + - guaranteed space on right side of agenda events (even when stacked) + - accepts ISO8601 dates with a space (instead of 'T') + + +v1.4.1 (2009-10-31) +------------------- + +- can exclude weekends with new 'weekends' option +- gcal feed 'currentTimezone' option +- bugfixes + - year/month/date option sometimes wouldn't set correctly (depending on current date) + - daylight savings issue caused agenda views to start at 1am (for BST users) +- cleanup of gcal.js code + + +v1.4 (2009-10-19) +----------------- + +- agendaWeek and agendaDay views +- added some options for agenda views: + - allDaySlot + - allDayText + - firstHour + - slotMinutes + - defaultEventMinutes + - axisFormat +- modified some existing options/triggers to work with agenda views: + - dragOpacity and timeFormat can now accept a "View Hash" (a new concept) + - dayClick now has an allDay parameter + - eventDrop now has an an allDay parameter + (this will affect those who use revertFunc, adjust parameter list) +- added 'prevYear' and 'nextYear' for buttons in header +- minor change for theme users, ui-state-hover not applied to active/inactive buttons +- added event-color-changing example in docs +- better defaults for right-to-left themed button icons + + +v1.3.2 (2009-10-13) +------------------- + +- Bugfixes (please upgrade from 1.3.1!) + - squashed potential infinite loop when addMonths and addDays + is called with an invalid date + - $.fullCalendar.parseDate() now correctly parses IETF format + - when switching views, the 'today' button sticks inactive, fixed +- gotoDate now can accept a single Date argument +- documentation for changes in 1.3.1 and 1.3.2 now on website + + +v1.3.1 (2009-09-30) +------------------- + +- Important Bugfixes (please upgrade from 1.3!) + - When current date was late in the month, for long months, and prev/next buttons + were clicked in month-view, some months would be skipped/repeated + - In certain time zones, daylight savings time would cause certain days + to be misnumbered in month-view +- Subtle change in way week interval is chosen when switching from month to basicWeek/basicDay view +- Added 'allDayDefault' option +- Added 'changeView' and 'render' methods + + +v1.3 (2009-09-21) +----------------- + +- different 'views': month/basicWeek/basicDay +- more flexible 'header' system for buttons +- themable by jQuery UI themes +- resizable events (require jQuery UI resizable plugin) +- rescoped & rewritten CSS, enhanced default look +- cleaner css & rendering techniques for right-to-left +- reworked options & API to support multiple views / be consistent with jQuery UI +- refactoring of entire codebase + - broken into different JS & CSS files, assembled w/ build scripts + - new test suite for new features, uses firebug-lite +- refactored docs +- Options + - + date + - + defaultView + - + aspectRatio + - + disableResizing + - + monthNames (use instead of $.fullCalendar.monthNames) + - + monthNamesShort (use instead of $.fullCalendar.monthAbbrevs) + - + dayNames (use instead of $.fullCalendar.dayNames) + - + dayNamesShort (use instead of $.fullCalendar.dayAbbrevs) + - + theme + - + buttonText + - + buttonIcons + - x draggable -> editable/disableDragging + - x fixedWeeks -> weekMode + - x abbrevDayHeadings -> columnFormat + - x buttons/title -> header + - x eventDragOpacity -> dragOpacity + - x eventRevertDuration -> dragRevertDuration + - x weekStart -> firstDay + - x rightToLeft -> isRTL + - x showTime (use 'allDay' CalEvent property instead) +- Triggered Actions + - + eventResizeStart + - + eventResizeStop + - + eventResize + - x monthDisplay -> viewDisplay + - x resize -> windowResize + - 'eventDrop' params changed, can revert if ajax cuts out +- CalEvent Properties + - x showTime -> allDay + - x draggable -> editable + - 'end' is now INCLUSIVE when allDay=true + - 'url' now produces a real tag, more native clicking/tab behavior +- Methods: + - + renderEvent + - x prevMonth -> prev + - x nextMonth -> next + - x prevYear/nextYear -> moveDate + - x refresh -> rerenderEvents/refetchEvents + - x removeEvent -> removeEvents + - x getEventsByID -> clientEvents +- Utilities: + - 'formatDate' format string completely changed (inspired by jQuery UI datepicker + datejs) + - 'formatDates' added to support date-ranges +- Google Calendar Options: + - x draggable -> editable +- Bugfixes + - gcal extension fetched 25 results max, now fetches all + + +v1.2.1 (2009-06-29) +------------------- + +- bugfixes + - allows and corrects invalid end dates for events + - doesn't throw an error in IE while rendering when display:none + - fixed 'loading' callback when used w/ multiple addEventSource calls + - gcal className can now be an array + + +v1.2 (2009-05-31) +----------------- + +- expanded API + - 'className' CalEvent attribute + - 'source' CalEvent attribute + - dynamically get/add/remove/update events of current month + - locale improvements: change month/day name text + - better date formatting ($.fullCalendar.formatDate) + - multiple 'event sources' allowed + - dynamically add/remove event sources +- options for prevYear and nextYear buttons +- docs have been reworked (include addition of Google Calendar docs) +- changed behavior of parseDate for number strings + (now interpets as unix timestamp, not MS times) +- bugfixes + - rightToLeft month start bug + - off-by-one errors with month formatting commands + - events from previous months sticking when clicking prev/next quickly +- Google Calendar API changed to work w/ multiple event sources + - can also provide 'className' and 'draggable' options +- date utilties moved from $ to $.fullCalendar +- more documentation in source code +- minified version of fullcalendar.js +- test suit (available from svn) +- top buttons now use `