voom-presenters 0.1.0
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/.gitignore +54 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +104 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/ROADMAP.md +21 -0
- data/Rakefile +6 -0
- data/app/demo/component_status.pom +76 -0
- data/app/demo/components.pom +19 -0
- data/app/demo/components/badges.pom +25 -0
- data/app/demo/components/buttons.pom +51 -0
- data/app/demo/components/cards.pom +79 -0
- data/app/demo/components/chips.pom +91 -0
- data/app/demo/components/dialogs.pom +27 -0
- data/app/demo/components/drawers.pom +34 -0
- data/app/demo/components/expansion_panels.pom +21 -0
- data/app/demo/components/fabs-mini.pom +18 -0
- data/app/demo/components/fabs.pom +16 -0
- data/app/demo/components/footers.pom +36 -0
- data/app/demo/components/forms.pom +30 -0
- data/app/demo/components/headers.pom +37 -0
- data/app/demo/components/hidden_fields.pom +20 -0
- data/app/demo/components/icons.pom +94 -0
- data/app/demo/components/layouts.pom +44 -0
- data/app/demo/components/lists.pom +124 -0
- data/app/demo/components/menus.pom +43 -0
- data/app/demo/components/nav/drawer.pom +5 -0
- data/app/demo/components/nav/menu.pom +15 -0
- data/app/demo/components/selects.pom +30 -0
- data/app/demo/components/snackbar.pom +24 -0
- data/app/demo/components/snackbar_attached.pom +6 -0
- data/app/demo/components/tables.pom +39 -0
- data/app/demo/components/text_areas.pom +19 -0
- data/app/demo/components/text_fields.pom +57 -0
- data/app/demo/components/toggles.pom +29 -0
- data/app/demo/components/tooltips.pom +120 -0
- data/app/demo/event/actions.rb +86 -0
- data/app/demo/event/actions/dialog/show_dialog.pom +9 -0
- data/app/demo/event/actions/dialog/trigger.pom +86 -0
- data/app/demo/event/actions/nav/drawer.pom +5 -0
- data/app/demo/event/actions/nav/menu.pom +19 -0
- data/app/demo/event/autocomplete.pom +27 -0
- data/app/demo/event/field_level.pom +22 -0
- data/app/demo/event/form_level.pom +26 -0
- data/app/demo/event/nav/drawer.pom +5 -0
- data/app/demo/event/nav/menu.pom +14 -0
- data/app/demo/event/new_text.pom +6 -0
- data/app/demo/events.pom +98 -0
- data/app/demo/helpers/indented_grid.rb +14 -0
- data/app/demo/index.pom +19 -0
- data/app/demo/markdown.pom +73 -0
- data/app/demo/nav/top_nav.pom +42 -0
- data/app/demo/shared/code.pom +20 -0
- data/app/demo/shared/context_list.pom +29 -0
- data/app/demo/shared/debug.pom +17 -0
- data/app/demo/styles.pom +26 -0
- data/bin/console +22 -0
- data/bin/setup +8 -0
- data/component-status.yml +219 -0
- data/config.ru +21 -0
- data/lib/voom-presenters.rb +9 -0
- data/lib/voom/container_methods.rb +40 -0
- data/lib/voom/logger_methods.rb +11 -0
- data/lib/voom/parameters.rb +73 -0
- data/lib/voom/presenters-engine.rb +40 -0
- data/lib/voom/presenters.rb +13 -0
- data/lib/voom/presenters/api/app.rb +53 -0
- data/lib/voom/presenters/api/router.rb +94 -0
- data/lib/voom/presenters/app.rb +55 -0
- data/lib/voom/presenters/container_item.rb +16 -0
- data/lib/voom/presenters/demo/echo.rb +29 -0
- data/lib/voom/presenters/demo/search-terms.yml +50 -0
- data/lib/voom/presenters/demo/search.rb +29 -0
- data/lib/voom/presenters/dsl.rb +60 -0
- data/lib/voom/presenters/dsl/components/action.rb +35 -0
- data/lib/voom/presenters/dsl/components/avatar.rb +27 -0
- data/lib/voom/presenters/dsl/components/badge.rb +21 -0
- data/lib/voom/presenters/dsl/components/base.rb +78 -0
- data/lib/voom/presenters/dsl/components/button.rb +49 -0
- data/lib/voom/presenters/dsl/components/card.rb +119 -0
- data/lib/voom/presenters/dsl/components/checkbox.rb +16 -0
- data/lib/voom/presenters/dsl/components/chip.rb +48 -0
- data/lib/voom/presenters/dsl/components/content.rb +33 -0
- data/lib/voom/presenters/dsl/components/date_time.rb +17 -0
- data/lib/voom/presenters/dsl/components/dialog.rb +50 -0
- data/lib/voom/presenters/dsl/components/drawer.rb +40 -0
- data/lib/voom/presenters/dsl/components/event.rb +101 -0
- data/lib/voom/presenters/dsl/components/event_base.rb +20 -0
- data/lib/voom/presenters/dsl/components/expansion_panel.rb +46 -0
- data/lib/voom/presenters/dsl/components/footer.rb +25 -0
- data/lib/voom/presenters/dsl/components/form.rb +42 -0
- data/lib/voom/presenters/dsl/components/grid.rb +64 -0
- data/lib/voom/presenters/dsl/components/header.rb +33 -0
- data/lib/voom/presenters/dsl/components/hidden_field.rb +25 -0
- data/lib/voom/presenters/dsl/components/icon.rb +21 -0
- data/lib/voom/presenters/dsl/components/icon_base.rb +24 -0
- data/lib/voom/presenters/dsl/components/icon_toggle.rb +21 -0
- data/lib/voom/presenters/dsl/components/image.rb +36 -0
- data/lib/voom/presenters/dsl/components/input.rb +19 -0
- data/lib/voom/presenters/dsl/components/list.rb +39 -0
- data/lib/voom/presenters/dsl/components/lists/action.rb +72 -0
- data/lib/voom/presenters/dsl/components/lists/line.rb +83 -0
- data/lib/voom/presenters/dsl/components/lists/separator.rb +16 -0
- data/lib/voom/presenters/dsl/components/menu.rb +66 -0
- data/lib/voom/presenters/dsl/components/mixins/append.rb +20 -0
- data/lib/voom/presenters/dsl/components/mixins/attaches.rb +18 -0
- data/lib/voom/presenters/dsl/components/mixins/avatar.rb +18 -0
- data/lib/voom/presenters/dsl/components/mixins/buttons.rb +15 -0
- data/lib/voom/presenters/dsl/components/mixins/chips.rb +21 -0
- data/lib/voom/presenters/dsl/components/mixins/common.rb +50 -0
- data/lib/voom/presenters/dsl/components/mixins/content.rb +15 -0
- data/lib/voom/presenters/dsl/components/mixins/dialogs.rb +19 -0
- data/lib/voom/presenters/dsl/components/mixins/event.rb +19 -0
- data/lib/voom/presenters/dsl/components/mixins/expansion_panels.rb +15 -0
- data/lib/voom/presenters/dsl/components/mixins/grids.rb +15 -0
- data/lib/voom/presenters/dsl/components/mixins/helpers.rb +20 -0
- data/lib/voom/presenters/dsl/components/mixins/icons.rb +17 -0
- data/lib/voom/presenters/dsl/components/mixins/images.rb +15 -0
- data/lib/voom/presenters/dsl/components/mixins/menus.rb +15 -0
- data/lib/voom/presenters/dsl/components/mixins/selects.rb +17 -0
- data/lib/voom/presenters/dsl/components/mixins/snackbars.rb +18 -0
- data/lib/voom/presenters/dsl/components/mixins/text_fields.rb +35 -0
- data/lib/voom/presenters/dsl/components/mixins/toggles.rb +40 -0
- data/lib/voom/presenters/dsl/components/mixins/tooltips.rb +18 -0
- data/lib/voom/presenters/dsl/components/mixins/typography.rb +37 -0
- data/lib/voom/presenters/dsl/components/page.rb +29 -0
- data/lib/voom/presenters/dsl/components/radio_button.rb +14 -0
- data/lib/voom/presenters/dsl/components/select.rb +64 -0
- data/lib/voom/presenters/dsl/components/snackbar.rb +32 -0
- data/lib/voom/presenters/dsl/components/switch.rb +14 -0
- data/lib/voom/presenters/dsl/components/table.rb +102 -0
- data/lib/voom/presenters/dsl/components/text_area.rb +20 -0
- data/lib/voom/presenters/dsl/components/text_field.rb +74 -0
- data/lib/voom/presenters/dsl/components/toggle_base.rb +26 -0
- data/lib/voom/presenters/dsl/components/tooltip.rb +25 -0
- data/lib/voom/presenters/dsl/components/typography.rb +25 -0
- data/lib/voom/presenters/dsl/definer.rb +13 -0
- data/lib/voom/presenters/dsl/definition.rb +31 -0
- data/lib/voom/presenters/dsl/invalid_presenter.rb +8 -0
- data/lib/voom/presenters/dsl/lockable.rb +15 -0
- data/lib/voom/presenters/dsl/user_interface.rb +135 -0
- data/lib/voom/presenters/errors/parameter_validation.rb +10 -0
- data/lib/voom/presenters/errors/unprocessable.rb +8 -0
- data/lib/voom/presenters/helpers.rb +18 -0
- data/lib/voom/presenters/helpers/currency.rb +14 -0
- data/lib/voom/presenters/helpers/date.rb +22 -0
- data/lib/voom/presenters/helpers/errors.rb +11 -0
- data/lib/voom/presenters/helpers/inflector.rb +16 -0
- data/lib/voom/presenters/helpers/rails.rb +60 -0
- data/lib/voom/presenters/helpers/route.rb +11 -0
- data/lib/voom/presenters/helpers/time.rb +27 -0
- data/lib/voom/presenters/settings.rb +35 -0
- data/lib/voom/presenters/version.rb +5 -0
- data/lib/voom/presenters/web_client/app.rb +128 -0
- data/lib/voom/presenters/web_client/markdown_render.rb +16 -0
- data/lib/voom/presenters/web_client/router.rb +96 -0
- data/lib/voom/serializer.rb +43 -0
- data/lib/voom/symbol/to_str.rb +29 -0
- data/lib/voom/trace.rb +19 -0
- data/presenters.gemspec +37 -0
- data/public/.gitignore +2 -0
- data/public/bundle.css +11413 -0
- data/public/bundle.js +16456 -0
- data/public/dialog-polyfill.js +738 -0
- data/public/favicon.ico +0 -0
- data/public/img/demo/dog.png +0 -0
- data/public/img/demo/image_card.jpg +0 -0
- data/public/img/demo/rx.png +0 -0
- data/public/img/demo/welcome_card.jpg +0 -0
- data/public/img/settings/blue.png +0 -0
- data/public/img/settings/green.png +0 -0
- data/public/img/settings/orange.png +0 -0
- data/public/img/settings/purple.png +0 -0
- data/public/img/settings/red.png +0 -0
- data/public/img/settings/teal.png +0 -0
- data/public/img/settings/white.png +0 -0
- data/public/img/settings/yellow.png +0 -0
- data/public/scripts.js +289 -0
- data/public/style-bundle.js +73 -0
- data/public/styles.css +16 -0
- data/views/mdc/.gitignore +1 -0
- data/views/mdc/assets/js/app.js +10 -0
- data/views/mdc/assets/js/components/base-component.js +5 -0
- data/views/mdc/assets/js/components/button.js +15 -0
- data/views/mdc/assets/js/components/cards.js +3 -0
- data/views/mdc/assets/js/components/checkboxes.js +15 -0
- data/views/mdc/assets/js/components/chips.js +12 -0
- data/views/mdc/assets/js/components/date-time.js +6 -0
- data/views/mdc/assets/js/components/dialogs.js +32 -0
- data/views/mdc/assets/js/components/events.js +151 -0
- data/views/mdc/assets/js/components/events/autocomplete.js +96 -0
- data/views/mdc/assets/js/components/events/base.js +41 -0
- data/views/mdc/assets/js/components/events/dialog.js +25 -0
- data/views/mdc/assets/js/components/events/errors.js +142 -0
- data/views/mdc/assets/js/components/events/loads.js +22 -0
- data/views/mdc/assets/js/components/events/navigates.js +17 -0
- data/views/mdc/assets/js/components/events/posts.js +99 -0
- data/views/mdc/assets/js/components/events/replaces.js +82 -0
- data/views/mdc/assets/js/components/events/selects.js +28 -0
- data/views/mdc/assets/js/components/events/snackbar.js +23 -0
- data/views/mdc/assets/js/components/events/toggle_visiblity.js +19 -0
- data/views/mdc/assets/js/components/forms.js +57 -0
- data/views/mdc/assets/js/components/icon-toggles.js +21 -0
- data/views/mdc/assets/js/components/initialize.js +34 -0
- data/views/mdc/assets/js/components/lists.js +4 -0
- data/views/mdc/assets/js/components/menus.js +31 -0
- data/views/mdc/assets/js/components/mixins/event-handler.js +13 -0
- data/views/mdc/assets/js/components/selects.js +45 -0
- data/views/mdc/assets/js/components/snackbar.js +32 -0
- data/views/mdc/assets/js/components/text-fields.js +77 -0
- data/views/mdc/assets/js/dialog-polyfill.js +738 -0
- data/views/mdc/assets/js/material.js +3996 -0
- data/views/mdc/assets/js/utils/urls.js +54 -0
- data/views/mdc/assets/scss/app.scss +31 -0
- data/views/mdc/assets/scss/components/avatar.scss +41 -0
- data/views/mdc/assets/scss/components/button.scss +47 -0
- data/views/mdc/assets/scss/components/card.scss +54 -0
- data/views/mdc/assets/scss/components/checkbox.scss +5 -0
- data/views/mdc/assets/scss/components/chip.scss +30 -0
- data/views/mdc/assets/scss/components/datetime.scss +0 -0
- data/views/mdc/assets/scss/components/dialog.scss +3 -0
- data/views/mdc/assets/scss/components/expansion-panel.scss +153 -0
- data/views/mdc/assets/scss/components/fab.scss +8 -0
- data/views/mdc/assets/scss/components/grid.scss +10 -0
- data/views/mdc/assets/scss/components/icon-toggles.scss +9 -0
- data/views/mdc/assets/scss/components/icon.scss +34 -0
- data/views/mdc/assets/scss/components/image.scss +24 -0
- data/views/mdc/assets/scss/components/list.scss +9 -0
- data/views/mdc/assets/scss/components/menu.scss +17 -0
- data/views/mdc/assets/scss/components/select.scss +16 -0
- data/views/mdc/assets/scss/components/snackbar.scss +5 -0
- data/views/mdc/assets/scss/components/switch.scss +6 -0
- data/views/mdc/assets/scss/components/table-pagination.scss +65 -0
- data/views/mdc/assets/scss/components/textfield.scss +1 -0
- data/views/mdc/assets/scss/components/typography.scss +25 -0
- data/views/mdc/assets/scss/material.blue_grey-orange.min.css +8 -0
- data/views/mdc/assets/scss/styles.scss +11 -0
- data/views/mdc/assets/scss/theme.scss +5 -0
- data/views/mdc/body/drawer.erb +18 -0
- data/views/mdc/body/drawers/menu.erb +25 -0
- data/views/mdc/body/footer.erb +1 -0
- data/views/mdc/body/footers/large.erb +27 -0
- data/views/mdc/body/footers/menu_item.erb +6 -0
- data/views/mdc/body/footers/small.erb +14 -0
- data/views/mdc/body/header.erb +25 -0
- data/views/mdc/body/snackbar.erb +10 -0
- data/views/mdc/components/avatar.erb +24 -0
- data/views/mdc/components/badge.erb +2 -0
- data/views/mdc/components/body.erb +2 -0
- data/views/mdc/components/button.erb +17 -0
- data/views/mdc/components/buttons/button.erb +20 -0
- data/views/mdc/components/buttons/fab.erb +22 -0
- data/views/mdc/components/buttons/icon.erb +24 -0
- data/views/mdc/components/card.erb +49 -0
- data/views/mdc/components/checkbox.erb +22 -0
- data/views/mdc/components/chip.erb +31 -0
- data/views/mdc/components/content.erb +11 -0
- data/views/mdc/components/date_time.erb +30 -0
- data/views/mdc/components/dialog.erb +27 -0
- data/views/mdc/components/display.erb +2 -0
- data/views/mdc/components/event.erb +18 -0
- data/views/mdc/components/expansion_panel.erb +11 -0
- data/views/mdc/components/form.erb +15 -0
- data/views/mdc/components/grid.erb +24 -0
- data/views/mdc/components/headline.erb +2 -0
- data/views/mdc/components/hidden_field.erb +1 -0
- data/views/mdc/components/icon.erb +30 -0
- data/views/mdc/components/icon_toggle.erb +15 -0
- data/views/mdc/components/image.erb +7 -0
- data/views/mdc/components/link.erb +14 -0
- data/views/mdc/components/list.erb +14 -0
- data/views/mdc/components/list/actions.erb +6 -0
- data/views/mdc/components/list/actions/button.erb +1 -0
- data/views/mdc/components/list/actions/checkbox.erb +1 -0
- data/views/mdc/components/list/actions/icon.erb +1 -0
- data/views/mdc/components/list/actions/icon_toggle.erb +1 -0
- data/views/mdc/components/list/actions/radio_button.erb +1 -0
- data/views/mdc/components/list/actions/switch.erb +1 -0
- data/views/mdc/components/list/avatar.erb +5 -0
- data/views/mdc/components/list/checkbox.erb +5 -0
- data/views/mdc/components/list/icon.erb +5 -0
- data/views/mdc/components/list/info.erb +1 -0
- data/views/mdc/components/list/line.erb +34 -0
- data/views/mdc/components/list/menu.erb +23 -0
- data/views/mdc/components/list/separator.erb +1 -0
- data/views/mdc/components/menu.erb +29 -0
- data/views/mdc/components/modal.erb +15 -0
- data/views/mdc/components/radio_button.erb +11 -0
- data/views/mdc/components/render.erb +4 -0
- data/views/mdc/components/select.erb +22 -0
- data/views/mdc/components/snackbar.erb +17 -0
- data/views/mdc/components/static.erb +7 -0
- data/views/mdc/components/subheading.erb +2 -0
- data/views/mdc/components/switch.erb +13 -0
- data/views/mdc/components/table.erb +13 -0
- data/views/mdc/components/table/header.erb +7 -0
- data/views/mdc/components/table/pagination.erb +24 -0
- data/views/mdc/components/table/row.erb +14 -0
- data/views/mdc/components/text_area.erb +8 -0
- data/views/mdc/components/text_field.erb +27 -0
- data/views/mdc/components/title.erb +4 -0
- data/views/mdc/components/tooltip.erb +5 -0
- data/views/mdc/components/typography.erb +13 -0
- data/views/mdc/init-depends.sh +2 -0
- data/views/mdc/layout.erb +50 -0
- data/views/mdc/package-lock.json +11524 -0
- data/views/mdc/package.json +39 -0
- data/views/mdc/web.erb +1 -0
- data/views/mdc/webpack.config.js +47 -0
- metadata +539 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
import {MDCCheckbox} from '@material/checkbox';
|
2
|
+
|
3
|
+
export function initCheckboxes() {
|
4
|
+
console.log('\tCheckboxes');
|
5
|
+
|
6
|
+
var components = document.querySelectorAll('.mdc-checkbox');
|
7
|
+
if (components) {
|
8
|
+
for (var i = 0; i < components.length; i++) {
|
9
|
+
var component = components[i];
|
10
|
+
if (!component.mdcComponent) {
|
11
|
+
component.mdcComponent = MDCCheckbox.attachTo(component);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import {MDCChip} from '@material/chips';
|
2
|
+
|
3
|
+
export function initChips() {
|
4
|
+
console.log('\tChips');
|
5
|
+
var components = document.querySelectorAll('.mdc-chip');
|
6
|
+
for (var i = 0; i < components.length; i++) {
|
7
|
+
var component = components[i];
|
8
|
+
if(!component.mdcComponent) {
|
9
|
+
component.mdcComponent = MDCChip.attachTo(component);
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
// This is used to get a proper binding of the actionData
|
2
|
+
// https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
|
3
|
+
function createDialogHandler(dialog) {
|
4
|
+
return function () {
|
5
|
+
dialog.close();
|
6
|
+
};
|
7
|
+
}
|
8
|
+
|
9
|
+
export function initDialogs() {
|
10
|
+
console.log('\tDialogs');
|
11
|
+
|
12
|
+
var dialogs = document.querySelectorAll('.v-js-dialog');
|
13
|
+
if (dialogs) {
|
14
|
+
for (var i = 0; i < dialogs.length; i++) {
|
15
|
+
var dialog = dialogs[i];
|
16
|
+
var dialogButtons = dialog.querySelectorAll('button:not([disabled])');
|
17
|
+
for (var j = 0; j != dialogButtons.length; j++) {
|
18
|
+
var dialogButton = dialogButtons[j];
|
19
|
+
if (!dialogButton.dialog) {
|
20
|
+
dialogButton.dialog = dialog;
|
21
|
+
var buttonEvents = dialogButton.dataset.events;
|
22
|
+
// If the dialog button does not have any events tied to it,
|
23
|
+
// then close the dialog on click, otherwise let the events handlers
|
24
|
+
// take care of the close.
|
25
|
+
if (!buttonEvents) {
|
26
|
+
dialogButton.addEventListener('click', createDialogHandler(dialog));
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import {VLoads} from './events/loads';
|
2
|
+
import {VPosts} from './events/posts';
|
3
|
+
import {VReplaces} from './events/replaces';
|
4
|
+
import {VDialog} from './events/dialog';
|
5
|
+
import {VErrors} from './events/errors';
|
6
|
+
import {VToggleVisiblity} from './events/toggle_visiblity';
|
7
|
+
import {VSnackbarEvent} from './events/snackbar';
|
8
|
+
import {VAutoComplete} from './events/autocomplete';
|
9
|
+
import {VSelects} from './events/selects';
|
10
|
+
import {VNavigates} from './events/navigates';
|
11
|
+
|
12
|
+
|
13
|
+
export class VEvents {
|
14
|
+
//[[type, url, target, params]]
|
15
|
+
constructor(actions, event) {
|
16
|
+
this.event = event;
|
17
|
+
this.actions = actions.map((action) => {
|
18
|
+
return this.constructor.action_class(action, event);
|
19
|
+
});
|
20
|
+
}
|
21
|
+
|
22
|
+
call() {
|
23
|
+
// Adapted from http://www.datchley.name/promise-patterns-anti-patterns/#executingpromisesinseries
|
24
|
+
var fnlist = this.actions.map((action) => {
|
25
|
+
return function (results) {
|
26
|
+
return Promise.resolve(action.call(results));
|
27
|
+
};
|
28
|
+
});
|
29
|
+
|
30
|
+
// Execute a list of Promise return functions in series
|
31
|
+
function pseries(list) {
|
32
|
+
var p = Promise.resolve([]);
|
33
|
+
return list.reduce(function (pacc, fn) {
|
34
|
+
return pacc = pacc.then(fn);
|
35
|
+
}, p);
|
36
|
+
}
|
37
|
+
|
38
|
+
var event = this.event;
|
39
|
+
|
40
|
+
pseries(fnlist)
|
41
|
+
.then(function (results) {
|
42
|
+
var result = results.pop();
|
43
|
+
var contentType = result.contentType;
|
44
|
+
var responseURL = result.responseURL;
|
45
|
+
|
46
|
+
if (event.target.dialog) {
|
47
|
+
event.target.dialog.close();
|
48
|
+
}
|
49
|
+
if (contentType && contentType.indexOf("text/html") !== -1 && typeof responseURL !== 'undefined') {
|
50
|
+
window.location = responseURL;
|
51
|
+
}
|
52
|
+
|
53
|
+
}).catch(function (results) {
|
54
|
+
var result = results.pop();
|
55
|
+
new VErrors(event).displayErrors(result);
|
56
|
+
});
|
57
|
+
}
|
58
|
+
|
59
|
+
static action_class(action, event) {
|
60
|
+
var action_type = action[0];
|
61
|
+
var url = action[1];
|
62
|
+
var options = action[2];
|
63
|
+
var params = action[3];
|
64
|
+
|
65
|
+
switch (action_type) {
|
66
|
+
case 'loads':
|
67
|
+
return new VLoads(options, url, params, event);
|
68
|
+
case 'replaces':
|
69
|
+
return new VReplaces(options, url, params, event);
|
70
|
+
case 'post':
|
71
|
+
return new VPosts(options, url, params, 'POST', event);
|
72
|
+
case 'update':
|
73
|
+
return new VPosts(options, url, params, 'PUT', event);
|
74
|
+
case 'delete':
|
75
|
+
return new VPosts(options, url, params, 'DELETE', event);
|
76
|
+
case 'dialog':
|
77
|
+
return new VDialog(options, params, event);
|
78
|
+
case 'toggle_visibility':
|
79
|
+
return new VToggleVisiblity(options, params, event);
|
80
|
+
case 'snackbar':
|
81
|
+
return new VSnackbarEvent(options, params, event);
|
82
|
+
case 'autocomplete':
|
83
|
+
return new VAutoComplete(options, url, params, event);
|
84
|
+
case 'selects':
|
85
|
+
return new VSelects(options, params, event);
|
86
|
+
case 'navigates':
|
87
|
+
return new VNavigates(options, params, event);
|
88
|
+
default:
|
89
|
+
throw action_type + ' is not supported.';
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
}
|
94
|
+
|
95
|
+
// This is used to get a proper binding of the actionData
|
96
|
+
// https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
|
97
|
+
function createEventHandler(actionsData) {
|
98
|
+
return function (event) {
|
99
|
+
new VEvents(actionsData, event).call();
|
100
|
+
};
|
101
|
+
}
|
102
|
+
|
103
|
+
export function initEvents() {
|
104
|
+
console.log('\tEvents');
|
105
|
+
|
106
|
+
var events = document.querySelectorAll('[data-events]');
|
107
|
+
for (var i = 0; i < events.length; i++) {
|
108
|
+
var eventElem = events[i];
|
109
|
+
var eventsData = JSON.parse(eventElem.dataset.events);
|
110
|
+
for (var j = 0; j < eventsData.length; j++) {
|
111
|
+
var eventData = eventsData[j];
|
112
|
+
var eventName = eventData[0];
|
113
|
+
var eventOptions = eventData[2];
|
114
|
+
var actionsData = eventData[1];
|
115
|
+
var eventHandler = createEventHandler(actionsData);
|
116
|
+
// Delegate to the component if possible
|
117
|
+
if (eventElem.vComponent && eventElem.vComponent.initEventListener) {
|
118
|
+
eventElem.vComponent.initEventListener(eventName, eventHandler);
|
119
|
+
} else {
|
120
|
+
if (typeof eventElem.eventsHandler === 'undefined') {
|
121
|
+
eventElem.eventsHandler = {};
|
122
|
+
}
|
123
|
+
if (!eventElem.eventsHandler[eventName]) {
|
124
|
+
// Delegate to the component if possible
|
125
|
+
eventElem.eventsHandler[eventName] = eventHandler;
|
126
|
+
eventElem.addEventListener(eventName, eventHandler, eventOptions);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
fireAfterLoad();
|
132
|
+
}
|
133
|
+
|
134
|
+
function fireAfterLoad() {
|
135
|
+
var events = document.querySelectorAll('[data-events]');
|
136
|
+
for (var i = 0; i < events.length; i++) {
|
137
|
+
var eventElem = events[i];
|
138
|
+
var eventsData = JSON.parse(eventElem.dataset.events);
|
139
|
+
for (var j = 0; j < eventsData.length; j++) {
|
140
|
+
var eventData = eventsData[j];
|
141
|
+
var eventName = eventData[0];
|
142
|
+
if(eventName==='after_init') {
|
143
|
+
var event = new Event('after_init');
|
144
|
+
// Dispatch the event.
|
145
|
+
eventElem.dispatchEvent(event);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import {VSnackbar} from '../snackbar';
|
2
|
+
import {VBase} from './base';
|
3
|
+
import {initialize} from '../initialize';
|
4
|
+
|
5
|
+
// Auto complete a datalist
|
6
|
+
// The elementId is a datalist
|
7
|
+
// The url is called as a GET expecting json back
|
8
|
+
export class VAutoComplete extends VBase {
|
9
|
+
constructor(options, url, params, event) {
|
10
|
+
super(options);
|
11
|
+
this.element_id = options.target;
|
12
|
+
this.url = url;
|
13
|
+
this.params = params;
|
14
|
+
this.event = event;
|
15
|
+
}
|
16
|
+
|
17
|
+
call(results) {
|
18
|
+
// Clear the timeout if it has already been set.
|
19
|
+
// This will prevent the previous task from executing
|
20
|
+
// if it has been less than <MILLISECONDS>
|
21
|
+
var parentElement = this.parentElement();
|
22
|
+
var updateElement = this.createUpdateElementHandler(this);
|
23
|
+
var promiseObj = new Promise(function (resolve) {
|
24
|
+
clearTimeout(parentElement.vTimeout);
|
25
|
+
// Make a new timeout
|
26
|
+
parentElement.vTimeout = setTimeout(updateElement, 500);
|
27
|
+
results.push({action:'autocomplete', statusCode: 200});
|
28
|
+
resolve(results);
|
29
|
+
});
|
30
|
+
return promiseObj;
|
31
|
+
}
|
32
|
+
|
33
|
+
// This is used to get a proper binding of the object
|
34
|
+
// https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
|
35
|
+
createUpdateElementHandler(_this_) {
|
36
|
+
return function () {
|
37
|
+
_this_.updateElement();
|
38
|
+
};
|
39
|
+
}
|
40
|
+
|
41
|
+
updateElement() {
|
42
|
+
this.clearErrors();
|
43
|
+
this.getData(this.populateOptions);
|
44
|
+
}
|
45
|
+
|
46
|
+
dataList() {
|
47
|
+
return document.getElementById(this.element_id);
|
48
|
+
}
|
49
|
+
|
50
|
+
getData(funcProcessData) {
|
51
|
+
var comp = this.component();
|
52
|
+
if(comp.value().length < 2){
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
var httpRequest = new XMLHttpRequest();
|
56
|
+
if (!httpRequest) {
|
57
|
+
throw new Error('Cannot talk to server! Please upgrade your browser to one that supports XMLHttpRequest.');
|
58
|
+
// new VSnackbar('Cannot talk to server! Please upgrade your browser to one that supports XMLHttpRequest.').display();
|
59
|
+
}
|
60
|
+
var dataList = this.dataList();
|
61
|
+
var url = this.buildURL(this.url, this.params, this.inputValues());
|
62
|
+
|
63
|
+
httpRequest.onreadystatechange = function () {
|
64
|
+
if (httpRequest.readyState === XMLHttpRequest.DONE) {
|
65
|
+
console.log(httpRequest.status + ':' + this.getResponseHeader('content-type'));
|
66
|
+
if (httpRequest.status === 200) {
|
67
|
+
var response = JSON.parse(httpRequest.responseText);
|
68
|
+
funcProcessData(response, dataList);
|
69
|
+
} else {
|
70
|
+
console.error("Unable to autocomplete! ElementId: " + this.element_id);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
};
|
74
|
+
console.log('GET:' + url);
|
75
|
+
httpRequest.open('GET', url, true);
|
76
|
+
httpRequest.send();
|
77
|
+
}
|
78
|
+
|
79
|
+
populateOptions(response, dataList) {
|
80
|
+
dataList.innerHTML = "";
|
81
|
+
|
82
|
+
response.forEach(function (item) {
|
83
|
+
var value = item;
|
84
|
+
var key = null;
|
85
|
+
if (Array.isArray(item)) {
|
86
|
+
value = item[0];
|
87
|
+
key = item[1];
|
88
|
+
}
|
89
|
+
// Create a new <option> element.
|
90
|
+
var option = document.createElement('option');
|
91
|
+
option.value = value;
|
92
|
+
option.dataset.key = key;
|
93
|
+
dataList.appendChild(option);
|
94
|
+
});
|
95
|
+
}
|
96
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import {VErrors} from './errors';
|
2
|
+
import {VUrls} from '../../utils/urls';
|
3
|
+
|
4
|
+
export class VBase extends VUrls {
|
5
|
+
constructor(options) {
|
6
|
+
super();
|
7
|
+
this.options = options;
|
8
|
+
}
|
9
|
+
|
10
|
+
clearErrors() {
|
11
|
+
new VErrors().clearErrors();
|
12
|
+
}
|
13
|
+
|
14
|
+
parentElement() {
|
15
|
+
return document.getElementById(this.options.__parent_id__);
|
16
|
+
}
|
17
|
+
|
18
|
+
inputValues(form) {
|
19
|
+
var params = [];
|
20
|
+
// Let input component push parameters
|
21
|
+
var vComp = this.component();
|
22
|
+
if (vComp) {
|
23
|
+
vComp.prepareSubmit(form, params);
|
24
|
+
}
|
25
|
+
return params;
|
26
|
+
}
|
27
|
+
|
28
|
+
component() {
|
29
|
+
let parent = this.parentElement();
|
30
|
+
return parent ? this.parentElement().vComponent : null;
|
31
|
+
}
|
32
|
+
|
33
|
+
validate() {
|
34
|
+
var errors = [];
|
35
|
+
var comp = this.component();
|
36
|
+
if (comp) {
|
37
|
+
errors = comp.validate();
|
38
|
+
}
|
39
|
+
return errors;
|
40
|
+
}
|
41
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
export class VDialog {
|
2
|
+
constructor(options, params, event) {
|
3
|
+
this.dialogId = options.target;
|
4
|
+
this.params = params;
|
5
|
+
this.event = event;
|
6
|
+
}
|
7
|
+
|
8
|
+
call(results) {
|
9
|
+
var dialog = document.querySelector('#' + this.dialogId);
|
10
|
+
if(dialog) {
|
11
|
+
if (!dialog.showModal) {
|
12
|
+
dialogPolyfill.registerDialog(dialog);
|
13
|
+
}
|
14
|
+
|
15
|
+
dialog.showModal();
|
16
|
+
}else {
|
17
|
+
console.error("Unable to find dialog with id: "+this.dialogId+". Usually this means you forgot to attach it to the currently rendered page.");
|
18
|
+
}
|
19
|
+
var promiseObj = new Promise(function (resolve) {
|
20
|
+
results.push({action:'dialog', statusCode: 200});
|
21
|
+
resolve(results);
|
22
|
+
});
|
23
|
+
return promiseObj;
|
24
|
+
}
|
25
|
+
}
|
@@ -0,0 +1,142 @@
|
|
1
|
+
export class VErrors {
|
2
|
+
constructor(event) {
|
3
|
+
this.event = event;
|
4
|
+
}
|
5
|
+
|
6
|
+
clearErrors() {
|
7
|
+
var errorMessages = document.querySelectorAll('.v-error-message');
|
8
|
+
|
9
|
+
for (var i = 0; i < errorMessages.length; i++) {
|
10
|
+
errorMessages[i].remove();
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
// Rails errors
|
15
|
+
// {
|
16
|
+
// "name": [
|
17
|
+
// "Requires name"
|
18
|
+
// ]
|
19
|
+
// }
|
20
|
+
|
21
|
+
// Validation errors
|
22
|
+
// { :email => ["must be filled"] }
|
23
|
+
|
24
|
+
// Custom errors
|
25
|
+
// { :email => "must be filled" }
|
26
|
+
|
27
|
+
// Exceptions
|
28
|
+
// {exception: 'Something bad happened' }
|
29
|
+
|
30
|
+
stringsToArrays(value) {
|
31
|
+
if (Array.isArray(value) || value.constructor === Object) {
|
32
|
+
return value;
|
33
|
+
}
|
34
|
+
return new Array(value);
|
35
|
+
}
|
36
|
+
|
37
|
+
normalizeErrors(errors) {
|
38
|
+
if (errors && errors.constructor === Object) {
|
39
|
+
return Object.keys(errors).reduce((previous, key) => {
|
40
|
+
previous[key] = this.stringsToArrays(errors[key]);
|
41
|
+
return previous;
|
42
|
+
}, {});
|
43
|
+
}
|
44
|
+
return [];
|
45
|
+
}
|
46
|
+
|
47
|
+
// [http_status, content_type, resultText]
|
48
|
+
displayErrors(result) {
|
49
|
+
var httpStatus = result.statusCode;
|
50
|
+
var contentType = result.contentType;
|
51
|
+
var resultText = result.content;
|
52
|
+
|
53
|
+
var responseErrors = null;
|
54
|
+
|
55
|
+
if (contentType && contentType.indexOf("application/json") !== -1) {
|
56
|
+
responseErrors = JSON.parse(resultText);
|
57
|
+
} else if (contentType && contentType.indexOf("v/errors") !== -1) {
|
58
|
+
responseErrors = resultText;
|
59
|
+
}
|
60
|
+
|
61
|
+
if (responseErrors) {
|
62
|
+
if (!Array.isArray(responseErrors)) {
|
63
|
+
responseErrors = [responseErrors];
|
64
|
+
}
|
65
|
+
for (var response of responseErrors) {
|
66
|
+
var pageErrors = Object.values(this.normalizeErrors(response)).reduce(function (previous, value) {
|
67
|
+
if (Array.isArray(value)) {
|
68
|
+
previous.push(value.join('<br/>'));
|
69
|
+
}
|
70
|
+
return previous;
|
71
|
+
}, []);
|
72
|
+
var fieldErrors = this.normalizeErrors(response.errors);
|
73
|
+
|
74
|
+
for (var field in fieldErrors) {
|
75
|
+
if (!this.displayInputError(field, fieldErrors[field])) {
|
76
|
+
// Collect errors that can't be displayed at the field level
|
77
|
+
pageErrors.push(fieldErrors[field]);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
this.prependErrors(pageErrors);
|
81
|
+
}
|
82
|
+
} else if (httpStatus === 0) {
|
83
|
+
this.prependErrors(["Unable to contact server. Please check that you are online and retry."]);
|
84
|
+
} else {
|
85
|
+
this.prependErrors(["The server returned an unexpected response! Status:" + httpStatus]);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
// Sets the helper text on the field
|
90
|
+
// Returns true if it was able to set the error on the control
|
91
|
+
displayInputError(divId, messages) {
|
92
|
+
var currentEl = document.getElementById(divId);
|
93
|
+
if (currentEl && currentEl.mdcComponent) {
|
94
|
+
currentEl.mdcComponent.helperTextContent = messages.join(', ');
|
95
|
+
var helperText = document.getElementById(divId + '-input-helper-text');
|
96
|
+
helperText.classList.add('mdc-text-field--invalid',
|
97
|
+
'mdc-text-field-helper-text--validation-msg',
|
98
|
+
'mdc-text-field-helper-text--persistent');
|
99
|
+
currentEl.mdcComponent.valid = false;
|
100
|
+
return true;
|
101
|
+
}
|
102
|
+
return false;
|
103
|
+
}
|
104
|
+
|
105
|
+
// Creates a div before the element with the same id as the error
|
106
|
+
// Used to display an error message without their being an input field to attach the error to
|
107
|
+
prependErrors(messages) {
|
108
|
+
var errorsDiv = this.findNearestErrorDiv();
|
109
|
+
// create a new div element
|
110
|
+
var newDiv = document.createElement("div");
|
111
|
+
newDiv.className = 'v-error-message';
|
112
|
+
// and give it some content
|
113
|
+
|
114
|
+
for (var message of messages) {
|
115
|
+
var newContent = document.createTextNode(message);
|
116
|
+
newDiv.appendChild(newContent);
|
117
|
+
let br = document.createElement('br');
|
118
|
+
// add the text node to the newly created div
|
119
|
+
newDiv.appendChild(br);
|
120
|
+
}
|
121
|
+
|
122
|
+
// add the newly created element and its content into the DOM
|
123
|
+
if (errorsDiv) {
|
124
|
+
errorsDiv.parentElement.insertBefore(newDiv, errorsDiv);
|
125
|
+
return true;
|
126
|
+
} else {
|
127
|
+
console.error("Unable to display Errors! ", messages);
|
128
|
+
}
|
129
|
+
return false;
|
130
|
+
}
|
131
|
+
|
132
|
+
findNearestErrorDiv() {
|
133
|
+
let errorsDiv = null;
|
134
|
+
const currentDiv = this.event.target;
|
135
|
+
if(currentDiv) {
|
136
|
+
errorsDiv = currentDiv.closest('.v-errors')
|
137
|
+
}else{
|
138
|
+
errorsDiv = document.querySelector('.v-errors');
|
139
|
+
}
|
140
|
+
return errorsDiv;
|
141
|
+
}
|
142
|
+
}
|