1
votes

It's pretty easy to get a Twitter Bootstrap modal working in XPages just by following the examples in the site. However, it doesn't seem to work if you want to use SSJS to affect the contents of the modal before it gets displayed. It seems to flash, and often just shows the background.

It seems to be a problem with using XPages Full or Partial refresh.

I've tried getting it to work "normally" and I've tried using jQuery and a Remote Service to get the change in with no luck.

Below is the code with the remote service.

Any examples on how to affect or refresh the modal contents prior to showing the dialog would be appreciated.

<?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"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xc:layout_Header></xc:layout_Header>
<xp:link escape="true" text="Link" id="link1" value="#myModal">
    <xp:this.attrs>
        <xp:attr name="role" value="button"></xp:attr>
        <xp:attr name="data-toggle" value="modal"></xp:attr>
    </xp:this.attrs>

</xp:link>
<xp:br></xp:br>

<xp:panel id="myPanel">
    <xc:bs_Modal idName="myModal">
        <xp:this.facets>
            <xp:panel xp:key="facet_1">
                My Dialog
                <xp:br></xp:br>
                <xp:br></xp:br>
                Time



                <xp:text escape="true" id="computedField1"
                    value="#{viewScope.vsTime}">
                    <xp:this.converter>
                        <xp:convertDateTime type="both"></xp:convertDateTime>
                    </xp:this.converter>
                </xp:text>
            </xp:panel>
        </xp:this.facets>
    </xc:bs_Modal>
</xp:panel>
<xp:br></xp:br>


<xe:jsonRpcService id="jsonRpcService1" serviceName="testService">
    <xe:this.methods>
        <xe:remoteMethod name="setTime">
            <xe:this.script><![CDATA[viewScope.put("vsTime", @Now())]]></xe:this.script>
        </xe:remoteMethod>
    </xe:this.methods></xe:jsonRpcService>
<xp:br></xp:br>
<xp:scriptBlock id="scriptBlock1">
    <xp:this.value><![CDATA[$('#myModal').on('show', function () {
testService.setTime();
var id =  "#{id:myPanel}"
XSP.partialRefreshGet(id)
})]]></xp:this.value>
</xp:scriptBlock></xp:view>
3
try using the oncomplete event of partial refresh to trigger the modal dialog, making the contents available before triggering the modalvikki_logs

3 Answers

0
votes

Since it already integrates completely with XPages, I'd use the <xe:dialog> from the Extension Library instead and modify that (adding/ removing classes) to make it look like a Bootstrap modal.

Here's some sample code to get you started:

<xe:dialog id="dialog1" title="Dialog title" styleClass="modal" style="margin-left: inherit">

    <xe:this.onShow>
        <![CDATA[//make the dialog look like a Bootstrap dialog using some jQuery magic

    //add the modal-header class to the title bar
    var titleBar = $(".modal .dijitDialogTitleBar").addClass("modal-header");

//replace title node (by default it's a span)
var titleNode = $(".dijitDialogTitle", titleBar);
var title = titleNode.text();
titleNode.remove();

//add a class to the close icon
$(".dijitDialogCloseIcon", titleBar).removeClass("dijitDialogCloseIcon").addClass("close");

//add a new h3 node with the title 
titleBar.append("<h3>" + title + "</h3>");
        ]]>
    </xe:this.onShow>

    <xe:dialogContent id="dialogContent1" styleClass="modal-body">
        dialog content here
    </xe:dialogContent>

    <xe:dialogButtonBar id="dialogButtonBar1" styleClass="modal-footer">
        <xp:button value="Close" id="button2"></xp:button>
    </xe:dialogButtonBar>

</xe:dialog>
0
votes

Make the modal contents available before triggering the modal, incase of things to happen after showing the modal dialog we can use the callback function option.

var id =  "#{id:myPanel}"
XSP.partialRefreshGet(id,{
    onComplete: function(){
    $('#myModal').modal('show');
    }
});
0
votes

I solve this problem in complex. After issue with save exist NotesXspDocument after partial refresh.

It works for me, maybe it is help for you.

1) Create template html for Dialog in WebContent folder, example WebContent/templates/CustomDialog.html:

<div class="modal fade" tabindex="-1" waiRole="dialog" waiState="labelledby-${id}_title" data-backdrop="static" data-keyboard="false">
    <div role="document" class="modal-dialog">
        <div class="modal-content">
            <div dojoAttachPoint="titleBar" class="modal-header">
                <span dojoAttachPoint="closeButtonNode">
                    <button type="button" title="${buttonCancel}" class="close" aria-hidden="true" dojoAttachEvent="onclick: onCancel">&times;</button>
                </span>
                <h4 class='modal-title' dojoAttachPoint="titleNode" id="${id}_title"></h4>
            </div>
            <div dojoAttachPoint="containerNode"></div>
        </div>
    </div>
</div>

2) Create csjs library with code:

dojo.provide("extlib.responsive.dijit.xsp.bootstrap.Dialog");
dojo.require("extlib.dijit.Dialog");
dojo.declare(
        "extlib.responsive.dijit.xsp.bootstrap.Dialog",
        extlib.dijit.Dialog,
        {
            baseClass: "",
            templateString: dojo.cache(new dojo._Url("templates/CustomDialog.html")),
            draggable: false,
            autofocus:false,
            iframePost: false,
            modalStyleClass: "",
            show: function() {
            if(this.open){
                return;
            }

            if(!this._started){
                this.startup();
            }

            // first time we show the dialog, there's some initialization stuff to do
            if(!this._alreadyInitialized){
                this._setup();
                this._alreadyInitialized = true;
            }

            // Recenter Dialog if user scrolls browser.  Connecting to document doesn't work on IE, need to use window.
            var win = dojo.window.get(this.ownerDocument);
            //this._modalconnects.push(dojo.on(win, "scroll", dojo.hitch(this, "resize")));
            this._modalconnects.push(dojo.on(this.domNode, "keydown", dojo.hitch(this, "_onKey")));

            dojo.style(this.domNode, {
                display: "",
                position: "",
                top: "",
                left: ""
            });

            this._set("open", true);
            this._onShow(); // lazy load trigger
            this._size();
            this._position();

            var node = $(this.domNode);
            if(this.modalStyleClass) node.children(".modal-dialog").addClass(this.modalStyleClass);
            node.modal('show').on('shown.bs.modal', dojo.hitch(this, function() {
                if(this.autofocus) this.focus();
            }));
            if(this.iframePost) {
                this.xhrPost = dojo.xhrPost;
                dojo.xhrPost = function(o) {
                    dojo.require("dojo.io.iframe");
                    o.handleAs = "html";
                    var load = o.load; 
                    o.load = function(response, ioArgs) {
                        load(response.body.innerHTML, ioArgs);
                    }
                    dojo.io.iframe.send(o)
                }       
            }
        },
        hide: function() {
            if(this.iframePost) {
                dojo.xhrPost = this.xhrPost;
            }

            if(!this._alreadyInitialized || !this.open){
                return;
            }

            if(this._scrollConnected){
                this._scrollConnected = false;
            }
            var h;
            while(h = this._modalconnects.pop()){
                h.remove();
            }

            if(this._relativePosition){
                delete this._relativePosition;
            }
            this._set("open", false);

            return $(this.domNode).modal('hide');
        },
        resize: function() {},
        _size: function() {},
        _position: function() {},
        destroy: function() {
            var h;
            while(h = this._modalconnects.pop()){
                h.remove();
            }
            $('body').removeClass('modal-open');
            $('.modal-backdrop').remove();
            this.inherited(arguments);}
        }
        }
);

XSP._dialog_type = "extlib.responsive.dijit.xsp.bootstrap.Dialog";

(big part of code i get from Extension Library)

Now we are have bootstrap dialog by dijit widget. This is called by XSP.openDialog and XSP.closeDialog, and work SSJS code

NOTE: if you need modal-lg or modal-sm dialog, then add to <xe:dialog> dojo attribute modalStyleClass(see in step 2) with value modal-lg