I'm trying to use the library docxtemplater in an XPages application.
Javascript library docxtemplater (https://docxtemplater.com/) use as a
dependency another library opensource jszip-utils.js
(http://stuk.github.io/jszip/) to zip and unzip the docx files.
The problem is that the javascript library jszip-utils.js in XPages is not
working .
I inserted javascript libraries in a folder (jslib) who is under the WebContent folder.
Here's my test page;
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<script src="jslib/main.min.js"></script>
<script src="jslib/angular-expressions.js"></script>
<script src="jslib/jszip.js"></script>
<script src="jslib/jszip-utils.js"></script>
<script src="jslib/FileSaver.min.js"></script>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[
var loadFile=function(url,callback){
JSZipUtils.getBinaryContent(url,callback);
}
loadFile("tagExample.docx",function(err,content){
doc=new DocxGen(content)
doc.setData( {"first_name":"Hipp",
"last_name":"Edgar",
"phone":"0652455478",
"description":"New Website",
"image":'image.png'
}
) //set the templateVariables
doc.render() //apply them (replace all occurences of {first_name} by Hipp, ...)
out=doc.getZip().generate({type:"blob"}) //Output the document using Data-URI
saveAs(out,"output.docx")
})]]></xp:this.script>
</xp:eventHandler></xp:button>
</xp:view>
Has anyone dealt with the problem?
It is an AMD loader issue. It conflicts with XPage's Dojo.
Use this XSnippet for workaround.
Your code would look like this then:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.resources>
<!-- temporary redefine define.amd object (Dojo AMD loader) -->
<xp:script clientSide="true" type="text/javascript">
<xp:this.contents><![CDATA[${javascript:"if (typeof define === 'function' && define.amd) {if(define.amd.vendor =='dojotoolkit.org'){define._amd = define.amd;delete define.amd;}}";}]]></xp:this.contents>
</xp:script>
<xp:script src="jslib/jszip.js" clientSide="true"></xp:script>
<xp:script src="jslib/jszip-utils.js" clientSide="true"></xp:script>
...
<!-- restore define.amd object (Dojo AMD loader) -->
<xp:script clientSide="true">
<xp:this.contents><![CDATA[${javascript:"if (typeof define === 'function' && define._amd) {define.amd = define._amd; delete define._amd;}"}]]></xp:this.contents>
</xp:script>
</xp:this.resources>
...
When you look at firebug in your web page, you most likely will see 404 for the JavaScript. You need to either add them as script libraries into xpages and use the xpages script tag with the client attribute or you add them to the web-inf directory and load them using your script tags. You still will need an client side event to trigger them.
Just refer the below java script in your html page.
<script src="http://kendo.cdn.telerik.com/2016.1.112/js/jszip.min.js"></script>
Related
In XPages I have enabled the "Use runtime optimized JS and CSS resources" but it raises and error:
inputmask is not a function.
I have loaded the script as followed:
<xp:this.resources>
<xp:script
src="/inputmask/jquery.inputmask.bundle.js"
clientSide="true">
</xp:script>
</xp:this.resources>
It works fine when I have the XSP property disabled.
How can I solve this?
can you just add the library as a normal script reference? e.g.
<script src="inputmask/jquery.inputmask.bundle.js" type="text/javascript"></script>
then it will be loaded as a separate file
I would like to generate the name of the custom control in it's design definition property. how should i do that?
i tried:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel>
<%=this.pageName %>
</xp:panel>
</xp:view>
because this.getPageName() gives you the name of custom control name on custom control's main level.
but that does not work there.
After few tests it seems you can read only custom properties.
Because you write design definition to some specific custom control, you can use:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel>
My control name
</xp:panel>
</xp:view>
I am aware of harder maintainability with copypasta coding style.
I am starting to get the dynamic nature of Xpages and am trying to make my coding more streamlined.
I am using the switchFacet cc in my xpages to control which custom control to load, depending on the value in a sessionScope variable.
To keep things simple I made the name of the cc match the sessionScope variable. So I ended up with the following code.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlnsstrong text:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xc:ccAppLayout>
<xp:this.facets>
<xc:ccAppNav xp:key="LeftColumn" />
<xe:switchFacet id="switchFacet1" xp:key="facet_1"
selectedFacet="#{javascript:return sessionScope.pageSelected}">
<xp:this.facets>
<xc:cpApp2Title1Page1 xp:key="cpApp2Title1Page1" />
<xc:cpApp2Title2Page1 xp:key="cpApp2Title2Page1" />
<xc:cpApp2Title2Page2 xp:key="cpApp2Title2Page2" />
<xc:cpApp2Title3Page1 xp:key="cpApp2Title3Page1" />
</xp:this.facets>
</xe:switchFacet>
</xp:this.facets>
</xc:ccAppLayout>
</xp:view>
Not to bad, but it seems to me things would be even cleaner if I could just directly set the cc to be the sessionScope variable. That way the code for this Xpage wouldn't have to change between different Xpages. I could get by with just one Xpage.
Is there a way to do this, and is it even a good idea?
Bryan
===============================================
What I am looking for is something like this:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlnsstrong text:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xc:ccAppLayout>
<xp:this.facets>
<xc:ccAppNav xp:key="LeftColumn" />
<xc:#{javascript:return sessionScope.pageSelected} xp:key="facet_1"></xc:#{javascript:return sessionScope.pageSelected}>
</xp:this.facets>
</xc:ccAppLayout>
</xp:view>
==============================================================
Knut,
That is a good suggestion, but as you indicated it only loads on page creation.
Is there a different way to do what I want, or is it just easier to leave the code as I originally had it?
<?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:ccAppLayout>
<xp:this.facets>
<xc:ccAppNav xp:key="LeftColumn" />
<xp:include id="include1" xp:key="facet_1">
<xp:this.pageName><![CDATA[${javascript:sessionScope.pageSelected + ".xsp"}]]></xp:this.pageName>
</xp:include></xp:this.facets>
</xc:ccAppLayout>
</xp:view>
You can use <xp:include... and "calculate" custom control's name:
<xp:include pageName="${sessionScope.yourCC}" />
The sessionScope variable has to contain the name of your custom control like "cpApp2Title1Page1.xsp". Don't forget ".xsp" at the end.
Be aware that pageName gets calculated only once at first page load.
I know from your previous question that you'd like to keep the possible pages flexible in a sessionScope variable. Assuming you have a sessionScope variable pages which contains all custom control names as an array then you'd use a repeat and put the xp:include in it:
<xp:repeat
id="repeat1"
rows="30"
var="key"
repeatControls="true"
value="${sessionScope.pages}">
<xp:panel
rendered="#{javascript:sessionScope.pageSelected == key}">
<xp:include
pageName="${javascript:key + '.xsp'}" />
</xp:panel>
</xp:repeat>
It will include all pages defined in sessionScope variable pages but render only the one page with the name contained in sessionScope variable pageSelected.
You'd include the code above instead your switchFacet.
Could you create one custom control to rule them all? A CC that takes the name of the desired CC as a custom property, then renders only the one you want. So shove the switchFacet into a new custom control, e.g. ccAll.xsp:
<?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">
<xe:switchFacet id="switchFacet1" selectedFacet="#{javascript:return compositeData.ccName}">
<xp:this.facets>
<xc:cc1 xp:key="cc1" />
<xc:cc2 xp:key="cc2" />
<xc:cc3 xp:key="cc3" />
</xp:this.facets>
</xe:switchFacet>
</xp:view>
Add a custom property of ccName to the custom control using the "property definition" tab in the CC's properties.
Then add that to your XPage and pass in the sessionScope variable.
<xc:ccAll ccName="#{javascript:return sessionScope.pageSelected}"></xc:ccAll>
A while ago I have created a component to switch custom controls on-the-fly. The code is available at github:
https://github.com/hasselbach/domino-ccinjector
The component can inject custom components whenever you want: during a partial refresh or depending on a variable.
Ok, I have two custom controls:
MainLayout: Contains an Application Layout control (from the Domino extension library)
Section1: Contains a section with a header and a few items
Now I create a new XPage, and drag the MainLayout control on it.
Now I want to drag Section1 to the page, and connect it to LeftColumn area of the MainLayout... which seems like something trivial, but I can't get it to work for some reason.
When I drag the section1 control to the leftColumn area, the component is always getting inserted at the top of the page. The little pencil-icon next to "LeftColumn" seems decoration-only to me, because no matter if you left-click or right-click on it, nothing happens...
How is this supposed to work?
Update:
This how my xpage looks like after adding the MainLayout control:
<?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="/custom.css"></xp:styleSheet>
</xp:this.resources>
<xc:MainLayout></xc:MainLayout>
</xp:view>
XML of the MainLayout custom component:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xe:applicationLayout id="applicationLayout1">
<xe:this.configuration>
<xe:oneuiApplication titleBarName="Test"
placeBarName="Server1" legalText="YadaYada">
<xe:this.footerLinks>
<xe:userTreeNode label="User 1"></xe:userTreeNode>
</xe:this.footerLinks>
<xe:this.bannerUtilityLinks>
<xe:loginTreeNode label="Login 1"></xe:loginTreeNode>
</xe:this.bannerUtilityLinks>
<xe:this.placeBarActions>
<xe:basicContainerNode label="Select server">
<xe:this.children>
<xe:basicLeafNode label="Server1"></xe:basicLeafNode>
</xe:this.children>
</xe:basicContainerNode>
</xe:this.placeBarActions>
</xe:oneuiApplication>
</xe:this.configuration>
</xe:applicationLayout>
</xp:view>
I also have a custom where i use the application layout.
in my custom control I have above the configuration tag the following code
And in my XPage which use my custom layout I referer to my LeftColumn editable area by the following code
I would like to add styling to the body tag, currently I end up with this code:
<body class="xspView tundra">
<div style="margin: 0px">
but I would like to achieve this:
<body class="xspView tundra" style="margin: 0px">
Is this possible without removing existing functionality (i.e. without removing dojo and default xpages functionality)?
Yes you can,
if you have for example one xpage called 'home'. You can add your style definitions to the tag in the xpage. For instance:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" styleClass="ddd" style="margin: 20px;">
// your content goes here
</xp:view>
If you have a multiple xpage design and you dont want to add these lines of code to every xpage you could use Themes to automaticaly add the styles to the body tag:
<control override="false">
<name>ViewRoot</name>
<property mode="concat">
<name>styleClass</name>
<value>xspView tundra</value>
</property>
<property mode="concat">
<name>style</name>
<value>margin: 20px</value>
</property>
</control>
You don't have to use a theme to add a style to the XPages body tag. You can do it right on the Page itself under the style property. The source looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
styleClass="myBodyStyle">
</xp:view>
Which renders to the browser as:
<body class="myBodyStyle">
Add a css file that has a BODY entry. Put your margin there. Add the css to a theme if u want to use it globally
Why don't you do it in a css file? Include this:
body {
margin: 0px;
}
Just like any HTML styling...
Or, maybe I don't exactly understand what do you mean...