cone.calendar 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. cone/calendar/__init__.py +20 -0
  2. cone/calendar/browser/__init__.py +88 -0
  3. cone/calendar/browser/calendar.pt +16 -0
  4. cone/calendar/browser/calendar.py +370 -0
  5. cone/calendar/browser/static/calendar/cone.calendar.css +23 -0
  6. cone/calendar/browser/static/calendar/cone.calendar.js +241 -0
  7. cone/calendar/browser/static/calendar/cone.calendar.min.js +1 -0
  8. cone/calendar/browser/static/fullcalendar/fullcalendar.css +1404 -0
  9. cone/calendar/browser/static/fullcalendar/fullcalendar.js +14206 -0
  10. cone/calendar/browser/static/fullcalendar/fullcalendar.min.css +5 -0
  11. cone/calendar/browser/static/fullcalendar/fullcalendar.min.js +10 -0
  12. cone/calendar/browser/static/fullcalendar/fullcalendar.print.css +208 -0
  13. cone/calendar/browser/static/fullcalendar/fullcalendar.print.min.css +5 -0
  14. cone/calendar/browser/static/fullcalendar/gcal.js +180 -0
  15. cone/calendar/browser/static/fullcalendar/gcal.min.js +6 -0
  16. cone/calendar/browser/static/fullcalendar/locale/af.js +1 -0
  17. cone/calendar/browser/static/fullcalendar/locale/ar-dz.js +1 -0
  18. cone/calendar/browser/static/fullcalendar/locale/ar-ly.js +1 -0
  19. cone/calendar/browser/static/fullcalendar/locale/ar-ma.js +1 -0
  20. cone/calendar/browser/static/fullcalendar/locale/ar-sa.js +1 -0
  21. cone/calendar/browser/static/fullcalendar/locale/ar-tn.js +1 -0
  22. cone/calendar/browser/static/fullcalendar/locale/ar.js +1 -0
  23. cone/calendar/browser/static/fullcalendar/locale/bg.js +1 -0
  24. cone/calendar/browser/static/fullcalendar/locale/ca.js +1 -0
  25. cone/calendar/browser/static/fullcalendar/locale/cs.js +1 -0
  26. cone/calendar/browser/static/fullcalendar/locale/da.js +1 -0
  27. cone/calendar/browser/static/fullcalendar/locale/de-at.js +1 -0
  28. cone/calendar/browser/static/fullcalendar/locale/de.js +1 -0
  29. cone/calendar/browser/static/fullcalendar/locale/el.js +1 -0
  30. cone/calendar/browser/static/fullcalendar/locale/en-au.js +1 -0
  31. cone/calendar/browser/static/fullcalendar/locale/en-ca.js +1 -0
  32. cone/calendar/browser/static/fullcalendar/locale/en-gb.js +1 -0
  33. cone/calendar/browser/static/fullcalendar/locale/en-ie.js +1 -0
  34. cone/calendar/browser/static/fullcalendar/locale/en-nz.js +1 -0
  35. cone/calendar/browser/static/fullcalendar/locale/es-do.js +1 -0
  36. cone/calendar/browser/static/fullcalendar/locale/es.js +1 -0
  37. cone/calendar/browser/static/fullcalendar/locale/eu.js +1 -0
  38. cone/calendar/browser/static/fullcalendar/locale/fa.js +1 -0
  39. cone/calendar/browser/static/fullcalendar/locale/fi.js +1 -0
  40. cone/calendar/browser/static/fullcalendar/locale/fr-ca.js +1 -0
  41. cone/calendar/browser/static/fullcalendar/locale/fr-ch.js +1 -0
  42. cone/calendar/browser/static/fullcalendar/locale/fr.js +1 -0
  43. cone/calendar/browser/static/fullcalendar/locale/gl.js +1 -0
  44. cone/calendar/browser/static/fullcalendar/locale/he.js +1 -0
  45. cone/calendar/browser/static/fullcalendar/locale/hi.js +1 -0
  46. cone/calendar/browser/static/fullcalendar/locale/hr.js +1 -0
  47. cone/calendar/browser/static/fullcalendar/locale/hu.js +1 -0
  48. cone/calendar/browser/static/fullcalendar/locale/id.js +1 -0
  49. cone/calendar/browser/static/fullcalendar/locale/is.js +1 -0
  50. cone/calendar/browser/static/fullcalendar/locale/it.js +1 -0
  51. cone/calendar/browser/static/fullcalendar/locale/ja.js +1 -0
  52. cone/calendar/browser/static/fullcalendar/locale/kk.js +1 -0
  53. cone/calendar/browser/static/fullcalendar/locale/ko.js +1 -0
  54. cone/calendar/browser/static/fullcalendar/locale/lb.js +1 -0
  55. cone/calendar/browser/static/fullcalendar/locale/lt.js +1 -0
  56. cone/calendar/browser/static/fullcalendar/locale/lv.js +1 -0
  57. cone/calendar/browser/static/fullcalendar/locale/mk.js +1 -0
  58. cone/calendar/browser/static/fullcalendar/locale/ms-my.js +1 -0
  59. cone/calendar/browser/static/fullcalendar/locale/ms.js +1 -0
  60. cone/calendar/browser/static/fullcalendar/locale/nb.js +1 -0
  61. cone/calendar/browser/static/fullcalendar/locale/nl-be.js +1 -0
  62. cone/calendar/browser/static/fullcalendar/locale/nl.js +1 -0
  63. cone/calendar/browser/static/fullcalendar/locale/nn.js +1 -0
  64. cone/calendar/browser/static/fullcalendar/locale/pl.js +1 -0
  65. cone/calendar/browser/static/fullcalendar/locale/pt-br.js +1 -0
  66. cone/calendar/browser/static/fullcalendar/locale/pt.js +1 -0
  67. cone/calendar/browser/static/fullcalendar/locale/ro.js +1 -0
  68. cone/calendar/browser/static/fullcalendar/locale/ru.js +1 -0
  69. cone/calendar/browser/static/fullcalendar/locale/sk.js +1 -0
  70. cone/calendar/browser/static/fullcalendar/locale/sl.js +1 -0
  71. cone/calendar/browser/static/fullcalendar/locale/sr-cyrl.js +1 -0
  72. cone/calendar/browser/static/fullcalendar/locale/sr.js +1 -0
  73. cone/calendar/browser/static/fullcalendar/locale/sv.js +1 -0
  74. cone/calendar/browser/static/fullcalendar/locale/th.js +1 -0
  75. cone/calendar/browser/static/fullcalendar/locale/tr.js +1 -0
  76. cone/calendar/browser/static/fullcalendar/locale/uk.js +1 -0
  77. cone/calendar/browser/static/fullcalendar/locale/vi.js +1 -0
  78. cone/calendar/browser/static/fullcalendar/locale/zh-cn.js +1 -0
  79. cone/calendar/browser/static/fullcalendar/locale/zh-tw.js +1 -0
  80. cone/calendar/browser/static/fullcalendar/locale-all.js +5 -0
  81. cone/calendar/browser/static/moment/locale/af.js +73 -0
  82. cone/calendar/browser/static/moment/locale/ar-dz.js +59 -0
  83. cone/calendar/browser/static/moment/locale/ar-ly.js +126 -0
  84. cone/calendar/browser/static/moment/locale/ar-ma.js +60 -0
  85. cone/calendar/browser/static/moment/locale/ar-sa.js +105 -0
  86. cone/calendar/browser/static/moment/locale/ar-tn.js +59 -0
  87. cone/calendar/browser/static/moment/locale/ar.js +142 -0
  88. cone/calendar/browser/static/moment/locale/az.js +105 -0
  89. cone/calendar/browser/static/moment/locale/be.js +134 -0
  90. cone/calendar/browser/static/moment/locale/bg.js +90 -0
  91. cone/calendar/browser/static/moment/locale/bn.js +119 -0
  92. cone/calendar/browser/static/moment/locale/bo.js +119 -0
  93. cone/calendar/browser/static/moment/locale/br.js +108 -0
  94. cone/calendar/browser/static/moment/locale/bs.js +143 -0
  95. cone/calendar/browser/static/moment/locale/ca.js +81 -0
  96. cone/calendar/browser/static/moment/locale/cs.js +172 -0
  97. cone/calendar/browser/static/moment/locale/cv.js +63 -0
  98. cone/calendar/browser/static/moment/locale/cy.js +81 -0
  99. cone/calendar/browser/static/moment/locale/da.js +60 -0
  100. cone/calendar/browser/static/moment/locale/de-at.js +79 -0
  101. cone/calendar/browser/static/moment/locale/de.js +78 -0
  102. cone/calendar/browser/static/moment/locale/dv.js +100 -0
  103. cone/calendar/browser/static/moment/locale/el.js +98 -0
  104. cone/calendar/browser/static/moment/locale/en-au.js +67 -0
  105. cone/calendar/browser/static/moment/locale/en-ca.js +63 -0
  106. cone/calendar/browser/static/moment/locale/en-gb.js +67 -0
  107. cone/calendar/browser/static/moment/locale/en-ie.js +67 -0
  108. cone/calendar/browser/static/moment/locale/en-nz.js +67 -0
  109. cone/calendar/browser/static/moment/locale/eo.js +73 -0
  110. cone/calendar/browser/static/moment/locale/es-do.js +80 -0
  111. cone/calendar/browser/static/moment/locale/es.js +81 -0
  112. cone/calendar/browser/static/moment/locale/et.js +80 -0
  113. cone/calendar/browser/static/moment/locale/eu.js +66 -0
  114. cone/calendar/browser/static/moment/locale/fa.js +107 -0
  115. cone/calendar/browser/static/moment/locale/fi.js +107 -0
  116. cone/calendar/browser/static/moment/locale/fo.js +60 -0
  117. cone/calendar/browser/static/moment/locale/fr-ca.js +60 -0
  118. cone/calendar/browser/static/moment/locale/fr-ch.js +64 -0
  119. cone/calendar/browser/static/moment/locale/fr.js +64 -0
  120. cone/calendar/browser/static/moment/locale/fy.js +73 -0
  121. cone/calendar/browser/static/moment/locale/gd.js +76 -0
  122. cone/calendar/browser/static/moment/locale/gl.js +77 -0
  123. cone/calendar/browser/static/moment/locale/he.js +99 -0
  124. cone/calendar/browser/static/moment/locale/hi.js +124 -0
  125. cone/calendar/browser/static/moment/locale/hr.js +145 -0
  126. cone/calendar/browser/static/moment/locale/hu.js +109 -0
  127. cone/calendar/browser/static/moment/locale/hy-am.js +95 -0
  128. cone/calendar/browser/static/moment/locale/id.js +83 -0
  129. cone/calendar/browser/static/moment/locale/is.js +127 -0
  130. cone/calendar/browser/static/moment/locale/it.js +70 -0
  131. cone/calendar/browser/static/moment/locale/ja.js +76 -0
  132. cone/calendar/browser/static/moment/locale/jv.js +83 -0
  133. cone/calendar/browser/static/moment/locale/ka.js +89 -0
  134. cone/calendar/browser/static/moment/locale/kk.js +87 -0
  135. cone/calendar/browser/static/moment/locale/km.js +58 -0
  136. cone/calendar/browser/static/moment/locale/ko.js +65 -0
  137. cone/calendar/browser/static/moment/locale/ky.js +88 -0
  138. cone/calendar/browser/static/moment/locale/lb.js +137 -0
  139. cone/calendar/browser/static/moment/locale/lo.js +70 -0
  140. cone/calendar/browser/static/moment/locale/lt.js +117 -0
  141. cone/calendar/browser/static/moment/locale/lv.js +97 -0
  142. cone/calendar/browser/static/moment/locale/me.js +111 -0
  143. cone/calendar/browser/static/moment/locale/mi.js +64 -0
  144. cone/calendar/browser/static/moment/locale/mk.js +90 -0
  145. cone/calendar/browser/static/moment/locale/ml.js +81 -0
  146. cone/calendar/browser/static/moment/locale/mr.js +159 -0
  147. cone/calendar/browser/static/moment/locale/ms-my.js +83 -0
  148. cone/calendar/browser/static/moment/locale/ms.js +82 -0
  149. cone/calendar/browser/static/moment/locale/my.js +96 -0
  150. cone/calendar/browser/static/moment/locale/nb.js +63 -0
  151. cone/calendar/browser/static/moment/locale/ne.js +123 -0
  152. cone/calendar/browser/static/moment/locale/nl-be.js +86 -0
  153. cone/calendar/browser/static/moment/locale/nl.js +86 -0
  154. cone/calendar/browser/static/moment/locale/nn.js +60 -0
  155. cone/calendar/browser/static/moment/locale/pa-in.js +124 -0
  156. cone/calendar/browser/static/moment/locale/pl.js +105 -0
  157. cone/calendar/browser/static/moment/locale/pt-br.js +61 -0
  158. cone/calendar/browser/static/moment/locale/pt.js +65 -0
  159. cone/calendar/browser/static/moment/locale/ro.js +75 -0
  160. cone/calendar/browser/static/moment/locale/ru.js +183 -0
  161. cone/calendar/browser/static/moment/locale/se.js +61 -0
  162. cone/calendar/browser/static/moment/locale/si.js +71 -0
  163. cone/calendar/browser/static/moment/locale/sk.js +150 -0
  164. cone/calendar/browser/static/moment/locale/sl.js +162 -0
  165. cone/calendar/browser/static/moment/locale/sq.js +70 -0
  166. cone/calendar/browser/static/moment/locale/sr-cyrl.js +110 -0
  167. cone/calendar/browser/static/moment/locale/sr.js +110 -0
  168. cone/calendar/browser/static/moment/locale/ss.js +89 -0
  169. cone/calendar/browser/static/moment/locale/sv.js +69 -0
  170. cone/calendar/browser/static/moment/locale/sw.js +59 -0
  171. cone/calendar/browser/static/moment/locale/ta.js +130 -0
  172. cone/calendar/browser/static/moment/locale/te.js +89 -0
  173. cone/calendar/browser/static/moment/locale/tet.js +68 -0
  174. cone/calendar/browser/static/moment/locale/th.js +67 -0
  175. cone/calendar/browser/static/moment/locale/tl-ph.js +62 -0
  176. cone/calendar/browser/static/moment/locale/tlh.js +120 -0
  177. cone/calendar/browser/static/moment/locale/tr.js +90 -0
  178. cone/calendar/browser/static/moment/locale/tzl.js +91 -0
  179. cone/calendar/browser/static/moment/locale/tzm-latn.js +58 -0
  180. cone/calendar/browser/static/moment/locale/tzm.js +58 -0
  181. cone/calendar/browser/static/moment/locale/uk.js +146 -0
  182. cone/calendar/browser/static/moment/locale/uz.js +58 -0
  183. cone/calendar/browser/static/moment/locale/vi.js +79 -0
  184. cone/calendar/browser/static/moment/locale/x-pseudo.js +68 -0
  185. cone/calendar/browser/static/moment/locale/yo.js +60 -0
  186. cone/calendar/browser/static/moment/locale/zh-cn.js +127 -0
  187. cone/calendar/browser/static/moment/locale/zh-hk.js +105 -0
  188. cone/calendar/browser/static/moment/locale/zh-tw.js +104 -0
  189. cone/calendar/browser/static/moment/locales.js +8624 -0
  190. cone/calendar/browser/static/moment/locales.min.js +663 -0
  191. cone/calendar/browser/static/moment/moment-with-locales.js +12910 -0
  192. cone/calendar/browser/static/moment/moment-with-locales.min.js +1216 -0
  193. cone/calendar/browser/static/moment/moment.min.js +551 -0
  194. cone/calendar/interfaces.py +14 -0
  195. cone/calendar/locale/cone.calendar.pot +0 -0
  196. cone/calendar/locale/de/LC_MESSAGES/cone.calendar.po +0 -0
  197. cone/calendar/locale/en/LC_MESSAGES/cone.calendar.po +0 -0
  198. cone/calendar/tests/test_calendar.py +340 -0
  199. cone_calendar-1.1.0.dist-info/METADATA +252 -0
  200. cone_calendar-1.1.0.dist-info/RECORD +202 -0
  201. cone_calendar-1.1.0.dist-info/WHEEL +4 -0
  202. cone_calendar-1.1.0.dist-info/licenses/LICENSE.rst +27 -0
@@ -0,0 +1,20 @@
1
+ from cone.app import main_hook
2
+ from cone.calendar.browser import configure_resources
3
+ import logging
4
+
5
+
6
+ logger = logging.getLogger('cone.calendar')
7
+
8
+
9
+ @main_hook
10
+ def initialize_calendar(config, global_config, settings):
11
+ # application startup initialization
12
+
13
+ # static resources
14
+ configure_resources(config, settings)
15
+
16
+ # add translation
17
+ config.add_translation_dirs('cone.calendar:locale/')
18
+
19
+ # scan browser package
20
+ config.scan('cone.calendar.browser')
@@ -0,0 +1,88 @@
1
+ from .calendar import CalendarEvents # noqa
2
+ from .calendar import CalendarTile # noqa
3
+ import os
4
+ import webresource as wr
5
+
6
+
7
+ resources_dir = os.path.join(os.path.dirname(__file__), 'static')
8
+
9
+ # moment js
10
+ moment_resources = wr.ResourceGroup(
11
+ name='cone.calendar-moment',
12
+ directory=os.path.join(resources_dir, 'moment'),
13
+ path='moment'
14
+ )
15
+ moment_resources.add(wr.ScriptResource(
16
+ name='moment-js',
17
+ resource='moment.min.js'
18
+ ))
19
+
20
+ # fullcalendar
21
+ fullcalendar_resources = wr.ResourceGroup(
22
+ name='cone.calendar-fullcalendar',
23
+ directory=os.path.join(resources_dir, 'fullcalendar'),
24
+ path='fullcalendar'
25
+ )
26
+ fullcalendar_resources.add(wr.ScriptResource(
27
+ name='fullcalendar-js',
28
+ depends=['moment-js', 'jquery-js'],
29
+ resource='fullcalendar.js',
30
+ compressed='fullcalendar.min.js'
31
+ ))
32
+ fullcalendar_resources.add(wr.StyleResource(
33
+ name='fullcalendar-css',
34
+ resource='fullcalendar.css',
35
+ compressed='fullcalendar.min.css'
36
+ ))
37
+ # XXX: print CSS needs to be delivered dynamically in dedicated print view
38
+ # fullcalendar_resources.add(wr.StyleResource(
39
+ # name='fullcalendar-print-css',
40
+ # resource='fullcalendar.print.css',
41
+ # compressed='fullcalendar.print.min.css'
42
+ # ))
43
+
44
+ # cone calendar
45
+ cone_calendar_resources = wr.ResourceGroup(
46
+ name='cone.calendar-calendar',
47
+ directory=os.path.join(resources_dir, 'calendar'),
48
+ path='calendar'
49
+ )
50
+ cone_calendar_resources.add(wr.ScriptResource(
51
+ name='cone-calendar-js',
52
+ depends='fullcalendar-js',
53
+ resource='cone.calendar.js',
54
+ compressed='cone.calendar.min.js'
55
+ ))
56
+ cone_calendar_resources.add(wr.StyleResource(
57
+ name='cone-calendar-css',
58
+ depends='fullcalendar-css',
59
+ resource='cone.calendar.css'
60
+ ))
61
+
62
+
63
+ def configure_resources(config, settings):
64
+ config.register_resource(moment_resources)
65
+ config.set_resource_include('moment-js', 'authenticated')
66
+
67
+ config.register_resource(fullcalendar_resources)
68
+ config.set_resource_include('fullcalendar-js', 'authenticated')
69
+ config.set_resource_include('fullcalendar-css', 'authenticated')
70
+
71
+ config.register_resource(cone_calendar_resources)
72
+ config.set_resource_include('cone-calendar-js', 'authenticated')
73
+ config.set_resource_include('cone-calendar-css', 'authenticated')
74
+
75
+ locales = settings.get('cone.calendar.locales')
76
+ if not locales:
77
+ return
78
+ locales_directory = os.path.join(resources_dir, 'fullcalendar', 'locale')
79
+ for locale in [loc.strip() for loc in locales.split(',') if loc]:
80
+ locale_name = 'fullcalendar-{}-js'.format(locale)
81
+ fullcalendar_resources.add(wr.ScriptResource(
82
+ name=locale_name,
83
+ depends='fullcalendar-js',
84
+ directory=locales_directory,
85
+ path='fullcalendar/locale',
86
+ resource='{}.js'.format(locale)
87
+ ))
88
+ config.set_resource_include(locale_name, 'authenticated')
@@ -0,0 +1,16 @@
1
+ <tal:block xmlns:tal="http://xml.zope.org/namespaces/tal"
2
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
3
+ xmlns:ajax="http://namespaces.conestack.org/ajax"
4
+ i18n:domain="cone.calendar"
5
+ omit-tag="True">
6
+
7
+ <tal:contextmenu condition="context.show_contextmenu"
8
+ replace="structure tile('contextmenu')" />
9
+
10
+ <div id="calendar"
11
+ data-calendar_target='${context.target}'
12
+ data-calendar_options='${context.options}'
13
+ data-calendar_sources='${context.sources}'
14
+ data-calendar_actions='${context.actions}'></div>
15
+
16
+ </tal:block>
@@ -0,0 +1,370 @@
1
+ from cone.app.browser import render_main_template
2
+ from cone.app.browser.utils import format_traceback
3
+ from cone.tile import Tile
4
+ from cone.tile import tile
5
+ from datetime import datetime
6
+ from pyramid.i18n import TranslationStringFactory
7
+ from pyramid.view import view_config
8
+ import json
9
+ import logging
10
+
11
+
12
+ logger = logging.getLogger('cone.calendar')
13
+ _ = TranslationStringFactory('cone.calendar')
14
+
15
+
16
+ def parse_date(seconds):
17
+ """Parse datetime from value received from fullcalendar.
18
+ """
19
+ return datetime.utcfromtimestamp(int(seconds))
20
+
21
+
22
+ def format_date(dt):
23
+ """Format datetime suitable for fullcalendar.
24
+ """
25
+ return dt.isoformat()
26
+
27
+
28
+ @tile(name='calendar', path='calendar.pt', permission='view')
29
+ class CalendarTile(Tile):
30
+ """Tile rendering the fullcalendar widget.
31
+
32
+ Reference: https://fullcalendar.io/docs/v3
33
+
34
+ Configuration of the calendar is done via ``model.properties`` object.
35
+
36
+ Available configuration properties:
37
+
38
+ ``calendar_locale``:
39
+ Corresponds to ``locale`` option passed to fullcalendar.
40
+
41
+ See https://fullcalendar.io/docs/v3/locale
42
+
43
+ Note: Locale files must be preloaded in order to provide the desored
44
+ locales. The available locales are configured in the application ini
45
+ file.
46
+
47
+ ``calendar_header``:
48
+ Corresponds to ``header`` option passed to fullcalendar.
49
+
50
+ See https://fullcalendar.io/docs/v3/header
51
+
52
+ ``calendar_footer``:
53
+ Corresponds to ``footer`` option passed to fullcalendar.
54
+
55
+ See https://fullcalendar.io/docs/v3/footer
56
+
57
+ ``calendar_first_day``:
58
+ Corresponds to ``firstDay`` option passed to fullcalendar.
59
+
60
+ See https://fullcalendar.io/docs/v3/firstDay
61
+
62
+ ``calendar_weekends``:
63
+ Corresponds to ``weekends`` option passed to fullcalendar.
64
+
65
+ See https://fullcalendar.io/docs/v3/weekends
66
+
67
+ ``calendar_week_numbers``:
68
+ Corresponds to ``weekNumbers`` option passed to fullcalendar.
69
+
70
+ See https://fullcalendar.io/docs/v3/weekNumbers
71
+
72
+ ``calendar_week_numbers_within_days``:
73
+ Corresponds to ``weekNumbersWithinDays`` option passed to fullcalendar.
74
+
75
+ See https://fullcalendar.io/docs/v3/weekNumbersWithinDays
76
+
77
+ ``calendar_business_hours``:
78
+ Corresponds to ``businessHours`` option passed to fullcalendar.
79
+
80
+ See https://fullcalendar.io/docs/v3/businessHours
81
+
82
+ ``calendar_sources``:
83
+ A list of dictionaries containing event source configurations.
84
+
85
+ See https://fullcalendar.io/docs/v3/event-source-object
86
+
87
+ As ``events`` attribute, a JSON view name is expected. On the client
88
+ side a callback handler gets created using this view name for fetching
89
+ event data. The base class for implementing JSON event data is
90
+ ``CalendarEvents``.
91
+
92
+ If ``calendar_sources`` is not defined on model properties,
93
+ ``CalendarTile.default_sources`` is used.
94
+
95
+ ``calendar_actions``:
96
+ List of actions for clicking empty day/time in calendar.
97
+
98
+ Action definition format and behavior is the same as for the ``actions``
99
+ attribute of event data.
100
+
101
+ See ``CalendarEvents.events`` documentation for details.
102
+
103
+ As default target the calendar context target is used if not defined
104
+ explicitely on actions.
105
+
106
+ If ``calendar_actions`` is not defined on model properties,
107
+ ``CalendarTile.default_actions`` is used.
108
+ """
109
+ show_contextmenu = False
110
+ option_mapping = {
111
+ 'calendar_locale': 'locale',
112
+ 'calendar_header': 'header',
113
+ 'calendar_footer': 'footer',
114
+ 'calendar_first_day': 'firstDay',
115
+ 'calendar_weekends': 'weekends',
116
+ 'calendar_week_numbers': 'weekNumbers',
117
+ 'calendar_week_numbers_within_days': 'weekNumbersWithinDays',
118
+ 'calendar_business_hours': 'businessHours'
119
+ }
120
+ default_options = {
121
+ 'calendar_locale': 'en'
122
+ }
123
+ default_sources = [{
124
+ 'events': 'calendar_events'
125
+ }]
126
+ default_actions = []
127
+
128
+ @property
129
+ def target(self):
130
+ """Calendar context target. Gets used for querying event sources.
131
+ """
132
+ return self.nodeurl
133
+
134
+ @property
135
+ def options(self):
136
+ options = {}
137
+ for prop_name, option_name in self.option_mapping.items():
138
+ value = getattr(self.model.properties, prop_name)
139
+ if value is None:
140
+ value = self.default_options.get(prop_name)
141
+ if value is not None:
142
+ options[option_name] = value
143
+ return json.dumps(options, sort_keys=True) if options else None
144
+
145
+ @property
146
+ def sources(self):
147
+ sources = self.model.properties.calendar_sources
148
+ if not sources:
149
+ sources = self.default_sources
150
+ return json.dumps(sources)
151
+
152
+ @property
153
+ def actions(self):
154
+ actions = self.model.properties.calendar_actions
155
+ if not actions:
156
+ actions = self.default_actions
157
+ return json.dumps(actions)
158
+
159
+
160
+ @view_config(name='calendar', permission='view')
161
+ def calendar(model, request):
162
+ """Traversable view rendering the ``calendar`` tile to content area.
163
+ """
164
+ return render_main_template(model, request, 'calendar')
165
+
166
+
167
+ class JSONView(object):
168
+ """Abstract JSON view.
169
+ """
170
+
171
+ def __init__(self, model, request):
172
+ self.model = model
173
+ self.request = request
174
+
175
+ def __call__(self):
176
+ """Return dict with JSON data result.
177
+
178
+ If success, dict contains data at key 'data'.
179
+
180
+ If an exception is raised while computing, dict contains flag indicating
181
+ error happends at key 'error' and the formatted traceback at key
182
+ 'message'.
183
+ """
184
+ try:
185
+ return dict(data=self.data())
186
+ except Exception as e:
187
+ logger.exception(e)
188
+ return dict(
189
+ error=True,
190
+ message=format_traceback()
191
+ )
192
+
193
+ def data(self):
194
+ """Supposed to be implemented on subclass. Responsible to compute JSON
195
+ data delivered to client.
196
+ """
197
+ raise NotImplementedError(
198
+ 'Abstract ``JSONView`` does not implement ``data``'
199
+ )
200
+
201
+
202
+ @view_config(
203
+ name='calendar_events',
204
+ accept='application/json',
205
+ renderer='json',
206
+ permission='view')
207
+ class CalendarEvents(JSONView):
208
+ """Abstract JSON event data view for fullcalendar.
209
+
210
+ Concrete even data providers must derive from this object and implement
211
+ ``events`` function.
212
+ """
213
+
214
+ @property
215
+ def range_start(self):
216
+ """Event range start as datetime.
217
+ """
218
+ start = self.request.params.get('start')
219
+ return parse_date(start)
220
+
221
+ @property
222
+ def range_end(self):
223
+ """Event range end as datetime.
224
+ """
225
+ end = self.request.params.get('end')
226
+ return parse_date(end)
227
+
228
+ def events(self, start, end):
229
+ """Return events for requested range.
230
+
231
+ Return format:
232
+
233
+ [{
234
+ 'id': uuid.UUID,
235
+ 'title': 'Event Title',
236
+ 'start': datetime.datetime,
237
+ 'end': datetime.datetime,
238
+ 'target': 'https://example.com/path/to/event',
239
+ 'actions': [{
240
+ 'title': 'Edit',
241
+ 'icon': 'glyphicons glyphicons-pencil',
242
+ 'target': 'https://example.com/path/to/event?param=value',
243
+ 'overlay': {
244
+ 'action': 'overlayedit',
245
+ 'selector': '#ajax-form',
246
+ 'content_selector': '.overlay_content',
247
+ 'css': 'overlay-form'
248
+ }
249
+ }, {
250
+ 'title': 'Delete',
251
+ 'icon': 'glyphicons glyphicons-remove-circle',
252
+ 'confirm': 'Do you really want to delete this event?',
253
+ 'action': {
254
+ 'name': 'delete',
255
+ 'selector': 'NONE',
256
+ 'mode': 'NONE'
257
+ }
258
+ }]
259
+ }]
260
+
261
+ For a full list of fullcalendar event attributes see
262
+ https://fullcalendar.io/docs/v3/event-object
263
+
264
+ The ``actions`` and ``target`` attributes are cone specific.
265
+
266
+ ``target`` defines the default target where actions get executed.
267
+ Target can be overwritten by specific actions. Target represents the URL of
268
+ the event without trailing view name and may contain a query string.
269
+ Target is mandatory if event is editable or actions are defined which
270
+ do not provide a target on their own.
271
+
272
+ ``actions`` defines a list of actions available for the specific event.
273
+
274
+ If one action is specified, it gets executed directly when event gets
275
+ clicked.
276
+
277
+ If multiple actions are specified, a dropdown menu containing the actions
278
+ as menu items gets rendered.
279
+
280
+ Action options:
281
+
282
+ ``title``
283
+ The action title as string.
284
+
285
+ ``icon``
286
+ Icon CSS class. Optional.
287
+
288
+ ``target``
289
+ Target on which the action gets executed. Target represents the URL
290
+ of the event without trailing view name and may contain a query
291
+ string. Optional, if skipped the default target is used.
292
+
293
+ ``action``
294
+ bdajax action definitions as dict containing:
295
+
296
+ {
297
+ 'name': 'action_name',
298
+ 'selector': '.some_selector',
299
+ 'mode': 'replace'
300
+ }
301
+
302
+ At least one option out of ``action``, ``event`` or ``overlay`` must
303
+ be defined. An arbitrary combination is possible.
304
+
305
+ ``event``
306
+ bdajax event definitions as dict containing:
307
+
308
+ {
309
+ 'name': 'eventname',
310
+ 'selector': '.some_selector'
311
+ }
312
+
313
+ At least one option out of ``action``, ``event`` or ``overlay`` must
314
+ be defined. An arbitrary combination is possible.
315
+
316
+ ``overlay``
317
+ bdajax overlay definitions as dict containing:
318
+
319
+ {
320
+ 'action': 'action_name',
321
+ 'selector': '#ajax-form',
322
+ 'content_selector': '.overlay_content',
323
+ 'css': 'additional_overlay_css_class'
324
+ }
325
+
326
+ At least one option out of ``action``, ``event`` or ``overlay`` must
327
+ be defined. An arbitrary combination is possible.
328
+
329
+ ``confirm``
330
+ Confirmation message as string. Optional.
331
+ """
332
+ raise NotImplementedError(
333
+ 'Abstract ``CalendarEvents`` does not implement ``events``'
334
+ )
335
+
336
+ def data(self):
337
+ events = self.events(self.range_start, self.range_end)
338
+ for event in events:
339
+ event['id'] = str(event['id'])
340
+ event['start'] = format_date(event['start'])
341
+ event['end'] = format_date(event['end'])
342
+ return events
343
+
344
+
345
+ @view_config(
346
+ name='calendar_event_drop',
347
+ # context=IScheduled,
348
+ accept='application/json',
349
+ renderer='json',
350
+ permission='view')
351
+ class CalendarEventDrop(JSONView):
352
+ """JSON view for modifying event start time.
353
+ """
354
+
355
+ def data(self):
356
+ return 'DROPPED'
357
+
358
+
359
+ @view_config(
360
+ name='calendar_event_resize',
361
+ # context=IScheduled,
362
+ accept='application/json',
363
+ renderer='json',
364
+ permission='view')
365
+ class CalendarEventResize(JSONView):
366
+ """JSON view for modifying event duration.
367
+ """
368
+
369
+ def data(self):
370
+ return 'RESIZED'
@@ -0,0 +1,23 @@
1
+ /* contextmenu */
2
+ .calendar-contextmenu-wrapper {
3
+ position:absolute;
4
+ z-index:1000;
5
+ top:0;
6
+ left:0;
7
+ width:100%;
8
+ }
9
+ .calendar-contextmenu {
10
+ background-color:#fff;
11
+ position:absolute;
12
+ z-index:1000;
13
+ }
14
+ .calendar-contextmenu li {
15
+ padding-left:10px;
16
+ cursor:pointer;
17
+ }
18
+ .calendar-contextmenu li:hover {
19
+ background-color:#ccc;
20
+ }
21
+ .calendar-contextmenu li span {
22
+ margin-right:10px;
23
+ }