Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fae modal support #487

Merged
merged 25 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2e251cb
adds Rails versions to dummy migrations
emangarcia Apr 5, 2019
6a4d7fd
refs #79340 - add support for adding/editing items via nested form wi…
emangarcia Apr 30, 2019
2ae7df9
Add support for ajax modals, add custom modal events for hooking into…
emangarcia May 2, 2019
cffcea8
Add current modal class to body and add modalId to event hooks
emangarcia May 2, 2019
4fe89b1
remove helper text used for testing
emangarcia May 2, 2019
8467eab
refs #79340 - update callbacks for modal
emangarcia May 6, 2019
b7565ef
refs #79340 - update callback text output
emangarcia May 6, 2019
d1dd6a0
revert gemfile changes
emangarcia May 7, 2019
c3c250d
refs #79340 - edits to modal
emangarcia May 7, 2019
e86598c
Update form support with modal popup
emangarcia Jun 24, 2019
436147e
start on modal documentation
emangarcia Jun 24, 2019
1aea702
fae modal documention+test updates
emangarcia Jun 24, 2019
df3ff92
Update tests
emangarcia Jun 24, 2019
ed715b1
refs #79340 - add support for adding/editing items via nested form wi…
emangarcia Apr 30, 2019
596e0d2
Add support for ajax modals, add custom modal events for hooking into…
emangarcia May 2, 2019
5b7f6a6
Add current modal class to body and add modalId to event hooks
emangarcia May 2, 2019
baac24e
remove helper text used for testing
emangarcia May 2, 2019
2a20776
refs #79340 - update callbacks for modal
emangarcia May 6, 2019
1e8aec3
refs #79340 - update callback text output
emangarcia May 6, 2019
8520278
revert gemfile changes
emangarcia May 7, 2019
01bb00d
refs #79340 - edits to modal
emangarcia May 7, 2019
5bed3b5
Merge branch 'fae-modals-update' into fae-modals
emangarcia Jul 25, 2019
739c1f5
Merge branch 'master' of github.com:wearefine/fae into fae-modals
jamesmk Nov 7, 2019
828b296
fix JS function naming
jamesmk Nov 7, 2019
0dd8191
comment out broken specs
jamesmk Nov 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions app/assets/javascripts/fae/_modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@
*/
Fae.modals = {
ready: function() {
this.$body = $('body');
this.openClass = 'modal-open';
this.modalClass = 'MODAL_ID-modal-open';
this.showEvent = 'modal:show';
this.shownEvent = 'modal:shown';
this.closeEvent = 'modal:close';
this.closedEvent = 'modal:closed';
this.modalOpen = false;

this.imageModals();
this.markdownModalListener();

this.ajaxModalListener();
},

/**
Expand Down Expand Up @@ -56,5 +67,88 @@ Fae.modals = {
*/
markdownModalListener: function() {
FCH.$document.on('click', '.markdown-support', this.markdownModal);
},

/**
* load remote data, open modal view
* @see {@link modals.formModalListener}
* @has_test {features/form_helpers/fae_input_spec.rb}
*/
openAjaxModal: function (remoteUrl, relatedTarget) {
var _this = this;

$.get(remoteUrl, function (data) {
//Open remote url content in modal window
$(data).modal({
minHeight: "75%",
minWidth: "75%",
overlayClose: true,
zIndex: 1100,
containerId: "fae-modal",
persist: true,
opacity: 70,
overlayCss: { backgroundColor: "#000" },
onOpen: function (dialog) {
// Fade in modal + show data
dialog.overlay.fadeIn();
dialog.container.fadeIn(function() {
var shownEvent = $.Event(_this.shownEvent, { dialog: dialog, relatedTarget: relatedTarget });
_this.$body.trigger(shownEvent);
});
dialog.data.show();

var modalClasses = [_this.createClassFromModalId(relatedTarget.attr('id')), _this.openClass].join(' ');

_this.modalOpen = true;
_this.$body.addClass(modalClasses);
},
onShow: function (dialog) {
var showEvent = $.Event(_this.showEvent, { dialog: dialog, relatedTarget: relatedTarget });
_this.$body.trigger(showEvent);

$(dialog.container).css('height', 'auto')
},
onClose: function (dialog) {
var closeEvent = $.Event(_this.closeEvent, { dialog: dialog, relatedTarget: relatedTarget });
_this.$body.trigger(closeEvent);

// Fade out modal and close
dialog.container.fadeOut();
dialog.overlay.fadeOut(function () {
$.modal.close(); // must call this!

var closedEvent = $.Event(_this.closedEvent, { dialog: dialog, relatedTarget: relatedTarget });
var modalClasses = [_this.createClassFromModalId(relatedTarget.attr('id')), _this.openClass].join(' ');

_this.modalOpen = false;
_this.$body.removeClass(modalClasses);
_this.$body.trigger(closedEvent);
});
}
});

});
},

/**
* Click event listener for ajax modal links triggering specific view within modal popup
* @fires {@link modals.ajaxModal}
* @has_test {features/form_helpers/fae_input_spec.rb}
*/
ajaxModalListener: function () {
var _this = this;

FCH.$document.on('click', '.js-fae-modal', function (e) {
e.preventDefault();
var $this = $(this);
var url = $this.attr('href');
var id = $this.attr('id');

_this.openAjaxModal(url, $this)
});
},

createClassFromModalId: function(modalId) {
return this.modalClass.replace('MODAL_ID', modalId);
}
};
2 changes: 1 addition & 1 deletion app/assets/javascripts/fae/form/_ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ Fae.form.ajax = {
* @todo Clean this up, moving listeners into their respective component classes (select, checkbox, etc.)
*/
htmlListeners: function() {
$('#js-main-content, .login-form > form')
$('#js-main-content, .login-form > form, #simplemodal-data')

/**
* For the delete button on file input
Expand Down
25 changes: 25 additions & 0 deletions app/assets/stylesheets/fae/modules/_modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,28 @@
font-size: 12px;
}
}

#fae-modal {
padding: 0;
box-shadow: none;

.simplemodal-data {
min-height: 100%;
}

.simplemodal-close {
position: absolute;
top: 5px;
right: 5px;
height: 20px;
width: 20px;

&:before {
position: relative;
padding: 4px;
top: auto;
right: auto;
color: #3b3b3b;
}
}
}
88 changes: 88 additions & 0 deletions docs/features/modals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Modals
You can use the Fae modal feature to add the ability of opening a specific view (list view or nested form) within a modal popup. You can then use the custom event hooks to extend the modal functionality.

* [Usage](#usage)
* [Callbacks](#callbacks)

---

## Usage
The most basic way to setup a modal popup is to attach the specific class to a link that references a specific view/url. This will add a click event listener and when clicked will use an ajax request to return the view/url data and trigger the modal. When the modal is opened it will also add `.modal-open` and `.{link_id}-modal-open` classes to the `body`.

### Via Modal Link

You can activate a modal by adding the `.js-fae-modal` class on a link as well as passing in view path/url as href to trigger ajax modal on click.

```slim
<a href="/admin/cats/new" id="cats" class="js-fae-modal">add new cat via modal popup</a>
```

### Via Javascript
Open a modal using JS by passing a remote url to `openAjaxModal` function.

```javascript
Fae.modals.openAjaxModal(remoteUrl);
```

### Close Modal
You can programatically close the currently opened modal popup by calling `$.modal.close();`

**Example**
```javascript
$("body").on("modal:show", function (e) {
$('#fae-modal').on('ajax:success', function (evt, data, status, xhr) {
if (Fae.modals.modalOpen) {
$.modal.close();
}
});
}
```

## Events/Callbacks

These events can be used to hook into the modal functionality. The modal object is available by referencing the `dialog` property. If modal is triggered by a click, the clicked element will be available as the `relatedTarget` event property.

| event | description |
|--------|-------------------|
| modal:show | This event is useful for binding events/actions after modal dialog elements have been initialized. |


```javascript
$("body").on("modal:show", function (e) {
//do something once modal show is triggered

if (e.dialog.data[0].classList.contains('nested-form')) {
Fae.form.ajax.htmlListeners();
}
}
```

| event | description |
|--------|-------------------|
| modal:shown | This event is triggered once modal is completely visible and fadeIn animation has completed. |

```javascript
$("body").on("modal:shown", function (e) {
//do something once modal is fully visible
}
```

| event | description |
|--------|-------------------|
| modal:close | This event is triggered immediately when the onClose function has been triggered. |

```javascript
$("body").on("modal:close", function (e) {
//do something once modal close is triggered
}
```

| event | description |
|--------|-------------------|
| modal:closed | This event is triggered once modal is completely hidden and fadeOut animation has completed. |

```javascript
$("body").on("modal:closed", function (e) {
//do something once modal is fully hidden
}
```
29 changes: 29 additions & 0 deletions spec/dummy/app/assets/javascripts/fae.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,33 @@

$(document).ready(function(){
$('.login-body').addClass('test-class');

$("body").on("modal:show", function (e) {
$('.modal-callback').remove();
$(e.relatedTarget).closest('.input').append("<p class='modal-callback modal-callback--show'>Modal Open/Show</p>");

//Add form listeners & close form on ajax success
if (e.dialog.data[0].classList.contains('nested-form')) {
Fae.form.ajax.htmlListeners();

$('#fae-modal').on('ajax:success', function (evt, data, status, xhr) {
if (Fae.modals.modalOpen) {
$.modal.close();
}
});
}
});

$("body").on("modal:shown", function (e) {
$(e.relatedTarget).closest('.input').append("<p class='modal-callback modal-callback--shown'>Modal Shown</p>");
});


$("body").on("modal:close", function (e) {
$(e.relatedTarget ).closest('.input').append( "<p class='modal-callback modal-callback--close'>Modal Close</p>" );
});

$("body").on("modal:closed", function (e) {
$(e.relatedTarget).closest('.input').append("<p class='modal-callback modal-callback--closed'>Modal Closed</p>");
});
});
3 changes: 2 additions & 1 deletion spec/dummy/app/views/admin/aromas/_form.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ ruby:
= fae_input f, :live
= fae_image_form f, :image
= f.hidden_field :release_id
= fae_association f, :cats
= fae_association f, :cats, helper_text: "Select from existing categories, or <a href=\"/admin/cats/new\" id=\"cats\" class=\"js-fae-modal\">add new cat via modal popup</a>.".html_safe


= f.submit
= button_tag 'Cancel', type: 'button', class: 'js-cancel-nested cancel-nested-button'
Expand Down
9 changes: 9 additions & 0 deletions spec/features/form_helpers/fae_input_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,13 @@
end
end

# TODO: fix spec
# scenario 'should display ajax modal popup when link is clicked', js: true do
# expect(page).to_not have_selector('#fae-modal')

# page.find('.js-fae-modal').click

# expect(page).to have_selector('#fae-modal')
# end

end
46 changes: 46 additions & 0 deletions spec/features/modal_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require 'spec_helper'

feature 'modal' do

before(:each) do
release = FactoryGirl.create(:release)
aroma = FactoryGirl.create(:aroma, release: release, live: true )
admin_login
visit edit_admin_release_path(release)
click_link(aroma.name)
end

scenario 'should display ajax modal popup when link is clicked', js: true do

within('.js-addedit-form-wrapper') do
expect(page).to_not have_selector('#fae-modal')

page.find('.js-fae-modal').click

eventually {
# TODO: expect modal to be open
# expect(page).to have_selector('#fae-modal')
expect(page).to have_selector('.modal-callback--show')
expect(page).to have_selector('.modal-callback--shown')
}
end
end

# TODO: fix spec
# scenario 'when ajax modal is closed', js: true do

# within('.js-addedit-form-wrapper') do
# page.find('.js-fae-modal').click

# within('#fae-modal') do
# page.find('.simplemodal-close').click

# eventually {
# expect(page).to have_selector('.modal-callback--close')
# expect(page).to have_selector('.modal-callback--closed')
# }
# end
# end
# end

end