你的位置:首页 > Java教程

[Java教程]Js: Extensible Calendar Examples


http://ext.ensible.com
https://github.com/bmoeskau/Extensible
https://github.com/TeamupCom/extensible
http://www.rahulsingla.com/sites/default/files/content/blog/extjs-calendar/dynamic-calendars.html
http://ext.ensible.com/deploy/dev/examples/
http://ext.ensible.com/products/calendar/download/choose.php

dynamic-calendars.js:

Ext.ns('Ext.ensible.sample');Ext.ensible.sample.CalendarData = {  "calendars":[{    "id":1,    "title":"Home",    "color":2  },{    "id":2,    "title":"Work",    "color":22  },{    "id":3,    "title":"School",    "color":7  },{    "id":4,    "title":"Sports",    //"hidden":true, // optionally init this calendar as hidden by default    "color":26  }]};var today = new Date().clearTime();Ext.ensible.sample.EventData = {  "evts":[{    "id":1001,    "cid":1,    "title":"Vacation",    "start":today.add(Date.DAY, -20).add(Date.HOUR, 10),    "end":today.add(Date.DAY, -10).add(Date.HOUR, 15),		"notes":"Have fun"  },{    "id":1002,    "cid":2,    "title":"Lunch with Matt",    "start":today.add(Date.HOUR, 11).add(Date.MINUTE, 30),    "end":today.add(Date.HOUR, 13),    "loc":"Chuy's!",    "url":"http://chuys.com",		"notes":"Order the queso",    "rem":"15"  },{    "id":1003,    "cid":3,    "title":"Project due",    "start":today.add(Date.HOUR, 15),    "end":today.add(Date.HOUR, 15)  },{    "id":1004,    "cid":1,    "title":"Sarah's birthday",    "start":today,    "end":today,    "notes":"Need to get a gift",    "ad":true  },{    "id":1005,    "cid":2,    "title":"A long one...",    "start":today.add(Date.DAY, -12),    "end":today.add(Date.DAY, 10).add(Date.SECOND, -1),    "ad":true  },{    "id":1006,    "cid":3,    "title":"School holiday",    "start":today.add(Date.DAY, 5),    "end":today.add(Date.DAY, 7).add(Date.SECOND, -1),    "ad":true,    "rem":"2880"  },{    "id":1007,    "cid":1,    "title":"Haircut",    "start":today.add(Date.HOUR, 9),    "end":today.add(Date.HOUR, 9).add(Date.MINUTE, 30),		"notes":"Get cash on the way"  },{    "id":1008,    "cid":3,    "title":"An old event",    "start":today.add(Date.DAY, -30),    "end":today.add(Date.DAY, -28),    "ad":true  },{    "id":1009,    "cid":2,    "title":"Board meeting",    "start":today.add(Date.DAY, -2).add(Date.HOUR, 13),    "end":today.add(Date.DAY, -2).add(Date.HOUR, 18),    "loc":"ABC Inc.",    "rem":"60"  },{    "id":1010,    "cid":3,    "title":"Jenny's final exams",    "start":today.add(Date.DAY, -2),    "end":today.add(Date.DAY, 3).add(Date.SECOND, -1),    "ad":true  },{    "id":1011,    "cid":1,    "title":"Movie night",    "start":today.add(Date.DAY, 2).add(Date.HOUR, 19),    "end":today.add(Date.DAY, 2).add(Date.HOUR, 23),    "notes":"Don't forget the tickets!",    "rem":"60"  },{    "id":1012,    "cid":4,    "title":"Gina's basketball tournament",    "start":today.add(Date.DAY, 8).add(Date.HOUR, 8),    "end":today.add(Date.DAY, 10).add(Date.HOUR, 17)  },{    "id":1013,    "cid":4,    "title":"Toby's soccer game",    "start":today.add(Date.DAY, 5).add(Date.HOUR, 10),    "end":today.add(Date.DAY, 5).add(Date.HOUR, 12)  }]};/* * A simple reusable store that loads static calendar field definitions into memory * and can be bound to the CalendarCombo widget and used for calendar color selection. */Ext.ensible.sample.CalendarStore = Ext.extend(Ext.data.Store, {  constructor: function(config){    config = Ext.applyIf(config || {}, {      storeId: 'calendarStore',      root: 'calendars',      idProperty: Ext.ensible.cal.CalendarMappings.CalendarId.mapping || 'id',      proxy: new Ext.data.MemoryProxy(),      autoLoad: true,      fields: Ext.ensible.cal.CalendarRecord.prototype.fields.getRange(),      sortInfo: {        field: Ext.ensible.cal.CalendarMappings.Title.name,        direction: 'ASC'      }    });    this.reader = new Ext.data.JsonReader(config);    Ext.ensible.sample.CalendarStore.superclass.constructor.call(this, config);  }});/* * This is a simple in-memory store implementation that is ONLY intended for use with * calendar samples running locally in the browser with no external data source. Under * normal circumstances, stores that use a MemoryProxy are read-only and intended only * for displaying data read from memory. In the case of the calendar, it's still quite * useful to be able to deal with in-memory data for sample purposes (as many people * may not have PHP set up to run locally), but by default, updates will not work since the * calendar fully expects all CRUD operations to be supported by the store (and in fact * will break, for example, if phantom records are not removed properly). This simple * class gives us a convenient way of loading and updating calendar event data in memory, * but should NOT be used outside of the local samples. * * For a real-world store implementation see the remote sample (remote.js). */Ext.ensible.sample.MemoryEventStore = Ext.extend(Ext.data.Store, {  constructor: function(config){    config = Ext.applyIf(config || {}, {      storeId: 'eventStore',      root: 'evts',      proxy: new Ext.data.MemoryProxy(),      writer: new Ext.data.DataWriter(),      fields: Ext.ensible.cal.EventRecord.prototype.fields.getRange(),      idProperty: Ext.ensible.cal.EventMappings.EventId.mapping || 'id'    });    this.reader = new Ext.data.JsonReader(config);    Ext.ensible.sample.MemoryEventStore.superclass.constructor.call(this, config);  },    // In real implementations the store is responsible for committing records  // after a remote transaction has returned success = true. Since we never do  // a real transaction, we never get any of the normal store callbacks telling  // us that an edit occurred. This simple hack works around that for the purposes  // of the local samples, but should NEVER actually be done in real code.  afterEdit : function(rec){    rec.commit();  },    listeners: {    // Since MemoeryProxy has no "create" implementation, added events    // get stuck as phantoms without an EventId. The calendar does not support    // batching transactions and expects records to be non-phantoms, so for    // the purpose of local samples we can hack that into place. In real remote    // scenarios this is handled automatically by the store, and so you should    // NEVER actually do something like this.    'add': function(store, rec){      var r = rec[0];      r.data[Ext.ensible.cal.EventMappings.EventId.name] = r.id;      r.phantom = false;      r.commit();    }  }});App = function() {  return {    init: function() {      Ext.BLANK_IMAGE_URL = 'http://extjs.cachefly.net/ext-3.1.0/resources/images/default/s.gif';      // This is an example calendar store that enables event color-coding      this.calendarStore = new Ext.ensible.sample.CalendarStore({        // defined in data-calendars.js        data: Ext.ensible.sample.CalendarData      });      // A sample event store that loads static JSON from a local file. Obviously a real      // implementation would likely be loading remote data via an HttpProxy, but the      // underlying store functionality is the same.      this.eventStore = new Ext.ensible.sample.MemoryEventStore({        // defined in data-events.js        data: Ext.ensible.sample.EventData      });      // This is the app UI layout code. All of the calendar views are subcomponents of      // CalendarPanel, but the app title bar and sidebar/navigation calendar are separate      // pieces that are composed in app-specific layout code since they could be omitted      // or placed elsewhere within the application.      new Ext.Viewport({        layout: 'border',        renderTo: 'calendar-ct',        items: [{          id: 'app-header',          region: 'north',          height: 35,          border: false,          contentEl: 'app-header-content'        }, {          id: 'app-center',          title: '...', // will be updated to the current view's date range          region: 'center',          layout: 'border',          listeners: {            'afterrender': function() {              Ext.getCmp('app-center').header.addClass('app-center-header');            }          },          items: [{            id: 'app-west',            region: 'west',            width: 176,            border: false,            items: [{              xtype: 'datepicker',              id: 'app-nav-picker',              cls: 'ext-cal-nav-picker',              listeners: {                'select': {                  fn: function(dp, dt) {                    App.calendarPanel.setStartDate(dt);                  },                  scope: this                }              }            }, {              xtype: 'extensible.calendarlist',              store: this.calendarStore,              border: false,              width: 175            }, {              xtype: 'button',              text: 'Manage Calendars',              handler: function() {                App.calendarWindow.show();              }}]            }, {              xtype: 'extensible.calendarpanel',              eventStore: this.eventStore,              calendarStore: this.calendarStore,              border: false,              id: 'app-calendar',              region: 'center',              activeItem: 3, // month view              // Any generic view options that should be applied to all sub views:              viewConfig: {              //enableFx: false            },            // View options specific to a certain view (if the same options exist in viewConfig            // they will be overridden by the view-specific config):            monthViewCfg: {              showHeader: true,              showWeekLinks: true,              showWeekNumbers: true            },            multiWeekViewCfg: {            //weekCount: 3          },          // Some optional CalendarPanel configs to experiment with:          //readOnly: true,          //showDayView: false,          //showMultiDayView: true,          //showWeekView: false,          //showMultiWeekView: false,          //showMonthView: false,          //showNavBar: false,          //showTodayText: false,          //showTime: false,          //editModal: true,          //title: 'My Calendar', // the header of the calendar, could be a subtitle for the app          // Once this component inits it will set a reference to itself as an application          // member property for easy reference in other functions within App.          initComponent: function() {            App.calendarPanel = this;            this.constructor.prototype.initComponent.apply(this, arguments);          },          //            plugins: [{          //              ptype: 'ext.ensible.cal.contextmenu'          //            }],          listeners: {            'eventclick': {              fn: function(vw, rec, el) {                this.clearMsg();              },              scope: this            },            'eventover': function(vw, rec, el) {              //console.log('Entered evt rec='+rec.data[Ext.ensible.cal.EventMappings.Title.name]', view='+ vw.id +', el='+el.id);            },            'eventout': function(vw, rec, el) {              //console.log('Leaving evt rec='+rec.data[Ext.ensible.cal.EventMappings.Title.name]+', view='+ vw.id +', el='+el.id);            },            'eventadd': {              fn: function(cp, rec) {                this.showMsg('Event ' + rec.data[Ext.ensible.cal.EventMappings.Title.name] + ' was added');              },              scope: this            },            'eventupdate': {              fn: function(cp, rec) {                this.showMsg('Event ' + rec.data[Ext.ensible.cal.EventMappings.Title.name] + ' was updated');              },              scope: this            },            'eventdelete': {              fn: function(cp, rec) {                //this.eventStore.remove(rec);                this.showMsg('Event ' + rec.data[Ext.ensible.cal.EventMappings.Title.name] + ' was deleted');              },              scope: this            },            'eventcancel': {              fn: function(cp, rec) {                // edit canceled              },              scope: this            },            'viewchange': {              fn: function(p, vw, dateInfo) {                if (this.editWin) {                  this.editWin.hide();                };                if (dateInfo !== null) {                  // will be null when switching to the event edit form so ignore                  Ext.getCmp('app-nav-picker').setValue(dateInfo.activeDate);                  this.updateTitle(dateInfo.viewStart, dateInfo.viewEnd);                }              },              scope: this            },            'dayclick': {              fn: function(vw, dt, ad, el) {                this.clearMsg();              },              scope: this            },            'rangeselect': {              fn: function(vw, dates, onComplete) {                this.clearMsg();              },              scope: this            },            'eventmove': {              fn: function(vw, rec) {                rec.commit();                var time = rec.data[Ext.ensible.cal.EventMappings.IsAllDay.name] ? '' : ' \\a\\t g:i a';                this.showMsg('Event ' + rec.data[Ext.ensible.cal.EventMappings.Title.name] + ' was moved to ' +                    rec.data[Ext.ensible.cal.EventMappings.StartDate.name].format('F jS' + time));              },              scope: this            },            'eventresize': {              fn: function(vw, rec) {                rec.commit();                this.showMsg('Event ' + rec.data[Ext.ensible.cal.EventMappings.Title.name] + ' was updated');              },              scope: this            },            'eventdelete': {              fn: function(win, rec) {                this.eventStore.remove(rec);                this.showMsg('Event ' + rec.data[Ext.ensible.cal.EventMappings.Title.name] + ' was deleted');              },              scope: this            },            'initdrag': {              fn: function(vw) {                if (this.editWin && this.editWin.isVisible()) {                  this.editWin.hide();                }              },              scope: this            }          }}]}]        });      },      // The CalendarPanel itself supports the standard Panel title config, but that title      // only spans the calendar views. For a title that spans the entire width of the app      // we added a title to the layout's outer center region that is app-specific. This code      // updates that outer title based on the currently-selected view range anytime the view changes.      updateTitle: function(startDt, endDt) {        var p = Ext.getCmp('app-center');        if (startDt.clearTime().getTime() == endDt.clearTime().getTime()) {          p.setTitle(startDt.format('F j, Y'));        }        else if (startDt.getFullYear() == endDt.getFullYear()) {          if (startDt.getMonth() == endDt.getMonth()) {            p.setTitle(startDt.format('F j') + ' - ' + endDt.format('j, Y'));          }          else {            p.setTitle(startDt.format('F j') + ' - ' + endDt.format('F j, Y'));          }        }        else {          p.setTitle(startDt.format('F j, Y') + ' - ' + endDt.format('F j, Y'));        }      },      // This is an application-specific way to communicate CalendarPanel event messages back to the user.      // This could be replaced with a function to do "toast" style messages, growl messages, etc. This will      // vary based on application requirements, which is why it's not baked into the CalendarPanel.      showMsg: function(msg) {        Ext.fly('app-msg').update(msg).removeClass('x-hidden');      },      clearMsg: function() {        Ext.fly('app-msg').update('').addClass('x-hidden');      }    }  } ();Ext.onReady(App.init, App);/////////////////////////////////////////////////////////////////////////////////////////////////////////////Dynamic Calendars support.Ext.onReady(function() {  App.calendarWindowMenu = new Ext.menu.Menu({    cls: 'x-calendar-list-menu',    items: [new Ext.ensible.cal.ColorPalette({      handler: function(palette, colorId) {        var record = App.calendarPanel.calendarStore.getAt(App.calendarWindowMenu.recordIndex);        record.set('ColorId', colorId);        App.calendarWindowMenu.hide();        App.calendarWindowDataView.refreshNode(App.calendarWindowMenu.recordIndex);      }    }),  new Ext.menu.Item({    text: 'Delete',    iconCls: 'no-icon',    handler: function() {      Ext.Msg.confirm('Action confirmation', 'Please ensure no Event is associated to this Calendar. Continue with deletion?',          function(btn) {            if (btn == 'yes') {              App.calendarPanel.calendarStore.removeAt(App.calendarWindowMenu.recordIndex);            }          });    }  })]  });  App.calendarWindow = new Ext.Window({    title: 'Manage Calendars',    width: 325,    height: 400,    modal: true,    layout: 'fit',    closeAction: 'hide',    bodyStyle: 'background-color: white',    items: [new Ext.DataView({      store: App.calendarPanel.calendarStore,      cls: 'x-combo-list',      style: 'background-color: white; padding: 5px',      itemSelector: '.x-combo-list-item',      selectedClass: 'x-combo-selected',      overClass: 'x-combo-selected',      autoScroll: true,      tpl: new Ext.XTemplate(      '<div>Click on a Calendar to change its color or remove it.</div>',      '<tpl for=".">',        '<div >',          '<div >',            '<div onmouseover="Ext.get(this).addClass(\'mail-calendar-cat-color-over\');" onmouseout="Ext.get(this).removeClass(\'mail-calendar-cat-color-over\');"> </div>',          '</div>',          '<div>{Title}</div>',        '</div>',      '</tpl>',      '<div ></div>'    ),      multiSelect: false,      listeners: {        click: function(view, index, node, e) {          App.calendarWindowMenu.recordIndex = index;          App.calendarWindowMenu.show(Ext.get(node));        }      }    })],    buttons: [{ text: 'Add Calendar',      handler: function() {        Ext.Msg.prompt('Enter name', 'Enter calendar name:',      function(btn, text) {        if (btn != 'ok')          return;        if (App.calendarPanel.calendarStore.findExact('Title', text) != -1) {          Ext.Msg.alert('Invalid input', 'A Calendar with the same name already exists.');        } else {          App.calendarPanel.calendarStore.loadData({ calendars: [{ title: text, color: 1}] }, true);        }      });      }    }, { text: 'Save Changes',      handler: function() {        Ext.Msg.alert('Save', 'Save changes to the Calendars on the server here.');        App.calendarPanel.calendarStore.commitChanges();        App.calendarWindow.hide();      }    }, { text: 'Cancel',      handler: function() {        App.calendarPanel.calendarStore.rejectAllChanges();        App.calendarWindowDataView.refresh();        App.calendarWindow.hide();      }    }  ]  });  App.calendarWindowDataView = App.calendarWindow.items.items[0];});Ext.data.Store.prototype.rejectAllChanges = function() {  this.rejectChanges();  for (var i = this.data.length - 1; i >= 0; i--) {    var rec = this.data.items[i];    if (rec.phantom) {      this.remove(rec);      if (Ext.isArray(this.deleted)) {        this.deleted.remove(rec);      }      if (Ext.isArray(this.removed)) {        this.removed.remove(rec);      }    }  }}

  dynamic-calendars.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html