Monday, 25 May 2015

Bootstrap JS Modal plugin in XPages: Stackable Modals using the Bootstrap-Modal jQuery plugin

In the previous blog post, Bootstrap JS Modal plugin in XPages: Trigger via JavaScript-including Modal Options, I showed how the Bootstrap JS Modal can be triggered via JavaScript-including some Modal Options. In this blog post I will show how the Bootstrap JS Modal can be extended with the Bootstrap-Modal plugin. In the example below I use a button to display Stackable Modals.
Bootstrap-Modal is a jQuery plugin that extends Bootstrap’s native Modals to provide additional functionality. Introduces a ModalManager class that operates behind the scenes to handle multiple modals by listening on their events. The Bootstrap-Modal plugin has the following features :

- Backwards compatible.
- Responsive.
- Stackable.
- Full width.
- Load content via AJAX.
- Disable background scrolling

In addition to the standard Bootstrap options, the Bootstrap-Modal plugin provides the following additional Modal options.

width Set the initial width of the modal
height Set the initial height of the modal
maxHeight Set the max-height of the modal-body
loading Toggle the loading state
spinner Provide a custom image or animation for the loading spinner
backdropTemplate Provide a custom modal backdrop
consumeTab Used to enable tabindexing for modals with data-tabindex. This is set to true by default
focusOn The element or selector to set the focus to once the modal is shown
replace If set to true, the modal will replace the topmost modal when opened
attentionAnimation Set the animation used by the attention method. Any animation in animate.css is supported but only the shake animation is included by default
modalOverflow Set this property to true for modals with highly dynamic content. This will force the modal to behave as if it is larger than the viewport
manager Set the modal's manager. By default this is set to the GlobalModalManager and will most likely not need to be overridden

The Bootstrap-Modal plugin provides the following additional ModalMamager options.

loading Toggle the loading state
backdropLimit Limit the amount of backdrops that will appear on the page at the same time
spinner Provide a custom image or animation for the loading spinner
backdropTemplate Provide a custom modalmanager backdrop. This backdrop is used when $element.modalmanager('loading') is called

To use the Bootstrap-modal plugin in XPages first we have to add the css and js files to the WebContent Folder in the Package Explorer. For this purpose I created a Folder 'bootstrapmodal'.


Important: if you are using Bootstrap 3 include the patch file, bootstrap-modal-bs3patch.css, before bootstrap modal.

Next we need to include  the js and css files on the XPage / Custom Control. In this example I include all files on an XPage.

<xp:this.resources>
<xp:styleSheet href="/bootstrap-modal-bs3patch.css"></xp:styleSheet>
<xp:styleSheet href="/bootstrap-modal.css"></xp:styleSheet>
</xp:this.resources>
<script type="text/javascript" src="bootstrapmodal/js/bootstrap-modal.js"></script>
<script type="text/javascript" src="bootstrapmodal/js/bootstrap-modalmamager.js"></script>

Furthermore we need the the great XSnippet by Mark Roden, x$ jQuery selector for XPages, to initialize the plugin and include it on the Custom Control / XPage. You can add the XSnippet to the Script Libraries.


<xp:this.resources>
<xp:script src="/JQueryXSnippet.js" clientSide="true"></xp:script>
</xp:this.resources>

The script itself can be made up as follows. The name of the ids in the script must correspond with the id of the Button and the id of the (first)Modal.

<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
$(document).ready(function(){
x$("#{id:button1}").click(function(){
x$("#{id:Modal1}").modal(
{backdrop: true,
keyboard: false,
show: true
}
);
});
});
]]></xp:this.value>

The last step is to create the button and the Stackable Modals.

<!-- Show the modal via a button in an XPage / Custom Control -->
<xp:button value="Open Modal" id="button1" styleClass="btn btn-info btn-lg">
</xp:button>

<!-- Modal 1 -->
<div id="Modal1" class="modal fade" tabindex="-1" data-focus-on="input:first" style="display: none;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal One</h4>
</div>
<div class="modal-body">
<p>Modal 1 - triggered via JavaScript including some Modal Options.</p>
<div class="form-group">
<label for="inputText1">First Name:</label>
<xp:inputText id="inputText1">
<xp:this.attrs>
<xp:attr name="class" value="form-control"></xp:attr>
<xp:attr name="data-tabindex" value="1"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText2">Last Name:</label>
<xp:inputText id="inputText2">
<xp:this.attrs>
<xp:attr name="class" value="form-control"></xp:attr>
<xp:attr name="data-tabindex" value="2"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText5">Address:</label>
<xp:inputText id="inputText5">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="3"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText6">Country:</label>
<xp:inputText id="inputText6">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="4"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<button class="btn btn-primary" data-toggle="modal"  href="#Modal2">Launch Modal 2</button>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-primary">Close</button>
</div>
</div>


<!-- Modal 2 -->
<div id="Modal2" class="modal fade" tabindex="-1" data-focus-on="input:first" style="display: none;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal Two</h4>
</div>
<div class="modal-body">
<p>Modal 2</p>
<div class="form-group">
<label for="inputText3">Company:</label>
<xp:inputText id="inputText3">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="1"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText4">Email:</label>
<xp:inputText id="inputText4">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="2"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<button class="btn btn-primary" data-toggle="modal"  href="#Modal3">Launch Modal 3</button>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Close</button>
</div>
</div>


<!-- Modal 3 -->
<div id="Modal3" class="modal fade" tabindex="-1" data-focus-on="input:first" style="display: none;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal Three</h4>
</div>
<div class="modal-body">
<p>Modal 3</p>
<div class="form-group">
<label for="inputText7">Bootstrap JS Modal:</label>
<xp:inputText id="inputText7">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="1"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Close</button>
</div>
</div>

The final result: Stackable Bootstrap Modals.


Code XPage
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.resources>
<xp:styleSheet href="/bootstrap-modal-bs3patch.css"></xp:styleSheet>
<xp:styleSheet href="/bootstrap-modal.css"></xp:styleSheet>
<xp:script src="/JQueryXSnippet.js" clientSide="true"></xp:script>
</xp:this.resources>
<script type="text/javascript" src="bootstrapmodal/js/bootstrap-modal.js"></script>
<script type="text/javascript" src="bootstrapmodal/js/bootstrap-modalmanager.js"></script>
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
 $(document).ready(function(){
 x$("#{id:button1}").click(function(){
 x$("#{id:Modal1}").modal(
{backdrop: true,
keyboard: false,
show: true
}
);
});
});
]]></xp:this.value>
</xp:scriptBlock>
<xc:ccLayoutBootstrap><xp:this.facets>
<xp:panel xp:key="facetMiddle">
<xp:this.attrs>
<xp:attr name="data-toggle" value="modal"></xp:attr>
</xp:this.attrs>
<xp:br></xp:br>
<!-- Show the modal via a button in an XPage / Custom Control -->
<xp:button value="Open Modal" id="button1" styleClass="btn btn-info btn-lg"></xp:button>
<xp:br></xp:br>
<!-- Modal 1 -->
<div id="Modal1" class="modal fade" tabindex="-1" data-focus-on="input:first" style="display: none;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal One</h4>
</div>
<div class="modal-body">
<p>Modal 1 - triggered via JavaScript including some Modal Options.</p>
<div class="form-group">
<label for="inputText1">First Name:</label>
<xp:inputText id="inputText1">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="1"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText2">Last Name:</label>
<xp:inputText id="inputText2">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="2"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText5">Address:</label>
<xp:inputText id="inputText5">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="3"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText6">Country:</label>
<xp:inputText id="inputText6">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="4"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<button class="btn btn-primary" data-toggle="modal" href="#Modal2">Launch Modal 2</button>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-primary">Close</button>
</div>
</div>
<!-- Modal 2 -->
<div id="Modal2" class="modal fade" tabindex="-1" data-focus-on="input:first" style="display: none;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal Two</h4>
</div>
<div class="modal-body">
<p>Modal 2</p>
<div class="form-group">
<label for="inputText3">Company:</label>
<xp:inputText id="inputText3">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="1"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class="form-group">
<label for="inputText4">Email:</label>
<xp:inputText id="inputText4">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="2"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<button class="btn btn-primary" data-toggle="modal" href="#Modal3">Launch Modal 3</button>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Close</button> </div>
</div>
<!-- Modal 3 -->
<div id="Modal3" class="modal fade" tabindex="-1" data-focus-on="input:first" style="display: none;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal Three</h4>
</div>
<div class="modal-body">
<p>Modal 3</p>
<div class="form-group">
<label for="inputText7">Bootstrap JS Modal:</label>
<xp:inputText id="inputText7">
<xp:this.attrs>
<xp:attr name="class" value="form-control">
</xp:attr>
<xp:attr name="data-tabindex" value="1"></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-default">Close</button>
</div>
</div>
</xp:panel>
</xp:this.facets>
</xc:ccLayoutBootstrap>
</xp:view>

The Bootstrap-Modal jQuery plugin can be downloaded from GitHub: Bootstrap-Modal Plugin

No comments:

Post a Comment