From 270edc7ee592b0f1a4e0103b15f9c30603f73eb9 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Tue, 26 Feb 2013 23:32:02 +0000 Subject: [PATCH] new timezone handling with timezoneJS.date.js Does not work with DST yet... Maybe rewrite the js date/timehandling in php.... Status: does not work as expected! --- build.xml | 23 +- changelog.txt | 4 + index.html | 124 + js/ABOUT.js | 36 + js/data/timezones.js | 4 + js/dialogs/ImportPanel.js | 100 +- js/plugin.calendarimporter.js | 14 +- js/timezone-js/Jakefile | 87 + js/timezone-js/README.md | 192 ++ js/timezone-js/fleegix.js | 1894 ++++++++++++ js/timezone-js/package.json | 31 + js/timezone-js/spec/date.spec.js | 466 +++ js/timezone-js/spec/test-utils.js | 86 + js/timezone-js/spec/tz.async.spec.js | 37 + js/timezone-js/spec/tz.default.spec.js | 15 + js/timezone-js/spec/tz.manual.spec.js | 25 + js/timezone-js/spec/tz.preload.spec.js | 23 + js/timezone-js/spec/tz.sync.spec.js | 176 ++ js/timezone-js/src/date.js | 993 ++++++ js/timezone-js/src/node-preparse.js | 56 + js/timezone-js/src/preparse.js | 65 + js/timezone-js/src/strip_olson_comments.rb | 30 + manifest.xml | 12 +- resources/tz/africa | 1181 +++++++ resources/tz/antarctica | 413 +++ resources/tz/asia | 2717 ++++++++++++++++ resources/tz/australasia | 1719 +++++++++++ resources/tz/backward | 117 + resources/tz/etcetera | 81 + resources/tz/europe | 2856 +++++++++++++++++ resources/tz/factory | 10 + resources/tz/iso3166.tab | 276 ++ resources/tz/leapseconds | 100 + resources/tz/northamerica | 3235 ++++++++++++++++++++ resources/tz/pacificnew | 28 + resources/tz/solar87 | 390 +++ resources/tz/solar88 | 390 +++ resources/tz/solar89 | 395 +++ resources/tz/southamerica | 1711 +++++++++++ resources/tz/systemv | 38 + resources/tz/yearistype.sh | 38 + resources/tz/zone.tab | 441 +++ 42 files changed, 20618 insertions(+), 11 deletions(-) create mode 100644 index.html create mode 100644 js/ABOUT.js create mode 100644 js/timezone-js/Jakefile create mode 100644 js/timezone-js/README.md create mode 100644 js/timezone-js/fleegix.js create mode 100644 js/timezone-js/package.json create mode 100644 js/timezone-js/spec/date.spec.js create mode 100644 js/timezone-js/spec/test-utils.js create mode 100644 js/timezone-js/spec/tz.async.spec.js create mode 100644 js/timezone-js/spec/tz.default.spec.js create mode 100644 js/timezone-js/spec/tz.manual.spec.js create mode 100644 js/timezone-js/spec/tz.preload.spec.js create mode 100644 js/timezone-js/spec/tz.sync.spec.js create mode 100644 js/timezone-js/src/date.js create mode 100644 js/timezone-js/src/node-preparse.js create mode 100644 js/timezone-js/src/preparse.js create mode 100644 js/timezone-js/src/strip_olson_comments.rb create mode 100644 resources/tz/africa create mode 100644 resources/tz/antarctica create mode 100644 resources/tz/asia create mode 100644 resources/tz/australasia create mode 100644 resources/tz/backward create mode 100644 resources/tz/etcetera create mode 100644 resources/tz/europe create mode 100644 resources/tz/factory create mode 100644 resources/tz/iso3166.tab create mode 100644 resources/tz/leapseconds create mode 100644 resources/tz/northamerica create mode 100644 resources/tz/pacificnew create mode 100644 resources/tz/solar87 create mode 100644 resources/tz/solar88 create mode 100644 resources/tz/solar89 create mode 100644 resources/tz/southamerica create mode 100644 resources/tz/systemv create mode 100644 resources/tz/yearistype.sh create mode 100644 resources/tz/zone.tab diff --git a/build.xml b/build.xml index 505c017..367e265 100644 --- a/build.xml +++ b/build.xml @@ -1,4 +1,9 @@ + + + + + @@ -64,6 +69,12 @@ + + + + + + @@ -76,7 +87,7 @@ - + @@ -86,12 +97,14 @@ + + @@ -135,6 +148,7 @@ var Ext = {}; var Zarafa = {}; + var timezoneJS = {}; var container = {}; var _ = function(key, domain) {}; var dgettext = function(domain, msgid) {}; @@ -226,8 +240,10 @@ - + + + @@ -236,6 +252,9 @@ + + + diff --git a/changelog.txt b/changelog.txt index ad339d1..2b9214e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +calendarimporter 1.1, 26.02.2013: + - daylight saving time + - webapp 1.3 about text added + calendarimporter 1.2: - New timezone management - more imported fields (Busystatus, importance, label, class, organizer, reminder) diff --git a/index.html b/index.html new file mode 100644 index 0000000..93f96a6 --- /dev/null +++ b/index.html @@ -0,0 +1,124 @@ + + + + DST Calculator + + + + + + \ No newline at end of file diff --git a/js/ABOUT.js b/js/ABOUT.js new file mode 100644 index 0000000..15c8040 --- /dev/null +++ b/js/ABOUT.js @@ -0,0 +1,36 @@ +Ext.namespace('Zarafa.plugins.calendarimporter'); + +/** + * @class Zarafa.plugins.calendarimporter.ABOUT + * @extends String + * + * The copyright string holding the copyright notice for the Zarafa calendarimporter Plugin. + */ +Zarafa.plugins.calendarimporter.ABOUT = "" + + "

Copyright (C) 2012-2013 Christoph Haas <christoph.h@sprinternet.at>

" + + + "

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

" + + + "

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

" + + + "

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

" + + + "
" + + + "

The calendarimporter plugin contains the following third-party components:

" + + + "

TimezoneJS.Date

" + + + "

Copyright 2010 Matthew Eernisse <mde@fleegix.org> and Open Source Applications Foundation.

" + + + "

Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

" + + + "

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

" + + + "

Fleegix.js JavaScript Toolkit

" + + + "

Copyright 2002-2007 Matthew Eernisse <mde@fleegix.org> and Open Source Applications Foundation.

" + + + "

Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

" + + + "

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

" \ No newline at end of file diff --git a/js/data/timezones.js b/js/data/timezones.js index ea2bbb9..778f328 100644 --- a/js/data/timezones.js +++ b/js/data/timezones.js @@ -744,6 +744,10 @@ Zarafa.plugins.calendarimporter.data.Timezones = Ext.extend(Object, { } return 0; // no offset found... + }, + + getDstOffset: function(time, timezone) { + return 0; // no offset } }); diff --git a/js/dialogs/ImportPanel.js b/js/dialogs/ImportPanel.js index a7af20f..98f90e3 100644 --- a/js/dialogs/ImportPanel.js +++ b/js/dialogs/ImportPanel.js @@ -18,6 +18,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { /* store the imported timezone here... */ timezone: null, + /* store the imported timezone here... */ + dst: true, + /* keep the parsed result here, for timezone changes... */ parsedresult: null, @@ -52,6 +55,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { items : [ this.createSelectBox(), this.createTimezoneBox(), + this.createDaylightSavingCheckBox(), this.initForm() ], buttons: [ @@ -101,7 +105,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { this.remove("eventgrid"); var parsedData = []; - var local_tz_offset = new Date().getTimezoneOffset() * 60000; // getTimezoneOffset returns minutes... we need milliseconds + + /* this is used to get rid of the local timezone... */ + var local_tz_offset = new Date().getTimezoneOffset() * 60; // getTimezoneOffset returns minutes... we need milliseconds var tz_offset = local_tz_offset; if(this.timezone != null) { @@ -113,12 +119,26 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { var i = 0; for(i = 0; i < eventdata.events.length; i++) { var trigger = null; + var dtrigger = null; if(eventdata.events[i]["VALARM"]) { trigger = eventdata.events[i]["VALARM"]["TRIGGER"]; - trigger = new Date(parseInt(trigger) + local_tz_offset + tz_offset); + dtrigger = new timezoneJS.Date(parseInt(trigger) + local_tz_offset + tz_offset, "Etc/UTC"); + if(this.timezone !== null) { + dtrigger.setTimezone(this.timezone); + } } - parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset + tz_offset), new Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset + tz_offset), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"],eventdata.events[i]["PRIORITY"],eventdata.events[i]["X-ZARAFA-LABEL"],eventdata.events[i]["X-MICROSOFT-CDO-BUSYSTATUS"],eventdata.events[i]["CLASS"],eventdata.events[i]["ORGANIZER"],trigger); + + var dstart = new timezoneJS.Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset + tz_offset, "Etc/UTC"); + var dend = new timezoneJS.Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset + tz_offset, "Etc/UTC"); + if(this.timezone !== null) { + dstart.setTimezone(this.timezone); + dend.setTimezone(this.timezone); + } + console.log(this.timezone); + console.log(dstart); + + parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], dstart, dend, eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"],eventdata.events[i]["PRIORITY"],eventdata.events[i]["X-ZARAFA-LABEL"],eventdata.events[i]["X-MICROSOFT-CDO-BUSYSTATUS"],eventdata.events[i]["CLASS"],eventdata.events[i]["ORGANIZER"], dtrigger); } } else { return null; @@ -159,8 +179,30 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }, columns: [ {id: 'Summary', header: 'Title', width: 300, sortable: true, dataIndex: 'title'}, - {header: 'Start', width: 150, sortable: true, dataIndex: 'start', renderer : Zarafa.common.ui.grid.Renderers.datetime}, - {header: 'End', width: 150, sortable: true, dataIndex: 'end', renderer : Zarafa.common.ui.grid.Renderers.datetime}, + { + header: 'Start', + width: 150, + sortable: true, + dataIndex: 'start', + renderer : function(value, p, record) { + p.css = 'mail_date'; + + // # TRANSLATORS: See http://docs.sencha.com/ext-js/3-4/#!/api/Date for the meaning of these formatting instructions + return ((value !== null) && ((typeof value) == "object") && ((typeof value.getTime) == "function")) ? value.toString("yyyy-MM-dd HH:mm:ss Z") :_('None'); + } + }, + { + header: 'End', + width: 150, + sortable: true, + dataIndex: 'end', + renderer : function(value, p, record) { + p.css = 'mail_date'; + + // # TRANSLATORS: See http://docs.sencha.com/ext-js/3-4/#!/api/Date for the meaning of these formatting instructions + return ((value !== null) && ((typeof value) == "object") && ((typeof value.getTime) == "function")) ? value.toString("yyyy-MM-dd HH:mm:ss Z") :_('None'); + } + }, {header: 'Location', width: 150, sortable: true, dataIndex: 'location'}, {header: 'Description', width: 150, sortable: true, dataIndex: 'description'}, {header: "Priority", dataIndex: 'priority', hidden: true}, @@ -168,7 +210,17 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { {header: "Busystatus", dataIndex: 'busy', hidden: true}, {header: "Privacystatus", dataIndex: 'privatestate', hidden: true}, {header: "Organizer", dataIndex: 'organizer', hidden: true}, - {header: "Alarm", dataIndex: 'trigger', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime} + { + header: "Alarm", + dataIndex: 'trigger', + hidden: true, + renderer : function(value, p, record) { + p.css = 'mail_date'; + + // # TRANSLATORS: See http://docs.sencha.com/ext-js/3-4/#!/api/Date for the meaning of these formatting instructions + return ((value !== null) && ((typeof value) == "object") && ((typeof value.getTime) == "function")) ? value.toString("yyyy-MM-dd HH:mm:ss Z") :_('None'); + } + } ] }), sm: new Ext.grid.RowSelectionModel({multiSelect:true}) @@ -241,6 +293,26 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { } }, + createDaylightSavingCheckBox: function() { + return { + xtype: "checkbox", + ref: 'dstcheck', + id: 'dstcheck', + name: "dst_check", + width: 100, + fieldLabel: "Ignore Daylight Saving Time (optional)", + labelSeperator: ":", + border: false, + anchor: "100%", + scope: this, + allowBlank: true, + listeners: { + 'check': this.onDstChecked, + scope: this + } + } + }, + createUploadField: function() { return { xtype: "fileuploadfield", @@ -336,6 +408,21 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { } }, + /** + * This is called when the dst checkbox has been selected + * @param {Ext.form.ComboBox} combo + * @param {Ext.data.Record} record + * @param {Number} index + */ + onDstChecked : function(checkbox, checked) { + this.dst = !checked; + + if(this.parsedresult != null) { + this.add(this.createGrid(this.parsedresult)); + this.doLayout(); + } + }, + /** * This is called when a file has been seleceted in the file dialog * in the {@link Ext.ux.form.FileUploadField} and the dialog is closed @@ -667,3 +754,4 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }); Ext.reg('calendarimporter.importpanel', Zarafa.plugins.calendarimporter.dialogs.ImportPanel); +; diff --git a/js/plugin.calendarimporter.js b/js/plugin.calendarimporter.js index 64ad96f..0f93c35 100644 --- a/js/plugin.calendarimporter.js +++ b/js/plugin.calendarimporter.js @@ -4,7 +4,7 @@ * Main entry point for the plugin * * @author Christoph Haas - * @modified 29.12.2012 + * @modified 26.02.2013 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ @@ -20,6 +20,12 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { constructor: function (config) { config = config || {}; + Ext.applyIf(config, { + name : 'calendarimporter', + displayName : _('Calendarimporter Plugin'), + about : Zarafa.plugins.calendarimporter.ABOUT + }); + Zarafa.plugins.calendarimporter.ImportPlugin.superclass.constructor.call(this, config); }, @@ -28,6 +34,12 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { * @protected */ initPlugin : function() { + + // First of all initialize timezone-js.... + timezoneJS.timezone.zoneFileBasePath = 'plugins/calendarimporter/resources/tz'; + timezoneJS.timezone.defaultZoneFile = @_@PLUGIN_TIMEZONES@_@; // replaced by buildscript -> https://github.com/mde/timezone-js + timezoneJS.timezone.init({async: false}); + Zarafa.plugins.calendarimporter.ImportPlugin.superclass.initPlugin.apply(this, arguments); Zarafa.core.data.SharedComponentType.addProperty('plugins.calendarimporter.dialogs.importevents'); diff --git a/js/timezone-js/Jakefile b/js/timezone-js/Jakefile new file mode 100644 index 0000000..9561690 --- /dev/null +++ b/js/timezone-js/Jakefile @@ -0,0 +1,87 @@ +var fs = require('fs') + , path = require('path'); + +namespace('test', function () { + + desc('Sets up tests by downloading the timezone data.'); + task('init', ['updateTzData'], function () { + complete(); + }, {async: true}); + + task('clobberTzData', function () { + console.log('Removing old timezone data.'); + jake.rmRf('lib/tz'); + }); + + desc('Downloads the newest timezone data.'); + task('updateTzData', ['clobberTzData'], function () { + var cmds = [ + 'echo "Downloading new timezone data ..."' + , 'curl ftp://ftp.iana.org/tz/tzdata-latest.tar.gz ' + + '-o lib/tz/tzdata-latest.tar.gz' + , 'echo "Expanding archive ..."' + , 'tar -xvzf lib/tz/tzdata-latest.tar.gz -C lib/tz' + ]; + jake.mkdirP('lib/tz'); + jake.exec(cmds, function () { + console.log('Retrieved new timezone data'); + console.log('Parsing tz...'); + jake.exec('node src/node-preparse.js lib/tz > lib/all_cities.json', function () { + console.log('Done parsing tz'); + complete(); + }, {printStdout: true, printStderr: true}); + }, {printStdout: true}); + }, {async: true}); + + task('run', function () { + //Comply to 0.8.0 and 0.6.x + var existsSync = fs.existsSync || path.existsSync; + if (!existsSync('lib/tz')) { + fail('No timezone data. Please run "jake test:init".'); + } + jake.exec(['jasmine-node spec'], function () { + complete(); + }, {printStdout: true}); + + }, {async: true}); + + task('cli', ['init', 'run']); + +}); + +desc('Runs the tests.'); +task('test', ['test:run'], function () {}); + +namespace('doc', function () { + task('generate', ['doc:clobber'], function () { + var cmd = 'docco src/date.js'; + console.log('Generating docs ...'); + jake.exec([cmd], function () { + console.log('Done.'); + complete(); + }); + }, {async: true}); + + task('clobber', function () { + var cmd = 'rm -fr ./docs'; + jake.exec([cmd], function () { + console.log('Clobbered old docs.'); + complete(); + }); + }, {async: true}); + +}); + +desc('Generates docs.'); +task('doc', ['doc:generate']); + +var p = new jake.NpmPublishTask('timezone-js', [ + 'Jakefile' +, 'README.md' +, 'package.json' +, 'spec/*' +, 'src/*' +]); + +jake.Task['npm:definePackage'].invoke(); + diff --git a/js/timezone-js/README.md b/js/timezone-js/README.md new file mode 100644 index 0000000..0dc1374 --- /dev/null +++ b/js/timezone-js/README.md @@ -0,0 +1,192 @@ +# TimezoneJS.Date + +[![Build Status](https://secure.travis-ci.org/mde/timezone-js.png)](https://secure.travis-ci.org/mde/timezone-js) + +A timezone-enabled, drop-in replacement for the stock JavaScript Date. The `timezoneJS.Date` object is API-compatible with JS Date, with the same getter and setter methods -- it should work fine in any code that works with normal JavaScript Dates. + +[Mailing list](http://groups.google.com/group/timezone-js) + +## Overview + +The `timezoneJS.Date` object gives you full-blown timezone support, independent from the timezone set on the end-user's machine running the browser. It uses the Olson zoneinfo files for its timezone data. + +The constructor function and setter methods use proxy JavaScript Date objects behind the scenes, so you can use strings like '10/22/2006' with the constructor. You also get the same sensible wraparound behavior with numeric parameters (like setting a value of 14 for the month wraps around to the next March). + +The other significant difference from the built-in JavaScript Date is that `timezoneJS.Date` also has named properties that store the values of year, month, date, etc., so it can be directly serialized to JSON and used for data transfer. + +## Setup + +First you'll need to include the code on your page. Both `timezoneJS.Date`, and the supporting code it needs in `timezoneJS.timezone` are bundled in the `date.js` file in `src` directory. Include the code on your page with a normal JavaScript script include, like so: + +