spina-admin-conferences 1.3.3
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +101 -0
- data/Rakefile +40 -0
- data/app/assets/config/spina_admin_conferences_manifest.js +4 -0
- data/app/assets/javascripts/spina/admin/conferences/application.es6 +20 -0
- data/app/assets/javascripts/spina/admin/conferences/controllers/conference_events_form_controller.es6 +175 -0
- data/app/assets/javascripts/spina/admin/conferences/controllers/presentation_attachments_form_controller.es6 +175 -0
- data/app/assets/javascripts/spina/admin/conferences/controllers/select_options_controller.es6 +216 -0
- data/app/assets/stylesheets/spina/admin/conferences/application.sass +14 -0
- data/app/controllers/spina/admin/conferences/application_controller.rb +20 -0
- data/app/controllers/spina/admin/conferences/conferences_controller.rb +148 -0
- data/app/controllers/spina/admin/conferences/delegates_controller.rb +116 -0
- data/app/controllers/spina/admin/conferences/dietary_requirements_controller.rb +106 -0
- data/app/controllers/spina/admin/conferences/events_controller.rb +24 -0
- data/app/controllers/spina/admin/conferences/institutions_controller.rb +106 -0
- data/app/controllers/spina/admin/conferences/presentation_attachment_types_controller.rb +104 -0
- data/app/controllers/spina/admin/conferences/presentation_attachments_controller.rb +24 -0
- data/app/controllers/spina/admin/conferences/presentation_types_controller.rb +109 -0
- data/app/controllers/spina/admin/conferences/presentations_controller.rb +124 -0
- data/app/controllers/spina/admin/conferences/rooms_controller.rb +109 -0
- data/app/controllers/spina/admin/conferences/sessions_controller.rb +118 -0
- data/app/helpers/spina/admin/conferences/conferences_helper.rb +44 -0
- data/app/jobs/spina/admin/conferences/application_job.rb +11 -0
- data/app/jobs/spina/admin/conferences/delegate_import_job.rb +37 -0
- data/app/jobs/spina/admin/conferences/import_job.rb +26 -0
- data/app/jobs/spina/admin/conferences/presentation_import_job.rb +38 -0
- data/app/mailers/spina/admin/conferences/application_mailer.rb +13 -0
- data/app/models/spina/admin/conferences.rb +11 -0
- data/app/models/spina/admin/conferences/application_record.rb +14 -0
- data/app/models/spina/admin/conferences/conference.rb +152 -0
- data/app/models/spina/admin/conferences/date_part.rb +15 -0
- data/app/models/spina/admin/conferences/delegate.rb +89 -0
- data/app/models/spina/admin/conferences/dietary_requirement.rb +33 -0
- data/app/models/spina/admin/conferences/email_address_part.rb +21 -0
- data/app/models/spina/admin/conferences/event.rb +120 -0
- data/app/models/spina/admin/conferences/institution.rb +46 -0
- data/app/models/spina/admin/conferences/part.rb +20 -0
- data/app/models/spina/admin/conferences/presentation.rb +143 -0
- data/app/models/spina/admin/conferences/presentation_attachment.rb +27 -0
- data/app/models/spina/admin/conferences/presentation_attachment_type.rb +35 -0
- data/app/models/spina/admin/conferences/presentation_type.rb +60 -0
- data/app/models/spina/admin/conferences/room.rb +52 -0
- data/app/models/spina/admin/conferences/session.rb +56 -0
- data/app/models/spina/admin/conferences/time_part.rb +53 -0
- data/app/models/spina/admin/conferences/url_part.rb +21 -0
- data/app/validators/spina/admin/conferences/conference_date_validator.rb +20 -0
- data/app/validators/spina/admin/conferences/email_address_validator.rb +28 -0
- data/app/validators/spina/admin/conferences/finish_date_validator.rb +20 -0
- data/app/validators/spina/admin/conferences/finish_time_validator.rb +20 -0
- data/app/validators/spina/admin/conferences/http_url_validator.rb +28 -0
- data/app/views/layouts/spina/admin/conferences/conferences.html.haml +19 -0
- data/app/views/layouts/spina/admin/conferences/delegates.html.haml +10 -0
- data/app/views/layouts/spina/admin/conferences/dietary_requirements.html.haml +10 -0
- data/app/views/layouts/spina/admin/conferences/institutions.html.haml +17 -0
- data/app/views/layouts/spina/admin/conferences/presentation_attachment_types.html.haml +10 -0
- data/app/views/layouts/spina/admin/conferences/presentations.html.haml +10 -0
- data/app/views/spina/admin/conferences/application/_empty_list.html.haml +3 -0
- data/app/views/spina/admin/conferences/application/_errors.html.haml +11 -0
- data/app/views/spina/admin/conferences/application/_errors.js.erb +2 -0
- data/app/views/spina/admin/conferences/conferences/_conference.html.haml +9 -0
- data/app/views/spina/admin/conferences/conferences/_event_fields.html.haml +39 -0
- data/app/views/spina/admin/conferences/conferences/_event_row.html.haml +5 -0
- data/app/views/spina/admin/conferences/conferences/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/conferences/_form_conference_details.html.haml +29 -0
- data/app/views/spina/admin/conferences/conferences/_form_delegates.html.haml +12 -0
- data/app/views/spina/admin/conferences/conferences/_form_parts.html.haml +15 -0
- data/app/views/spina/admin/conferences/conferences/_form_presentation_types.html.haml +12 -0
- data/app/views/spina/admin/conferences/conferences/_form_presentations.html.haml +12 -0
- data/app/views/spina/admin/conferences/conferences/_form_rooms.html.haml +12 -0
- data/app/views/spina/admin/conferences/conferences/_form_structure.html.haml +19 -0
- data/app/views/spina/admin/conferences/conferences/_form_structure_item.html.haml +13 -0
- data/app/views/spina/admin/conferences/conferences/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/conferences/index.html.haml +18 -0
- data/app/views/spina/admin/conferences/conferences/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/delegates/_delegate.html.haml +13 -0
- data/app/views/spina/admin/conferences/delegates/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/delegates/_form_conferences.html.haml +14 -0
- data/app/views/spina/admin/conferences/delegates/_form_delegate_details.html.haml +38 -0
- data/app/views/spina/admin/conferences/delegates/_form_presentations.html.haml +12 -0
- data/app/views/spina/admin/conferences/delegates/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/delegates/index.html.haml +23 -0
- data/app/views/spina/admin/conferences/delegates/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/dietary_requirements/_dietary_requirement.html.haml +6 -0
- data/app/views/spina/admin/conferences/dietary_requirements/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/dietary_requirements/_form_delegates.html.haml +12 -0
- data/app/views/spina/admin/conferences/dietary_requirements/_form_dietary_requirement_details.html.haml +9 -0
- data/app/views/spina/admin/conferences/dietary_requirements/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/dietary_requirements/index.html.haml +15 -0
- data/app/views/spina/admin/conferences/dietary_requirements/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/events/new.js.erb +27 -0
- data/app/views/spina/admin/conferences/institutions/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/institutions/_form_delegates.html.haml +12 -0
- data/app/views/spina/admin/conferences/institutions/_form_institution_details.html.haml +35 -0
- data/app/views/spina/admin/conferences/institutions/_form_rooms.html.haml +12 -0
- data/app/views/spina/admin/conferences/institutions/_institution.html.haml +7 -0
- data/app/views/spina/admin/conferences/institutions/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/institutions/index.html.haml +16 -0
- data/app/views/spina/admin/conferences/institutions/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/presentation_attachment_types/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/presentation_attachment_types/_presentation_attachment_type.html.haml +6 -0
- data/app/views/spina/admin/conferences/presentation_attachment_types/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/presentation_attachment_types/index.html.haml +15 -0
- data/app/views/spina/admin/conferences/presentation_attachment_types/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/presentation_attachments/new.js.erb +21 -0
- data/app/views/spina/admin/conferences/presentation_types/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/presentation_types/_form_presentation_type_details.html.haml +20 -0
- data/app/views/spina/admin/conferences/presentation_types/_form_presentations.html.haml +12 -0
- data/app/views/spina/admin/conferences/presentation_types/_form_sessions.html.haml +12 -0
- data/app/views/spina/admin/conferences/presentation_types/_presentation_type.html.haml +8 -0
- data/app/views/spina/admin/conferences/presentation_types/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/presentation_types/index.html.haml +17 -0
- data/app/views/spina/admin/conferences/presentation_types/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/presentations/_attachment_fields.html.haml +27 -0
- data/app/views/spina/admin/conferences/presentations/_attachment_row.html.haml +2 -0
- data/app/views/spina/admin/conferences/presentations/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/presentations/_form_presentation_details.html.haml +55 -0
- data/app/views/spina/admin/conferences/presentations/_form_presenters.html.haml +12 -0
- data/app/views/spina/admin/conferences/presentations/_presentation.html.haml +11 -0
- data/app/views/spina/admin/conferences/presentations/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/presentations/index.html.haml +23 -0
- data/app/views/spina/admin/conferences/presentations/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/rooms/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/rooms/_form_presentations.html.haml +12 -0
- data/app/views/spina/admin/conferences/rooms/_form_room_details.html.haml +18 -0
- data/app/views/spina/admin/conferences/rooms/_room.html.haml +8 -0
- data/app/views/spina/admin/conferences/rooms/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/rooms/index.html.haml +17 -0
- data/app/views/spina/admin/conferences/rooms/new.html.haml +1 -0
- data/app/views/spina/admin/conferences/sessions/_form.html.haml +23 -0
- data/app/views/spina/admin/conferences/sessions/_form_presentations.html.haml +12 -0
- data/app/views/spina/admin/conferences/sessions/_form_session_details.html.haml +23 -0
- data/app/views/spina/admin/conferences/sessions/_session.html.haml +8 -0
- data/app/views/spina/admin/conferences/sessions/edit.html.haml +1 -0
- data/app/views/spina/admin/conferences/sessions/index.html.haml +17 -0
- data/app/views/spina/admin/conferences/sessions/new.html.haml +1 -0
- data/app/views/spina/admin/hooks/conferences/_head.html.haml +2 -0
- data/app/views/spina/admin/hooks/conferences/_primary_navigation.html.haml +20 -0
- data/app/views/spina/admin/hooks/conferences/_settings_secondary_navigation.html.haml +4 -0
- data/app/views/spina/admin/partables/admin/conferences/date_parts/_form.html.haml +5 -0
- data/app/views/spina/admin/partables/admin/conferences/email_address_parts/_form.html.haml +5 -0
- data/app/views/spina/admin/partables/admin/conferences/time_parts/_form.html.haml +7 -0
- data/app/views/spina/admin/partables/admin/conferences/url_parts/_form.html.haml +5 -0
- data/config/initializers/assets.rb +13 -0
- data/config/initializers/types.rb +13 -0
- data/config/locales/en.yml +354 -0
- data/config/routes.rb +27 -0
- data/db/migrate/20180907141228_create_spina_dates.rb +11 -0
- data/db/migrate/20180907141229_create_spina_email_addresses.rb +11 -0
- data/db/migrate/20180907141230_create_spina_urls.rb +11 -0
- data/db/migrate/20180907141231_create_spina_conferences_institutions.rb +12 -0
- data/db/migrate/20180907141232_create_spina_conferences_delegates.rb +15 -0
- data/db/migrate/20180907141234_create_spina_conferences_dietary_requirements.rb +11 -0
- data/db/migrate/20180907141235_create_spina_conferences_conferences.rb +12 -0
- data/db/migrate/20180907141236_create_spina_conferences_presentation_types.rb +13 -0
- data/db/migrate/20180907141238_create_join_table_spina_conferences_conference_delegate.rb +7 -0
- data/db/migrate/20180907141239_create_join_table_spina_conferences_delegate_presentation.rb +7 -0
- data/db/migrate/20180907141240_create_join_table_spina_conferences_delegate_dietary_requirement.rb +7 -0
- data/db/migrate/20180907141242_add_type_to_spina_pages.rb +7 -0
- data/db/migrate/20180907141243_create_spina_conferences_conference_page_parts.rb +14 -0
- data/db/migrate/20180914121905_add_logo_ref_to_spina_conferences_institutions.rb +7 -0
- data/db/migrate/20180916135431_create_spina_conferences_rooms.rb +13 -0
- data/db/migrate/20180916135432_create_spina_conferences_room_possessions.rb +10 -0
- data/db/migrate/20180916135433_create_spina_conferences_room_uses.rb +10 -0
- data/db/migrate/20180916135434_create_spina_conferences_presentations.rb +15 -0
- data/db/migrate/20181009122503_create_spina_times.rb +11 -0
- data/db/migrate/20181009130631_rename_spina_page_parts.rb +10 -0
- data/db/migrate/20181012190811_rename_spina_conferences_page_parts.rb +10 -0
- data/db/migrate/20181012213049_change_start_time_in_spina_conferences_conferences.rb +15 -0
- data/db/migrate/20181012214813_rename_start_time_in_spina_conferences_conferences.rb +7 -0
- data/db/migrate/20181017155705_add_dependent_option_to_foreign_keys.rb +36 -0
- data/db/migrate/20190408131354_change_spina_resources.rb +56 -0
- data/db/migrate/20190622131423_create_spina_conferences_parts.rb +12 -0
- data/db/migrate/20190701174807_remove_spina_conference_pages.rb +199 -0
- data/db/migrate/20190704135524_add_constraints_to_columns.rb +24 -0
- data/db/migrate/20200126034441_create_spina_conferences_presentation_attachment_types.rb +11 -0
- data/db/migrate/20200126213718_create_spina_conferences_presentation_attachments.rb +19 -0
- data/db/migrate/20200420104603_create_spina_conferences_dietary_requirement_name_translations.rb +19 -0
- data/db/migrate/20200420104740_create_spina_conferences_institution_name_and_city_translations.rb +20 -0
- data/db/migrate/20200420105057_create_spina_conferences_presentation_title_and_abstract_translations.rb +20 -0
- data/db/migrate/20200420105144_create_spina_conferences_presentation_attachment_type_name_translations.rb +20 -0
- data/db/migrate/20200420105201_create_spina_conferences_presentation_type_name_translations.rb +19 -0
- data/db/migrate/20200420105458_create_spina_conferences_room_building_and_number_translations.rb +20 -0
- data/db/migrate/20200420110407_move_attributes_to_translation_tables.rb +161 -0
- data/db/migrate/20200420120706_remove_name_from_spina_conferences_dietary_requirements.rb +7 -0
- data/db/migrate/20200420120759_remove_name_and_city_from_spina_conferences_institutions.rb +8 -0
- data/db/migrate/20200420120946_remove_title_and_abstract_from_spina_conferences_presentations.rb +8 -0
- data/db/migrate/20200420121310_remove_name_from_spina_conferences_presentation_attachment_types.rb +7 -0
- data/db/migrate/20200420121321_remove_name_from_spina_conferences_presentation_types.rb +7 -0
- data/db/migrate/20200420121443_remove_building_and_number_from_spina_conferences_rooms.rb +8 -0
- data/db/migrate/20200502133408_create_spina_conferences_conference_name_translations.rb +19 -0
- data/db/migrate/20200502183409_set_name_for_spina_conferences_conferences.rb +47 -0
- data/db/migrate/20200502183410_remove_institution_from_spina_conferences_conferences.rb +8 -0
- data/db/migrate/20200502183719_remove_spina_conferences_room_possessions.rb +60 -0
- data/db/migrate/20200503230732_rename_spina_conferences_room_uses.rb +8 -0
- data/db/migrate/20200510125131_create_spina_conferences_session_name_translations.rb +19 -0
- data/db/migrate/20200802165242_create_spina_conferences_events.rb +13 -0
- data/db/migrate/20200802184921_create_spina_conferences_event_name_description_and_location_translations.rb +21 -0
- data/db/migrate/20200911161632_update_spina_conferences_parts.rb +23 -0
- data/db/migrate/20200911161651_update_spina_parts.rb +37 -0
- data/db/migrate/20200911161726_move_presentation_parts.rb +101 -0
- data/db/migrate/20200911161739_move_conference_parts.rb +219 -0
- data/db/migrate/20201002122517_remove_spina_conferences_conference_page_parts.rb +14 -0
- data/db/migrate/20201007125625_add_timestamps_to_spina_conferences_parts.rb +9 -0
- data/lib/spina/admin/conferences.rb +20 -0
- data/lib/spina/admin/conferences/engine.rb +26 -0
- data/lib/spina/admin/conferences/migration/renaming.rb +81 -0
- data/lib/spina/admin/conferences/railtie.rb +34 -0
- data/lib/spina/admin/conferences/types/interval_type.rb +29 -0
- data/lib/spina/admin/conferences/version.rb +10 -0
- data/lib/tasks/spina/admin/conferences_tasks.rake +4 -0
- metadata +561 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/* global Stimulus */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @external Stimulus
|
|
5
|
+
* @see {@link https://stimulusjs.org}
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @classdesc Controller that links related select elements.
|
|
10
|
+
*/
|
|
11
|
+
class SelectOptionsController extends Stimulus.Controller { // eslint-disable-line no-unused-vars
|
|
12
|
+
// noinspection JSUnusedGlobalSymbols
|
|
13
|
+
static get targets() {
|
|
14
|
+
return [
|
|
15
|
+
/**
|
|
16
|
+
* @private
|
|
17
|
+
* @property {HTMLElement[]} selectTargets - The select elements.
|
|
18
|
+
*/
|
|
19
|
+
'select'
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
// noinspection JSUnusedGlobalSymbols
|
|
23
|
+
static get values() {
|
|
24
|
+
return {
|
|
25
|
+
/**
|
|
26
|
+
* @private
|
|
27
|
+
* @property {Array} recordValues - The record values.
|
|
28
|
+
*/
|
|
29
|
+
record: Array,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// noinspection JSUnusedGlobalSymbols
|
|
34
|
+
/**
|
|
35
|
+
* Hook to ensure that the initial value of each select element is used to set visibility of the corresponding records.
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
connect() {
|
|
39
|
+
this.selectTargets.forEach(target => target.dispatchEvent(new Event('change')))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// noinspection JSUnusedGlobalSymbols
|
|
43
|
+
/**
|
|
44
|
+
* Hook to update select targets when record values change.
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
recordValuesChanged() {
|
|
48
|
+
this.selectTargets.forEach(target => {
|
|
49
|
+
if (!(target instanceof HTMLSelectElement)) return
|
|
50
|
+
this.updateOptions(target)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// noinspection JSUnusedGlobalSymbols
|
|
55
|
+
/**
|
|
56
|
+
* Updates the visibility of records according to the selected option of a select element.
|
|
57
|
+
* @param {Event} event - The event fired by the select element.
|
|
58
|
+
*/
|
|
59
|
+
setVisibility(event) {
|
|
60
|
+
const target = event.currentTarget
|
|
61
|
+
if (!(target instanceof HTMLSelectElement)) return
|
|
62
|
+
const recordFilter = new SelectOptionsController.RecordFilter(this.recordValues, target)
|
|
63
|
+
this.recordValues = recordFilter.setVisibility()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Updates the options of a select element.
|
|
68
|
+
* @private
|
|
69
|
+
* @param {HTMLSelectElement} target - The select element to update the options of.
|
|
70
|
+
*/
|
|
71
|
+
updateOptions(target) {
|
|
72
|
+
let newRecords = this.recordValues
|
|
73
|
+
if ('keyPath' in target.dataset) {
|
|
74
|
+
const keyPath = new SelectOptionsController.KeyPath(target.dataset.keyPath)
|
|
75
|
+
newRecords = keyPath.visibleObjectsAtKeyPath(newRecords)
|
|
76
|
+
}
|
|
77
|
+
const textKey = target.dataset.textKey
|
|
78
|
+
if (!('valueKey' in target.dataset)) target.dataset.valueKey = 'id'
|
|
79
|
+
const valueKey = target.dataset.valueKey
|
|
80
|
+
const newOptions = newRecords.map(record => new Option(record[textKey], record[valueKey] ))
|
|
81
|
+
const oldOptions = Array.from(target.options).filter(option => option.value !== '')
|
|
82
|
+
oldOptions.filter(option => !newOptions.some(newOption => newOption.value === option.value))
|
|
83
|
+
.forEach(option => target.remove(option.index))
|
|
84
|
+
newOptions.filter(newOption => !oldOptions.some(option => option.value === newOption.value)).forEach(option => target.add(option))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @private
|
|
90
|
+
* @classdesc A series of property keys, used to traverse objects. A parent object or array of objects is recursively mapped to child
|
|
91
|
+
* objects identified by each property key.
|
|
92
|
+
*/
|
|
93
|
+
SelectOptionsController.KeyPath = class {
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new key path.
|
|
96
|
+
* @private
|
|
97
|
+
* @constructor
|
|
98
|
+
* @param {String} string - The string used to create the key path. Should be in the format 'segment:segment:segment'.
|
|
99
|
+
*/
|
|
100
|
+
constructor(string) {
|
|
101
|
+
if (typeof string !== 'string') throw TypeError(`${string} is not a string`)
|
|
102
|
+
/**
|
|
103
|
+
* @property {string[]} segments - The segments of the key path.
|
|
104
|
+
*/
|
|
105
|
+
this.segments = string.split(':')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Traverses an object or array of objects by recursively mapping objects to the objects identified by the series of key path segments.
|
|
110
|
+
* @private
|
|
111
|
+
* @param {Object|Object[]} object - The object or array of objects to be traversed.
|
|
112
|
+
* @param {Boolean} filter - Whether, when encountering an array within the top-level object or array,
|
|
113
|
+
* elements marked as invisible should be ignored.
|
|
114
|
+
* @return Any
|
|
115
|
+
*/
|
|
116
|
+
traverseObject(object, filter = false) {
|
|
117
|
+
let childObject = object
|
|
118
|
+
this.segments.forEach(key => {
|
|
119
|
+
switch (childObject.constructor) {
|
|
120
|
+
case Array:
|
|
121
|
+
if (filter) childObject = childObject.filter(object => object.hidden !== true)
|
|
122
|
+
childObject = childObject.flatMap(object => object[key])
|
|
123
|
+
break
|
|
124
|
+
case String:
|
|
125
|
+
case Number:
|
|
126
|
+
case Boolean:
|
|
127
|
+
break
|
|
128
|
+
case Object:
|
|
129
|
+
childObject = childObject[key]
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
return childObject ? childObject : []
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Traverses an object or array of objects by recursively mapping objects to the objects identified by the series of key path segments.
|
|
138
|
+
* When encountering an array within the top-level object or array, elements marked as invisible are ignored.
|
|
139
|
+
* @private
|
|
140
|
+
* @param {Object|Object[]} object - The object or array of objects to be traversed.
|
|
141
|
+
* @return Any
|
|
142
|
+
*/
|
|
143
|
+
visibleObjectsAtKeyPath(object) {
|
|
144
|
+
return this.traverseObject(object, true)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Traverses an object or array of objects by recursively mapping objects to the objects identified by the series of key path segments.
|
|
149
|
+
* @private
|
|
150
|
+
* @param {Object|Object[]} object - The object or array of objects to be traversed.
|
|
151
|
+
* @return Any
|
|
152
|
+
*/
|
|
153
|
+
objectsAtKeyPath(object) {
|
|
154
|
+
return this.traverseObject(object)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @private
|
|
160
|
+
* @classdesc Identifies a set of records presented as options by a select element target within a possibly larger set of records.
|
|
161
|
+
* The visibility of each target record can be set by comparing the value of the target to the value of some property of each target record.
|
|
162
|
+
*/
|
|
163
|
+
SelectOptionsController.RecordFilter = class {
|
|
164
|
+
/**
|
|
165
|
+
* @private
|
|
166
|
+
* @property {Object[]} targetRecords - If a key path exists, the records within the raw records identified by the key path.
|
|
167
|
+
* Else the raw records.
|
|
168
|
+
*/
|
|
169
|
+
get targetRecords() {
|
|
170
|
+
return this.keyPath ? this.keyPath.objectsAtKeyPath(this.rawRecords) : this.rawRecords
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Creates a new record filter.
|
|
175
|
+
* @private
|
|
176
|
+
* @constructor
|
|
177
|
+
* @param {Object[]} rawRecords - The records to be filtered.
|
|
178
|
+
* @param {HTMLSelectElement} target - The target providing the value.
|
|
179
|
+
* @param {String} [target.dataset.keyPath] - The key path.
|
|
180
|
+
* @param {String} [target.dataset.valueKey=id] - The value key.
|
|
181
|
+
*/
|
|
182
|
+
constructor(rawRecords, target) {
|
|
183
|
+
/**
|
|
184
|
+
* @private
|
|
185
|
+
* @property {Object[]} rawRecords - The entire set of records.
|
|
186
|
+
*/
|
|
187
|
+
this.rawRecords = Array.from(rawRecords)
|
|
188
|
+
if ('keyPath' in target.dataset) {
|
|
189
|
+
/**
|
|
190
|
+
* @private
|
|
191
|
+
* @property {KeyPath} [keyPath] - The key path used to filter records.
|
|
192
|
+
*/
|
|
193
|
+
this.keyPath = new SelectOptionsController.KeyPath(target.dataset.keyPath)
|
|
194
|
+
}
|
|
195
|
+
if (!('valueKey' in target.dataset)) target.dataset.valueKey = 'id'
|
|
196
|
+
/**
|
|
197
|
+
* @private
|
|
198
|
+
* @property {String} valueKey - The property of the target records to be compared to the target value.
|
|
199
|
+
*/
|
|
200
|
+
this.valueKey = target.dataset.valueKey
|
|
201
|
+
/**
|
|
202
|
+
* @private
|
|
203
|
+
* @property {String} targetValue - The value of the target.
|
|
204
|
+
*/
|
|
205
|
+
this.targetValue = target.value
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Marks the target record whose property value matches the value of the target as visible and others as invisible.
|
|
210
|
+
* @returns {Object[]} The raw records, with the target records marked for visibility.
|
|
211
|
+
*/
|
|
212
|
+
setVisibility() {
|
|
213
|
+
this.targetRecords.forEach(record => record.hidden = record[this.valueKey].toString() !== this.targetValue)
|
|
214
|
+
return this.rawRecords
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
input::-webkit-calendar-picker-indicator
|
|
2
|
+
display: none
|
|
3
|
+
input[type="date"]::-webkit-outer-spin-button, input[type="date"]::-webkit-inner-spin-button, input[type="time"]::-webkit-inner-spin-button, input[type="time"]::-webkit-inner-spin-button
|
|
4
|
+
display: none
|
|
5
|
+
input[type="date"]
|
|
6
|
+
padding-right: 30px
|
|
7
|
+
|
|
8
|
+
.multiple.select-dropdown
|
|
9
|
+
z-index: 0
|
|
10
|
+
&:before
|
|
11
|
+
content: none
|
|
12
|
+
select
|
|
13
|
+
padding: 11px 10px
|
|
14
|
+
width: 100%
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spina
|
|
4
|
+
module Admin
|
|
5
|
+
module Conferences
|
|
6
|
+
# @abstract Subclass to implement a custom controller.
|
|
7
|
+
class ApplicationController < ::Spina::Admin::AdminController
|
|
8
|
+
add_flash_types :success
|
|
9
|
+
|
|
10
|
+
layout :admin_layout, only: %i[new edit]
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def admin_layout
|
|
15
|
+
'spina/admin/admin'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spina
|
|
4
|
+
module Admin
|
|
5
|
+
module Conferences
|
|
6
|
+
# Controller for {Conference} objects.
|
|
7
|
+
# @see Conference
|
|
8
|
+
class ConferencesController < ApplicationController
|
|
9
|
+
PARTS = [
|
|
10
|
+
{ name: 'text', title: 'Text', partable_type: 'Spina::Text' },
|
|
11
|
+
{ name: 'submission_url', title: 'Submission URL', partable_type: 'Spina::Admin::Conferences::UrlPart' },
|
|
12
|
+
{ name: 'submission_email_address', title: 'Submission email address',
|
|
13
|
+
partable_type: 'Spina::Admin::Conferences::EmailAddressPart' },
|
|
14
|
+
{ name: 'submission_date', title: 'Submission date', partable_type: 'Spina::Admin::Conferences::DatePart' },
|
|
15
|
+
{ name: 'submission_text', title: 'Submission text', partable_type: 'Spina::Line' },
|
|
16
|
+
{ name: 'gallery', title: 'Gallery', partable_type: 'Spina::ImageCollection' },
|
|
17
|
+
{ name: 'sponsors', title: 'Sponsors', partable_type: 'Spina::Structure' }
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
before_action :set_conference, only: %i[edit update destroy]
|
|
21
|
+
before_action :set_conferences_breadcrumb
|
|
22
|
+
before_action :set_tabs
|
|
23
|
+
before_action :set_institutions, :set_parts_attributes, only: %i[new edit]
|
|
24
|
+
before_action :build_parts, only: :edit
|
|
25
|
+
|
|
26
|
+
# @!group Actions
|
|
27
|
+
|
|
28
|
+
# Renders a list of conferences.
|
|
29
|
+
# @return [void]
|
|
30
|
+
def index
|
|
31
|
+
@conferences = Conference.sorted
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Renders a form for a new conference.
|
|
35
|
+
# @return [void]
|
|
36
|
+
def new
|
|
37
|
+
@conference = Conference.new
|
|
38
|
+
build_parts
|
|
39
|
+
add_breadcrumb t('.new')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Renders a form for an existing conference.
|
|
43
|
+
# @return [void]
|
|
44
|
+
def edit
|
|
45
|
+
add_breadcrumb @conference.name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Creates a conference.
|
|
49
|
+
# @return [void]
|
|
50
|
+
def create # rubocop:disable Metrics/MethodLength
|
|
51
|
+
@conference = Conference.new(conference_params)
|
|
52
|
+
|
|
53
|
+
if @conference.save
|
|
54
|
+
redirect_to admin_conferences_conferences_path, success: t('.saved')
|
|
55
|
+
else
|
|
56
|
+
respond_to do |format|
|
|
57
|
+
format.html do
|
|
58
|
+
add_breadcrumb t('.new')
|
|
59
|
+
render :new
|
|
60
|
+
end
|
|
61
|
+
format.js { render partial: 'errors', locals: { errors: @conference.errors } }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Updates a conference.
|
|
67
|
+
# @return [void]
|
|
68
|
+
def update # rubocop:disable Metrics/MethodLength
|
|
69
|
+
if @conference.update(conference_params)
|
|
70
|
+
redirect_to admin_conferences_conferences_path, success: t('.saved')
|
|
71
|
+
else
|
|
72
|
+
respond_to do |format|
|
|
73
|
+
format.html do
|
|
74
|
+
add_breadcrumb @conference.name
|
|
75
|
+
render :edit
|
|
76
|
+
end
|
|
77
|
+
format.js { render partial: 'errors', locals: { errors: @conference.errors } }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Destroys a conference.
|
|
83
|
+
# @return [void]
|
|
84
|
+
def destroy # rubocop:disable Metrics/MethodLength
|
|
85
|
+
if @conference.destroy
|
|
86
|
+
redirect_to admin_conferences_conferences_path, success: t('.destroyed')
|
|
87
|
+
else
|
|
88
|
+
respond_to do |format|
|
|
89
|
+
format.html do
|
|
90
|
+
add_breadcrumb @conference.name
|
|
91
|
+
render :edit
|
|
92
|
+
end
|
|
93
|
+
format.js { render partial: 'errors', locals: { errors: @conference.errors } }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @!endgroup
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def set_conference
|
|
103
|
+
@conference = Conference.find params[:id]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def set_institutions
|
|
107
|
+
@institutions = Institution.all.to_json include: { rooms: { methods: [:name] } }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def set_conferences_breadcrumb
|
|
111
|
+
add_breadcrumb Conference.model_name.human(count: 0), admin_conferences_conferences_path
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def set_tabs
|
|
115
|
+
@tabs = %w[conference_details parts delegates presentation_types rooms presentations]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def set_parts_attributes
|
|
119
|
+
@parts_attributes = PARTS
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def build_parts
|
|
123
|
+
return unless @parts_attributes.is_a? Array
|
|
124
|
+
|
|
125
|
+
@conference.parts = @parts_attributes.collect do |part_attributes|
|
|
126
|
+
@conference.parts.where(name: part_attributes[:name]).first_or_initialize(**part_attributes)
|
|
127
|
+
.tap { |part| part.partable ||= part.partable_type.constantize.new }
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def conference_params # rubocop:disable Metrics/MethodLength
|
|
132
|
+
params.require(:admin_conferences_conference).permit(:start_date, :finish_date, :name,
|
|
133
|
+
events_attributes:
|
|
134
|
+
%i[id name date start_time finish_time description location],
|
|
135
|
+
parts_attributes:
|
|
136
|
+
[:id, :title, :name, :partable_type, :partable_id,
|
|
137
|
+
{ partable_attributes:
|
|
138
|
+
[:id, :content, :image_tokens, :image_positions, :date, :time,
|
|
139
|
+
{ structure_items_attributes:
|
|
140
|
+
[:id, :position, :_destroy,
|
|
141
|
+
{ structure_parts_attributes:
|
|
142
|
+
[:id, :title, :structure_partable_type, :name, :partable_id,
|
|
143
|
+
{ partable_attributes: {} }] }] }] }])
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spina
|
|
4
|
+
module Admin
|
|
5
|
+
module Conferences
|
|
6
|
+
# Controller for {Delegate} objects.
|
|
7
|
+
# @see Delegate
|
|
8
|
+
class DelegatesController < ApplicationController
|
|
9
|
+
before_action :set_delegate, only: %i[edit update destroy]
|
|
10
|
+
before_action :set_breadcrumb
|
|
11
|
+
before_action :set_tabs
|
|
12
|
+
|
|
13
|
+
# @!group Actions
|
|
14
|
+
|
|
15
|
+
# Renders a list of delegates.
|
|
16
|
+
# @return [void]
|
|
17
|
+
def index
|
|
18
|
+
@delegates = Delegate.sorted
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Renders a form for a new delegate.
|
|
22
|
+
# @return [void]
|
|
23
|
+
def new
|
|
24
|
+
@delegate = Delegate.new
|
|
25
|
+
add_breadcrumb t('.new')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Renders a form for an existing delegate.
|
|
29
|
+
# @return [void]
|
|
30
|
+
def edit
|
|
31
|
+
add_breadcrumb @delegate.full_name
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Creates a delegate.
|
|
35
|
+
# @return [void]
|
|
36
|
+
def create # rubocop:disable Metrics/MethodLength
|
|
37
|
+
@delegate = Delegate.new(delegate_params)
|
|
38
|
+
|
|
39
|
+
if @delegate.save
|
|
40
|
+
redirect_to admin_conferences_delegates_path, success: t('.saved')
|
|
41
|
+
else
|
|
42
|
+
respond_to do |format|
|
|
43
|
+
format.html do
|
|
44
|
+
add_breadcrumb t('.new')
|
|
45
|
+
render :new
|
|
46
|
+
end
|
|
47
|
+
format.js { render partial: 'errors', locals: { errors: @delegate.errors } }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Updates a delegate.
|
|
53
|
+
# @return [void]
|
|
54
|
+
def update # rubocop:disable Metrics/MethodLength
|
|
55
|
+
if @delegate.update(delegate_params)
|
|
56
|
+
redirect_to admin_conferences_delegates_path, success: t('.saved')
|
|
57
|
+
else
|
|
58
|
+
respond_to do |format|
|
|
59
|
+
format.html do
|
|
60
|
+
add_breadcrumb @delegate.full_name
|
|
61
|
+
render :edit
|
|
62
|
+
end
|
|
63
|
+
format.js { render partial: 'errors', locals: { errors: @delegate.errors } }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Destroys a delegate.
|
|
69
|
+
# @return [void]
|
|
70
|
+
def destroy # rubocop:disable Metrics/MethodLength
|
|
71
|
+
if @delegate.destroy
|
|
72
|
+
redirect_to admin_conferences_delegates_path, success: t('.destroyed')
|
|
73
|
+
else
|
|
74
|
+
respond_to do |format|
|
|
75
|
+
format.html do
|
|
76
|
+
add_breadcrumb @delegate.full_name
|
|
77
|
+
render :edit
|
|
78
|
+
end
|
|
79
|
+
format.js { render partial: 'errors', locals: { errors: @delegate.errors } }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Imports a delegate.
|
|
85
|
+
# @return [void]
|
|
86
|
+
# @see Delegate#import
|
|
87
|
+
def import
|
|
88
|
+
Delegate.import params[:file]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @!endgroup
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def set_delegate
|
|
96
|
+
@delegate = Delegate.find params[:id]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def set_breadcrumb
|
|
100
|
+
add_breadcrumb Delegate.model_name.human(count: 0), admin_conferences_delegates_path
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def set_tabs
|
|
104
|
+
@tabs = %w[delegate_details conferences presentations]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def delegate_params
|
|
108
|
+
params.require(:admin_conferences_delegate).permit(:first_name, :last_name, :email_address, :url,
|
|
109
|
+
:institution_id,
|
|
110
|
+
conference_ids: [],
|
|
111
|
+
dietary_requirement_ids: [])
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|