├── schedule ├── __init__.py ├── conf │ ├── __init__.py │ └── settings.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ ├── load_sample_data.py │ │ └── load_example_data.py ├── templatetags │ └── __init__.py ├── templates │ ├── schedule │ │ ├── _event_title.html │ │ ├── _create_event_options.html │ │ ├── calendar_compact_month.html │ │ ├── _prevnext.html │ │ ├── delete_event.html │ │ ├── create_event.html │ │ ├── edit_occurrence.html │ │ ├── _month_table.html │ │ ├── calendar_list.html │ │ ├── cancel_occurrence.html │ │ ├── calendar_month.html │ │ ├── base.html │ │ ├── calendar.html │ │ ├── _daily_table.html │ │ ├── calendar_tri_month.html │ │ ├── _detail.html │ │ ├── calendar_day.html │ │ ├── calendar_year.html │ │ ├── calendar_week.html │ │ ├── _dialogs.html │ │ ├── event_form_base.html │ │ ├── occurrence.html │ │ ├── _event_options.html │ │ ├── _day_cell.html │ │ └── event.html │ └── profiles │ │ └── schedule.html ├── locale │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── fr │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── models │ ├── __init__.py │ ├── rules.py │ └── calendars.py ├── tests │ ├── __init__.py │ ├── test_templatetags.py │ ├── test_utils.py │ ├── test_rule.py │ ├── test_views.py │ └── test_models.py ├── admin.py ├── signals.py ├── feeds │ ├── icalendar.py │ └── __init__.py ├── forms.py ├── urls.py ├── utils.py └── fixtures │ └── schedule.json ├── project_sample ├── __init__.py ├── templates │ ├── site_base.html │ ├── 404.html │ ├── 500.html │ ├── base.html │ └── homepage.html ├── site_media │ ├── css │ │ ├── images │ │ │ ├── _x_. │ │ │ ├── 222222_7x7_arrow_up.gif │ │ │ ├── 888888_7x7_arrow_up.gif │ │ │ ├── ffffff_7x7_arrow_up.gif │ │ │ ├── 222222_11x11_icon_doc.gif │ │ │ ├── 222222_7x7_arrow_down.gif │ │ │ ├── 222222_7x7_arrow_left.gif │ │ │ ├── 888888_11x11_icon_doc.gif │ │ │ ├── 888888_7x7_arrow_down.gif │ │ │ ├── 888888_7x7_arrow_left.gif │ │ │ ├── ffffff_11x11_icon_doc.gif │ │ │ ├── ffffff_7x7_arrow_down.gif │ │ │ ├── ffffff_7x7_arrow_left.gif │ │ │ ├── 222222_11x11_icon_close.gif │ │ │ ├── 222222_11x11_icon_minus.gif │ │ │ ├── 222222_11x11_icon_plus.gif │ │ │ ├── 222222_7x7_arrow_right.gif │ │ │ ├── 888888_11x11_icon_close.gif │ │ │ ├── 888888_11x11_icon_minus.gif │ │ │ ├── 888888_11x11_icon_plus.gif │ │ │ ├── 888888_7x7_arrow_right.gif │ │ │ ├── ffffff_11x11_icon_close.gif │ │ │ ├── ffffff_11x11_icon_minus.gif │ │ │ ├── ffffff_11x11_icon_plus.gif │ │ │ ├── ffffff_7x7_arrow_right.gif │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_4b8e0b_256x240.png │ │ │ ├── ui-icons_a83300_256x240.png │ │ │ ├── ui-icons_cccccc_256x240.png │ │ │ ├── ui-icons_ffffff_256x240.png │ │ │ ├── 222222_11x11_icon_folder_open.gif │ │ │ ├── 222222_11x11_icon_resize_se.gif │ │ │ ├── 888888_11x11_icon_folder_open.gif │ │ │ ├── ffffff_11x11_icon_folder_open.gif │ │ │ ├── ui-bg_flat_30_cccccc_40x100.png │ │ │ ├── ui-bg_flat_50_5c5c5c_40x100.png │ │ │ ├── ui-bg_glass_20_555555_1x400.png │ │ │ ├── ui-bg_glass_40_0078a3_1x400.png │ │ │ ├── ui-bg_glass_40_ffc73d_1x400.png │ │ │ ├── 222222_11x11_icon_arrows_updown.gif │ │ │ ├── 222222_11x11_icon_folder_closed.gif │ │ │ ├── 888888_11x11_icon_arrows_updown.gif │ │ │ ├── 888888_11x11_icon_folder_closed.gif │ │ │ ├── ffffff_11x11_icon_arrows_updown.gif │ │ │ ├── ffffff_11x11_icon_folder_closed.gif │ │ │ ├── 222222_11x11_icon_arrows_leftright.gif │ │ │ ├── 888888_11x11_icon_arrows_leftright.gif │ │ │ ├── 8ab9ff_40x100_textures_02_glass_50.png │ │ │ ├── d8d8d8_40x100_textures_02_glass_90.png │ │ │ ├── e0e0e0_40x100_textures_02_glass_80.png │ │ │ ├── f3f3f3_40x100_textures_01_flat_0.png │ │ │ ├── ffffff_11x11_icon_arrows_leftright.gif │ │ │ ├── ui-bg_gloss-wave_25_333333_500x100.png │ │ │ ├── ui-bg_inset-soft_25_000000_1x100.png │ │ │ ├── ui-bg_inset-soft_30_f58400_1x100.png │ │ │ ├── ui-bg_highlight-soft_80_eeeeee_1x100.png │ │ │ └── 222222_35x9_colorpicker_indicator.gif.gif │ │ └── jquery.tooltip.css │ ├── schedule │ │ ├── img │ │ │ ├── add.png │ │ │ ├── view.png │ │ │ ├── delete.png │ │ │ ├── pencil.png │ │ │ ├── shadow.png │ │ │ ├── left_grey.png │ │ │ ├── left_mod.png │ │ │ ├── right_mod.png │ │ │ └── right_grey.png │ │ └── css │ │ │ └── schedule.css │ └── js │ │ ├── jquery.bgiframe.js │ │ ├── jquery.timePicker.js │ │ └── jquery.tooltip.js ├── manage.py ├── urls.py └── settings.py ├── docs ├── models.txt ├── index.txt ├── install.txt ├── template_tags.txt ├── settings.txt ├── utils.txt ├── overview.txt ├── Makefile ├── periods.txt ├── conf.py └── views.txt ├── .gitignore ├── MANIFEST.in ├── AUTHORS ├── setup.py ├── LICENCSE.txt └── README.textile /schedule/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project_sample/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /schedule/conf/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /schedule/management/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /schedule/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /schedule/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/models.txt: -------------------------------------------------------------------------------- 1 | ====== 2 | Models 3 | ====== 4 | 5 | Not Documented yet -------------------------------------------------------------------------------- /project_sample/templates/site_base.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_event_title.html: -------------------------------------------------------------------------------- 1 | {{occurrence.title}} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | *.pyc 4 | /project_sample/project_sample.db 5 | /docs/_build/ 6 | django_schedule.egg-info 7 | -------------------------------------------------------------------------------- /schedule/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/schedule/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /schedule/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/schedule/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /schedule/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/schedule/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /schedule/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/schedule/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /project_sample/site_media/css/images/_x_.: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/_x_. -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/add.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/view.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/delete.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/pencil.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/shadow.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/left_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/left_grey.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/left_mod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/left_mod.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/right_mod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/right_mod.png -------------------------------------------------------------------------------- /project_sample/site_media/schedule/img/right_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/schedule/img/right_grey.png -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include docs * 2 | recursive-include schedule/templates * 3 | recursive-include schedule/models/fixtures *.json 4 | recursive-include project_sample * 5 | -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_7x7_arrow_up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_7x7_arrow_up.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_7x7_arrow_up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_7x7_arrow_up.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_7x7_arrow_up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_7x7_arrow_up.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_doc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_doc.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_7x7_arrow_down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_7x7_arrow_down.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_7x7_arrow_left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_7x7_arrow_left.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_doc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_doc.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_7x7_arrow_down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_7x7_arrow_down.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_7x7_arrow_left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_7x7_arrow_left.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_doc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_doc.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_7x7_arrow_down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_7x7_arrow_down.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_7x7_arrow_left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_7x7_arrow_left.gif -------------------------------------------------------------------------------- /schedule/templates/schedule/_create_event_options.html: -------------------------------------------------------------------------------- 1 | Add Event 2 | -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_close.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_close.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_minus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_minus.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_plus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_plus.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_7x7_arrow_right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_7x7_arrow_right.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_close.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_close.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_minus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_minus.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_plus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_plus.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_7x7_arrow_right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_7x7_arrow_right.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_close.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_close.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_minus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_minus.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_plus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_plus.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_7x7_arrow_right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_7x7_arrow_right.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-icons_4b8e0b_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-icons_4b8e0b_256x240.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-icons_a83300_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-icons_a83300_256x240.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-icons_cccccc_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-icons_cccccc_256x240.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /schedule/models/__init__.py: -------------------------------------------------------------------------------- 1 | from schedule.models.calendars import * 2 | from schedule.models.events import * 3 | from schedule.models.rules import * 4 | 5 | from schedule.signals import * 6 | -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_folder_open.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_folder_open.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_resize_se.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_resize_se.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_folder_open.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_folder_open.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_folder_open.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_folder_open.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_flat_30_cccccc_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_flat_30_cccccc_40x100.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_flat_50_5c5c5c_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_flat_50_5c5c5c_40x100.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_glass_20_555555_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_glass_20_555555_1x400.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_glass_40_0078a3_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_glass_40_0078a3_1x400.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_glass_40_ffc73d_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_glass_40_ffc73d_1x400.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_arrows_updown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_arrows_updown.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_folder_closed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_folder_closed.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_arrows_updown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_arrows_updown.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_folder_closed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_folder_closed.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_arrows_updown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_arrows_updown.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_folder_closed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_folder_closed.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_11x11_icon_arrows_leftright.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_11x11_icon_arrows_leftright.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/888888_11x11_icon_arrows_leftright.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/888888_11x11_icon_arrows_leftright.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/8ab9ff_40x100_textures_02_glass_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/8ab9ff_40x100_textures_02_glass_50.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/d8d8d8_40x100_textures_02_glass_90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/d8d8d8_40x100_textures_02_glass_90.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/e0e0e0_40x100_textures_02_glass_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/e0e0e0_40x100_textures_02_glass_80.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/f3f3f3_40x100_textures_01_flat_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/f3f3f3_40x100_textures_01_flat_0.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ffffff_11x11_icon_arrows_leftright.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ffffff_11x11_icon_arrows_leftright.gif -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_gloss-wave_25_333333_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_gloss-wave_25_333333_500x100.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_inset-soft_25_000000_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_inset-soft_25_000000_1x100.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_inset-soft_30_f58400_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_inset-soft_30_f58400_1x100.png -------------------------------------------------------------------------------- /project_sample/site_media/css/images/ui-bg_highlight-soft_80_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/ui-bg_highlight-soft_80_eeeeee_1x100.png -------------------------------------------------------------------------------- /schedule/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from test_models import * 2 | from test_utils import * 3 | from test_periods import * 4 | from test_templatetags import * 5 | from test_views import * 6 | from test_rule import * 7 | 8 | -------------------------------------------------------------------------------- /project_sample/site_media/css/images/222222_35x9_colorpicker_indicator.gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartekgorny/django-schedule/HEAD/project_sample/site_media/css/images/222222_35x9_colorpicker_indicator.gif.gif -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_compact_month.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load scheduletags %} 3 | {% block body %} 4 |

{{ calendar.name }}

5 | {% month_table calendar periods.month "small" %} 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /project_sample/site_media/css/jquery.tooltip.css: -------------------------------------------------------------------------------- 1 | #tooltip { 2 | position: absolute; 3 | z-index: 3000; 4 | border: 1px solid #111; 5 | background-color: #eee; 6 | padding: 5px; 7 | opacity: 0.85; 8 | } 9 | #tooltip h3, #tooltip div { margin: 0; } 10 | -------------------------------------------------------------------------------- /project_sample/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "site_base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Not Found" %}{% endblock %} 6 | 7 | {% block body %} 8 |

{% trans "We're sorry but that page could not be found." %}

9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /project_sample/templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends "site_base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Server Error" %}{% endblock %} 6 | 7 | {% block body %} 8 |

{% trans "We're sorry but a server error has occurred. We've been notified and will look into it as soon as possible." %}

9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_prevnext.html: -------------------------------------------------------------------------------- 1 | {% load scheduletags %} 2 |
3 | 4 | 5 | 6 |   {{period_name}}   7 | 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /schedule/tests/test_templatetags.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.test import TestCase 4 | 5 | from schedule.templatetags.scheduletags import querystring_for_date 6 | 7 | class TestTemplateTags(TestCase): 8 | 9 | def test_querystring_for_datetime(self): 10 | date = datetime.datetime(2008,1,1,0,0,0) 11 | query_string=querystring_for_date(date) 12 | self.assertEqual("?year=2008&month=1&day=1&hour=0&minute=0&second=0", 13 | query_string) -------------------------------------------------------------------------------- /schedule/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from schedule.forms import RuleForm 3 | 4 | from schedule.models import Calendar, Event, CalendarRelation, Rule 5 | 6 | class CalendarAdminOptions(admin.ModelAdmin): 7 | prepopulated_fields = {"slug": ("name",)} 8 | search_fields = ['name'] 9 | 10 | class RuleAdmin(admin.ModelAdmin): 11 | form = RuleForm 12 | 13 | admin.site.register(Calendar, CalendarAdminOptions) 14 | admin.site.register(Rule, RuleAdmin) 15 | admin.site.register([Event, CalendarRelation]) 16 | -------------------------------------------------------------------------------- /schedule/templates/schedule/delete_event.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block body %} 5 |

{% trans "Delete" %}

6 | {% trans "Are you sure that you really want to delete it?" %} 7 | 8 |
9 | {{ object }}
10 | 11 | 12 | 13 | 14 |
15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /schedule/templates/schedule/create_event.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/event_form_base.html" %} 2 | {% load i18n %} 3 | 4 | {% block body %} 5 | {% trans "Create or change event. All fields are required." %} 6 |

7 |
8 | 9 | {{ form.as_table }} 10 |
11 |
12 | 13 | 14 | 15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /schedule/templates/schedule/edit_occurrence.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/event_form_base.html" %} 2 | {% load i18n %} 3 | 4 | {% block body %} 5 | {% trans "Create or change occurrence. All fields are required." %} 6 |

7 |
8 | 9 | {{ form.as_table }} 10 |
11 |
12 | 13 | 14 | 15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /project_sample/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | import imp 4 | try: 5 | imp.find_module('settings') # Assumed to be in the same directory. 6 | except ImportError: 7 | import sys 8 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) 9 | sys.exit(1) 10 | 11 | import settings 12 | 13 | if __name__ == "__main__": 14 | execute_manager(settings) 15 | -------------------------------------------------------------------------------- /docs/index.txt: -------------------------------------------------------------------------------- 1 | .. DjangoSchedule documentation master file, created by sphinx-quickstart on Mon Mar 30 15:19:11 2009. 2 | 3 | Welcome to DjangoSchedule's documentation! 4 | ========================================== 5 | 6 | DjangoSchedule is an open-source calendaring application. 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | install 12 | overview 13 | periods 14 | utils 15 | template_tags 16 | views 17 | models 18 | settings 19 | 20 | 21 | Indices and tables 22 | ================== 23 | 24 | * :ref:`genindex` 25 | * :ref:`modindex` 26 | * :ref:`search` 27 | 28 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Primary Authors: 2 | 3 | * Tony Hauber 4 | * Bartek Gorny 5 | 6 | Contributors (in alphabetical order): 7 | 8 | * John Anderson 9 | * Greg Brown 10 | * Daniel Gatis Carrazzoni 11 | * Johan Charpentier 12 | * Bruno Clermont 13 | * adolfo fittoria 14 | * Alex Gaynor 15 | * Rock Howard 16 | * Alik Kurdyukow 17 | * Jannis Leidel 18 | * Yann Malet 19 | * James Pic 20 | * Colin Powell 21 | * Justin Quick 22 | * Mark Rogers 23 | * Skylar Saveland 24 | * Erik Simmler 25 | * Jonathan Stoppani 26 | * ptoal 27 | * Wes Winham 28 | * Carlos Zuniga 29 | -------------------------------------------------------------------------------- /schedule/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import pre_save 2 | 3 | from models import Event, Calendar 4 | 5 | def optionnal_calendar(sender, **kwargs): 6 | event = kwargs.pop('instance') 7 | 8 | if not isinstance(event, Event): 9 | return True 10 | if not event.calendar: 11 | try: 12 | calendar = Calendar._default_manager.get(name='default') 13 | except Calendar.DoesNotExist: 14 | calendar = Calendar(name='default', slug='default') 15 | calendar.save() 16 | 17 | event.calendar = calendar 18 | return True 19 | 20 | pre_save.connect(optionnal_calendar) 21 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_month_table.html: -------------------------------------------------------------------------------- 1 | {% load scheduletags %} 2 | 3 | {% if day_names %} 4 | 5 | 6 | {% for day_name in day_names %}{{ day_name }} 7 | {% endfor %} 8 | {% endif %} 9 | {% for week in month.get_weeks %} 10 | 11 | 16 | {% for day in week.get_days %} 17 | {% day_cell calendar day month size %} 18 | {% endfor %} 19 | 20 | {% endfor %} 21 |
 
12 | 13 | {{week.start|date:"W"}} 14 | 15 |
22 | -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_list.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% block head_title %}Available Calendars{% endblock %} 3 | {% block body %} 4 |

Available Calendars

5 | 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /schedule/templates/schedule/cancel_occurrence.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block body %} 5 |

{% trans "Delete" %}

6 | {% trans "Are you sure that you really want to cancel this occurrence?" %} 7 | 8 |
9 |

{{ occurrence.title }}

10 | From {{ occurrence.start|date:_("DATETIME_FORMAT") }} 11 | to {{ occurrence.end|date:_("DATETIME_FORMAT") }}
12 | 13 | 14 | 15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /project_sample/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.defaults import * 3 | from django.views.generic.simple import direct_to_template 4 | 5 | from django.contrib import admin 6 | admin.autodiscover() 7 | 8 | urlpatterns = patterns('', 9 | url(r'^$', direct_to_template,{"template":"homepage.html"}), 10 | (r'^schedule/', include('schedule.urls')), 11 | 12 | url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 13 | url(r'^admin/', include(admin.site.urls)), 14 | ) 15 | 16 | if settings.DEBUG: 17 | urlpatterns += patterns('', 18 | (r'^site_media/(?P.*)$', 19 | 'django.views.static.serve', 20 | {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), 21 | ) 22 | 23 | -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_month.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load scheduletags %} 3 | 4 | {% block extra_head %} 5 | {{ block.super }} 6 | {% include "schedule/_dialogs.html" %} 7 | {% endblock %} 8 | 9 | {% block body %} 10 |
11 |
{{ calendar.name }}
12 | {% prevnext "month_calendar" calendar.slug periods.month "F Y"%} 13 | 18 | {% month_table calendar periods.month "regular" %} 19 |
20 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /schedule/templates/schedule/base.html: -------------------------------------------------------------------------------- 1 | {% extends "site_base.html" %} 2 | {% block extra_head %} 3 | {{ block.super }} 4 | 5 | 6 | 7 | 8 | 9 | 10 | {% endblock %} 11 | 12 | {% block rtab_id %}id="schedule_tab"{% endblock %} 13 | 14 | {% block subnav %} 15 | 23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load i18n %} 3 | {% load scheduletags %} 4 | 5 | 6 | {% block body %} 7 | 8 |

Calendar metadata

9 | 10 |

Name: {{calendar.name}}

11 |

Slug: {{calendar.slug}}

12 |

Event count: {{calendar.events.count}}

13 | 14 |
15 |

See as:

16 | 25 |
26 | 27 |
Now see docstring for schedule.views.calendar
28 | 29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_daily_table.html: -------------------------------------------------------------------------------- 1 | {% load scheduletags %} 2 |
3 | {% for slot in slots %} 4 |
5 | {{ slot.start|time:"G:i" }} 6 | {% if addable %} 7 | {% create_event_url calendar slot.start %} 8 | {% endif %} 9 |
10 | {% endfor %} 11 |
12 |
13 | {% for occ in occurrences %} 14 |
16 | {% options occ %} 17 | {% title occ %} 18 | 19 |
20 | 23 | {% endfor %} 24 |
25 | -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_tri_month.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load scheduletags %} 3 | {% block body %} 4 |
5 |
{{ calendar.name }}
6 | {% prevnext "tri_month_calendar" calendar.slug periods.month "F Y"%} 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
{% month_table calendar periods.month "small" -1 %} {% month_table calendar periods.month "small" %} {% month_table calendar periods.month "small" +1 %}
21 |
22 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_detail.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 |

{{occurrence.title}}

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% if occurrence.event.rule %} 14 | {% if not occurrence.id %} 15 | 16 | 17 | 18 | {% if occurrence.event.end_recurring_period %} 19 | 20 | 21 | 22 | 23 | {% endif %} 24 | {% endif %} 25 | {% endif %} 26 |
Starts{% blocktrans with occurrence.start|date:_("DATETIME_FORMAT") as start_date %}{{ start_date }}{% endblocktrans %}
Ends{% blocktrans with occurrence.end|date:_("DATETIME_FORMAT") as end_date %}{{ end_date }}{% endblocktrans %}
Reoccurs{{occurrence.event.rule}}
Until{% blocktrans with occurrence.event.end_recurring_period|date:_("DATETIME_FORMAT") as end_date %}{{ end_date }}{% endblocktrans %}
27 | {% if occurrence.description %} 28 |

Description

29 |

{{occurrence.description}}

30 | {% endif %} 31 |
32 | 33 | -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_day.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load scheduletags %} 3 | 4 | {% block extra_head %} 5 | {{ block.super }} 6 | {% include "schedule/_dialogs.html" %} 7 | {% endblock %} 8 | 9 | {% block body %} 10 | 11 | 22 |
23 |
{{ calendar.name }}
24 | {% prevnext "day_calendar" calendar.slug periods.day "l, F d, Y" %} 25 | 30 |
31 |
32 |
33 | {% daily_table periods.day 420 120 600 0 12 %} 34 |
35 | 36 |
37 | {% daily_table periods.day 420 120 600 12 24 %} 38 |
39 |
40 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_year.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load scheduletags %} 3 | {% block body %} 4 |
5 |
{{ calendar.name }}
6 | {% prevnext "year_calendar" calendar.slug periods.year "Y" %} 7 | 8 | 9 | {% for month in periods.year.get_months %} 10 | 15 | 16 | {% ifequal forloop.counter 3 %} 17 | 18 | 19 | {% endifequal %} 20 | {% ifequal forloop.counter 6 %} 21 | 22 | 23 | {% endifequal %} 24 | {% ifequal forloop.counter 9 %} 25 | 26 | 27 | {% endifequal %} 28 | {% endfor %} 29 | 30 |
11 | 12 | {{month.name}} 13 | 14 | {% month_table calendar month "small" %} 

31 | 39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /project_sample/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | {% if site_name %}{{ site_name }} : {% endif %}{% block head_title %}{% endblock %} 7 | 12 | {% if LANGUAGE_BIDI %} 13 | 18 | {% endif %} 19 | {% block extra_head %} 20 | {% endblock %} 21 | 22 | 23 | 24 |

This is a demo of a django-schedule calendar

25 |

26 | 27 |

28 | {% block body %} 29 | {% endblock %} 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/install.txt: -------------------------------------------------------------------------------- 1 | .. _ref-install: 2 | ============ 3 | Installation 4 | ============ 5 | 6 | The project is available through Bartek Gorny's `Github Repository `_. 7 | 8 | Requirements 9 | ------------ 10 | 11 | python-dateutil 12 | 13 | Installing the Latest Stable Version 14 | ------------------------------------ 15 | 16 | There is no official release at the moment, as the project is being reviewed after 17 | a year of stagnation. Anyway, the current version should be stable. Release 18 | is coming soon. 19 | 20 | Installing the Latest Development Version 21 | ----------------------------------------- 22 | 23 | Clone the github repo via: 24 | 25 | git clone git://github.com/bartekgorny/django-schedule.git 26 | 27 | .. _ref-configure: 28 | 29 | ============= 30 | Configuration 31 | ============= 32 | 33 | 1. Add ``schedule`` to your ``INSTALLED_APPS`` 34 | 35 | 2. Add ``(r'^schedule/', include('schedule.urls')),`` to your urls.py (changing ``r`^schedule/'`` to whatever url pattern you'd like django-schedule to live at) 36 | 37 | 3. Resync your database ``./manage.py syncdb`` 38 | 39 | ============================= 40 | Installing the Ajax interface 41 | ============================= 42 | 43 | This feature should work fine, though it is not guaranteed. To use it: 44 | 45 | 1. Check out ajax_ui branch 46 | 47 | 2. Add "schedule_weekcal/templates" to TEMPLATE_DIRS 48 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | from setuptools import setup, find_packages 5 | 6 | dateutil = 'python-dateutil' 7 | if sys.version_info < (3, 0): 8 | dateutil = 'python-dateutil==1.5' 9 | 10 | setup( 11 | name='django-schedule', 12 | version='0.5b', 13 | description='A calendaring app for Django.', 14 | author='Anthony Robert Hauber', 15 | author_email='thauber@gmail.com', 16 | url='http://github.com/thauber/django-schedule/tree/master', 17 | packages=[ 18 | 'schedule', 19 | 'schedule.conf', 20 | 'schedule.feeds', 21 | 'schedule.management', 22 | 'schedule.management.commands', 23 | 'schedule.models', 24 | 'schedule.templatetags', 25 | 'schedule.tests', 26 | ], 27 | include_package_data=True, 28 | zip_safe=False, 29 | classifiers=['Development Status :: 4 - Beta', 30 | 'Environment :: Web Environment', 31 | 'Framework :: Django', 32 | 'Intended Audience :: Developers', 33 | 'License :: OSI Approved :: BSD License', 34 | 'Operating System :: OS Independent', 35 | 'Programming Language :: Python', 36 | 'Topic :: Utilities'], 37 | install_requires=['setuptools', 'vobject', dateutil], 38 | license='BSD', 39 | test_suite = "schedule.tests", 40 | ) 41 | -------------------------------------------------------------------------------- /docs/template_tags.txt: -------------------------------------------------------------------------------- 1 | ==================== 2 | Useful Template Tags 3 | ==================== 4 | 5 | All of the templatetags are located in templatetags/scheduletags.py. You can look at more of them there. I am only going to talk about a few here. 6 | 7 | To load the template tags this must be in your template 8 | 9 | ``{% load scheduletags %}`` 10 | 11 | ``querystring_for_date`` 12 | ------------------------ 13 | 14 | Usage 15 | ``{% querystring_for_date [ ] %}`` 16 | 17 | This template tag produces a querystring that describes ``date``. It turns date into a dictionary and then turns that dictionary into a querystring, in this fashion: 18 | 19 | >>> date = datetime.datetime(2009,4,1) 20 | >>> querystring_for_date(date) 21 | '?year=2009&month=4&day=1&hour=0&minute=0&second=0' 22 | 23 | This is useful when creating links as the calendar_by_period view uses this to display any date besides ``datetime.datetime.now()``. The ``num`` argument can be used to say how specific you want to be about the date. If you were displaying a yearly calendar you only care about the year so ``num`` would only have to be ``1``. See the examples below 24 | 25 | >>> querystring_for_date(date, num=1) 26 | '?year=2009' 27 | >>> # Now if we only need the month 28 | >>> querystring_for_date(date, num=2) 29 | '?year=2009&month=4' 30 | >>> # Now everything except the seconds 31 | >>> querystring_for_date(date, num=5) 32 | '?year=2009&month=4&day=1&hour=0&minute=0' 33 | 34 | 35 | -------------------------------------------------------------------------------- /schedule/feeds/icalendar.py: -------------------------------------------------------------------------------- 1 | import vobject 2 | 3 | from django.http import HttpResponse 4 | 5 | EVENT_ITEMS = ( 6 | ('uid', 'uid'), 7 | ('dtstart', 'start'), 8 | ('dtend', 'end'), 9 | ('summary', 'summary'), 10 | ('location', 'location'), 11 | ('last_modified', 'last_modified'), 12 | ('created', 'created'), 13 | ) 14 | 15 | class ICalendarFeed(object): 16 | 17 | def __call__(self, *args, **kwargs): 18 | self.args = args 19 | self.kwargs = kwargs 20 | 21 | cal = vobject.iCalendar() 22 | 23 | for item in self.items(): 24 | 25 | event = cal.add('vevent') 26 | 27 | for vkey, key in EVENT_ITEMS: 28 | value = getattr(self, 'item_' + key)(item) 29 | if value: 30 | event.add(vkey).value = value 31 | 32 | response = HttpResponse(cal.serialize()) 33 | response['Content-Type'] = 'text/calendar' 34 | 35 | return response 36 | 37 | def items(self): 38 | return [] 39 | 40 | def item_uid(self, item): 41 | pass 42 | 43 | def item_start(self, item): 44 | pass 45 | 46 | def item_end(self, item): 47 | pass 48 | 49 | def item_summary(self, item): 50 | return str(item) 51 | 52 | def item_location(self, item): 53 | pass 54 | 55 | def item_last_modified(self, item): 56 | pass 57 | 58 | def item_created(self, item): 59 | pass -------------------------------------------------------------------------------- /schedule/templates/schedule/calendar_week.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load scheduletags %} 3 | 4 | {% block extra_head %} 5 | {{ block.super }} 6 | {% include "schedule/_dialogs.html" %} 7 | {% endblock %} 8 | 9 | {% block body %} 10 | 11 | 19 | 20 |
21 |
{{ calendar.name }}
22 | {% prevnext "week_calendar" calendar.slug periods.week "\Week W, M Y" %} 23 | 28 |
29 | 30 |
31 | {% for day in periods.week.get_days %} 32 |
33 | 38 |
39 | {% if forloop.first %} 40 | {% daily_table day 230 80 600 9 21 %} 41 | {% else %} 42 | {% daily_table day 150 15 600 9 21 %} 43 | {% endif %} 44 |
45 |
46 | {% endfor %} 47 |
48 | 49 | {% endblock %} 50 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_dialogs.html: -------------------------------------------------------------------------------- 1 | {{ block.super }} 2 | 31 | 32 | 35 | 36 | 39 | 40 | -------------------------------------------------------------------------------- /LICENCSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008, Tony Hauber 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following 12 | disclaimer in the documentation and/or other materials provided 13 | with the distribution. 14 | * Neither the name of the author nor the names of other 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /schedule/templates/schedule/event_form_base.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | 3 | {% block extra_head %} 4 | {{ block.super }} 5 | 6 | 36 | {% endblock %} 37 | 38 | -------------------------------------------------------------------------------- /schedule/templates/schedule/occurrence.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load i18n %} 3 | {% load scheduletags %} 4 | 5 | {% block body %} 6 | 14 |
15 | {% if back_url %} 16 | {% trans   17 | {% endif %} 18 | {% trans   19 | {% trans 20 |
21 |

{{occurrence.title}}

22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | {% if occurrence.event.rule %} 32 | 33 | 34 | 35 | {% endif %} 36 |
Starts{% blocktrans with occurrence.start|date:_("DATETIME_FORMAT") as start_date %}{{ start_date }}{% endblocktrans %}
Ends{% blocktrans with occurrence.end|date:_("DATETIME_FORMAT") as end_date %}{{ end_date }}{% endblocktrans %}
Reoccurs{{event.rule}}
37 | {% if occurrence.description %} 38 |

Description

39 |

{{occurrence.description}}

40 | {% endif %} 41 | 42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_event_options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% if edit_event %} 4 | 5 | {% if occurrence.event.rule %} 6 | {% if occurrence.id %} 7 | 8 | Edit Event 9 | 10 | {% else %} 11 | 12 | Edit Event 13 | 14 | {% endif %} 15 | {% else %} 16 | 17 | Edit Event 18 | 19 | {% endif %} 20 | {% endif %} 21 | 22 | {% if delete_event %} 23 | 24 | {% if occurrence.event.rule %} 25 | {% if occurrence.id %} 26 | 27 | Delete Event 28 | 29 | {% else %} 30 | 31 | Delete Event 32 | 33 | {% endif %} 34 | {% else %} 35 | 36 | Delete Event 37 | 38 | {% endif %} 39 | {% endif %} 40 | 41 | 42 | -------------------------------------------------------------------------------- /schedule/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.utils.translation import ugettext_lazy as _ 3 | from schedule.models import Event, Occurrence, Rule 4 | import datetime 5 | import time 6 | 7 | 8 | class SpanForm(forms.ModelForm): 9 | 10 | start = forms.DateTimeField(widget=forms.SplitDateTimeWidget) 11 | end = forms.DateTimeField(widget=forms.SplitDateTimeWidget, help_text = _("The end time must be later than start time.")) 12 | 13 | def clean_end(self): 14 | if self.cleaned_data['end'] <= self.cleaned_data['start']: 15 | raise forms.ValidationError(_("The end time must be later than start time.")) 16 | return self.cleaned_data['end'] 17 | 18 | 19 | class EventForm(SpanForm): 20 | def __init__(self, hour24=False, *args, **kwargs): 21 | super(EventForm, self).__init__(*args, **kwargs) 22 | 23 | end_recurring_period = forms.DateTimeField(help_text = _("This date is ignored for one time only events."), required=False) 24 | 25 | class Meta: 26 | model = Event 27 | exclude = ('creator', 'created_on', 'calendar') 28 | 29 | 30 | class OccurrenceForm(SpanForm): 31 | 32 | class Meta: 33 | model = Occurrence 34 | exclude = ('original_start', 'original_end', 'event', 'cancelled') 35 | 36 | 37 | class RuleForm(forms.ModelForm): 38 | params = forms.CharField(widget=forms.Textarea, help_text=_("Extra parameters to define this type of recursion. Should follow this format: rruleparam:value;otherparam:value.")) 39 | 40 | def clean_params(self): 41 | params = self.cleaned_data["params"] 42 | try: 43 | Rule(params=params).get_params() 44 | except (ValueError, SyntaxError): 45 | raise forms.ValidationError(_("Params format looks invalid")) 46 | return self.cleaned_data["params"] 47 | -------------------------------------------------------------------------------- /docs/settings.txt: -------------------------------------------------------------------------------- 1 | .. _ref-settings: 2 | 3 | Settings 4 | ======== 5 | 6 | .. _ref-settings-first-day-of-week: 7 | 8 | FIRST_DAY_OF_WEEK 9 | ----------------- 10 | 11 | This setting determines which day of the week your calendar begins on if your locale doesn't already set it. Default is 0, which is Sunday. 12 | 13 | .. _ref-settings-OCCURRENCE_CANCEL_REDIRECT: 14 | 15 | OCCURRENCE_CANCEL_REDIRECT 16 | -------------------------- 17 | 18 | This setting controls the behavior of :func:`Views.get_next_url`. If set, all calendar modifications will redirect here (unless there is a `next` set in the request.) 19 | 20 | .. _ref-settings-show-cancelled-occurrences: 21 | 22 | SHOW_CANCELLED_OCCURRENCES 23 | -------------------------- 24 | 25 | This setting controls the behavior of :func:`Period.classify_occurence`. If True, then occurences that have been cancelled will be displayed with a css class of canceled, otherwise they won't appear at all. 26 | 27 | Defaults to False 28 | 29 | .. _ref-settings-check-permission-func: 30 | 31 | CHECK_PERMISSION_FUNC 32 | --------------------- 33 | 34 | This setting controls the callable used to determine if a user has permission to edit an event or occurance. The callable must take the object and the user and return a boolean. 35 | 36 | example:: 37 | 38 | check_edit_permission(ob, user): 39 | return user.is_authenticated() 40 | 41 | If ob is None, then the function is checking for permission to add new occurrences. 42 | 43 | .. _ref-settings-get-events-func: 44 | 45 | GET_EVENTS_FUNC 46 | --------------- 47 | 48 | This setting controls the callable that gets all events for calendar display. The callable must take the request and the calendar and return a `QuerySet` of events. Modifying this setting allows you to pull events from multiple calendars or to filter events based on permissions 49 | 50 | example:: 51 | 52 | get_events(request, calendar): 53 | return calendar.event_set.all() 54 | 55 | -------------------------------------------------------------------------------- /schedule/templates/schedule/_day_cell.html: -------------------------------------------------------------------------------- 1 | {% load scheduletags %} 2 | {% ifnotequal day.start.month month.start.month %} 3 | 4 | {% else %} 5 | {% if day.has_occurrences %} 6 | 7 | {% else %} 8 | 9 | {% endif %} 10 | 15 | {% ifnotequal size "small" %} 16 |
17 | {% if day.has_occurrences %} 18 | {% for o in day.get_occurrence_partials %} 19 |
21 |
22 | {% ifequal o.class 0 %}{{ o.occurrence.start|time:"G:i" }}{% endifequal %} 23 | {% ifequal o.class 1 %}{{ o.occurrence.start|time:"G:i" }}{% endifequal %} 24 | {% ifequal o.class 2 %}(All day){% endifequal %} 25 | {% ifequal o.class 3 %}Ends at {{ o.occurrence.end|time:"G:i" }}{% endifequal %} 26 |
27 |
28 | {% title o.occurrence %} 29 |
30 |
31 | 34 | {% endfor %} 35 | {% endif %} 36 |
37 | {% endifnotequal %} 38 | 39 | {% endifnotequal %} 40 | -------------------------------------------------------------------------------- /schedule/templates/schedule/event.html: -------------------------------------------------------------------------------- 1 | {% extends "schedule/base.html" %} 2 | {% load i18n %} 3 | {% load scheduletags %} 4 | 5 | {% block body %} 6 | 7 | 18 | 19 |
20 | {% if back_url %} 21 | 22 | {% trans 23 | 24 |   25 | {% endif %} 26 | 27 | {% trans 28 | 29 |   30 | 31 | {% trans 32 | 33 |
34 |

{{event.title}}

35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {% if event.rule %} 47 | 48 | {% else %} 49 | 50 | {% endif %} 51 |
Starts{% blocktrans with event.start|date:_("DATETIME_FORMAT") as start_date %}{{ start_date }}{% endblocktrans %}
Ends{% blocktrans with event.end|date:_("DATETIME_FORMAT") as end_date %}{{ end_date }}{% endblocktrans %}
Reoccurs{{ event.rule }} until {% blocktrans with event.end_recurring_period|date:_("DATETIME_FORMAT") as end_recurring_date %}{{ end_recurring_date }}{% endblocktrans %}{% trans "Never. This is a 'one time only' event." %}
52 | {% if event.description %} 53 |

Description

54 |

{{event.description}}

55 | {% endif %} 56 | 57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /schedule/conf/settings.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext, ugettext_lazy as _ 2 | from django.conf import settings 3 | from django.core.exceptions import ImproperlyConfigured 4 | 5 | fdow_default = 0 # Sunday 6 | 7 | # Look for FIRST_DAY_OF_WEEK as a locale setting 8 | fdow = ugettext('FIRST_DAY_OF_WEEK') 9 | try: 10 | FIRST_DAY_OF_WEEK = int(fdow) 11 | except ValueError: 12 | # Let's try our settings 13 | fdow = getattr(settings, 'FIRST_DAY_OF_WEEK', fdow_default) 14 | FIRST_DAY_OF_WEEK = int(fdow) 15 | except ValueError: 16 | raise ImproperlyConfigured("FIRST_DAY_OF_WEEK must be an integer between 0 and 6") 17 | 18 | 19 | # whether to display cancelled occurrences 20 | # (if they are displayed then they have a css class "cancelled") 21 | # this controls behaviour of Period.classify_occurrence method 22 | SHOW_CANCELLED_OCCURRENCES = getattr(settings, 'SHOW_CANCELLED_OCCURRENCES', 23 | False) 24 | 25 | # Callable used to check if a user has edit permissions to event 26 | # (and occurrence). Used by check_edit_permission decorator 27 | # if ob==None we check permission to add occurrence 28 | CHECK_PERMISSION_FUNC = getattr(settings, 'CHECK_PERMISSION_FUNC', None) 29 | if not CHECK_PERMISSION_FUNC: 30 | def check_edit_permission(ob, user): 31 | return user.is_authenticated() 32 | 33 | CHECK_PERMISSION_FUNC = check_edit_permission 34 | 35 | # Callable used to customize the event list given for a calendar and user 36 | # (e.g. all events on that calendar, those events plus another calendar's events, 37 | # or the events filtered based on user permissions) 38 | # Imports have to be placed within the function body to avoid circular imports 39 | GET_EVENTS_FUNC = getattr(settings, 'GET_EVENTS_FUNC', None) 40 | if not GET_EVENTS_FUNC: 41 | def get_events(request, calendar): 42 | return calendar.event_set.all() 43 | 44 | GET_EVENTS_FUNC = get_events 45 | 46 | # URL to redirect to to after an occurrence is canceled 47 | OCCURRENCE_CANCEL_REDIRECT = getattr(settings, 'OCCURRENCE_CANCEL_REDIRECT', None) 48 | -------------------------------------------------------------------------------- /schedule/templates/profiles/schedule.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load scheduletags %} 3 | 4 |

{% trans "Schedule" %}

5 | 6 | {% get_or_create_calendar other_user other_user.username as calendar %} 7 | 8 | {% if calendar.event_set.count %} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for event in calendar.event_set.all %} 20 | 21 | 22 | 23 | 24 | 39 | 40 | {% endfor %} 41 | 42 |
{% trans "Start" %}{% trans "End" %}{% trans "Title" %} 
{{ event.start }}{{ event.end }}{{ event.title }} 25 | {% block schedule_event_controls %} 26 | 27 | {% trans 28 | 29 | {% ifequal request.user other_user %} 30 | 31 | {% trans 32 | 33 | 34 | {% trans 35 | 36 | {% endifequal %} 37 | {% endblock schedule_event_controls %} 38 |
43 | {% else %} 44 | {% url calendar_create_event as add_event_url %} 45 |

{% blocktrans %}You haven't added any event yet.{% endblocktrans %}

46 | {% endif %} 47 | 48 |

49 | {% block schedule_add_event_link_label %}{% trans "Add event" %}{% endblock %} 50 |

51 | 52 | -------------------------------------------------------------------------------- /schedule/feeds/__init__.py: -------------------------------------------------------------------------------- 1 | from schedule.models import Calendar 2 | from django.contrib.syndication.feeds import FeedDoesNotExist 3 | from django.core.exceptions import ObjectDoesNotExist 4 | from django.conf import settings 5 | from schedule.feeds.atom import Feed 6 | from schedule.feeds.icalendar import ICalendarFeed 7 | from django.http import HttpResponse 8 | import datetime, itertools 9 | 10 | class UpcomingEventsFeed(Feed): 11 | feed_id = "upcoming" 12 | 13 | def feed_title(self, obj): 14 | return "Upcoming Events for %s" % obj.name 15 | 16 | def get_object(self, bits): 17 | if len(bits) != 1: 18 | raise ObjectDoesNotExist 19 | return Calendar.objects.get(pk=bits[0]) 20 | 21 | def link(self, obj): 22 | if not obj: 23 | raise FeedDoesNotExist 24 | return obj.get_absolute_url() 25 | 26 | def items(self, obj): 27 | return itertools.islice(obj.occurrences_after(datetime.datetime.now()), 28 | getattr(settings, "FEED_LIST_LENGTH", 10)) 29 | 30 | def item_id(self, item): 31 | return str(item.id) 32 | 33 | def item_title(self, item): 34 | return item.event.title 35 | 36 | def item_authors(self, item): 37 | if item.event.creator is None: 38 | return [{'name': ''}] 39 | return [{"name": item.event.creator.username}] 40 | 41 | def item_updated(self, item): 42 | return item.event.created_on 43 | 44 | def item_content(self, item): 45 | return "%s \n %s" % (item.event.title, item.event.description) 46 | 47 | 48 | class CalendarICalendar(ICalendarFeed): 49 | def items(self): 50 | cal_id = self.args[1] 51 | cal = Calendar.objects.get(pk=cal_id) 52 | 53 | return cal.events.all() 54 | 55 | def item_uid(self, item): 56 | return str(item.id) 57 | 58 | def item_start(self, item): 59 | return item.start 60 | 61 | def item_end(self, item): 62 | return item.end 63 | 64 | def item_summary(self, item): 65 | return item.title 66 | 67 | def item_created(self, item): 68 | return item.created_on -------------------------------------------------------------------------------- /schedule/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | 4 | from django.test import TestCase 5 | from django.core.urlresolvers import reverse 6 | 7 | from schedule.models import Event, Rule, Occurrence, Calendar 8 | from schedule.periods import Period, Month, Day 9 | from schedule.utils import EventListManager 10 | 11 | class TestEventListManager(TestCase): 12 | def setUp(self): 13 | weekly = Rule(frequency = "WEEKLY") 14 | weekly.save() 15 | daily = Rule(frequency = "DAILY") 16 | daily.save() 17 | cal = Calendar(name="MyCal") 18 | cal.save() 19 | 20 | self.event1 = Event(**{ 21 | 'title': 'Weekly Event', 22 | 'start': datetime.datetime(2009, 4, 1, 8, 0), 23 | 'end': datetime.datetime(2009, 4, 1, 9, 0), 24 | 'end_recurring_period' : datetime.datetime(2009, 10, 5, 0, 0), 25 | 'rule': weekly, 26 | 'calendar': cal 27 | }) 28 | self.event1.save() 29 | self.event2 = Event(**{ 30 | 'title': 'Recent Event', 31 | 'start': datetime.datetime(2008, 1, 5, 9, 0), 32 | 'end': datetime.datetime(2008, 1, 5, 10, 0), 33 | 'end_recurring_period' : datetime.datetime(2009, 5, 5, 0, 0), 34 | 'rule': daily, 35 | 'calendar': cal 36 | }) 37 | self.event2.save() 38 | 39 | def test_occurrences_after(self): 40 | eml = EventListManager([self.event1, self.event2]) 41 | occurrences = eml.occurrences_after(datetime.datetime(2009,4,1,0,0)) 42 | self.assertEqual(occurrences.next().event, self.event1) 43 | self.assertEqual(occurrences.next().event, self.event2) 44 | self.assertEqual(occurrences.next().event, self.event2) 45 | self.assertEqual(occurrences.next().event, self.event2) 46 | self.assertEqual(occurrences.next().event, self.event2) 47 | self.assertEqual(occurrences.next().event, self.event2) 48 | self.assertEqual(occurrences.next().event, self.event2) 49 | self.assertEqual(occurrences.next().event, self.event2) 50 | self.assertEqual(occurrences.next().event, self.event1) 51 | -------------------------------------------------------------------------------- /docs/utils.txt: -------------------------------------------------------------------------------- 1 | ========= 2 | Utilities 3 | ========= 4 | 5 | There are some utility classes found in the utils module that help with certain tasks. 6 | 7 | EventListManager 8 | ---------------- 9 | 10 | EventListManager objects are instantiated with a list of events. That list of events dictates the following methods 11 | 12 | ``occurrences_after(after)`` 13 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | Creates a generator that produces the next occurrence inclusively after the datetime ``after``. 16 | 17 | OccurrenceReplacer 18 | ------------------ 19 | 20 | If you get more into the internals of django-schedule, and decide to create your own method for producing occurrences, instead of using one of the public facing methods for this, you are going to want to replace the occurrence you produce with a persisted one, if a persisted one exists. To facilitate this in a standardized way you have the OccurrenceReplacer class. 21 | 22 | To instantiate it you give it the pool of persisted occurrences you would like to check in. 23 | 24 | >>> persisted_occurrences = my_event.occurrence_set.all() 25 | >>> occ_replacer = OccurrenceReplacer(persisted_occurrences) 26 | 27 | Now you have two convenient methods 28 | 29 | ``get_occurrence(occurrence)`` 30 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | 32 | This method returns either the passed in occurrence or the equivalent persisted occurrences from the pool of persisted occurrences this OccurrenceReplacer was instantiated with. 33 | 34 | >>> # my_generated_occurrence is an occurrence that was programatically 35 | >>> # generated from an event 36 | >>> occurrence = occ_replacer.get_occurrence(my_generated_occurrence) 37 | 38 | ``has_occurrence(occurrence)`` 39 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 | 41 | This method returns a boolean. It returns True of the OccurrenceReplacer has an occurrence it would like to replace with the give occurrence, and false if it does not 42 | 43 | >>> hasattr(my_generated_occurrence, 'pk') 44 | False 45 | >>> occ_replacer.has_occurrence(my_generated_occurrence) 46 | True 47 | >>> occurrence = occ_replacer.get_occurrence(my_generated_occurrence) 48 | >>> hasattr(occurrence, 'pk') 49 | True 50 | >>> # Now with my_other_occurrence which does not have a persisted counterpart 51 | >>> hasattr(my_other_occurrence, 'pk') 52 | False 53 | >>> occ_replacer.has_occurrence(my_other_occurrence) 54 | False 55 | >>> occurrence = occ_replacer.get_occurrence(my_other_occurrence) 56 | >>> hasattr(occurrence, 'pk') 57 | False -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. Django-schedule 2 | 3 | A calendaring/scheduling application, featuring: 4 | 5 | * one-time and recurring events 6 | * calendar exceptions (occurrences changed or cancelled) 7 | * occurrences accessible through Event API and Period API 8 | * relations of events to generic objects 9 | * ready to use, nice user interface 10 | * view day, week, month, three months and year 11 | * project sample which can be launched immediately and reused in your project 12 | 13 | See "wiki page":http://wiki.github.com/bartekgorny/django-schedule/wiki for more 14 | 15 | h2. Installation 16 | 17 | Download the code; put in into your project's directory or run
python setup.py install
to install system-wide. 18 | 19 | REQUIREMENTS: 20 | 21 | * python-vobject 22 | * python-dateutil from Labix 23 | 24 | (both come with most distributions) 25 | 26 | h2. Settings.py 27 | 28 | h3. REQUIRED 29 | 30 | INSTALLED_APPS - add: 31 | 'schedule' 32 | 33 | TEMPLATE_CONTEXT_PROCESSORS - add: 34 | "django.core.context_processors.request" 35 | 36 | h4. Optional 37 | 38 | FIRST_DAY_OF_WEEK 39 | 40 | This setting determines which day of the week your calendar begins on if your locale doesn't already set it. Default is 0, which is Sunday. 41 | 42 | OCCURRENCE_CANCEL_REDIRECT 43 | 44 | This setting controls the behavior of :func:`Views.get_next_url`. If set, all calendar modifications will redirect here (unless there is a `next` set in the request.) 45 | 46 | SHOW_CANCELLED_OCCURRENCES 47 | 48 | This setting controls the behavior of :func:`Period.classify_occurence`. If True, then occurences that have been cancelled will be displayed with a css class of canceled, otherwise they won't appear at all. 49 | 50 | Defaults to False 51 | 52 | CHECK_PERMISSION_FUNC 53 | 54 | This setting controls the callable used to determine if a user has permission to edit an event or occurance. The callable must take the object and the user and return a boolean. 55 | 56 | Default: 57 |
58 |     check_edit_permission(ob, user):
59 |         return user.is_authenticated()
60 | 
61 | 62 | If ob is None, then the function is checking for permission to add new events 63 | 64 | GET_EVENTS_FUNC 65 | 66 | This setting controls the callable that gets all events for calendar display. The callable must take the request and the calendar and return a `QuerySet` of events. Modifying this setting allows you to pull events from multiple calendars or to filter events based on permissions 67 | 68 | Default: 69 |
70 |     get_events(request, calendar):
71 |         return calendar.event_set.all()
72 | 
73 | 74 | h2. urls.py 75 | 76 | Add : 77 |
78 |     (r'^schedule/', include('schedule.urls')),
79 | 
80 | -------------------------------------------------------------------------------- /project_sample/templates/homepage.html: -------------------------------------------------------------------------------- 1 | {% extends "site_base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Welcome" %}{% endblock %} 6 | 7 | {% block tab_id %}id="home_tab"{% endblock %} 8 | 9 | {% block body %} 10 | {% blocktrans %} 11 |

django-schedule

12 | {% endblocktrans %} 13 | {% blocktrans %} 14 |

This project is a scheduling app. At its core are events that constitute a start and end date implemented via two DateTimeFields together with a some meta datax such as title, description, etc.

15 |

To make it more user friendly there is the idea of EventRelation which links generic objects and an Event object. The idea is that you will keep more information about the event in these relations such as who is authorized to view them. It could be the case that User is linked to Event to represent who is authorized to view the event, and also User is linked to event to represent who is attending the event.

16 |

The EventRelation has another field called distinction. So in the previous example we could add an EventRelation which links a User to an Event with the distinction "viewer" and another EventRelation which links a User to an Event with the distinction "attendee."

17 | {% endblocktrans %} 18 | {% blocktrans %} 19 |

Want to see it in action?

20 | {% endblocktrans %} 21 | {% blocktrans %} 22 |

The sample project come with two management commands that enable you to load some data:

23 |

./manage.py load_sample_data

24 |

./manage.py load_example_data

25 | {% endblocktrans %} 26 |

{% trans "The list of available Calendars." %}


27 | {% blocktrans %} 28 |

Core developers

29 |
    30 |
  • Bartek Górny
  • 31 |
  • Tony Hauber (retired)
  • 32 |
33 |

Contributors (in alphabetical order)

34 |
    35 |
  • John Anderson
  • 36 |
  • Greg Brown
  • 37 |
  • Daniel Gatis Carrazzoni
  • 38 |
  • Johan Charpentier
  • 39 |
  • Bruno Clermont
  • 40 |
  • adolfo fittoria
  • 41 |
  • Alex Gaynor
  • 42 |
  • Rock Howard
  • 43 |
  • Alik Kurdyukow
  • 44 |
  • Jannis Leidel
  • 45 |
  • Yann Malet
  • 46 |
  • James Pic
  • 47 |
  • Colin Powell
  • 48 |
  • Justin Quick
  • 49 |
  • Mark Rogers
  • 50 |
  • Skylar Saveland
  • 51 |
  • Erik Simmler
  • 52 |
  • Jonathan Stoppani
  • 53 |
  • ptoal
  • 54 |
  • Wes Winham
  • 55 |
  • Carlos Zuniga
  • 56 |
57 | {% endblocktrans %} 58 | 59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /schedule/tests/test_rule.py: -------------------------------------------------------------------------------- 1 | #coding:UTF-8 2 | 3 | import datetime 4 | import os 5 | 6 | from django.test import TestCase 7 | from django.core.urlresolvers import reverse 8 | 9 | from schedule.models import Event, Rule, Occurrence, Calendar 10 | from schedule.periods import Period, Month, Day 11 | from schedule.utils import EventListManager 12 | 13 | class TestRule(TestCase): 14 | """ 15 | test some more sophisticated rule settings 16 | """ 17 | 18 | def setUp(self): 19 | cal, created = Calendar.objects.get_or_create(name="MyCal") 20 | cal.save() 21 | 22 | def test_daily(self): 23 | kw = {'frequency':'DAILY'} 24 | exp = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] 25 | self._test_rule(kw, exp) 26 | 27 | def test_daily_limit(self): 28 | kw = {'frequency':'DAILY', 'params':'count:5'} 29 | exp = [1, 2, 3, 4, 5] 30 | self._test_rule(kw, exp) 31 | 32 | def test_monday(self): 33 | kw = {'frequency':'WEEKLY', 'params':'byweekday:MO'} 34 | exp = [4, 11, 18, 25] 35 | self._test_rule(kw, exp) 36 | 37 | def test_monday_thursday(self): 38 | kw = {'frequency':'WEEKLY', 'params':'byweekday:MO,TH'} 39 | exp = [4, 7, 11, 14, 18, 21, 25, 28] 40 | self._test_rule(kw, exp) 41 | 42 | def test_every_other_day(self): 43 | kw = {'frequency':'DAILY', 'params':'interval:2'} 44 | exp = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] 45 | self._test_rule(kw, exp) 46 | 47 | def test_every_other_monday(self): 48 | kw = {'frequency':'WEEKLY', 'params':'byweekday:MO;interval:2'} 49 | exp = [11, 25] 50 | self._test_rule(kw, exp) 51 | 52 | def test_first_thursday_of_month(self): 53 | kw = {'frequency':'MONTHLY', 'params':'byweekday:TH(1)'} 54 | exp = [7] 55 | self._test_rule(kw, exp) 56 | 57 | def _test_rule(self, kw, exp): 58 | print 59 | print "Rule", kw 60 | print exp 61 | print 62 | rule = Rule(**kw) 63 | ocs = self.make_occurrences(rule) 64 | self.assertEqual(ocs, exp) 65 | 66 | def make_occurrences(self, rule): 67 | cal = Calendar.objects.get(name="MyCal") 68 | recurring_data = { 69 | 'title': 'Recent Event', 70 | 'start': datetime.datetime(2010, 1, 1, 8, 0), 71 | 'end': datetime.datetime(2010, 1, 1, 9, 0), 72 | 'end_recurring_period' : datetime.datetime(2010, 2, 1, 0, 0), 73 | 'rule': rule, 74 | 'calendar': cal 75 | } 76 | recurring_event = Event(**recurring_data) 77 | occurrences = recurring_event.get_occurrences(start=datetime.datetime(2010, 1, 1, 0, 0), 78 | end=datetime.datetime(2010, 2, 1, 0, 0)) 79 | return [o.start.day for o in occurrences] -------------------------------------------------------------------------------- /schedule/management/commands/load_sample_data.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import NoArgsCommand 2 | 3 | from django.core.management.color import no_style 4 | 5 | class Command(NoArgsCommand): 6 | help = "Load some sample data into the db" 7 | 8 | def handle_noargs(self, **options): 9 | import datetime 10 | from schedule.models import Calendar 11 | from schedule.models import Event 12 | from schedule.models import Rule 13 | 14 | print "checking for existing data ..." 15 | try: 16 | cal = Calendar.objects.get(name="yml_cal") 17 | print "It looks like you already have loaded the sample data, quitting." 18 | import sys 19 | sys.exit(1) 20 | except Calendar.DoesNotExist: 21 | print "Sample data not found in db." 22 | print "Install it..." 23 | 24 | 25 | print "Create 2 calendars : tony_cal, yml_cal" 26 | yml_cal = Calendar(name="yml_cal",slug="yml") 27 | yml_cal.save() 28 | print "First calendar is created" 29 | tony_cal = Calendar(name="tony_cal",slug="tony") 30 | tony_cal.save() 31 | print "Second calendar is created" 32 | print "Do we need to create the most common rules?" 33 | try: 34 | rule = Rule.objects.get(name="Daily") 35 | except Rule.DoesNotExist: 36 | rule = Rule(frequency = "YEARLY", name = "Yearly", description = "will recur once every Year") 37 | rule.save() 38 | print "YEARLY recurrence created" 39 | rule = Rule(frequency = "MONTHLY", name = "Monthly", description = "will recur once every Month") 40 | rule.save() 41 | print "Monthly recurrence created" 42 | rule = Rule(frequency = "WEEKLY", name = "Weekly", description = "will recur once every Week") 43 | rule.save() 44 | print "Weekly recurrence created" 45 | rule = Rule(frequency = "DAILY", name = "Daily", description = "will recur once every Day") 46 | rule.save() 47 | print "Daily recurrence created" 48 | print "The common rules are installed." 49 | 50 | print "Create some events" 51 | rule = Rule.objects.get(frequency="WEEKLY") 52 | data = { 53 | 'title': 'Ping pong', 54 | 'start': datetime.datetime(2008, 11, 1, 8, 0), 55 | 'end': datetime.datetime(2008, 11, 1, 9, 0), 56 | 'end_recurring_period' : datetime.datetime(2010, 5, 5, 0, 0), 57 | 'rule': rule, 58 | 'calendar': tony_cal 59 | } 60 | event = Event(**data) 61 | event.save() 62 | rule = Rule.objects.get(frequency="DAILY") 63 | data = { 64 | 'title': 'Home work', 65 | 'start': datetime.datetime(2008, 11, 1, 18, 0), 66 | 'end': datetime.datetime(2008, 11, 1, 19, 0), 67 | 'end_recurring_period' : datetime.datetime(2010, 5, 5, 0, 0), 68 | 'rule': rule, 69 | 'calendar': tony_cal 70 | } 71 | event = Event(**data) 72 | event.save() 73 | -------------------------------------------------------------------------------- /docs/overview.txt: -------------------------------------------------------------------------------- 1 | ================ 2 | A Quick Overview 3 | ================ 4 | 5 | What is an Event? 6 | ----------------- 7 | 8 | An event doesn't have any date or time associated with it just a rule for how it recurs. In a way it designates a set of occurrences. A weekly staff meeting is a perfect example. A weekly staff meeting is an event, it says what it is and how often it recurs. Now if we were to say Tuesday's staff meeting, thats an occurrence. That is an a specific element in the set of occurrences designated by weekly staff meeting. 9 | 10 | There is an exception, and that is the "one-time" event. If your boss calls and sets up an meeting today at 3. Thats a one-time event. Its only going to happen this one time. That doesn't mean its an occurrence. It just means that its an event which represents a set of occurrences that only has one occurrence in it. 11 | 12 | What is an Occurrence? 13 | ---------------------- 14 | 15 | An occurrence is an instance of an event. If we have an event and it is Weekly staff meetings which occur every tuesday then next Tuesday's staff meeting is an occurrence. 16 | 17 | What does persisted Occurrences mean? 18 | ------------------------------------- 19 | 20 | Occurrences are generated programatically. This is because we can not store all of the occurrences in the database, because there could be infinite occurrences. But we still want to be able to persist data about occurrences. Like, canceling an occurrence, moving an occurrence, storing a list of attendees with the occurrence. This is done lazily. An occurrence is generated programatically until it needs to be saved to the database. When you use any function to get an occurrence, it will be completely transparent whether it was generated programatically or whether it is persisted (except that persisted ones will have a ``pk``). Just treat them like they are persisted and you shouldn't run into any trouble. 21 | 22 | What is a Rule? 23 | --------------- 24 | 25 | A rule defines how and event will recur. As of right now, there are no rules 26 | included with the app, so you will have to create your own. Doing this is somewhat straight forward 27 | 28 | Accessing Occurrences with an Event 29 | ----------------------------------- 30 | 31 | Because some Event can recur indefinitely, you can not have a function like, 32 | ``event.get_all_occurrences()``, because that would be an infinite list. So, there are two ways of getting occurrences given an event. 33 | 34 | ``get_occurrences(start, end)`` 35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 | 37 | This gives you a list of all occurrences that occur inclusively after start and exclusively before end. When we say occur, that means that they exist at all between start and end. If occurrence ends 10 seconds after ``start`` then it will be in the list, and if an occurrence starts 10 seconds before ``end`` then it will also be in the list. 38 | 39 | ``occurrences_after(after)`` 40 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 41 | 42 | This method produces a generator that generates events inclusively after the given datetime ``after``. If no date is given then it uses now. 43 | 44 | Accessing Occurrences from lists of Events 45 | ------------------------------------------ 46 | 47 | You are often going to have a list of events and want to get occurrences from them. To do this you can use Periods, and EventListManagers. -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | 9 | # Internal variables. 10 | PAPEROPT_a4 = -D latex_paper_size=a4 11 | PAPEROPT_letter = -D latex_paper_size=letter 12 | ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 13 | 14 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 15 | 16 | help: 17 | @echo "Please use \`make ' where is one of" 18 | @echo " html to make standalone HTML files" 19 | @echo " dirhtml to make HTML files named index.html in directories" 20 | @echo " pickle to make pickle files" 21 | @echo " json to make JSON files" 22 | @echo " htmlhelp to make HTML files and a HTML help project" 23 | @echo " qthelp to make HTML files and a qthelp project" 24 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 25 | @echo " changes to make an overview of all changed/added/deprecated items" 26 | @echo " linkcheck to check all external links for integrity" 27 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 28 | 29 | clean: 30 | -rm -rf _build/* 31 | 32 | html: 33 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html 34 | @echo 35 | @echo "Build finished. The HTML pages are in _build/html." 36 | 37 | dirhtml: 38 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml 39 | @echo 40 | @echo "Build finished. The HTML pages are in _build/dirhtml." 41 | 42 | pickle: 43 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle 44 | @echo 45 | @echo "Build finished; now you can process the pickle files." 46 | 47 | json: 48 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json 49 | @echo 50 | @echo "Build finished; now you can process the JSON files." 51 | 52 | htmlhelp: 53 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp 54 | @echo 55 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 56 | ".hhp project file in _build/htmlhelp." 57 | 58 | qthelp: 59 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp 60 | @echo 61 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 62 | ".qhcp project file in _build/qthelp, like this:" 63 | @echo "# qcollectiongenerator _build/qthelp/DjangoSchedule.qhcp" 64 | @echo "To view the help file:" 65 | @echo "# assistant -collectionFile _build/qthelp/DjangoSchedule.qhc" 66 | 67 | latex: 68 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex 69 | @echo 70 | @echo "Build finished; the LaTeX files are in _build/latex." 71 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 72 | "run these through (pdf)latex." 73 | 74 | changes: 75 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes 76 | @echo 77 | @echo "The overview file is in _build/changes." 78 | 79 | linkcheck: 80 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck 81 | @echo 82 | @echo "Link check complete; look for any errors in the above output " \ 83 | "or in _build/linkcheck/output.txt." 84 | 85 | doctest: 86 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest 87 | @echo "Testing of doctests in the sources finished, look at the " \ 88 | "results in _build/doctest/output.txt." 89 | -------------------------------------------------------------------------------- /schedule/models/rules.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils.translation import ugettext, ugettext_lazy as _ 3 | 4 | from dateutil import rrule 5 | 6 | RRULE_WEEKDAYS = {"MO":0,"TU":1,"WE":2,"TH":3,"FR":4,"SA":5,"SU":6} 7 | 8 | freqs = ( ("YEARLY", _("Yearly")), 9 | ("MONTHLY", _("Monthly")), 10 | ("WEEKLY", _("Weekly")), 11 | ("DAILY", _("Daily")), 12 | ("HOURLY", _("Hourly")), 13 | ("MINUTELY", _("Minutely")), 14 | ("SECONDLY", _("Secondly"))) 15 | 16 | class Rule(models.Model): 17 | """ 18 | This defines a rule by which an event will recur. This is defined by the 19 | rrule in the dateutil documentation. 20 | 21 | * name - the human friendly name of this kind of recursion. 22 | * description - a short description describing this type of recursion. 23 | * frequency - the base recurrence period 24 | * param - extra params required to define this type of recursion. The params 25 | should follow this format: 26 | 27 | param = [rruleparam:value;]* 28 | rruleparam = see list below 29 | value = int[,int]* 30 | 31 | The options are: (documentation for these can be found at 32 | http://labix.org/python-dateutil#head-470fa22b2db72000d7abe698a5783a46b0731b57) 33 | ** count 34 | ** bysetpos 35 | ** bymonth 36 | ** bymonthday 37 | ** byyearday 38 | ** byweekno 39 | ** byweekday 40 | ** byhour 41 | ** byminute 42 | ** bysecond 43 | ** byeaster 44 | """ 45 | name = models.CharField(_("name"), max_length=32) 46 | description = models.TextField(_("description")) 47 | frequency = models.CharField(_("frequency"), choices=freqs, max_length=10) 48 | params = models.TextField(_("params"), null=True, blank=True) 49 | 50 | class Meta: 51 | verbose_name = _('rule') 52 | verbose_name_plural = _('rules') 53 | app_label = 'schedule' 54 | 55 | def parse_param(self, param_value): 56 | param = param_value.split('(',1)[0] 57 | if param in RRULE_WEEKDAYS: 58 | try: 59 | return eval("rrule.%s" % param_value) 60 | except ValueError: 61 | raise ValueError('rrule parameter improperly formatted. Error on: %s' % param_value) 62 | try: 63 | return int(param_value) 64 | except ValueError: 65 | raise ValueError('rrule parameter should be integer or weekday constant (e.g. MO, TU, etc.). Error on: %s' % param_value) 66 | 67 | def get_params(self): 68 | """ 69 | >>> rule = Rule(params = "count:1;bysecond:1;byminute:1,2,4,5") 70 | >>> rule.get_params() 71 | {'count': 1, 'byminute': [1, 2, 4, 5], 'bysecond': 1} 72 | """ 73 | if self.params is None: 74 | return {} 75 | params = self.params.split(';') 76 | param_dict = [] 77 | for param in params: 78 | if param.strip() == "": 79 | continue # skip blanks 80 | param = param.split(':') 81 | if len(param) == 2: 82 | param = (str(param[0]).strip(), [self.parse_param(p.strip()) for p in param[1].split(',')]) 83 | if len(param[1]) == 1: 84 | param = (param[0], param[1][0]) 85 | param_dict.append(param) 86 | return dict(param_dict) 87 | 88 | def __unicode__(self): 89 | """Human readable string for Rule""" 90 | return self.name 91 | 92 | -------------------------------------------------------------------------------- /schedule/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2009-01-06 10:15-0400\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: forms.py:18 20 | msgid "AM" 21 | msgstr "" 22 | 23 | #: forms.py:18 24 | msgid "PM" 25 | msgstr "" 26 | 27 | #: forms.py:57 28 | msgid "The end time must be later than start time." 29 | msgstr "" 30 | 31 | #: forms.py:58 models.py:300 32 | msgid "This date is ignored for one time only events." 33 | msgstr "" 34 | 35 | #: models.py:15 36 | msgid "Yearly" 37 | msgstr "" 38 | 39 | #: models.py:16 40 | msgid "Monthly" 41 | msgstr "" 42 | 43 | #: models.py:17 44 | msgid "Weekly" 45 | msgstr "" 46 | 47 | #: models.py:18 48 | msgid "Daily" 49 | msgstr "" 50 | 51 | #: models.py:19 52 | msgid "Hourly" 53 | msgstr "" 54 | 55 | #: models.py:20 56 | msgid "Minutely" 57 | msgstr "" 58 | 59 | #: models.py:21 60 | msgid "Secondly" 61 | msgstr "" 62 | 63 | #: models.py:52 models.py:491 64 | msgid "name" 65 | msgstr "" 66 | 67 | #: models.py:53 models.py:296 68 | msgid "description" 69 | msgstr "" 70 | 71 | #: models.py:54 72 | msgid "frequency" 73 | msgstr "" 74 | 75 | #: models.py:55 76 | msgid "params" 77 | msgstr "" 78 | 79 | #: models.py:58 models.py:299 80 | msgid "rule" 81 | msgstr "" 82 | 83 | #: models.py:59 84 | msgid "rules" 85 | msgstr "" 86 | 87 | #: models.py:293 88 | msgid "start" 89 | msgstr "" 90 | 91 | #: models.py:294 92 | msgid "end" 93 | msgstr "" 94 | 95 | #: models.py:294 96 | msgid "The end time must be later than the start time." 97 | msgstr "" 98 | 99 | #: models.py:295 100 | msgid "title" 101 | msgstr "" 102 | 103 | #: models.py:297 104 | msgid "creator" 105 | msgstr "" 106 | 107 | #: models.py:298 108 | msgid "created on" 109 | msgstr "" 110 | 111 | #: models.py:299 112 | msgid "Select '----' for a one time only event." 113 | msgstr "" 114 | 115 | #: models.py:300 116 | msgid "end recurring period" 117 | msgstr "" 118 | 119 | #: models.py:305 models.py:754 120 | msgid "event" 121 | msgstr "" 122 | 123 | #: models.py:306 models.py:493 124 | msgid "events" 125 | msgstr "" 126 | 127 | #: models.py:309 periods.py:163 periods.py:216 periods.py:232 128 | msgid "DATE_FORMAT" 129 | msgstr "" 130 | 131 | #: models.py:310 132 | #, python-format 133 | msgid "%(title)s: %(start)s-%(end)s" 134 | msgstr "" 135 | 136 | #: models.py:492 137 | msgid "slug" 138 | msgstr "" 139 | 140 | #: models.py:498 models.py:499 models.py:589 141 | msgid "calendar" 142 | msgstr "" 143 | 144 | #: models.py:593 models.py:758 145 | msgid "distinction" 146 | msgstr "" 147 | 148 | #: models.py:594 149 | msgid "inheritable" 150 | msgstr "" 151 | 152 | #: models.py:599 153 | msgid "calendar relation" 154 | msgstr "" 155 | 156 | #: models.py:600 157 | msgid "calendar relations" 158 | msgstr "" 159 | 160 | #: models.py:763 161 | msgid "event relation" 162 | msgstr "" 163 | 164 | #: models.py:764 165 | msgid "event relations" 166 | msgstr "" 167 | 168 | #: occurrence.py:14 169 | #, python-format 170 | msgid "%(start)s to %(end)s" 171 | msgstr "" 172 | 173 | #: periods.py:10 174 | msgid "FIRST_DAY_OF_WEEK" 175 | msgstr "" 176 | 177 | #: periods.py:164 178 | #, python-format 179 | msgid "Month: %(start)s-%(end)s" 180 | msgstr "" 181 | 182 | #: periods.py:217 183 | #, python-format 184 | msgid "Week: %(start)s-%(end)s" 185 | msgstr "" 186 | 187 | #: periods.py:233 188 | #, python-format 189 | msgid "Day: %(start)s-%(end)s" 190 | msgstr "" 191 | -------------------------------------------------------------------------------- /schedule/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | from django.views.generic.list_detail import object_list 3 | from schedule.models import Calendar 4 | from schedule.feeds import UpcomingEventsFeed 5 | from schedule.feeds import CalendarICalendar 6 | from schedule.periods import Year, Month, Week, Day 7 | 8 | info_dict = { 9 | 'queryset': Calendar.objects.all(), 10 | } 11 | 12 | urlpatterns = patterns('', 13 | 14 | # urls for Calendars 15 | url(r'^calendar/$', 16 | object_list, 17 | name="schedule", 18 | kwargs={'queryset':Calendar.objects.all(), 'template_name':'schedule/calendar_list.html'}), 19 | 20 | url(r'^calendar/year/(?P[-\w]+)/$', 21 | 'schedule.views.calendar_by_periods', 22 | name="year_calendar", 23 | kwargs={'periods': [Year], 'template_name': 'schedule/calendar_year.html'}), 24 | 25 | url(r'^calendar/tri_month/(?P[-\w]+)/$', 26 | 'schedule.views.calendar_by_periods', 27 | name="tri_month_calendar", 28 | kwargs={'periods': [Month], 'template_name': 'schedule/calendar_tri_month.html'}), 29 | 30 | url(r'^calendar/compact_month/(?P[-\w]+)/$', 31 | 'schedule.views.calendar_by_periods', 32 | name = "compact_calendar", 33 | kwargs={'periods': [Month], 'template_name': 'schedule/calendar_compact_month.html'}), 34 | 35 | url(r'^calendar/month/(?P[-\w]+)/$', 36 | 'schedule.views.calendar_by_periods', 37 | name = "month_calendar", 38 | kwargs={'periods': [Month], 'template_name': 'schedule/calendar_month.html'}), 39 | 40 | url(r'^calendar/week/(?P[-\w]+)/$', 41 | 'schedule.views.calendar_by_periods', 42 | name = "week_calendar", 43 | kwargs={'periods': [Week], 'template_name': 'schedule/calendar_week.html'}), 44 | 45 | url(r'^calendar/daily/(?P[-\w]+)/$', 46 | 'schedule.views.calendar_by_periods', 47 | name = "day_calendar", 48 | kwargs={'periods': [Day], 'template_name': 'schedule/calendar_day.html'}), 49 | 50 | url(r'^calendar/(?P[-\w]+)/$', 51 | 'schedule.views.calendar', 52 | name = "calendar_home", 53 | ), 54 | 55 | #Event Urls 56 | url(r'^event/create/(?P[-\w]+)/$', 57 | 'schedule.views.create_or_edit_event', 58 | name='calendar_create_event'), 59 | url(r'^event/edit/(?P[-\w]+)/(?P\d+)/$', 60 | 'schedule.views.create_or_edit_event', 61 | name='edit_event'), 62 | url(r'^event/(?P\d+)/$', 63 | 'schedule.views.event', 64 | name="event"), 65 | url(r'^event/delete/(?P\d+)/$', 66 | 'schedule.views.delete_event', 67 | name="delete_event"), 68 | 69 | #urls for already persisted occurrences 70 | url(r'^occurrence/(?P\d+)/(?P\d+)/$', 71 | 'schedule.views.occurrence', 72 | name="occurrence"), 73 | url(r'^occurrence/cancel/(?P\d+)/(?P\d+)/$', 74 | 'schedule.views.cancel_occurrence', 75 | name="cancel_occurrence"), 76 | url(r'^occurrence/edit/(?P\d+)/(?P\d+)/$', 77 | 'schedule.views.edit_occurrence', 78 | name="edit_occurrence"), 79 | 80 | #urls for unpersisted occurrences 81 | url(r'^occurrence/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', 82 | 'schedule.views.occurrence', 83 | name="occurrence_by_date"), 84 | url(r'^occurrence/cancel/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', 85 | 'schedule.views.cancel_occurrence', 86 | name="cancel_occurrence_by_date"), 87 | url(r'^occurrence/edit/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', 88 | 'schedule.views.edit_occurrence', 89 | name="edit_occurrence_by_date"), 90 | 91 | 92 | #feed urls 93 | url(r'^feed/calendar/(.*)/$', 94 | 'django.contrib.syndication.views.feed', 95 | { "feed_dict": { "upcoming": UpcomingEventsFeed } }), 96 | 97 | (r'^ical/calendar/(.*)/$', CalendarICalendar()), 98 | 99 | url(r'^$', object_list, info_dict, name='schedule'), 100 | ) 101 | -------------------------------------------------------------------------------- /schedule/locale/fr/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: django-scheduleN\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2009-01-06 10:15-0400\n" 11 | "PO-Revision-Date: 2008-12-05 23:59-0400\n" 12 | "Last-Translator: Yann Malet \n" 13 | "Language-Team: Yann Malet \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: forms.py:18 19 | msgid "AM" 20 | msgstr "AM" 21 | 22 | #: forms.py:18 23 | msgid "PM" 24 | msgstr "PM" 25 | 26 | #: forms.py:57 27 | msgid "The end time must be later than start time." 28 | msgstr "" 29 | 30 | #: forms.py:58 models.py:300 31 | msgid "This date is ignored for one time only events." 32 | msgstr "" 33 | 34 | #: models.py:15 35 | msgid "Yearly" 36 | msgstr "Annuel" 37 | 38 | #: models.py:16 39 | msgid "Monthly" 40 | msgstr "Mensuel" 41 | 42 | #: models.py:17 43 | msgid "Weekly" 44 | msgstr "Hebdomadaire" 45 | 46 | #: models.py:18 47 | msgid "Daily" 48 | msgstr "Quotidien" 49 | 50 | #: models.py:19 51 | msgid "Hourly" 52 | msgstr "Toutes les heures " 53 | 54 | #: models.py:20 55 | msgid "Minutely" 56 | msgstr "Toutes les minutes" 57 | 58 | #: models.py:21 59 | msgid "Secondly" 60 | msgstr "Toutes les secondes" 61 | 62 | #: models.py:52 models.py:491 63 | msgid "name" 64 | msgstr "Nom" 65 | 66 | #: models.py:53 models.py:296 67 | msgid "description" 68 | msgstr "description" 69 | 70 | #: models.py:54 71 | msgid "frequency" 72 | msgstr "fréquence" 73 | 74 | #: models.py:55 75 | msgid "params" 76 | msgstr "params" 77 | 78 | #: models.py:58 models.py:299 79 | msgid "rule" 80 | msgstr "régle" 81 | 82 | #: models.py:59 83 | msgid "rules" 84 | msgstr "régles" 85 | 86 | #: models.py:293 87 | msgid "start" 88 | msgstr "début" 89 | 90 | #: models.py:294 91 | msgid "end" 92 | msgstr "fin" 93 | 94 | #: models.py:294 95 | msgid "The end time must be later than the start time." 96 | msgstr "" 97 | 98 | #: models.py:295 99 | msgid "title" 100 | msgstr "titre" 101 | 102 | #: models.py:297 103 | msgid "creator" 104 | msgstr "Créateur" 105 | 106 | #: models.py:298 107 | msgid "created on" 108 | msgstr "" 109 | 110 | #: models.py:299 111 | msgid "Select '----' for a one time only event." 112 | msgstr "" 113 | 114 | #: models.py:300 115 | msgid "end recurring period" 116 | msgstr "fin de la période de récurrence" 117 | 118 | #: models.py:305 models.py:754 119 | msgid "event" 120 | msgstr "évènement" 121 | 122 | #: models.py:306 models.py:493 123 | msgid "events" 124 | msgstr "évènements" 125 | 126 | #: models.py:309 periods.py:163 periods.py:216 periods.py:232 127 | msgid "DATE_FORMAT" 128 | msgstr "" 129 | 130 | #: models.py:310 131 | #, python-format 132 | msgid "%(title)s: %(start)s-%(end)s" 133 | msgstr "" 134 | 135 | #: models.py:492 136 | msgid "slug" 137 | msgstr "" 138 | 139 | #: models.py:498 models.py:499 models.py:589 140 | msgid "calendar" 141 | msgstr "calendrier" 142 | 143 | #: models.py:593 models.py:758 144 | msgid "distinction" 145 | msgstr "distinction" 146 | 147 | #: models.py:594 148 | msgid "inheritable" 149 | msgstr "" 150 | 151 | #: models.py:599 152 | msgid "calendar relation" 153 | msgstr "" 154 | 155 | #: models.py:600 156 | msgid "calendar relations" 157 | msgstr "" 158 | 159 | #: models.py:763 160 | msgid "event relation" 161 | msgstr "" 162 | 163 | #: models.py:764 164 | msgid "event relations" 165 | msgstr "" 166 | 167 | #: occurrence.py:14 168 | #, python-format 169 | msgid "%(start)s to %(end)s" 170 | msgstr "%(start)s à %(end)s" 171 | 172 | #: periods.py:10 173 | msgid "FIRST_DAY_OF_WEEK" 174 | msgstr "" 175 | 176 | #: periods.py:164 177 | #, python-format 178 | msgid "Month: %(start)s-%(end)s" 179 | msgstr "Mois : %(start)s-%(end)s" 180 | 181 | #: periods.py:217 182 | #, python-format 183 | msgid "Week: %(start)s-%(end)s" 184 | msgstr "Semaine : %(start)s-%(end)s" 185 | 186 | #: periods.py:233 187 | #, python-format 188 | msgid "Day: %(start)s-%(end)s" 189 | msgstr "Jour: %(start)s-%(end)s" 190 | -------------------------------------------------------------------------------- /schedule/locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the django-schedule package. 4 | # Jannis Leidel , 2008. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: django-schedule\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2009-01-06 10:15-0400\n" 12 | "PO-Revision-Date: 2008-12-04 10:25+0100\n" 13 | "Last-Translator: Jannis Leidel \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: forms.py:18 20 | msgid "AM" 21 | msgstr "vorm." 22 | 23 | #: forms.py:18 24 | msgid "PM" 25 | msgstr "nachm." 26 | 27 | #: forms.py:57 28 | msgid "The end time must be later than start time." 29 | msgstr "" 30 | 31 | #: forms.py:58 models.py:300 32 | msgid "This date is ignored for one time only events." 33 | msgstr "" 34 | 35 | #: models.py:15 36 | msgid "Yearly" 37 | msgstr "jährlich" 38 | 39 | #: models.py:16 40 | msgid "Monthly" 41 | msgstr "monatlich" 42 | 43 | #: models.py:17 44 | msgid "Weekly" 45 | msgstr "wöchentlich" 46 | 47 | #: models.py:18 48 | msgid "Daily" 49 | msgstr "täglich" 50 | 51 | #: models.py:19 52 | msgid "Hourly" 53 | msgstr "stündlich" 54 | 55 | #: models.py:20 56 | msgid "Minutely" 57 | msgstr "minütlich" 58 | 59 | #: models.py:21 60 | msgid "Secondly" 61 | msgstr "sekündlich" 62 | 63 | #: models.py:52 models.py:491 64 | msgid "name" 65 | msgstr "Name" 66 | 67 | #: models.py:53 models.py:296 68 | msgid "description" 69 | msgstr "Beschreibung" 70 | 71 | #: models.py:54 72 | msgid "frequency" 73 | msgstr "Wiederholen" 74 | 75 | #: models.py:55 76 | msgid "params" 77 | msgstr "Parameter" 78 | 79 | #: models.py:58 models.py:299 80 | msgid "rule" 81 | msgstr "Regel" 82 | 83 | #: models.py:59 84 | msgid "rules" 85 | msgstr "Regeln" 86 | 87 | #: models.py:293 88 | msgid "start" 89 | msgstr "Beginn" 90 | 91 | #: models.py:294 92 | msgid "end" 93 | msgstr "Ende" 94 | 95 | #: models.py:294 96 | msgid "The end time must be later than the start time." 97 | msgstr "" 98 | 99 | #: models.py:295 100 | msgid "title" 101 | msgstr "Titel" 102 | 103 | #: models.py:297 104 | msgid "creator" 105 | msgstr "Urheber" 106 | 107 | #: models.py:298 108 | msgid "created on" 109 | msgstr "Erstellt" 110 | 111 | #: models.py:299 112 | msgid "Select '----' for a one time only event." 113 | msgstr "" 114 | 115 | #: models.py:300 116 | msgid "end recurring period" 117 | msgstr "Ende der Wiederholung" 118 | 119 | #: models.py:305 models.py:754 120 | msgid "event" 121 | msgstr "Termin" 122 | 123 | #: models.py:306 models.py:493 124 | msgid "events" 125 | msgstr "Termine" 126 | 127 | #: models.py:309 periods.py:163 periods.py:216 periods.py:232 128 | msgid "DATE_FORMAT" 129 | msgstr "" 130 | 131 | #: models.py:310 132 | #, python-format 133 | msgid "%(title)s: %(start)s-%(end)s" 134 | msgstr "%(title)s: %(start)s - %(end)s" 135 | 136 | #: models.py:492 137 | msgid "slug" 138 | msgstr "" 139 | 140 | #: models.py:498 models.py:499 models.py:589 141 | msgid "calendar" 142 | msgstr "Kalender" 143 | 144 | #: models.py:593 models.py:758 145 | msgid "distinction" 146 | msgstr "Unterscheidungsmerkmal" 147 | 148 | #: models.py:594 149 | msgid "inheritable" 150 | msgstr "vererbbar" 151 | 152 | #: models.py:599 153 | msgid "calendar relation" 154 | msgstr "Kalenderzuordnung" 155 | 156 | #: models.py:600 157 | msgid "calendar relations" 158 | msgstr "Kalenderzuordnungen" 159 | 160 | #: models.py:763 161 | msgid "event relation" 162 | msgstr "Terminzuordnung" 163 | 164 | #: models.py:764 165 | msgid "event relations" 166 | msgstr "Terminzuordnungen" 167 | 168 | #: occurrence.py:14 169 | #, python-format 170 | msgid "%(start)s to %(end)s" 171 | msgstr "%(start)s bis %(end)s" 172 | 173 | #: periods.py:10 174 | msgid "FIRST_DAY_OF_WEEK" 175 | msgstr "" 176 | 177 | #: periods.py:164 178 | #, python-format 179 | msgid "Month: %(start)s-%(end)s" 180 | msgstr "Monat: %(start)s - %(end)s" 181 | 182 | #: periods.py:217 183 | #, python-format 184 | msgid "Week: %(start)s-%(end)s" 185 | msgstr "Woche: %(start)s-%(end)s" 186 | 187 | #: periods.py:233 188 | #, python-format 189 | msgid "Day: %(start)s-%(end)s" 190 | msgstr "Tag: %(start)s-%(end)s" 191 | -------------------------------------------------------------------------------- /schedule/locale/es/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2009-01-06 10:15-0400\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: forms.py:18 20 | msgid "AM" 21 | msgstr "AM" 22 | 23 | #: forms.py:18 24 | msgid "PM" 25 | msgstr "PM" 26 | 27 | #: forms.py:57 28 | msgid "The end time must be later than start time." 29 | msgstr "El tiempo de fin debe de ser mayor que el tiempo de inicio." 30 | 31 | #: forms.py:58 models.py:300 32 | msgid "This date is ignored for one time only events." 33 | msgstr "Esta fecha es ignorada para eventos de una sola ocurrencia." 34 | 35 | #: models.py:15 36 | msgid "Yearly" 37 | msgstr "Anual" 38 | 39 | #: models.py:16 40 | msgid "Monthly" 41 | msgstr "Mensual" 42 | 43 | #: models.py:17 44 | msgid "Weekly" 45 | msgstr "Semanal" 46 | 47 | #: models.py:18 48 | msgid "Daily" 49 | msgstr "Diario" 50 | 51 | #: models.py:19 52 | msgid "Hourly" 53 | msgstr "Por Hora" 54 | 55 | #: models.py:20 56 | msgid "Minutely" 57 | msgstr "Por Minuto" 58 | 59 | #: models.py:21 60 | msgid "Secondly" 61 | msgstr "Por Segundo" 62 | 63 | #: models.py:52 models.py:491 64 | msgid "name" 65 | msgstr "nombre" 66 | 67 | #: models.py:53 models.py:296 68 | msgid "description" 69 | msgstr "descripción" 70 | 71 | #: models.py:54 72 | msgid "frequency" 73 | msgstr "frecuencia" 74 | 75 | #: models.py:55 76 | msgid "params" 77 | msgstr "parametros" 78 | 79 | #: models.py:58 models.py:299 80 | msgid "rule" 81 | msgstr "regla" 82 | 83 | #: models.py:59 84 | msgid "rules" 85 | msgstr "reglas" 86 | 87 | #: models.py:293 88 | msgid "start" 89 | msgstr "inicio" 90 | 91 | #: models.py:294 92 | msgid "end" 93 | msgstr "final" 94 | 95 | #: models.py:294 96 | msgid "The end time must be later than the start time." 97 | msgstr "El tiempo final debe de ser después del tiempo de inicio" 98 | 99 | #: models.py:295 100 | msgid "title" 101 | msgstr "título" 102 | 103 | #: models.py:297 104 | msgid "creator" 105 | msgstr "creador" 106 | 107 | #: models.py:298 108 | msgid "created on" 109 | msgstr "creado el" 110 | 111 | #: models.py:299 112 | msgid "Select '----' for a one time only event." 113 | msgstr "Seleccione '----' para un evento de una sola ocurrencia." 114 | 115 | #: models.py:300 116 | msgid "end recurring period" 117 | msgstr "fin del período recurrente" 118 | 119 | #: models.py:305 models.py:754 120 | msgid "event" 121 | msgstr "evento" 122 | 123 | #: models.py:306 models.py:493 124 | msgid "events" 125 | msgstr "eventos" 126 | 127 | #: models.py:309 periods.py:163 periods.py:216 periods.py:232 128 | msgid "DATE_FORMAT" 129 | msgstr "DATE_FORMAT" 130 | 131 | #: models.py:310 132 | #, python-format 133 | msgid "%(title)s: %(start)s-%(end)s" 134 | msgstr "" 135 | 136 | #: models.py:492 137 | msgid "slug" 138 | msgstr "slug" 139 | 140 | #: models.py:498 models.py:499 models.py:589 141 | msgid "calendar" 142 | msgstr "calendario" 143 | 144 | #: models.py:593 models.py:758 145 | msgid "distinction" 146 | msgstr "distinción" 147 | 148 | #: models.py:594 149 | msgid "inheritable" 150 | msgstr "heredable" 151 | 152 | #: models.py:599 153 | msgid "calendar relation" 154 | msgstr "relación de calendario" 155 | 156 | #: models.py:600 157 | msgid "calendar relations" 158 | msgstr "relaciones de calendario" 159 | 160 | #: models.py:763 161 | msgid "event relation" 162 | msgstr "relación de evento" 163 | 164 | #: models.py:764 165 | msgid "event relations" 166 | msgstr "relaciones de eventos" 167 | 168 | #: occurrence.py:14 169 | #, python-format 170 | msgid "%(start)s to %(end)s" 171 | msgstr "" 172 | 173 | #: periods.py:10 174 | msgid "FIRST_DAY_OF_WEEK" 175 | msgstr "" 176 | 177 | #: periods.py:164 178 | #, python-format 179 | msgid "Month: %(start)s-%(end)s" 180 | msgstr "Mes: %(start)s-%(end)s" 181 | 182 | #: periods.py:217 183 | #, python-format 184 | msgid "Week: %(start)s-%(end)s" 185 | msgstr "Semana: %(start)s-%(end)s" 186 | 187 | #: periods.py:233 188 | #, python-format 189 | msgid "Day: %(start)s-%(end)s" 190 | msgstr "Día: %(start)s-%(end)s" 191 | -------------------------------------------------------------------------------- /project_sample/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for project_sample project. 2 | import os 3 | 4 | PROJECT_DIR = os.path.abspath(os.path.dirname(__file__)) 5 | 6 | DEBUG = True 7 | TEMPLATE_DEBUG = DEBUG 8 | 9 | ADMINS = ( 10 | # ('Your Name', 'your_email@domain.com'), 11 | ) 12 | 13 | MANAGERS = ADMINS 14 | 15 | DATABASES = { 16 | 'default': { 17 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 18 | 'NAME': os.path.join(PROJECT_DIR, 'project_sample.db'), # Or path to database file if using sqlite3. 19 | 'USER': '', # Not used with sqlite3. 20 | 'PASSWORD': '', # Not used with sqlite3. 21 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 22 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 23 | } 24 | } 25 | # Local time zone for this installation. Choices can be found here: 26 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 27 | # although not all choices may be available on all operating systems. 28 | # If running in a Windows environment this must be set to the same as your 29 | # system time zone. 30 | TIME_ZONE = 'America/Chicago' 31 | 32 | # Language code for this installation. All choices can be found here: 33 | # http://www.i18nguy.com/unicode/language-identifiers.html 34 | LANGUAGE_CODE = 'en-us' 35 | 36 | SITE_ID = 1 37 | 38 | # If you set this to False, Django will make some optimizations so as not 39 | # to load the internationalization machinery. 40 | USE_I18N = True 41 | 42 | # Absolute path to the directory that holds media. 43 | # Example: "/home/media/media.lawrence.com/" 44 | MEDIA_ROOT = os.path.join(PROJECT_DIR, "site_media") 45 | 46 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 47 | # trailing slash if there is a path component (optional in other cases). 48 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 49 | MEDIA_URL = '/site_media/' 50 | 51 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 52 | # trailing slash. 53 | # Examples: "http://foo.com/media/", "/media/". 54 | ADMIN_MEDIA_PREFIX = '/media/' 55 | 56 | # Make this unique, and don't share it with anybody. 57 | SECRET_KEY = '+3^08&lnsm^nl1iozv=a-9!e4x$*o%g6pkx=y$)oc8#r$ndn7t' 58 | 59 | # List of callables that know how to import templates from various sources. 60 | TEMPLATE_LOADERS = ( 61 | 'django.template.loaders.filesystem.Loader', 62 | 'django.template.loaders.app_directories.Loader', 63 | ) 64 | 65 | MIDDLEWARE_CLASSES = ( 66 | 'django.contrib.sessions.middleware.SessionMiddleware', 67 | 'django.middleware.locale.LocaleMiddleware', 68 | 'django.middleware.common.CommonMiddleware', 69 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 70 | 'debug_toolbar.middleware.DebugToolbarMiddleware', 71 | ) 72 | 73 | ROOT_URLCONF = 'project_sample.urls' 74 | 75 | TEMPLATE_DIRS = ( 76 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 77 | # Always use forward slashes, even on Windows. 78 | # Don't forget to use absolute paths, not relative paths. 79 | os.path.join(PROJECT_DIR,"templates"), 80 | ) 81 | 82 | INSTALLED_APPS = ( 83 | 'django.contrib.auth', 84 | 'django.contrib.contenttypes', 85 | 'django.contrib.sessions', 86 | 'django.contrib.sites', 87 | 'django.contrib.admin', 88 | 'django.contrib.admindocs', 89 | 'schedule', 90 | 'debug_toolbar', 91 | ) 92 | 93 | TEMPLATE_CONTEXT_PROCESSORS = ( 94 | 'django.contrib.auth.context_processors.auth', 95 | "django.core.context_processors.debug", 96 | "django.core.context_processors.i18n", 97 | "django.core.context_processors.media", 98 | "django.core.context_processors.request", 99 | ) 100 | 101 | FIRST_DAY_OF_WEEK = 1 # Monday 102 | 103 | # Needed for debug toolbar 104 | INTERNAL_IPS = ('127.0.0.1',) 105 | DEBUG_TOOLBAR_PANELS = ( 106 | 'debug_toolbar.panels.version.VersionDebugPanel', 107 | 'debug_toolbar.panels.timer.TimerDebugPanel', 108 | 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel', 109 | 'debug_toolbar.panels.headers.HeaderDebugPanel', 110 | 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel', 111 | 'debug_toolbar.panels.template.TemplateDebugPanel', 112 | 'debug_toolbar.panels.sql.SQLDebugPanel', 113 | 'debug_toolbar.panels.signals.SignalDebugPanel', 114 | 'debug_toolbar.panels.logger.LoggingPanel', 115 | ) 116 | 117 | DEBUG_TOOLBAR_CONFIG = {'INTERCEPT_REDIRECTS': False} 118 | -------------------------------------------------------------------------------- /schedule/utils.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import heapq 3 | from django.contrib.contenttypes.models import ContentType 4 | from django.http import HttpResponseRedirect 5 | from django.conf import settings 6 | from schedule.conf.settings import CHECK_PERMISSION_FUNC 7 | 8 | class EventListManager(object): 9 | """ 10 | This class is responsible for doing functions on a list of events. It is 11 | used to when one has a list of events and wants to access the occurrences 12 | from these events in as a group 13 | """ 14 | def __init__(self, events): 15 | self.events = events 16 | 17 | def occurrences_after(self, after=None): 18 | """ 19 | It is often useful to know what the next occurrence is given a list of 20 | events. This function produces a generator that yields the 21 | the most recent occurrence after the date ``after`` from any of the 22 | events in ``self.events`` 23 | """ 24 | from schedule.models import Occurrence 25 | if after is None: 26 | after = datetime.datetime.now() 27 | occ_replacer = OccurrenceReplacer( 28 | Occurrence.objects.filter(event__in = self.events)) 29 | generators = [event._occurrences_after_generator(after) for event in self.events] 30 | occurrences = [] 31 | 32 | for generator in generators: 33 | try: 34 | heapq.heappush(occurrences, (generator.next(), generator)) 35 | except StopIteration: 36 | pass 37 | 38 | while True: 39 | if len(occurrences) == 0: raise StopIteration 40 | 41 | generator=occurrences[0][1] 42 | 43 | try: 44 | next = heapq.heapreplace(occurrences, (generator.next(), generator))[0] 45 | except StopIteration: 46 | next = heapq.heappop(occurrences)[0] 47 | yield occ_replacer.get_occurrence(next) 48 | 49 | 50 | class OccurrenceReplacer(object): 51 | """ 52 | When getting a list of occurrences, the last thing that needs to be done 53 | before passing it forward is to make sure all of the occurrences that 54 | have been stored in the datebase replace, in the list you are returning, 55 | the generated ones that are equivalent. This class makes this easier. 56 | """ 57 | def __init__(self, persisted_occurrences): 58 | lookup = [((occ.event_id, occ.original_start, occ.original_end), occ) for 59 | occ in persisted_occurrences] 60 | self.lookup = dict(lookup) 61 | 62 | def get_occurrence(self, occ): 63 | """ 64 | Return a persisted occurrences matching the occ and remove it from lookup since it 65 | has already been matched 66 | """ 67 | return self.lookup.pop( 68 | (occ.event_id, occ.original_start, occ.original_end), 69 | occ) 70 | 71 | def has_occurrence(self, occ): 72 | return (occ.event_id, occ.original_start, occ.original_end) in self.lookup 73 | 74 | def get_additional_occurrences(self, start, end): 75 | """ 76 | Return persisted occurrences which are now in the period 77 | """ 78 | return [occ for key,occ in self.lookup.items() if (occ.start < end and occ.end >= start and not occ.cancelled)] 79 | 80 | 81 | class check_event_permissions(object): 82 | 83 | def __init__(self, f): 84 | self.f = f 85 | self.__name__ = f.__name__ 86 | self.contenttype = ContentType.objects.get(app_label='schedule', model='event') 87 | 88 | def __call__(self, request, *args, **kwargs): 89 | user = request.user 90 | object_id = kwargs.get('event_id', None) 91 | try: 92 | obj = self.contenttype.get_object_for_this_type(pk=object_id) 93 | except self.contenttype.model_class().DoesNotExist: 94 | obj = None 95 | allowed = CHECK_PERMISSION_FUNC(obj, user) 96 | if not allowed: 97 | return HttpResponseRedirect(settings.LOGIN_URL) 98 | return self.f(request, *args, **kwargs) 99 | 100 | 101 | def coerce_date_dict(date_dict): 102 | """ 103 | given a dictionary (presumed to be from request.GET) it returns a tuple 104 | that represents a date. It will return from year down to seconds until one 105 | is not found. ie if year, month, and seconds are in the dictionary, only 106 | year and month will be returned, the rest will be returned as min. If none 107 | of the parts are found return an empty tuple. 108 | """ 109 | keys = ['year', 'month', 'day', 'hour', 'minute', 'second'] 110 | retVal = { 111 | 'year': 1, 112 | 'month': 1, 113 | 'day': 1, 114 | 'hour': 0, 115 | 'minute': 0, 116 | 'second': 0} 117 | modified = False 118 | for key in keys: 119 | try: 120 | retVal[key] = int(date_dict[key]) 121 | modified = True 122 | except KeyError: 123 | break 124 | return modified and retVal or {} 125 | 126 | -------------------------------------------------------------------------------- /schedule/management/commands/load_example_data.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import NoArgsCommand 2 | 3 | from django.core.management.color import no_style 4 | 5 | class Command(NoArgsCommand): 6 | help = "Load some sample data into the db" 7 | 8 | def handle_noargs(self, **options): 9 | import datetime 10 | from schedule.models import Calendar 11 | from schedule.models import Event 12 | from schedule.models import Rule 13 | 14 | print "checking for existing data ..." 15 | try: 16 | cal = Calendar.objects.get(name="Example Calendar") 17 | print "It looks like you already have loaded this sample data, quitting." 18 | import sys 19 | sys.exit(1) 20 | except Calendar.DoesNotExist: 21 | print "Sample data not found in db." 22 | print "Install it..." 23 | 24 | 25 | print "Create Example Calendar ..." 26 | cal = Calendar(name="Example Calendar",slug="example") 27 | cal.save() 28 | print "The Example Calendar is created." 29 | print "Do we need to install the most common rules?" 30 | try: 31 | rule = Rule.objects.get(name="Daily") 32 | except Rule.DoesNotExist: 33 | print "Need to install the basic rules" 34 | rule = Rule(frequency = "YEARLY", name = "Yearly", description = "will recur once every Year") 35 | rule.save() 36 | print "YEARLY recurrence created" 37 | rule = Rule(frequency = "MONTHLY", name = "Monthly", description = "will recur once every Month") 38 | rule.save() 39 | print "Monthly recurrence created" 40 | rule = Rule(frequency = "WEEKLY", name = "Weekly", description = "will recur once every Week") 41 | rule.save() 42 | print "Weekly recurrence created" 43 | rule = Rule(frequency = "DAILY", name = "Daily", description = "will recur once every Day") 44 | rule.save() 45 | print "Daily recurrence created" 46 | print "Rules installed." 47 | 48 | print "Create some events" 49 | rule = Rule.objects.get(frequency="WEEKLY") 50 | data = { 51 | 'title': 'Exercise', 52 | 'start': datetime.datetime(2008, 11, 3, 8, 0), 53 | 'end': datetime.datetime(2008, 11, 3, 9, 0), 54 | 'end_recurring_period' : datetime.datetime(2009, 6, 1, 0, 0), 55 | 'rule': rule, 56 | 'calendar': cal 57 | } 58 | event = Event(**data) 59 | event.save() 60 | 61 | data = { 62 | 'title': 'Exercise', 63 | 'start': datetime.datetime(2008, 11, 5, 15, 0), 64 | 'end': datetime.datetime(2008, 11, 5, 16, 30), 65 | 'end_recurring_period' : datetime.datetime(2009, 6, 1, 0, 0), 66 | 'rule': rule, 67 | 'calendar': cal 68 | } 69 | event = Event(**data) 70 | event.save() 71 | 72 | data = { 73 | 'title': 'Exercise', 74 | 'start': datetime.datetime(2008, 11, 7, 8, 0), 75 | 'end': datetime.datetime(2008, 11, 7, 9, 30), 76 | 'end_recurring_period' : datetime.datetime(2009, 6, 1, 0, 0), 77 | 'rule': rule, 78 | 'calendar': cal 79 | } 80 | event = Event(**data) 81 | event.save() 82 | 83 | rule = Rule.objects.get(frequency="MONTHLY") 84 | data = { 85 | 'title': 'Pay Mortgage', 86 | 'start': datetime.datetime(2008, 11, 1, 14, 0), 87 | 'end': datetime.datetime(2008, 11, 1, 14, 30), 88 | 'end_recurring_period' : datetime.datetime(2009, 10, 2, 0, 0), 89 | 'rule': rule, 90 | 'calendar': cal 91 | } 92 | event = Event(**data) 93 | event.save() 94 | 95 | rule = Rule.objects.get(frequency="YEARLY") 96 | data = { 97 | 'title': "Rock's Birthday Party", 98 | 'start': datetime.datetime(2008, 12, 11, 19, 0), 99 | 'end': datetime.datetime(2008, 12, 11, 23, 59), 100 | 'end_recurring_period' : datetime.datetime(2009, 12, 22, 0, 0), 101 | 'rule': rule, 102 | 'calendar': cal 103 | } 104 | event = Event(**data) 105 | event.save() 106 | 107 | data = { 108 | 'title': 'Christmas Party', 109 | 'start': datetime.datetime(2008, 12, 25, 19, 30), 110 | 'end': datetime.datetime(2008, 12, 25, 23, 59), 111 | 'end_recurring_period' : datetime.datetime(2010, 12, 31, 0, 0), 112 | 'rule': rule, 113 | 'calendar': cal 114 | } 115 | event = Event(**data) 116 | event.save() 117 | 118 | data = { 119 | 'title': 'New Pinax site goes live', 120 | 'start': datetime.datetime(2009, 1, 6, 11, 0), 121 | 'end': datetime.datetime(2009, 1, 6, 12, 00), 122 | 'end_recurring_period' : datetime.datetime(2009, 1, 7, 0, 0), 123 | 'calendar': cal 124 | } 125 | event = Event(**data) 126 | event.save() 127 | 128 | -------------------------------------------------------------------------------- /docs/periods.txt: -------------------------------------------------------------------------------- 1 | ======= 2 | Periods 3 | ======= 4 | 5 | One of the goals of DjangoSchedule is to make occurrence generation and persistence easy. To do this it creates simple classes for accessing these 6 | occurrences. These are Periods. Period is an object that is initiated with an iterable object of events, a start datetime, and an end datetime. 7 | 8 | It is common to subclass Period for common periods of time. Some of these already exist in the project. Year, Month, Week, Day 9 | 10 | Expect more in the future: Hour, HalfHour 11 | 12 | Period Base Class 13 | ----------------- 14 | 15 | This is the base class from which all other periods inherit. It contains all 16 | of the base functionality for retrieving occurrences. It is instantiated with 17 | a list of events, a start date, and an end date. *The start date is inclusive, 18 | the end date is exclusive.* ie [start, end) 19 | 20 | >>> p = Period(datetime.datetime(2008,4,1,0,0)) 21 | 22 | ``get_occurrences()`` 23 | ~~~~~~~~~~~~~~~~~~~~~ 24 | 25 | This method is for getting the occurrences from the list of passed in events. It returns the occurrences that exist in the period for every event. If I have a list of events ``my_events``, and I want to know all of the occurrences from today to next week I simply create a Period object and then call get_occurrences. It will return a sorted list of Occurrences. 26 | 27 | :: 28 | 29 | import datetime 30 | 31 | today = datetime.datetime.now() 32 | this_week = Period(my_events, today, today+datetime.timedelta(days=7)) 33 | this_week.get_occurrences() 34 | 35 | ``classify_occurrence(occurrence)`` 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | You use this method to determine how the Occurrence ``occurrence`` relates to the period. This method returns a dictionary. The keys are ``"class"`` and ``"occurrence"``. The class key returns a a number from 0 to 3 and the occurrence key returns the occurrence. 39 | 40 | Classes: 41 | 42 | 0: Only started during this period. 43 | 44 | 1: Started and ended during this period. 45 | 46 | 2: Didn't start or end in this period, but does exist during this period. 47 | 48 | 3: Only ended during this period. 49 | 50 | ``get_occurrence_partials()`` 51 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 52 | 53 | This method is used for getting all the occurrences, but getting them as classified occurrences. Simply it runs classify_occurrence on each occurrence in get_occurrence and returns that list. 54 | 55 | :: 56 | 57 | import datetime 58 | 59 | today = datetime.datetime.now() 60 | this_week = Period(my_events, today, today+datetime.timedelta(days=7)) 61 | this_week.get_occurrences() == [classified_occurrence['occurrence'] for classified_occurrence in this_week.get_occurrence_partials()] 62 | 63 | ``has_occurrence()`` 64 | ~~~~~~~~~~~~~~~~~~~~ 65 | 66 | This method returns whether there are any occurrences in this period 67 | 68 | Year 69 | ---- 70 | 71 | The year period is instaniated with a list of events and a date or datetime object. It will resemble the year in which that date exists. 72 | 73 | >>> p = Year(events, datetime.datetime(2008,4,1)) 74 | >>> p.start 75 | datetime.datetime(2008, 1, 1, 0, 0) 76 | >>> p.end 77 | datetime.datetime(2009, 1, 1, 0, 0) 78 | >>> -Remember start is inclusive and end is exclusive 79 | 80 | ``get_months()`` 81 | ~~~~~~~~~~~~~~~~ 82 | 83 | This function returns 12 Month objects which resemble the 12 months in the Year period. 84 | 85 | Month 86 | ----- 87 | 88 | The Month period is instantiated with a list of events and a date or datetime object. It resembles the month that contains the date or datetime object that was passed in. 89 | 90 | >>> p = Month(events, datetime.datetime(2008,4,4)) 91 | >>> p.start 92 | datetime.datetime(2008, 4, 1, 0, 0) 93 | >>> p.end 94 | datetime.datetime(2008, 5, 1, 0, 0) 95 | >>> -Remember start is inclusive and end is exclusive 96 | 97 | ``get_weeks()`` 98 | ~~~~~~~~~~~~~~~ 99 | 100 | This method returns a list of Week objects that occur at all during that month. The week does not have to be fully encapsulated in the month just have 101 | exist in the month at all 102 | 103 | ``get_days()`` 104 | ~~~~~~~~~~~~~~ 105 | 106 | This method returns a list of Day objects that occur during the month. 107 | 108 | ``get_day(day_number)`` 109 | ~~~~~~~~~~~~~~~~~~~~~~~ 110 | 111 | This method returns a specific day in a year given its day number. 112 | 113 | Week 114 | ---- 115 | 116 | The Week period is instantiated with a list of events and a date or datetime object. It resembles the week that contains the date or datetime object that was passed in. 117 | 118 | >>> p = Week(events, datetime.datetime(2008,4,1)) 119 | >>> p.start 120 | datetime.datetime(2008, 3, 30, 0, 0) 121 | >>> p.end 122 | datetime.datetime(2008, 4, 6, 0, 0) 123 | >>> -Remember start is inclusive and end is exclusive 124 | 125 | ``get_days()`` 126 | ~~~~~~~~~~~~~~ 127 | 128 | This method returns the 7 Day objects that represent the days in a Week period. 129 | 130 | Day 131 | --- 132 | 133 | The Day period is instantiated with a list of events and a date or datetime object. It resembles the day that contains the date or datetime object that was passed in. 134 | 135 | >>> p = Day(events, datetime.datetime(2008,4,1)) 136 | >>> p.start 137 | datetime.datetime(2008, 4, 1, 0, 0) 138 | >>> p.end 139 | datetime.datetime(2008, 4, 2, 0, 0) 140 | >>> -Remember start is inclusive and end is exclusive 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /project_sample/site_media/js/jquery.bgiframe.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net) 2 | * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 | * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 | * 5 | * $LastChangedDate: 2007-06-20 03:23:36 +0200 (Mi, 20 Jun 2007) $ 6 | * $Rev: 2110 $ 7 | * 8 | * Version 2.1 9 | */ 10 | 11 | (function($){ 12 | 13 | /** 14 | * The bgiframe is chainable and applies the iframe hack to get 15 | * around zIndex issues in IE6. It will only apply itself in IE 16 | * and adds a class to the iframe called 'bgiframe'. The iframe 17 | * is appeneded as the first child of the matched element(s) 18 | * with a tabIndex and zIndex of -1. 19 | * 20 | * By default the plugin will take borders, sized with pixel units, 21 | * into account. If a different unit is used for the border's width, 22 | * then you will need to use the top and left settings as explained below. 23 | * 24 | * NOTICE: This plugin has been reported to cause perfromance problems 25 | * when used on elements that change properties (like width, height and 26 | * opacity) a lot in IE6. Most of these problems have been caused by 27 | * the expressions used to calculate the elements width, height and 28 | * borders. Some have reported it is due to the opacity filter. All 29 | * these settings can be changed if needed as explained below. 30 | * 31 | * @example $('div').bgiframe(); 32 | * @before

Paragraph

33 | * @result