File Upload og File Download Controls

1363487986_note_uploadFile Upload virker som den skal – undtagen hvis den indsættes i en Extension Library Dialog. Men der findes en work-around som er beskrevet i denne artikel: “File Upload XPage Forms via OpenNTF.org Extension Library Dialogs” – eller i denne video.

File Download skal styles en del førend den kan bruges – det har Ferry Kranenburg fundet en løsning på.

Upload kontrollen skal se således ud:

<xp:fileDownload rows="30" id="fileDownload1"
	displayLastModified="false" displayType="true" allowDelete="false"
	hideWhen="true" value="#{document1.body}" createdTitle="upload datum"
	sizeTitle="grootte" displayCreated="false" displaySize="false"
	style="width:450.0px;text-align:left;font-size:9pt;" disabled="false"
	columnClasses="fdownload_typeClass,fdownload_fileClass,fdownload_sizeClass,"
	var="rowFile" indexVar="rowIndex">
	<xp:this.fileNameValue><![CDATA[#{javascript:var aSizes:Array = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB'];
var calcnr:Number = Math.floor(Math.log(rowFile.getLength())/Math.log(1024));
var fSize = (rowFile.getLength()/Math.pow(1024, Math.floor(calcnr))).toFixed(2)+" "+aSizes[calcnr];
rowFile.getName() + " (" + fSize + ")"}]]>
	</xp:this.fileNameValue>
</xp:fileDownload>

herefter kan resten klares med CSS:

.xspDataTableFileDownload {
	border-collapse: none;
}

.xspDataTableFileDownload TBODY TR TD {
	border: none;
	padding-right: 0px;
}

.xspDataTableFileDownload THEAD {
	display: none;
}

.fdownload_typeClass {
	width: 0px;
}

.fdownload_typeClass .xspTextComputedField {
	display: none;
	padding-right: 0px;
}

.fdownload_fileClass {

}

.fdownload_sizeClass {
	color: #D3056E;
}

Problemer med ‘See attached file” referencer i RichText?

Det er der fundet en løsning på her:

Kort fortalt så kan det fjernes med  lille javascript funktion der laver søg og erstat:

function replaceSeeAttached(the_id) {
	//var the_id = "entryBody";
	h=getComponent(the_id).getValue().toString();
	h=h.replace(/\<i class=\"domino-attachment-ref\"\>\(.*\:\s(.+?)\)\<\/i\>/g,
	"");
	getComponent(the_id).setValue(h);
}
Koden kan kaldes ‘afterPageLoad’
<xp:this.afterPageLoad>
	<![CDATA[#{javascript:replaceSeeAttached( "body" );}]]>
</xp:this.afterPageLoad>

Kopier tekst til klippebordet med ZeroClipboard

16290425_sZeroClipboard benytter en skjult flash fil som ‘motor’ – dermed er det lykkedes at lave en funktion der virker i alle browsere.

Step 1: Importer ZeroClipboard script og flash filen som fileressources. Bemærk at ZeroClipboard fra version 1.1.0 ikke længere virker sammen med Dojo. Benyt i stedet en tidligere version, f.eks. ZeroClipboard-1.0.7

Step 2: Lav din XPage

Først skal javascript filen inkluderes

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

Så skal ZeroClipboard loades og initialiseres i en Script block

<xp:scriptBlock id="scriptBlock">
	<xp:this.value><![CDATA[
var clip = null;

dojo.addOnLoad( function() {
	clip = new ZeroClipboard.Client();
	clip.setHandCursor( true );
          clip.setText( "#{javascript:'Some SSJS to generate the text to copy'}" );
          clip.glue( "#{id:clip_button}" );
	});
]]></xp:this.value>
</xp:scriptBlock>

Tilsidst indsætter du en ‘copy’ knap

<xp:button value="Copy" id="clip_button">
	<xp:eventHandler event="onmouseover" submit="false">
		<xp:this.script><![CDATA[clip.reposition();]]></xp:this.script>
	</xp:eventHandler>
</xp:button>

ZeroClipboard lægger en skjult (transparrent) flash fil hen over din copy knap (det gøres med clip.glue metoden). Hvis siden resizes eller der på anden vise flyttes rundt på side elementer, så kan det ske at flash objektet ikke længere matcher knapper . Dette klares ved at kalde clip.reposition fra en onmouseover event. (hvis flash objektet ligger korrekt, så kaldes knappens events ikke)

Bemærk: Version 1.07 kan også give problemer med Dojo. F.eks. fik jeg ikke umiddelbart DialogBoxen fra Extension Library til at virke sammen med ZeroClipboard. Kunne dog nemt løses ved kun at vise ‘Copy’ knappen i Read mode og dialogboksen i Edit mode.

Links

Brug af properties filer og flersprogsdatabaser

15639432_sHvis du har en tekst eller indstilling du ænsker at bruge på tværs af flere XPages, så kan du med fordel gemme teksten i en .properties fil.

Step 1: Opret en .properties fil

Gemmes under ‘Resources\Files’ – skal have extension .properties, kald den f.eks. messages.properties

properties

Step 2: Inkludér filen via dit theme

<!-- From: http://www.dominoguru.com/pages/ibm_xpages_resource_bundle_datasources.html -->
<resources>
    <bundle
        target="xsp"
        src="messages.properties"
        var="messages"
        loaded="true"
        rendered="true" />
</resources>

src angiver filnavnet og var definerer hvilket navn du efterfølgende vil bruge i JavaScript

Step 3: Læs værdier med JavaScript

Herefter kan du nemt læse værdier fra filen – her er vist et eksempel hvor værdien indlæses i et computet field:

<xp:text escape="true" id="computedField1">
	<xp:this.value><![CDATA[#{javascript:messages['LegalText'];}]]></xp:this.value>
</xp:text>

Links

Dynamisk Dropdown menu med Bootstrap

Med Twitter Bootstrap kan man nemt lave en dynamisk dropdown menu i flere niveauerdropdown

Menuen er lavet som en Twitter Basic navbar. Til at beregne menuen automatisk benyttes en managed bean. Nedenfor ses noget at koden – bemærk at html koden er tweaket lidt for at få menuen til at åbne ‘OnMouserOver’ i stedet for ‘OnClick’ som er standarden foir Twitter Menuen. Bl.a. er class=\”dropdown-toggle\” data-toggle=\”dropdown\” fjernet og der der tilføjet en class=”cascading” til sub menuerne

/* Creates LI elements */
private String GetHtmlFromDocument( Document doc, int level ) {
	String html = "";
	try {
		if ( IsLinkSupportedOnWeb( doc )) {
			html += "<li class=\"dropdown\">";
			html += "<a  href=\""+GetUrlFromDocument( doc )+"\" target=\"_blank\">" + doc.getItemValueString("Subject"); //class=\"dropdown-toggle\" data-toggle=\"dropdown\"
			html += "</a>";
			html += GetHtmlFromResponses( doc.getResponses(), level+1);
			html += "</li>";
		}
		
	} catch (NotesException e1) {
		e1.printStackTrace();
	}
	return html;
}

/* Creates the UL element */
private String GetHtmlFromResponses( DocumentCollection coll, int level ) {
	Document doc;
	String html="";
	
	if (coll==null) return "";
	if(level==0){
		// top navigator
		html += "<ul class=\"nav\">";
	} else if (level==1) {
		// immediate dropdown menu
		html += "<ul class=\"dropdown-menu\" role=\"menu\" >";
	} else {
		// sub dropdown menu
		html += "<ul class=\"dropdown-menu cascading\" role=\"menu\" >";
	}
	
	try {
		doc = coll.getFirstDocument();
		if (doc==null) return "";
		
		while (doc!=null) {
			html += GetHtmlFromDocument( doc, level );
			doc = coll.getNextDocument(doc);
		}
	}
	catch (NotesException e) {
		e.printStackTrace();
	}
	
	html += "</ul>";
	return html;
}

På en XPage kan menuen indsættes med dette kode:

		<div class="navbar">
			<div class="navbar-inner">
				<div class="container">
					<!-- All menu html is read by a managed bean -->
					<xp:text escape="false" value="#{javascript:Menu.getHtml('Top');}"></xp:text>
				</div>
			</div>
		</div><!-- /.navbar -->

MouseOver effekt og formatering af undermenuer klares med nogle få CSS tilføjelser

/* Show on hover: http://stackoverflow.com/questions/8878033/how-to-make-twitter-bootstrap-menu-dropdown-on-hover-rather-than-click */
ul.nav li.dropdown:hover>ul.dropdown-menu {
	display: block;
}

ul.dropdown-menu li:hover>ul {
	display: block;
}

.navbar .dropdown-menu {
	margin-top: 0px;
}

/* Cascading menu */
.cascading {
	position: absolute;
	top: 20px;
	left: 50px;
	z-index: top;
}

Links:

Quick search i views lavet med en Repeat Control

Views laves bedst med en Repeat Control – her får du meget mere fleksibilitet end med et view. Her vil jeg vise hvordan med laver Quick Search direkte i view’et. Nedenstående eksempel er i øvrigt lavet med Bootstrap – og viser hvordan Quick Search baren automatisk har selected alle de dokumenter der starter med ‘LA’

Løsningen består af 3 dele. Først er datakilden defineret – bemærk at jeg benytter en viewscope variable til at søge i viewet:

<xp:this.data>
	<xp:dominoView var="view1" viewName="CustomerLookup"
		keysExactMatch="false" keys="#{javascript:viewScope.quicksearch}">
	</xp:dominoView>
</xp:this.data>

Søgefeltet er et standard input felt – men benytter viewscope variable som datakilde og laver en partial refresh af mit ‘viewpanel’ (et alm. panel hvori jeg har min repeat control). Der laves et refresh efter hvert keypress:

<xp:inputText id="quicksearch" value="#{viewScope.quicksearch}">
	<xp:eventHandler event="onkeyup" submit="true"
		refreshMode="partial" refreshId="viewpanel">
	</xp:eventHandler>
</xp:inputText>

Tilsidst er der selve Repeat Controllen – den looper direkte på viewet og viser blot de 30 første linjer. Bemærk this.facets sektionen – her kan man defineret en header og footer som kun bliver vist én gang – og kun hvis der er data i viewet. Her er det brugt til at lave en table header.

<xp:panel id="viewpanel">
	<xp:repeat id="repeat" rows="30" var="viewentry"
		value="#{view1}" removeRepeat="true">
		<xp:this.facets>
			<!-- Header -->
			<xp:text disableTheme="true" xp:key="header" escape="false">
				<xp:this.value><![CDATA[#{javascript:'<table class="table table-striped"><thead><tr><th>Firma</th><th>Adresse</th><th>Telefon</th></tr></thead><tbody> '}]]></xp:this.value>
			</xp:text>

			<!-- Footer -->
			<xp:text disableTheme="true" xp:key="footer" escape="false">
				<xp:this.value><![CDATA[#{javascript:'</tbody></table>'}]]></xp:this.value>
			</xp:text>
		</xp:this.facets>

		<!-- Repeated rows -->
		<tr>
			<td>
				<i class="viewicon-069"></i>
				<xp:text escape="false" disableTheme="true">
					<xp:this.value><![CDATA[#{javascript:viewentry.getColumnValue("Firma")}]]></xp:this.value>
				</xp:text>
			</td>
			<td>
				<xp:text escape="false" disableTheme="true">
					<xp:this.value><![CDATA[#{javascript:viewentry.getColumnValue("Adresse")}]]></xp:this.value>
				</xp:text>

Links